Skip to content

Commit b472529

Browse files
committed
tests: fs_windows: add Windows tests to reflect improved delete behavior
- Update delete tests to expect success with auto-cleanup - Change tests to verify proper resource cleanup (unmap and close) - Update test comments to reflect new expected behavior - Use public APIs (cio_chunk_is_up) for state verification instead of directly accessing native functions Signed-off-by: Eduardo Silva <[email protected]>
1 parent 89ac0ba commit b472529

File tree

1 file changed

+85
-95
lines changed

1 file changed

+85
-95
lines changed

tests/fs_windows.c

Lines changed: 85 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
#include <chunkio/cio_stream.h>
4949
#include <chunkio/cio_chunk.h>
5050

51+
/* Note: We still need to include cio_file_native.h for testing native functions
52+
* directly to verify bug fixes, but we use public APIs for state checks */
53+
5154
#include "cio_tests_internal.h"
5255

5356
#define CIO_ENV "tmp"
@@ -66,8 +69,8 @@ static int log_cb(struct cio_ctx *ctx, int level, const char *file, int line,
6669
/*
6770
* ISSUE #1: Test deleting a file that is open/mapped
6871
*
69-
* Expected behavior: Should fail with CIO_ERROR (as Unix does)
70-
* Current behavior: Succeeds and may cause resource leaks
72+
* Expected behavior: Delete should succeed after automatically releasing
73+
* any outstanding mappings and handles.
7174
*/
7275
static void test_win32_delete_while_open()
7376
{
@@ -101,20 +104,16 @@ static void test_win32_delete_while_open()
101104
cf = (struct cio_file *) chunk->backend;
102105
TEST_CHECK(cf != NULL);
103106

104-
/* Verify file is open */
105-
TEST_CHECK(cio_file_native_is_open(cf) == 1);
107+
/* Verify file is open (using public API) */
108+
TEST_CHECK(cio_chunk_is_up(chunk) == CIO_TRUE);
106109

107-
/* Try to delete while open - THIS SHOULD FAIL but currently doesn't on Windows */
110+
/* Delete while open - should succeed and close resources automatically */
108111
ret = cio_file_native_delete(cf);
109-
printf("Result of delete while open: %d (expected: CIO_ERROR=%d)\n",
110-
ret, CIO_ERROR);
111-
112-
/* On Unix this returns CIO_ERROR, on Windows it currently succeeds */
113-
/* This TEST_CHECK will FAIL in CI, highlighting the inconsistency */
114-
TEST_CHECK(ret == CIO_ERROR);
115-
if (ret != CIO_ERROR) {
116-
printf("ISSUE DETECTED: Delete succeeded while file is open (inconsistent with Unix)\n");
117-
}
112+
printf("Result of delete while open: %d (expected: CIO_OK=%d)\n",
113+
ret, CIO_OK);
114+
TEST_CHECK(ret == CIO_OK);
115+
TEST_CHECK(cio_file_native_is_open(cf) == CIO_FALSE);
116+
TEST_CHECK(cio_file_native_is_mapped(cf) == CIO_FALSE);
118117

119118
cio_chunk_close(chunk, CIO_FALSE);
120119
cio_stream_delete(stream);
@@ -124,8 +123,8 @@ static void test_win32_delete_while_open()
124123
/*
125124
* ISSUE #2: Test deleting a file that is mapped
126125
*
127-
* Expected behavior: Should fail with CIO_ERROR (as Unix does)
128-
* Current behavior: Succeeds and may cause crashes
126+
* Expected behavior: Delete should succeed after the implementation releases
127+
* the mapping safely.
129128
*/
130129
static void test_win32_delete_while_mapped()
131130
{
@@ -163,21 +162,16 @@ static void test_win32_delete_while_mapped()
163162
ret = cio_chunk_write(chunk, "test data", 9);
164163
TEST_CHECK(ret == 0);
165164

166-
/* Verify file is mapped */
167-
TEST_CHECK(cio_file_native_is_mapped(cf) == 1);
165+
/* Verify file is mapped (using public API) */
166+
TEST_CHECK(cio_chunk_is_up(chunk) == CIO_TRUE);
168167

169-
/* Try to delete while mapped - THIS SHOULD FAIL but currently doesn't on Windows */
168+
/* Delete while mapped - should succeed and release mapping */
170169
ret = cio_file_native_delete(cf);
171-
printf("Result of delete while mapped: %d (expected: CIO_ERROR=%d)\n",
172-
ret, CIO_ERROR);
173-
174-
/* On Unix this returns CIO_ERROR, on Windows it currently succeeds */
175-
/* This TEST_CHECK will FAIL in CI, highlighting the inconsistency */
176-
TEST_CHECK(ret == CIO_ERROR);
177-
if (ret != CIO_ERROR) {
178-
printf("ISSUE DETECTED: Delete succeeded while file is mapped (inconsistent with Unix)\n");
179-
printf("WARNING: This can cause crashes when accessing the mapped memory\n");
180-
}
170+
printf("Result of delete while mapped: %d (expected: CIO_OK=%d)\n",
171+
ret, CIO_OK);
172+
TEST_CHECK(ret == CIO_OK);
173+
TEST_CHECK(cio_file_native_is_open(cf) == CIO_FALSE);
174+
TEST_CHECK(cio_file_native_is_mapped(cf) == CIO_FALSE);
181175

182176
cio_chunk_close(chunk, CIO_FALSE);
183177
cio_stream_delete(stream);
@@ -222,41 +216,30 @@ static void test_win32_sync_without_map()
222216
cf = (struct cio_file *) chunk->backend;
223217
TEST_CHECK(cf != NULL);
224218

225-
/* Manually unmap if it was auto-mapped */
226-
if (cio_file_native_is_mapped(cf)) {
227-
ret = cio_file_native_unmap(cf);
228-
TEST_CHECK(ret == CIO_OK);
219+
/* Manually unmap if it was auto-mapped (using public API) */
220+
if (cio_chunk_is_up(chunk) == CIO_TRUE) {
221+
ret = cio_file_down(chunk);
222+
TEST_CHECK(ret == 0);
229223
}
230224

231-
/* Verify file is not mapped */
232-
TEST_CHECK(cio_file_native_is_mapped(cf) == 0);
233-
234-
/* Verify cf->map is actually NULL (this is the issue) */
235-
TEST_CHECK(cf->map == NULL);
236-
printf("Verified: cf->map is NULL\n");
237-
238-
/* Try to sync without mapping - THIS SHOULD CHECK FIRST */
239-
/* On Windows, cio_file_native_sync accesses cf->map directly without checking */
240-
/* This will likely cause a crash or access violation because FlushViewOfFile
241-
* is called with a NULL pointer */
242-
printf("Attempting sync on unmapped file (cf->map is NULL)...\n");
243-
printf("WARNING: cio_file_native_sync will call FlushViewOfFile(cf->map, ...)\n");
244-
printf(" which will fail or crash if cf->map is NULL\n");
245-
246-
/* This test is designed to highlight the issue - on Windows it may crash */
247-
/* On Windows, cio_file_native_sync accesses cf->map without checking if NULL */
248-
/* This TEST_CHECK will FAIL in CI if sync succeeds or crashes, highlighting the issue */
249-
/* Note: If it crashes, the test will fail anyway */
250-
ret = cio_file_native_sync(cf, 0);
251-
printf("Result of sync without map: %d (expected: CIO_ERROR=%d)\n", ret, CIO_ERROR);
252-
253-
/* Expected: CIO_ERROR due to NULL map pointer */
254-
/* This TEST_CHECK will FAIL in CI, highlighting the inconsistency */
255-
TEST_CHECK(ret == CIO_ERROR);
256-
if (ret != CIO_ERROR) {
257-
printf("ISSUE DETECTED: Sync succeeded with NULL map pointer (inconsistent behavior)\n");
258-
printf("Expected: CIO_ERROR due to NULL map pointer\n");
259-
}
225+
/* Verify file is not mapped (using public API) */
226+
TEST_CHECK(cio_chunk_is_up(chunk) == CIO_FALSE);
227+
printf("Verified: chunk is down (not mapped)\n");
228+
229+
/* Set synced flag to FALSE to force sync path (since cio_file_down syncs before unmapping) */
230+
cf->synced = CIO_FALSE;
231+
232+
/* Try to sync without mapping using public API */
233+
/* cio_file_sync should auto-remap and emit a warning */
234+
printf("Attempting sync on unmapped file using cio_file_sync()...\n");
235+
printf("cio_file_sync() should remap and warn instead of failing\n");
236+
237+
ret = cio_file_sync(chunk);
238+
printf("Result of sync without map: %d (expected: 0 for success with warning)\n", ret);
239+
240+
TEST_CHECK(ret == 0);
241+
TEST_CHECK(cio_chunk_is_up(chunk) == CIO_FALSE);
242+
TEST_CHECK(cio_file_native_is_open(cf) == CIO_FALSE);
260243

261244
cio_chunk_close(chunk, CIO_FALSE);
262245
cio_stream_delete(stream);
@@ -326,40 +309,58 @@ static void test_win32_map_size_mismatch()
326309
cf = (struct cio_file *) chunk->backend;
327310
TEST_CHECK(cf != NULL);
328311

312+
/* Unmap if cio_chunk_open auto-mapped the file (using public API) */
313+
if (cio_chunk_is_up(chunk) == CIO_TRUE) {
314+
ret = cio_file_down(chunk);
315+
TEST_CHECK(ret == 0);
316+
}
317+
318+
/* Ensure file is still open */
319+
if (!cio_file_native_is_open(cf)) {
320+
ret = cio_file_native_open(cf);
321+
TEST_CHECK(ret == CIO_OK);
322+
}
323+
329324
/* Try to map with a size larger than the file */
330325
map_size = file_size + 4096; /* Request 4KB more than file size */
331326
printf("Attempting to map %zu bytes (file is %zu bytes)\n", map_size, file_size);
332327

333-
/* Open file */
334-
ret = cio_file_native_open(cf);
335-
TEST_CHECK(ret == CIO_OK);
336-
337328
/* This is where the issue occurs: CreateFileMapping uses current file size (0,0),
338329
* but MapViewOfFile tries to map a larger size */
339330
ret = cio_file_native_map(cf, map_size);
340331
printf("Result of mapping %zu bytes to %zu byte file: %d\n",
341332
map_size, file_size, ret);
342333

343-
/* The issue: CreateFileMapping is called with (0, 0) which uses file size,
344-
* but MapViewOfFile requests map_size. This mismatch can cause issues.
345-
* If mapping succeeds, alloc_size should match map_size, not file_size */
334+
/* For read-only files, mapping beyond file size is not possible on Windows.
335+
* The mapping should be limited to file_size, and alloc_size should reflect
336+
* the actual mapped size (file_size), not the requested size (map_size).
337+
* This ensures consistency between CreateFileMappingA and MapViewOfFile sizes. */
346338
if (ret == CIO_OK) {
347-
printf("WARNING: Mapping succeeded with size mismatch\n");
348-
printf("Expected alloc_size: %zu (map_size), file_size: %zu\n", map_size, file_size);
339+
printf("Mapping succeeded\n");
340+
printf("Requested map_size: %zu, file_size: %zu\n", map_size, file_size);
349341

350-
/* Verify what was actually mapped - this may expose the issue */
351-
if (cio_file_native_is_mapped(cf)) {
342+
/* Verify what was actually mapped (using public API) */
343+
if (cio_chunk_is_up(chunk) == CIO_TRUE) {
352344
printf("File is mapped, alloc_size: %zu\n", cf->alloc_size);
353-
/* This TEST_CHECK will highlight if alloc_size doesn't match requested map_size */
354-
/* Due to the bug, it may match file_size instead of map_size */
355-
TEST_CHECK(cf->alloc_size == map_size);
345+
346+
/* For read-only files, alloc_size should match file_size (the actual mapped size),
347+
* not the requested map_size (which exceeds file size) */
348+
/* This ensures consistency: CreateFileMappingA and MapViewOfFile both use actual_map_size */
349+
TEST_CHECK(cf->alloc_size == file_size);
350+
351+
if (cf->alloc_size != file_size) {
352+
printf("ISSUE DETECTED: alloc_size (%zu) doesn't match file_size (%zu)\n",
353+
cf->alloc_size, file_size);
354+
printf("For read-only files, mapping is limited to file_size\n");
355+
}
356356
}
357357

358358
ret = cio_file_native_unmap(cf);
359359
TEST_CHECK(ret == CIO_OK);
360360
}
361361
else {
362-
printf("Mapping failed when size mismatch occurs (may be correct behavior)\n");
362+
printf("Mapping failed when size mismatch occurs\n");
363+
/* For read-only files, this might be expected if map_size > file_size */
363364
}
364365

365366
cio_file_native_close(cf);
@@ -405,26 +406,15 @@ static void test_win32_fd_check_inconsistency()
405406
cf = (struct cio_file *) chunk->backend;
406407
TEST_CHECK(cf != NULL);
407408

408-
/* Verify file is open using the proper macro */
409-
ret = cio_file_native_is_open(cf);
410-
TEST_CHECK(ret == 1);
411-
printf("cio_file_native_is_open(cf): %d\n", ret);
412-
413-
/* Check cf->fd value on Windows (should be -1 or not set properly) */
414-
printf("cf->fd value: %d\n", cf->fd);
415-
printf("cf->fd > 0 check: %d\n", (cf->fd > 0));
416-
printf("cio_file_native_is_open(cf): %d\n", cio_file_native_is_open(cf));
409+
/* Verify file is open (using public API) */
410+
ret = cio_chunk_is_up(chunk);
411+
TEST_CHECK(ret == CIO_TRUE);
412+
printf("cio_chunk_is_up(chunk): %d\n", ret);
417413

418-
/* This highlights that cf->fd > 0 doesn't work on Windows */
414+
/* Check cf->fd value on Windows (internal check for documentation) */
419415
/* On Windows, cf->fd is typically -1, but the file is still open via backing_file */
420-
/* This TEST_CHECK will FAIL in CI, highlighting the inconsistency */
421-
/* cio_file.c line 804 uses cf->fd > 0 which is Unix-specific and doesn't work on Windows */
422-
TEST_CHECK((cf->fd > 0) == cio_file_native_is_open(cf));
423-
if ((cf->fd > 0) != cio_file_native_is_open(cf)) {
424-
printf("ISSUE DETECTED: cf->fd check (%d) doesn't match cio_file_native_is_open (%d)\n",
425-
(cf->fd > 0), cio_file_native_is_open(cf));
426-
printf("WARNING: cio_file.c line 804 uses cf->fd > 0 which is Unix-specific\n");
427-
}
416+
printf("cf->fd value: %d (internal, not used on Windows)\n", cf->fd);
417+
printf("Note: cio_file.c now uses cio_file_native_is_open() instead of cf->fd > 0\n");
428418

429419
cio_chunk_close(chunk, CIO_FALSE);
430420
cio_stream_delete(stream);

0 commit comments

Comments
 (0)