diff options
author | Christopher Haster <geky@geky.net> | 2023-04-26 21:47:58 +0300 |
---|---|---|
committer | Christopher Haster <geky@geky.net> | 2023-04-26 21:47:58 +0300 |
commit | b6773e68bf3f6377df3c555678acd636b0695a05 (patch) | |
tree | 603a62a2307af6155eaa5426d1d023f96e9d84c8 /tests | |
parent | b33a5b3f856db91e556bc13ad4b7a6c86f75e892 (diff) | |
parent | 92298c749d868cbc248f00eabd644e5b08e0c8df (diff) |
Merge remote-tracking branch 'origin/devel' into fix-dir-seek-endfix-dir-seek-end
Diffstat (limited to 'tests')
-rw-r--r-- | tests/test_alloc.toml | 292 | ||||
-rw-r--r-- | tests/test_attrs.toml | 50 | ||||
-rw-r--r-- | tests/test_badblocks.toml | 171 | ||||
-rw-r--r-- | tests/test_bd.toml | 248 | ||||
-rw-r--r-- | tests/test_compat.toml | 1360 | ||||
-rw-r--r-- | tests/test_dirs.toml | 280 | ||||
-rw-r--r-- | tests/test_entries.toml | 87 | ||||
-rw-r--r-- | tests/test_evil.toml | 116 | ||||
-rw-r--r-- | tests/test_exhaustion.toml | 274 | ||||
-rw-r--r-- | tests/test_files.toml | 262 | ||||
-rw-r--r-- | tests/test_interspersed.toml | 72 | ||||
-rw-r--r-- | tests/test_move.toml | 458 | ||||
-rw-r--r-- | tests/test_orphans.toml | 65 | ||||
-rw-r--r-- | tests/test_paths.toml | 121 | ||||
-rw-r--r-- | tests/test_powerloss.toml | 182 | ||||
-rw-r--r-- | tests/test_relocations.toml | 174 | ||||
-rw-r--r-- | tests/test_seek.toml | 97 | ||||
-rw-r--r-- | tests/test_superblocks.toml | 86 | ||||
-rw-r--r-- | tests/test_truncate.toml | 154 |
19 files changed, 3469 insertions, 1080 deletions
diff --git a/tests/test_alloc.toml b/tests/test_alloc.toml index fa92da5..205efbb 100644 --- a/tests/test_alloc.toml +++ b/tests/test_alloc.toml @@ -1,27 +1,30 @@ # allocator tests # note for these to work there are a number constraints on the device geometry -if = 'LFS_BLOCK_CYCLES == -1' +if = 'BLOCK_CYCLES == -1' -[[case]] # parallel allocation test -define.FILES = 3 -define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' +# parallel allocation test +[cases.test_alloc_parallel] +defines.FILES = 3 +defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' code = ''' - const char *names[FILES] = {"bacon", "eggs", "pancakes"}; + const char *names[] = {"bacon", "eggs", "pancakes"}; lfs_file_t files[FILES]; - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "breakfast") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int n = 0; n < FILES; n++) { + char path[1024]; sprintf(path, "breakfast/%s", names[n]); lfs_file_open(&lfs, &files[n], path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; } for (int n = 0; n < FILES; n++) { - size = strlen(names[n]); + size_t size = strlen(names[n]); for (lfs_size_t i = 0; i < SIZE; i += size) { lfs_file_write(&lfs, &files[n], names[n], size) => size; } @@ -31,12 +34,15 @@ code = ''' } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int n = 0; n < FILES; n++) { + char path[1024]; sprintf(path, "breakfast/%s", names[n]); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - size = strlen(names[n]); + size_t size = strlen(names[n]); for (lfs_size_t i = 0; i < SIZE; i += size) { + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, size) => size; assert(memcmp(buffer, names[n], size) == 0); } @@ -45,23 +51,28 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # serial allocation test -define.FILES = 3 -define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' +# serial allocation test +[cases.test_alloc_serial] +defines.FILES = 3 +defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' code = ''' - const char *names[FILES] = {"bacon", "eggs", "pancakes"}; + const char *names[] = {"bacon", "eggs", "pancakes"}; - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "breakfast") => 0; lfs_unmount(&lfs) => 0; for (int n = 0; n < FILES; n++) { - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + char path[1024]; sprintf(path, "breakfast/%s", names[n]); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - size = strlen(names[n]); + size_t size = strlen(names[n]); + uint8_t buffer[1024]; memcpy(buffer, names[n], size); for (int i = 0; i < SIZE; i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; @@ -70,12 +81,15 @@ code = ''' lfs_unmount(&lfs) => 0; } - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int n = 0; n < FILES; n++) { + char path[1024]; sprintf(path, "breakfast/%s", names[n]); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - size = strlen(names[n]); + size_t size = strlen(names[n]); for (int i = 0; i < SIZE; i += size) { + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, size) => size; assert(memcmp(buffer, names[n], size) == 0); } @@ -84,29 +98,32 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # parallel allocation reuse test -define.FILES = 3 -define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' -define.CYCLES = [1, 10] +# parallel allocation reuse test +[cases.test_alloc_parallel_reuse] +defines.FILES = 3 +defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' +defines.CYCLES = [1, 10] code = ''' - const char *names[FILES] = {"bacon", "eggs", "pancakes"}; + const char *names[] = {"bacon", "eggs", "pancakes"}; lfs_file_t files[FILES]; - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; for (int c = 0; c < CYCLES; c++) { - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "breakfast") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int n = 0; n < FILES; n++) { + char path[1024]; sprintf(path, "breakfast/%s", names[n]); lfs_file_open(&lfs, &files[n], path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; } for (int n = 0; n < FILES; n++) { - size = strlen(names[n]); + size_t size = strlen(names[n]); for (int i = 0; i < SIZE; i += size) { lfs_file_write(&lfs, &files[n], names[n], size) => size; } @@ -116,12 +133,15 @@ code = ''' } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int n = 0; n < FILES; n++) { + char path[1024]; sprintf(path, "breakfast/%s", names[n]); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - size = strlen(names[n]); + size_t size = strlen(names[n]); for (int i = 0; i < SIZE; i += size) { + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, size) => size; assert(memcmp(buffer, names[n], size) == 0); } @@ -129,8 +149,9 @@ code = ''' } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int n = 0; n < FILES; n++) { + char path[1024]; sprintf(path, "breakfast/%s", names[n]); lfs_remove(&lfs, path) => 0; } @@ -139,26 +160,31 @@ code = ''' } ''' -[[case]] # serial allocation reuse test -define.FILES = 3 -define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' -define.CYCLES = [1, 10] +# serial allocation reuse test +[cases.test_alloc_serial_reuse] +defines.FILES = 3 +defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)' +defines.CYCLES = [1, 10] code = ''' - const char *names[FILES] = {"bacon", "eggs", "pancakes"}; + const char *names[] = {"bacon", "eggs", "pancakes"}; - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; for (int c = 0; c < CYCLES; c++) { - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "breakfast") => 0; lfs_unmount(&lfs) => 0; for (int n = 0; n < FILES; n++) { - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + char path[1024]; sprintf(path, "breakfast/%s", names[n]); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - size = strlen(names[n]); + size_t size = strlen(names[n]); + uint8_t buffer[1024]; memcpy(buffer, names[n], size); for (int i = 0; i < SIZE; i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; @@ -167,12 +193,15 @@ code = ''' lfs_unmount(&lfs) => 0; } - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int n = 0; n < FILES; n++) { + char path[1024]; sprintf(path, "breakfast/%s", names[n]); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; - size = strlen(names[n]); + size_t size = strlen(names[n]); for (int i = 0; i < SIZE; i += size) { + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, size) => size; assert(memcmp(buffer, names[n], size) == 0); } @@ -180,8 +209,9 @@ code = ''' } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int n = 0; n < FILES; n++) { + char path[1024]; sprintf(path, "breakfast/%s", names[n]); lfs_remove(&lfs, path) => 0; } @@ -190,12 +220,16 @@ code = ''' } ''' -[[case]] # exhaustion test +# exhaustion test +[cases.test_alloc_exhaustion] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); - size = strlen("exhaustion"); + size_t size = strlen("exhaustion"); + uint8_t buffer[1024]; memcpy(buffer, "exhaustion", size); lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_sync(&lfs, &file) => 0; @@ -216,7 +250,7 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); size = strlen("exhaustion"); lfs_file_size(&lfs, &file) => size; @@ -226,14 +260,18 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # exhaustion wraparound test -define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / 3)' +# exhaustion wraparound test +[cases.test_alloc_exhaustion_wraparound] +defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)' code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT); - size = strlen("buffering"); + size_t size = strlen("buffering"); + uint8_t buffer[1024]; memcpy(buffer, "buffering", size); for (int i = 0; i < SIZE; i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; @@ -263,7 +301,7 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); size = strlen("exhaustion"); lfs_file_size(&lfs, &file) => size; @@ -274,17 +312,22 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # dir exhaustion test +# dir exhaustion test +[cases.test_alloc_dir_exhaustion] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // find out max file size lfs_mkdir(&lfs, "exhaustiondir") => 0; - size = strlen("blahblahblahblah"); + size_t size = strlen("blahblahblahblah"); + uint8_t buffer[1024]; memcpy(buffer, "blahblahblahblah", size); + lfs_file_t file; lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); int count = 0; + int err; while (true) { err = lfs_file_write(&lfs, &file, buffer, size); if (err < 0) { @@ -323,17 +366,21 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # what if we have a bad block during an allocation scan? +# what if we have a bad block during an allocation scan? +[cases.test_alloc_bad_blocks] in = "lfs.c" -define.LFS_ERASE_CYCLES = 0xffffffff -define.LFS_BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_READERROR' +defines.ERASE_CYCLES = 0xffffffff +defines.BADBLOCK_BEHAVIOR = 'LFS_EMUBD_BADBLOCK_READERROR' code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // first fill to exhaustion to find available space + lfs_file_t file; lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; + uint8_t buffer[1024]; strcpy((char*)buffer, "waka"); - size = strlen("waka"); + size_t size = strlen("waka"); lfs_size_t filesize = 0; while (true) { lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); @@ -345,7 +392,7 @@ code = ''' } lfs_file_close(&lfs, &file) => 0; // now fill all but a couple of blocks of the filesystem with data - filesize -= 3*LFS_BLOCK_SIZE; + filesize -= 3*BLOCK_SIZE; lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; strcpy((char*)buffer, "waka"); size = strlen("waka"); @@ -358,11 +405,11 @@ code = ''' lfs_unmount(&lfs) => 0; // remount to force an alloc scan - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // but mark the head of our file as a "bad block", this is force our // scan to bail early - lfs_testbd_setwear(&cfg, fileblock, 0xffffffff) => 0; + lfs_emubd_setwear(cfg, fileblock, 0xffffffff) => 0; lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; strcpy((char*)buffer, "chomp"); size = strlen("chomp"); @@ -377,7 +424,7 @@ code = ''' // now reverse the "bad block" and try to write the file again until we // run out of space - lfs_testbd_setwear(&cfg, fileblock, 0) => 0; + lfs_emubd_setwear(cfg, fileblock, 0) => 0; lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; strcpy((char*)buffer, "chomp"); size = strlen("chomp"); @@ -393,7 +440,7 @@ code = ''' lfs_unmount(&lfs) => 0; // check that the disk isn't hurt - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "pacman", LFS_O_RDONLY) => 0; strcpy((char*)buffer, "waka"); size = strlen("waka"); @@ -411,24 +458,29 @@ code = ''' # on the geometry of the block device. But they are valuable. Eventually they # should be removed and replaced with generalized tests. -[[case]] # chained dir exhaustion test -define.LFS_BLOCK_SIZE = 512 -define.LFS_BLOCK_COUNT = 1024 -if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' +# chained dir exhaustion test +[cases.test_alloc_chained_dir_exhaustion] +if = 'BLOCK_SIZE == 512' +defines.BLOCK_COUNT = 1024 code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // find out max file size lfs_mkdir(&lfs, "exhaustiondir") => 0; for (int i = 0; i < 10; i++) { + char path[1024]; sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); lfs_mkdir(&lfs, path) => 0; } - size = strlen("blahblahblahblah"); + size_t size = strlen("blahblahblahblah"); + uint8_t buffer[1024]; memcpy(buffer, "blahblahblahblah", size); + lfs_file_t file; lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); int count = 0; + int err; while (true) { err = lfs_file_write(&lfs, &file, buffer, size); if (err < 0) { @@ -443,6 +495,7 @@ code = ''' lfs_remove(&lfs, "exhaustion") => 0; lfs_remove(&lfs, "exhaustiondir") => 0; for (int i = 0; i < 10; i++) { + char path[1024]; sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); lfs_remove(&lfs, path) => 0; } @@ -455,6 +508,7 @@ code = ''' lfs_file_sync(&lfs, &file) => 0; for (int i = 0; i < 10; i++) { + char path[1024]; sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); lfs_mkdir(&lfs, path) => 0; } @@ -482,27 +536,31 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # split dir test -define.LFS_BLOCK_SIZE = 512 -define.LFS_BLOCK_COUNT = 1024 -if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' +# split dir test +[cases.test_alloc_split_dir] +if = 'BLOCK_SIZE == 512' +defines.BLOCK_COUNT = 1024 code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // create one block hole for half a directory + lfs_file_t file; lfs_file_open(&lfs, &file, "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0; - for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { + for (lfs_size_t i = 0; i < cfg->block_size; i += 2) { + uint8_t buffer[1024]; memcpy(&buffer[i], "hi", 2); } - lfs_file_write(&lfs, &file, buffer, cfg.block_size) => cfg.block_size; + uint8_t buffer[1024]; + lfs_file_write(&lfs, &file, buffer, cfg->block_size) => cfg->block_size; lfs_file_close(&lfs, &file) => 0; lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); - size = strlen("blahblahblahblah"); + size_t size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < (cfg.block_count-4)*(cfg.block_size-8); + i < (cfg->block_count-4)*(cfg->block_size-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -510,7 +568,7 @@ code = ''' // remount to force reset of lookahead lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // open hole lfs_remove(&lfs, "bump") => 0; @@ -518,30 +576,33 @@ code = ''' lfs_mkdir(&lfs, "splitdir") => 0; lfs_file_open(&lfs, &file, "splitdir/bump", LFS_O_WRONLY | LFS_O_CREAT) => 0; - for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { + for (lfs_size_t i = 0; i < cfg->block_size; i += 2) { memcpy(&buffer[i], "hi", 2); } - lfs_file_write(&lfs, &file, buffer, 2*cfg.block_size) => LFS_ERR_NOSPC; + lfs_file_write(&lfs, &file, buffer, 2*cfg->block_size) => LFS_ERR_NOSPC; lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; ''' -[[case]] # outdated lookahead test -define.LFS_BLOCK_SIZE = 512 -define.LFS_BLOCK_COUNT = 1024 -if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' +# outdated lookahead test +[cases.test_alloc_outdated_lookahead] +if = 'BLOCK_SIZE == 512' +defines.BLOCK_COUNT = 1024 code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // fill completely with two files + lfs_file_t file; lfs_file_open(&lfs, &file, "exhaustion1", LFS_O_WRONLY | LFS_O_CREAT) => 0; - size = strlen("blahblahblahblah"); + size_t size = strlen("blahblahblahblah"); + uint8_t buffer[1024]; memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < ((cfg.block_count-2)/2)*(cfg.block_size-8); + i < ((cfg->block_count-2)/2)*(cfg->block_size-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -552,7 +613,7 @@ code = ''' size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); + i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -560,7 +621,7 @@ code = ''' // remount to force reset of lookahead lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // rewrite one file lfs_file_open(&lfs, &file, "exhaustion1", @@ -569,7 +630,7 @@ code = ''' size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < ((cfg.block_count-2)/2)*(cfg.block_size-8); + i < ((cfg->block_count-2)/2)*(cfg->block_size-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -583,7 +644,7 @@ code = ''' size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); + i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -592,21 +653,24 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # outdated lookahead and split dir test -define.LFS_BLOCK_SIZE = 512 -define.LFS_BLOCK_COUNT = 1024 -if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' +# outdated lookahead and split dir test +[cases.test_alloc_outdated_lookahead_split_dir] +if = 'BLOCK_SIZE == 512' +defines.BLOCK_COUNT = 1024 code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // fill completely with two files + lfs_file_t file; lfs_file_open(&lfs, &file, "exhaustion1", LFS_O_WRONLY | LFS_O_CREAT) => 0; - size = strlen("blahblahblahblah"); + size_t size = strlen("blahblahblahblah"); + uint8_t buffer[1024]; memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < ((cfg.block_count-2)/2)*(cfg.block_size-8); + i < ((cfg->block_count-2)/2)*(cfg->block_size-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -617,7 +681,7 @@ code = ''' size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); + i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -625,7 +689,7 @@ code = ''' // remount to force reset of lookahead lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // rewrite one file with a hole of one block lfs_file_open(&lfs, &file, "exhaustion1", @@ -634,7 +698,7 @@ code = ''' size = strlen("blahblahblahblah"); memcpy(buffer, "blahblahblahblah", size); for (lfs_size_t i = 0; - i < ((cfg.block_count-2)/2 - 1)*(cfg.block_size-8); + i < ((cfg->block_count-2)/2 - 1)*(cfg->block_size-8); i += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } diff --git a/tests/test_attrs.toml b/tests/test_attrs.toml index db8d0c7..3c69001 100644 --- a/tests/test_attrs.toml +++ b/tests/test_attrs.toml @@ -1,14 +1,17 @@ -[[case]] # set/get attribute +[cases.test_attrs_get_set] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "hello") => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs_file_close(&lfs, &file); lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + uint8_t buffer[1024]; memset(buffer, 0, sizeof(buffer)); lfs_setattr(&lfs, "hello", 'A', "aaaa", 4) => 0; lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0; @@ -60,7 +63,7 @@ code = ''' lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; memset(buffer, 0, sizeof(buffer)); lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9; @@ -76,17 +79,20 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # set/get root attribute +[cases.test_attrs_get_set_root] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "hello") => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs_file_close(&lfs, &file); lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + uint8_t buffer[1024]; memset(buffer, 0, sizeof(buffer)); lfs_setattr(&lfs, "/", 'A', "aaaa", 4) => 0; lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0; @@ -137,7 +143,7 @@ code = ''' lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; memset(buffer, 0, sizeof(buffer)); lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9; @@ -153,17 +159,20 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # set/get file attribute +[cases.test_attrs_get_set_file] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "hello") => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs_file_close(&lfs, &file); lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + uint8_t buffer[1024]; memset(buffer, 0, sizeof(buffer)); struct lfs_attr attrs1[] = { {'A', buffer, 4}, @@ -238,7 +247,7 @@ code = ''' lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; memset(buffer, 0, sizeof(buffer)); struct lfs_attr attrs3[] = { {'A', buffer, 4}, @@ -260,20 +269,23 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # deferred file attributes +[cases.test_attrs_deferred_file] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "hello") => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs_file_close(&lfs, &file); lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_setattr(&lfs, "hello/hello", 'B', "fffffffff", 9) => 0; lfs_setattr(&lfs, "hello/hello", 'C', "ccccc", 5) => 0; + uint8_t buffer[1024]; memset(buffer, 0, sizeof(buffer)); struct lfs_attr attrs1[] = { {'B', "gggg", 4}, diff --git a/tests/test_badblocks.toml b/tests/test_badblocks.toml index 06967a6..b50b393 100644 --- a/tests/test_badblocks.toml +++ b/tests/test_badblocks.toml @@ -1,28 +1,30 @@ # bad blocks with block cycles should be tested in test_relocations -if = 'LFS_BLOCK_CYCLES == -1' - -[[case]] # single bad blocks -define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster -define.LFS_ERASE_CYCLES = 0xffffffff -define.LFS_ERASE_VALUE = [0x00, 0xff, -1] -define.LFS_BADBLOCK_BEHAVIOR = [ - 'LFS_TESTBD_BADBLOCK_PROGERROR', - 'LFS_TESTBD_BADBLOCK_ERASEERROR', - 'LFS_TESTBD_BADBLOCK_READERROR', - 'LFS_TESTBD_BADBLOCK_PROGNOOP', - 'LFS_TESTBD_BADBLOCK_ERASENOOP', +if = '(int32_t)BLOCK_CYCLES == -1' + +[cases.test_badblocks_single] +defines.BLOCK_COUNT = 256 # small bd so test runs faster +defines.ERASE_CYCLES = 0xffffffff +defines.ERASE_VALUE = [0x00, 0xff, -1] +defines.BADBLOCK_BEHAVIOR = [ + 'LFS_EMUBD_BADBLOCK_PROGERROR', + 'LFS_EMUBD_BADBLOCK_ERASEERROR', + 'LFS_EMUBD_BADBLOCK_READERROR', + 'LFS_EMUBD_BADBLOCK_PROGNOOP', + 'LFS_EMUBD_BADBLOCK_ERASENOOP', ] -define.NAMEMULT = 64 -define.FILEMULT = 1 +defines.NAMEMULT = 64 +defines.FILEMULT = 1 code = ''' - for (lfs_block_t badblock = 2; badblock < LFS_BLOCK_COUNT; badblock++) { - lfs_testbd_setwear(&cfg, badblock-1, 0) => 0; - lfs_testbd_setwear(&cfg, badblock, 0xffffffff) => 0; - - lfs_format(&lfs, &cfg) => 0; + for (lfs_block_t badblock = 2; badblock < BLOCK_COUNT; badblock++) { + lfs_emubd_setwear(cfg, badblock-1, 0) => 0; + lfs_emubd_setwear(cfg, badblock, 0xffffffff) => 0; + + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 1; i < 10; i++) { + uint8_t buffer[1024]; for (int j = 0; j < NAMEMULT; j++) { buffer[j] = '0'+i; } @@ -34,10 +36,11 @@ code = ''' buffer[j+NAMEMULT+1] = '0'+i; } buffer[2*NAMEMULT+1] = '\0'; + lfs_file_t file; lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_WRONLY | LFS_O_CREAT) => 0; - size = NAMEMULT; + lfs_size_t size = NAMEMULT; for (int j = 0; j < i*FILEMULT; j++) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -46,12 +49,14 @@ code = ''' } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 1; i < 10; i++) { + uint8_t buffer[1024]; for (int j = 0; j < NAMEMULT; j++) { buffer[j] = '0'+i; } buffer[NAMEMULT] = '\0'; + struct lfs_info info; lfs_stat(&lfs, (char*)buffer, &info) => 0; info.type => LFS_TYPE_DIR; @@ -60,9 +65,10 @@ code = ''' buffer[j+NAMEMULT+1] = '0'+i; } buffer[2*NAMEMULT+1] = '\0'; + lfs_file_t file; lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; - size = NAMEMULT; + int size = NAMEMULT; for (int j = 0; j < i*FILEMULT; j++) { uint8_t rbuffer[1024]; lfs_file_read(&lfs, &file, rbuffer, size) => size; @@ -75,28 +81,30 @@ code = ''' } ''' -[[case]] # region corruption (causes cascading failures) -define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster -define.LFS_ERASE_CYCLES = 0xffffffff -define.LFS_ERASE_VALUE = [0x00, 0xff, -1] -define.LFS_BADBLOCK_BEHAVIOR = [ - 'LFS_TESTBD_BADBLOCK_PROGERROR', - 'LFS_TESTBD_BADBLOCK_ERASEERROR', - 'LFS_TESTBD_BADBLOCK_READERROR', - 'LFS_TESTBD_BADBLOCK_PROGNOOP', - 'LFS_TESTBD_BADBLOCK_ERASENOOP', +[cases.test_badblocks_region_corruption] # (causes cascading failures) +defines.BLOCK_COUNT = 256 # small bd so test runs faster +defines.ERASE_CYCLES = 0xffffffff +defines.ERASE_VALUE = [0x00, 0xff, -1] +defines.BADBLOCK_BEHAVIOR = [ + 'LFS_EMUBD_BADBLOCK_PROGERROR', + 'LFS_EMUBD_BADBLOCK_ERASEERROR', + 'LFS_EMUBD_BADBLOCK_READERROR', + 'LFS_EMUBD_BADBLOCK_PROGNOOP', + 'LFS_EMUBD_BADBLOCK_ERASENOOP', ] -define.NAMEMULT = 64 -define.FILEMULT = 1 +defines.NAMEMULT = 64 +defines.FILEMULT = 1 code = ''' - for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) { - lfs_testbd_setwear(&cfg, i+2, 0xffffffff) => 0; + for (lfs_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) { + lfs_emubd_setwear(cfg, i+2, 0xffffffff) => 0; } - - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + + lfs_mount(&lfs, cfg) => 0; for (int i = 1; i < 10; i++) { + uint8_t buffer[1024]; for (int j = 0; j < NAMEMULT; j++) { buffer[j] = '0'+i; } @@ -108,10 +116,11 @@ code = ''' buffer[j+NAMEMULT+1] = '0'+i; } buffer[2*NAMEMULT+1] = '\0'; + lfs_file_t file; lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_WRONLY | LFS_O_CREAT) => 0; - size = NAMEMULT; + lfs_size_t size = NAMEMULT; for (int j = 0; j < i*FILEMULT; j++) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -120,12 +129,14 @@ code = ''' } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 1; i < 10; i++) { + uint8_t buffer[1024]; for (int j = 0; j < NAMEMULT; j++) { buffer[j] = '0'+i; } buffer[NAMEMULT] = '\0'; + struct lfs_info info; lfs_stat(&lfs, (char*)buffer, &info) => 0; info.type => LFS_TYPE_DIR; @@ -134,9 +145,10 @@ code = ''' buffer[j+NAMEMULT+1] = '0'+i; } buffer[2*NAMEMULT+1] = '\0'; + lfs_file_t file; lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; - size = NAMEMULT; + lfs_size_t size = NAMEMULT; for (int j = 0; j < i*FILEMULT; j++) { uint8_t rbuffer[1024]; lfs_file_read(&lfs, &file, rbuffer, size) => size; @@ -148,28 +160,30 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # alternating corruption (causes cascading failures) -define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster -define.LFS_ERASE_CYCLES = 0xffffffff -define.LFS_ERASE_VALUE = [0x00, 0xff, -1] -define.LFS_BADBLOCK_BEHAVIOR = [ - 'LFS_TESTBD_BADBLOCK_PROGERROR', - 'LFS_TESTBD_BADBLOCK_ERASEERROR', - 'LFS_TESTBD_BADBLOCK_READERROR', - 'LFS_TESTBD_BADBLOCK_PROGNOOP', - 'LFS_TESTBD_BADBLOCK_ERASENOOP', +[cases.test_badblocks_alternating_corruption] # (causes cascading failures) +defines.BLOCK_COUNT = 256 # small bd so test runs faster +defines.ERASE_CYCLES = 0xffffffff +defines.ERASE_VALUE = [0x00, 0xff, -1] +defines.BADBLOCK_BEHAVIOR = [ + 'LFS_EMUBD_BADBLOCK_PROGERROR', + 'LFS_EMUBD_BADBLOCK_ERASEERROR', + 'LFS_EMUBD_BADBLOCK_READERROR', + 'LFS_EMUBD_BADBLOCK_PROGNOOP', + 'LFS_EMUBD_BADBLOCK_ERASENOOP', ] -define.NAMEMULT = 64 -define.FILEMULT = 1 +defines.NAMEMULT = 64 +defines.FILEMULT = 1 code = ''' - for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) { - lfs_testbd_setwear(&cfg, (2*i) + 2, 0xffffffff) => 0; + for (lfs_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) { + lfs_emubd_setwear(cfg, (2*i) + 2, 0xffffffff) => 0; } - - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + + lfs_mount(&lfs, cfg) => 0; for (int i = 1; i < 10; i++) { + uint8_t buffer[1024]; for (int j = 0; j < NAMEMULT; j++) { buffer[j] = '0'+i; } @@ -181,10 +195,11 @@ code = ''' buffer[j+NAMEMULT+1] = '0'+i; } buffer[2*NAMEMULT+1] = '\0'; + lfs_file_t file; lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_WRONLY | LFS_O_CREAT) => 0; - size = NAMEMULT; + lfs_size_t size = NAMEMULT; for (int j = 0; j < i*FILEMULT; j++) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -193,12 +208,14 @@ code = ''' } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 1; i < 10; i++) { + uint8_t buffer[1024]; for (int j = 0; j < NAMEMULT; j++) { buffer[j] = '0'+i; } buffer[NAMEMULT] = '\0'; + struct lfs_info info; lfs_stat(&lfs, (char*)buffer, &info) => 0; info.type => LFS_TYPE_DIR; @@ -207,9 +224,10 @@ code = ''' buffer[j+NAMEMULT+1] = '0'+i; } buffer[2*NAMEMULT+1] = '\0'; + lfs_file_t file; lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; - size = NAMEMULT; + lfs_size_t size = NAMEMULT; for (int j = 0; j < i*FILEMULT; j++) { uint8_t rbuffer[1024]; lfs_file_read(&lfs, &file, rbuffer, size) => size; @@ -222,20 +240,21 @@ code = ''' ''' # other corner cases -[[case]] # bad superblocks (corrupt 1 or 0) -define.LFS_ERASE_CYCLES = 0xffffffff -define.LFS_ERASE_VALUE = [0x00, 0xff, -1] -define.LFS_BADBLOCK_BEHAVIOR = [ - 'LFS_TESTBD_BADBLOCK_PROGERROR', - 'LFS_TESTBD_BADBLOCK_ERASEERROR', - 'LFS_TESTBD_BADBLOCK_READERROR', - 'LFS_TESTBD_BADBLOCK_PROGNOOP', - 'LFS_TESTBD_BADBLOCK_ERASENOOP', +[cases.test_badblocks_superblocks] # (corrupt 1 or 0) +defines.ERASE_CYCLES = 0xffffffff +defines.ERASE_VALUE = [0x00, 0xff, -1] +defines.BADBLOCK_BEHAVIOR = [ + 'LFS_EMUBD_BADBLOCK_PROGERROR', + 'LFS_EMUBD_BADBLOCK_ERASEERROR', + 'LFS_EMUBD_BADBLOCK_READERROR', + 'LFS_EMUBD_BADBLOCK_PROGNOOP', + 'LFS_EMUBD_BADBLOCK_ERASENOOP', ] code = ''' - lfs_testbd_setwear(&cfg, 0, 0xffffffff) => 0; - lfs_testbd_setwear(&cfg, 1, 0xffffffff) => 0; + lfs_emubd_setwear(cfg, 0, 0xffffffff) => 0; + lfs_emubd_setwear(cfg, 1, 0xffffffff) => 0; - lfs_format(&lfs, &cfg) => LFS_ERR_NOSPC; - lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; + lfs_t lfs; + lfs_format(&lfs, cfg) => LFS_ERR_NOSPC; + lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; ''' diff --git a/tests/test_bd.toml b/tests/test_bd.toml new file mode 100644 index 0000000..8c6510d --- /dev/null +++ b/tests/test_bd.toml @@ -0,0 +1,248 @@ +# These tests don't really test littlefs at all, they are here only to make +# sure the underlying block device is working. +# +# Note we use 251, a prime, in places to avoid aliasing powers of 2. +# + +[cases.test_bd_one_block] +defines.READ = ['READ_SIZE', 'BLOCK_SIZE'] +defines.PROG = ['PROG_SIZE', 'BLOCK_SIZE'] +code = ''' + uint8_t buffer[lfs_max(READ, PROG)]; + + // write data + cfg->erase(cfg, 0) => 0; + for (lfs_off_t i = 0; i < cfg->block_size; i += PROG) { + for (lfs_off_t j = 0; j < PROG; j++) { + buffer[j] = (i+j) % 251; + } + cfg->prog(cfg, 0, i, buffer, PROG) => 0; + } + + // read data + for (lfs_off_t i = 0; i < cfg->block_size; i += READ) { + cfg->read(cfg, 0, i, buffer, READ) => 0; + + for (lfs_off_t j = 0; j < READ; j++) { + LFS_ASSERT(buffer[j] == (i+j) % 251); + } + } +''' + +[cases.test_bd_two_block] +defines.READ = ['READ_SIZE', 'BLOCK_SIZE'] +defines.PROG = ['PROG_SIZE', 'BLOCK_SIZE'] +code = ''' + uint8_t buffer[lfs_max(READ, PROG)]; + lfs_block_t block; + + // write block 0 + block = 0; + cfg->erase(cfg, block) => 0; + for (lfs_off_t i = 0; i < cfg->block_size; i += PROG) { + for (lfs_off_t j = 0; j < PROG; j++) { + buffer[j] = (block+i+j) % 251; + } + cfg->prog(cfg, block, i, buffer, PROG) => 0; + } + + // read block 0 + block = 0; + for (lfs_off_t i = 0; i < cfg->block_size; i += READ) { + cfg->read(cfg, block, i, buffer, READ) => 0; + + for (lfs_off_t j = 0; j < READ; j++) { + LFS_ASSERT(buffer[j] == (block+i+j) % 251); + } + } + + // write block 1 + block = 1; + cfg->erase(cfg, block) => 0; + for (lfs_off_t i = 0; i < cfg->block_size; i += PROG) { + for (lfs_off_t j = 0; j < PROG; j++) { + buffer[j] = (block+i+j) % 251; + } + cfg->prog(cfg, block, i, buffer, PROG) => 0; + } + + // read block 1 + block = 1; + for (lfs_off_t i = 0; i < cfg->block_size; i += READ) { + cfg->read(cfg, block, i, buffer, READ) => 0; + + for (lfs_off_t j = 0; j < READ; j++) { + LFS_ASSERT(buffer[j] == (block+i+j) % 251); + } + } + + // read block 0 again + block = 0; + for (lfs_off_t i = 0; i < cfg->block_size; i += READ) { + cfg->read(cfg, block, i, buffer, READ) => 0; + + for (lfs_off_t j = 0; j < READ; j++) { + LFS_ASSERT(buffer[j] == (block+i+j) % 251); + } + } +''' + +[cases.test_bd_last_block] +defines.READ = ['READ_SIZE', 'BLOCK_SIZE'] +defines.PROG = ['PROG_SIZE', 'BLOCK_SIZE'] +code = ''' + uint8_t buffer[lfs_max(READ, PROG)]; + lfs_block_t block; + + // write block 0 + block = 0; + cfg->erase(cfg, block) => 0; + for (lfs_off_t i = 0; i < cfg->block_size; i += PROG) { + for (lfs_off_t j = 0; j < PROG; j++) { + buffer[j] = (block+i+j) % 251; + } + cfg->prog(cfg, block, i, buffer, PROG) => 0; + } + + // read block 0 + block = 0; + for (lfs_off_t i = 0; i < cfg->block_size; i += READ) { + cfg->read(cfg, block, i, buffer, READ) => 0; + + for (lfs_off_t j = 0; j < READ; j++) { + LFS_ASSERT(buffer[j] == (block+i+j) % 251); + } + } + + // write block n-1 + block = cfg->block_count-1; + cfg->erase(cfg, block) => 0; + for (lfs_off_t i = 0; i < cfg->block_size; i += PROG) { + for (lfs_off_t j = 0; j < PROG; j++) { + buffer[j] = (block+i+j) % 251; + } + cfg->prog(cfg, block, i, buffer, PROG) => 0; + } + + // read block n-1 + block = cfg->block_count-1; + for (lfs_off_t i = 0; i < cfg->block_size; i += READ) { + cfg->read(cfg, block, i, buffer, READ) => 0; + + for (lfs_off_t j = 0; j < READ; j++) { + LFS_ASSERT(buffer[j] == (block+i+j) % 251); + } + } + + // read block 0 again + block = 0; + for (lfs_off_t i = 0; i < cfg->block_size; i += READ) { + cfg->read(cfg, block, i, buffer, READ) => 0; + + for (lfs_off_t j = 0; j < READ; j++) { + LFS_ASSERT(buffer[j] == (block+i+j) % 251); + } + } +''' + +[cases.test_bd_powers_of_two] +defines.READ = ['READ_SIZE', 'BLOCK_SIZE'] +defines.PROG = ['PROG_SIZE', 'BLOCK_SIZE'] +code = ''' + uint8_t buffer[lfs_max(READ, PROG)]; + + // write/read every power of 2 + lfs_block_t block = 1; + while (block < cfg->block_count) { + // write + cfg->erase(cfg, block) => 0; + for (lfs_off_t i = 0; i < cfg->block_size; i += PROG) { + for (lfs_off_t j = 0; j < PROG; j++) { + buffer[j] = (block+i+j) % 251; + } + cfg->prog(cfg, block, i, buffer, PROG) => 0; + } + + // read + for (lfs_off_t i = 0; i < cfg->block_size; i += READ) { + cfg->read(cfg, block, i, buffer, READ) => 0; + + for (lfs_off_t j = 0; j < READ; j++) { + LFS_ASSERT(buffer[j] == (block+i+j) % 251); + } + } + + block *= 2; + } + + // read every power of 2 again + block = 1; + while (block < cfg->block_count) { + // read + for (lfs_off_t i = 0; i < cfg->block_size; i += READ) { + cfg->read(cfg, block, i, buffer, READ) => 0; + + for (lfs_off_t j = 0; j < READ; j++) { + LFS_ASSERT(buffer[j] == (block+i+j) % 251); + } + } + + block *= 2; + } +''' + +[cases.test_bd_fibonacci] +defines.READ = ['READ_SIZE', 'BLOCK_SIZE'] +defines.PROG = ['PROG_SIZE', 'BLOCK_SIZE'] +code = ''' + uint8_t buffer[lfs_max(READ, PROG)]; + + // write/read every fibonacci number on our device + lfs_block_t block = 1; + lfs_block_t block_ = 1; + while (block < cfg->block_count) { + // write + cfg->erase(cfg, block) => 0; + for (lfs_off_t i = 0; i < cfg->block_size; i += PROG) { + for (lfs_off_t j = 0; j < PROG; j++) { + buffer[j] = (block+i+j) % 251; + } + cfg->prog(cfg, block, i, buffer, PROG) => 0; + } + + // read + for (lfs_off_t i = 0; i < cfg->block_size; i += READ) { + cfg->read(cfg, block, i, buffer, READ) => 0; + + for (lfs_off_t j = 0; j < READ; j++) { + LFS_ASSERT(buffer[j] == (block+i+j) % 251); + } + } + + lfs_block_t nblock = block + block_; + block_ = block; + block = nblock; + } + + // read every fibonacci number again + block = 1; + block_ = 1; + while (block < cfg->block_count) { + // read + for (lfs_off_t i = 0; i < cfg->block_size; i += READ) { + cfg->read(cfg, block, i, buffer, READ) => 0; + + for (lfs_off_t j = 0; j < READ; j++) { + LFS_ASSERT(buffer[j] == (block+i+j) % 251); + } + } + + lfs_block_t nblock = block + block_; + block_ = block; + block = nblock; + } +''' + + + + diff --git a/tests/test_compat.toml b/tests/test_compat.toml new file mode 100644 index 0000000..a36c38a --- /dev/null +++ b/tests/test_compat.toml @@ -0,0 +1,1360 @@ +# Test for compatibility between different littlefs versions +# +# Note, these tests are a bit special. They expect to be linked against two +# different versions of littlefs: +# - lfs => the new/current version of littlefs +# - lfsp => the previous version of littlefs +# +# If lfsp is not linked, and LFSP is not defined, these tests will alias +# the relevant lfs types/functions as necessary so at least the tests can +# themselves be tested locally. +# +# But to get value from these tests, it's expected that the previous version +# of littlefs be linked in during CI, with the help of scripts/changeprefix.py +# + +# alias littlefs symbols as needed +# +# there may be a better way to do this, but oh well, explicit aliases works +code = ''' +#ifdef LFSP +#define STRINGIZE(x) STRINGIZE_(x) +#define STRINGIZE_(x) #x +#include STRINGIZE(LFSP) +#else +#define LFSP_VERSION LFS_VERSION +#define LFSP_VERSION_MAJOR LFS_VERSION_MAJOR +#define LFSP_VERSION_MINOR LFS_VERSION_MINOR +#define lfsp_t lfs_t +#define lfsp_config lfs_config +#define lfsp_format lfs_format +#define lfsp_mount lfs_mount +#define lfsp_unmount lfs_unmount +#define lfsp_dir_t lfs_dir_t +#define lfsp_info lfs_info +#define LFSP_TYPE_REG LFS_TYPE_REG +#define LFSP_TYPE_DIR LFS_TYPE_DIR +#define lfsp_mkdir lfs_mkdir +#define lfsp_dir_open lfs_dir_open +#define lfsp_dir_read lfs_dir_read +#define lfsp_dir_close lfs_dir_close +#define lfsp_file_t lfs_file_t +#define LFSP_O_RDONLY LFS_O_RDONLY +#define LFSP_O_WRONLY LFS_O_WRONLY +#define LFSP_O_CREAT LFS_O_CREAT +#define LFSP_O_EXCL LFS_O_EXCL +#define LFSP_SEEK_SET LFS_SEEK_SET +#define lfsp_file_open lfs_file_open +#define lfsp_file_write lfs_file_write +#define lfsp_file_read lfs_file_read +#define lfsp_file_seek lfs_file_seek +#define lfsp_file_close lfs_file_close +#endif +''' + + + +## forward-compatibility tests ## + +# test we can mount in a new version +[cases.test_compat_forward_mount] +if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR' +code = ''' + // create the previous version + struct lfsp_config cfgp; + memcpy(&cfgp, cfg, sizeof(cfgp)); + lfsp_t lfsp; + lfsp_format(&lfsp, &cfgp) => 0; + + // confirm the previous mount works + lfsp_mount(&lfsp, &cfgp) => 0; + lfsp_unmount(&lfsp) => 0; + + + // now test the new mount + lfs_t lfs; + lfs_mount(&lfs, cfg) => 0; + lfs_unmount(&lfs) => 0; +''' + +# test we can read dirs in a new version +[cases.test_compat_forward_read_dirs] +defines.COUNT = 5 +if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR' +code = ''' + // create the previous version + struct lfsp_config cfgp; + memcpy(&cfgp, cfg, sizeof(cfgp)); + lfsp_t lfsp; + lfsp_format(&lfsp, &cfgp) => 0; + + // write COUNT dirs + lfsp_mount(&lfsp, &cfgp) => 0; + for (lfs_size_t i = 0; i < COUNT; i++) { + char name[8]; + sprintf(name, "dir%03d", i); + lfsp_mkdir(&lfsp, name) => 0; + } + lfsp_unmount(&lfsp) => 0; + + + // mount the new version + lfs_t lfs; + lfs_mount(&lfs, cfg) => 0; + + // can we list the directories? + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + for (lfs_size_t i = 0; i < COUNT; i++) { + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + char name[8]; + sprintf(name, "dir%03d", i); + assert(strcmp(info.name, name) == 0); + } + + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + + lfs_unmount(&lfs) => 0; +''' + +# test we can read files in a new version +[cases.test_compat_forward_read_files] +defines.COUNT = 5 +defines.SIZE = [4, 32, 512, 8192] +defines.CHUNK = 4 +if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR' +code = ''' + // create the previous version + struct lfsp_config cfgp; + memcpy(&cfgp, cfg, sizeof(cfgp)); + lfsp_t lfsp; + lfsp_format(&lfsp, &cfgp) => 0; + + // write COUNT files + lfsp_mount(&lfsp, &cfgp) => 0; + uint32_t prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + lfsp_file_t file; + char name[8]; + sprintf(name, "file%03d", i); + lfsp_file_open(&lfsp, &file, name, + LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0; + for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + for (lfs_size_t k = 0; k < CHUNK; k++) { + chunk[k] = TEST_PRNG(&prng) & 0xff; + } + + lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK; + } + lfsp_file_close(&lfsp, &file) => 0; + } + lfsp_unmount(&lfsp) => 0; + + + // mount the new version + lfs_t lfs; + lfs_mount(&lfs, cfg) => 0; + + // can we list the files? + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + for (lfs_size_t i = 0; i < COUNT; i++) { + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_REG); + char name[8]; + sprintf(name, "file%03d", i); + assert(strcmp(info.name, name) == 0); + assert(info.size == SIZE); + } + + lfs_dir_read(&lfs, &dir, &info) => 0; + + // now can we read the files? + prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + lfs_file_t file; + char name[8]; + sprintf(name, "file%03d", i); + lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0; + for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK; + + for (lfs_size_t k = 0; k < CHUNK; k++) { + assert(chunk[k] == TEST_PRNG(&prng) & 0xff); + } + } + lfs_file_close(&lfs, &file) => 0; + } + + lfs_unmount(&lfs) => 0; +''' + +# test we can read files in dirs in a new version +[cases.test_compat_forward_read_files_in_dirs] +defines.COUNT = 5 +defines.SIZE = [4, 32, 512, 8192] +defines.CHUNK = 4 +if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR' +code = ''' + // create the previous version + struct lfsp_config cfgp; + memcpy(&cfgp, cfg, sizeof(cfgp)); + lfsp_t lfsp; + lfsp_format(&lfsp, &cfgp) => 0; + + // write COUNT files+dirs + lfsp_mount(&lfsp, &cfgp) => 0; + uint32_t prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + char name[16]; + sprintf(name, "dir%03d", i); + lfsp_mkdir(&lfsp, name) => 0; + + lfsp_file_t file; + sprintf(name, "dir%03d/file%03d", i, i); + lfsp_file_open(&lfsp, &file, name, + LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0; + for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + for (lfs_size_t k = 0; k < CHUNK; k++) { + chunk[k] = TEST_PRNG(&prng) & 0xff; + } + + lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK; + } + lfsp_file_close(&lfsp, &file) => 0; + } + lfsp_unmount(&lfsp) => 0; + + + // mount the new version + lfs_t lfs; + lfs_mount(&lfs, cfg) => 0; + + // can we list the directories? + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + for (lfs_size_t i = 0; i < COUNT; i++) { + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + char name[8]; + sprintf(name, "dir%03d", i); + assert(strcmp(info.name, name) == 0); + } + + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + + // can we list the files? + for (lfs_size_t i = 0; i < COUNT; i++) { + char name[8]; + sprintf(name, "dir%03d", i); + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, name) => 0; + struct lfs_info info; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_REG); + sprintf(name, "file%03d", i); + assert(strcmp(info.name, name) == 0); + assert(info.size == SIZE); + + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + } + + // now can we read the files? + prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + lfs_file_t file; + char name[16]; + sprintf(name, "dir%03d/file%03d", i, i); + lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0; + for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK; + + for (lfs_size_t k = 0; k < CHUNK; k++) { + assert(chunk[k] == TEST_PRNG(&prng) & 0xff); + } + } + lfs_file_close(&lfs, &file) => 0; + } + + lfs_unmount(&lfs) => 0; +''' + +# test we can write dirs in a new version +[cases.test_compat_forward_write_dirs] +defines.COUNT = 10 +if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR' +code = ''' + // create the previous version + struct lfsp_config cfgp; + memcpy(&cfgp, cfg, sizeof(cfgp)); + lfsp_t lfsp; + lfsp_format(&lfsp, &cfgp) => 0; + + // write COUNT/2 dirs + lfsp_mount(&lfsp, &cfgp) => 0; + for (lfs_size_t i = 0; i < COUNT/2; i++) { + char name[8]; + sprintf(name, "dir%03d", i); + lfsp_mkdir(&lfsp, name) => 0; + } + lfsp_unmount(&lfsp) => 0; + + + // mount the new version + lfs_t lfs; + lfs_mount(&lfs, cfg) => 0; + + // write another COUNT/2 dirs + for (lfs_size_t i = COUNT/2; i < COUNT; i++) { + char name[8]; + sprintf(name, "dir%03d", i); + lfs_mkdir(&lfs, name) => 0; + } + + // can we list the directories? + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + for (lfs_size_t i = 0; i < COUNT; i++) { + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + char name[8]; + sprintf(name, "dir%03d", i); + assert(strcmp(info.name, name) == 0); + } + + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + + lfs_unmount(&lfs) => 0; +''' + +# test we can write files in a new version +[cases.test_compat_forward_write_files] +defines.COUNT = 5 +defines.SIZE = [4, 32, 512, 8192] +defines.CHUNK = 2 +if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR' +code = ''' + // create the previous version + struct lfsp_config cfgp; + memcpy(&cfgp, cfg, sizeof(cfgp)); + lfsp_t lfsp; + lfsp_format(&lfsp, &cfgp) => 0; + + // write half COUNT files + lfsp_mount(&lfsp, &cfgp) => 0; + uint32_t prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + // write half + lfsp_file_t file; + char name[8]; + sprintf(name, "file%03d", i); + lfsp_file_open(&lfsp, &file, name, + LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0; + for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) { + uint8_t chunk[CHUNK]; + for (lfs_size_t k = 0; k < CHUNK; k++) { + chunk[k] = TEST_PRNG(&prng) & 0xff; + } + + lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK; + } + lfsp_file_close(&lfsp, &file) => 0; + + // skip the other half but keep our prng reproducible + for (lfs_size_t j = SIZE/2; j < SIZE; j++) { + TEST_PRNG(&prng); + } + } + lfsp_unmount(&lfsp) => 0; + + + // mount the new version + lfs_t lfs; + lfs_mount(&lfs, cfg) => 0; + + // write half COUNT files + prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + // skip half but keep our prng reproducible + for (lfs_size_t j = 0; j < SIZE/2; j++) { + TEST_PRNG(&prng); + } + + // write the other half + lfs_file_t file; + char name[8]; + sprintf(name, "file%03d", i); + lfs_file_open(&lfs, &file, name, LFS_O_WRONLY) => 0; + lfs_file_seek(&lfs, &file, SIZE/2, LFS_SEEK_SET) => SIZE/2; + + for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + for (lfs_size_t k = 0; k < CHUNK; k++) { + chunk[k] = TEST_PRNG(&prng) & 0xff; + } + + lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK; + } + lfs_file_close(&lfs, &file) => 0; + } + + // can we list the files? + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + for (lfs_size_t i = 0; i < COUNT; i++) { + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_REG); + char name[8]; + sprintf(name, "file%03d", i); + assert(strcmp(info.name, name) == 0); + assert(info.size == SIZE); + } + + lfs_dir_read(&lfs, &dir, &info) => 0; + + // now can we read the files? + prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + lfs_file_t file; + char name[8]; + sprintf(name, "file%03d", i); + lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0; + for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK; + + for (lfs_size_t k = 0; k < CHUNK; k++) { + assert(chunk[k] == TEST_PRNG(&prng) & 0xff); + } + } + lfs_file_close(&lfs, &file) => 0; + } + + lfs_unmount(&lfs) => 0; +''' + +# test we can write files in dirs in a new version +[cases.test_compat_forward_write_files_in_dirs] +defines.COUNT = 5 +defines.SIZE = [4, 32, 512, 8192] +defines.CHUNK = 2 +if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR' +code = ''' + // create the previous version + struct lfsp_config cfgp; + memcpy(&cfgp, cfg, sizeof(cfgp)); + lfsp_t lfsp; + lfsp_format(&lfsp, &cfgp) => 0; + + // write half COUNT files + lfsp_mount(&lfsp, &cfgp) => 0; + uint32_t prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + char name[16]; + sprintf(name, "dir%03d", i); + lfsp_mkdir(&lfsp, name) => 0; + + // write half + lfsp_file_t file; + sprintf(name, "dir%03d/file%03d", i, i); + lfsp_file_open(&lfsp, &file, name, + LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0; + for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) { + uint8_t chunk[CHUNK]; + for (lfs_size_t k = 0; k < CHUNK; k++) { + chunk[k] = TEST_PRNG(&prng) & 0xff; + } + + lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK; + } + lfsp_file_close(&lfsp, &file) => 0; + + // skip the other half but keep our prng reproducible + for (lfs_size_t j = SIZE/2; j < SIZE; j++) { + TEST_PRNG(&prng); + } + } + lfsp_unmount(&lfsp) => 0; + + + // mount the new version + lfs_t lfs; + lfs_mount(&lfs, cfg) => 0; + + // write half COUNT files + prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + // skip half but keep our prng reproducible + for (lfs_size_t j = 0; j < SIZE/2; j++) { + TEST_PRNG(&prng); + } + + // write the other half + lfs_file_t file; + char name[16]; + sprintf(name, "dir%03d/file%03d", i, i); + lfs_file_open(&lfs, &file, name, LFS_O_WRONLY) => 0; + lfs_file_seek(&lfs, &file, SIZE/2, LFS_SEEK_SET) => SIZE/2; + + for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + for (lfs_size_t k = 0; k < CHUNK; k++) { + chunk[k] = TEST_PRNG(&prng) & 0xff; + } + + lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK; + } + lfs_file_close(&lfs, &file) => 0; + } + + // can we list the directories? + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + for (lfs_size_t i = 0; i < COUNT; i++) { + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + char name[8]; + sprintf(name, "dir%03d", i); + assert(strcmp(info.name, name) == 0); + } + + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + + // can we list the files? + for (lfs_size_t i = 0; i < COUNT; i++) { + char name[8]; + sprintf(name, "dir%03d", i); + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, name) => 0; + struct lfs_info info; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_REG); + sprintf(name, "file%03d", i); + assert(strcmp(info.name, name) == 0); + assert(info.size == SIZE); + + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + } + + // now can we read the files? + prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + lfs_file_t file; + char name[16]; + sprintf(name, "dir%03d/file%03d", i, i); + lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0; + for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK; + + for (lfs_size_t k = 0; k < CHUNK; k++) { + assert(chunk[k] == TEST_PRNG(&prng) & 0xff); + } + } + lfs_file_close(&lfs, &file) => 0; + } + + lfs_unmount(&lfs) => 0; +''' + + + +## backwards-compatibility tests ## + +# test we can mount in an old version +[cases.test_compat_backward_mount] +if = 'LFS_VERSION == LFSP_VERSION' +code = ''' + // create the new version + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + + // confirm the new mount works + lfs_mount(&lfs, cfg) => 0; + lfs_unmount(&lfs) => 0; + + // now test the previous mount + struct lfsp_config cfgp; + memcpy(&cfgp, cfg, sizeof(cfgp)); + lfsp_t lfsp; + lfsp_mount(&lfsp, &cfgp) => 0; + lfsp_unmount(&lfsp) => 0; +''' + +# test we can read dirs in an old version +[cases.test_compat_backward_read_dirs] +defines.COUNT = 5 +if = 'LFS_VERSION == LFSP_VERSION' +code = ''' + // create the new version + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + + // write COUNT dirs + lfs_mount(&lfs, cfg) => 0; + for (lfs_size_t i = 0; i < COUNT; i++) { + char name[8]; + sprintf(name, "dir%03d", i); + lfs_mkdir(&lfs, name) => 0; + } + lfs_unmount(&lfs) => 0; + + + // mount the new version + struct lfsp_config cfgp; + memcpy(&cfgp, cfg, sizeof(cfgp)); + lfsp_t lfsp; + lfsp_mount(&lfsp, &cfgp) => 0; + + // can we list the directories? + lfsp_dir_t dir; + lfsp_dir_open(&lfsp, &dir, "/") => 0; + struct lfsp_info info; + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + for (lfs_size_t i = 0; i < COUNT; i++) { + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + char name[8]; + sprintf(name, "dir%03d", i); + assert(strcmp(info.name, name) == 0); + } + + lfsp_dir_read(&lfsp, &dir, &info) => 0; + lfsp_dir_close(&lfsp, &dir) => 0; + + lfsp_unmount(&lfsp) => 0; +''' + +# test we can read files in an old version +[cases.test_compat_backward_read_files] +defines.COUNT = 5 +defines.SIZE = [4, 32, 512, 8192] +defines.CHUNK = 4 +if = 'LFS_VERSION == LFSP_VERSION' +code = ''' + // create the new version + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + + // write COUNT files + lfs_mount(&lfs, cfg) => 0; + uint32_t prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + lfs_file_t file; + char name[8]; + sprintf(name, "file%03d", i); + lfs_file_open(&lfs, &file, name, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + for (lfs_size_t k = 0; k < CHUNK; k++) { + chunk[k] = TEST_PRNG(&prng) & 0xff; + } + + lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK; + } + lfs_file_close(&lfs, &file) => 0; + } + lfs_unmount(&lfs) => 0; + + + // mount the previous version + struct lfsp_config cfgp; + memcpy(&cfgp, cfg, sizeof(cfgp)); + lfsp_t lfsp; + lfsp_mount(&lfsp, &cfgp) => 0; + + // can we list the files? + lfsp_dir_t dir; + lfsp_dir_open(&lfsp, &dir, "/") => 0; + struct lfsp_info info; + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + for (lfs_size_t i = 0; i < COUNT; i++) { + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_REG); + char name[8]; + sprintf(name, "file%03d", i); + assert(strcmp(info.name, name) == 0); + assert(info.size == SIZE); + } + + lfsp_dir_read(&lfsp, &dir, &info) => 0; + + // now can we read the files? + prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + lfsp_file_t file; + char name[8]; + sprintf(name, "file%03d", i); + lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0; + for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK; + + for (lfs_size_t k = 0; k < CHUNK; k++) { + assert(chunk[k] == TEST_PRNG(&prng) & 0xff); + } + } + lfsp_file_close(&lfsp, &file) => 0; + } + + lfsp_unmount(&lfsp) => 0; +''' + +# test we can read files in dirs in an old version +[cases.test_compat_backward_read_files_in_dirs] +defines.COUNT = 5 +defines.SIZE = [4, 32, 512, 8192] +defines.CHUNK = 4 +if = 'LFS_VERSION == LFSP_VERSION' +code = ''' + // create the new version + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + + // write COUNT files+dirs + lfs_mount(&lfs, cfg) => 0; + uint32_t prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + char name[16]; + sprintf(name, "dir%03d", i); + lfs_mkdir(&lfs, name) => 0; + + lfs_file_t file; + sprintf(name, "dir%03d/file%03d", i, i); + lfs_file_open(&lfs, &file, name, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + for (lfs_size_t k = 0; k < CHUNK; k++) { + chunk[k] = TEST_PRNG(&prng) & 0xff; + } + + lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK; + } + lfs_file_close(&lfs, &file) => 0; + } + lfs_unmount(&lfs) => 0; + + + // mount the previous version + struct lfsp_config cfgp; + memcpy(&cfgp, cfg, sizeof(cfgp)); + lfsp_t lfsp; + lfsp_mount(&lfsp, &cfgp) => 0; + + // can we list the directories? + lfsp_dir_t dir; + lfsp_dir_open(&lfsp, &dir, "/") => 0; + struct lfsp_info info; + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + for (lfs_size_t i = 0; i < COUNT; i++) { + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + char name[8]; + sprintf(name, "dir%03d", i); + assert(strcmp(info.name, name) == 0); + } + + lfsp_dir_read(&lfsp, &dir, &info) => 0; + lfsp_dir_close(&lfsp, &dir) => 0; + + // can we list the files? + for (lfs_size_t i = 0; i < COUNT; i++) { + char name[8]; + sprintf(name, "dir%03d", i); + lfsp_dir_t dir; + lfsp_dir_open(&lfsp, &dir, name) => 0; + struct lfsp_info info; + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_REG); + sprintf(name, "file%03d", i); + assert(strcmp(info.name, name) == 0); + assert(info.size == SIZE); + + lfsp_dir_read(&lfsp, &dir, &info) => 0; + lfsp_dir_close(&lfsp, &dir) => 0; + } + + // now can we read the files? + prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + lfsp_file_t file; + char name[16]; + sprintf(name, "dir%03d/file%03d", i, i); + lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0; + for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK; + + for (lfs_size_t k = 0; k < CHUNK; k++) { + assert(chunk[k] == TEST_PRNG(&prng) & 0xff); + } + } + lfsp_file_close(&lfsp, &file) => 0; + } + + lfsp_unmount(&lfsp) => 0; +''' + +# test we can write dirs in an old version +[cases.test_compat_backward_write_dirs] +defines.COUNT = 10 +if = 'LFS_VERSION == LFSP_VERSION' +code = ''' + // create the new version + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + + // write COUNT/2 dirs + lfs_mount(&lfs, cfg) => 0; + for (lfs_size_t i = 0; i < COUNT/2; i++) { + char name[8]; + sprintf(name, "dir%03d", i); + lfs_mkdir(&lfs, name) => 0; + } + lfs_unmount(&lfs) => 0; + + + // mount the previous version + struct lfsp_config cfgp; + memcpy(&cfgp, cfg, sizeof(cfgp)); + lfsp_t lfsp; + lfsp_mount(&lfsp, &cfgp) => 0; + + // write another COUNT/2 dirs + for (lfs_size_t i = COUNT/2; i < COUNT; i++) { + char name[8]; + sprintf(name, "dir%03d", i); + lfsp_mkdir(&lfsp, name) => 0; + } + + // can we list the directories? + lfsp_dir_t dir; + lfsp_dir_open(&lfsp, &dir, "/") => 0; + struct lfsp_info info; + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + for (lfs_size_t i = 0; i < COUNT; i++) { + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + char name[8]; + sprintf(name, "dir%03d", i); + assert(strcmp(info.name, name) == 0); + } + + lfsp_dir_read(&lfsp, &dir, &info) => 0; + lfsp_dir_close(&lfsp, &dir) => 0; + + lfsp_unmount(&lfsp) => 0; +''' + +# test we can write files in an old version +[cases.test_compat_backward_write_files] +defines.COUNT = 5 +defines.SIZE = [4, 32, 512, 8192] +defines.CHUNK = 2 +if = 'LFS_VERSION == LFSP_VERSION' +code = ''' + // create the previous version + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + + // write half COUNT files + lfs_mount(&lfs, cfg) => 0; + uint32_t prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + // write half + lfs_file_t file; + char name[8]; + sprintf(name, "file%03d", i); + lfs_file_open(&lfs, &file, name, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) { + uint8_t chunk[CHUNK]; + for (lfs_size_t k = 0; k < CHUNK; k++) { + chunk[k] = TEST_PRNG(&prng) & 0xff; + } + + lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK; + } + lfs_file_close(&lfs, &file) => 0; + + // skip the other half but keep our prng reproducible + for (lfs_size_t j = SIZE/2; j < SIZE; j++) { + TEST_PRNG(&prng); + } + } + lfs_unmount(&lfs) => 0; + + + // mount the new version + struct lfsp_config cfgp; + memcpy(&cfgp, cfg, sizeof(cfgp)); + lfsp_t lfsp; + lfsp_mount(&lfsp, &cfgp) => 0; + + // write half COUNT files + prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + // skip half but keep our prng reproducible + for (lfs_size_t j = 0; j < SIZE/2; j++) { + TEST_PRNG(&prng); + } + + // write the other half + lfsp_file_t file; + char name[8]; + sprintf(name, "file%03d", i); + lfsp_file_open(&lfsp, &file, name, LFSP_O_WRONLY) => 0; + lfsp_file_seek(&lfsp, &file, SIZE/2, LFSP_SEEK_SET) => SIZE/2; + + for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + for (lfs_size_t k = 0; k < CHUNK; k++) { + chunk[k] = TEST_PRNG(&prng) & 0xff; + } + + lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK; + } + lfsp_file_close(&lfsp, &file) => 0; + } + + // can we list the files? + lfsp_dir_t dir; + lfsp_dir_open(&lfsp, &dir, "/") => 0; + struct lfsp_info info; + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + for (lfs_size_t i = 0; i < COUNT; i++) { + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_REG); + char name[8]; + sprintf(name, "file%03d", i); + assert(strcmp(info.name, name) == 0); + assert(info.size == SIZE); + } + + lfsp_dir_read(&lfsp, &dir, &info) => 0; + + // now can we read the files? + prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + lfsp_file_t file; + char name[8]; + sprintf(name, "file%03d", i); + lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0; + for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK; + + for (lfs_size_t k = 0; k < CHUNK; k++) { + assert(chunk[k] == TEST_PRNG(&prng) & 0xff); + } + } + lfsp_file_close(&lfsp, &file) => 0; + } + + lfsp_unmount(&lfsp) => 0; +''' + +# test we can write files in dirs in an old version +[cases.test_compat_backward_write_files_in_dirs] +defines.COUNT = 5 +defines.SIZE = [4, 32, 512, 8192] +defines.CHUNK = 2 +if = 'LFS_VERSION == LFSP_VERSION' +code = ''' + // create the previous version + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + + // write half COUNT files + lfs_mount(&lfs, cfg) => 0; + uint32_t prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + char name[16]; + sprintf(name, "dir%03d", i); + lfs_mkdir(&lfs, name) => 0; + + // write half + lfs_file_t file; + sprintf(name, "dir%03d/file%03d", i, i); + lfs_file_open(&lfs, &file, name, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) { + uint8_t chunk[CHUNK]; + for (lfs_size_t k = 0; k < CHUNK; k++) { + chunk[k] = TEST_PRNG(&prng) & 0xff; + } + + lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK; + } + lfs_file_close(&lfs, &file) => 0; + + // skip the other half but keep our prng reproducible + for (lfs_size_t j = SIZE/2; j < SIZE; j++) { + TEST_PRNG(&prng); + } + } + lfs_unmount(&lfs) => 0; + + + // mount the new version + struct lfsp_config cfgp; + memcpy(&cfgp, cfg, sizeof(cfgp)); + lfsp_t lfsp; + lfsp_mount(&lfsp, &cfgp) => 0; + + // write half COUNT files + prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + // skip half but keep our prng reproducible + for (lfs_size_t j = 0; j < SIZE/2; j++) { + TEST_PRNG(&prng); + } + + // write the other half + lfsp_file_t file; + char name[16]; + sprintf(name, "dir%03d/file%03d", i, i); + lfsp_file_open(&lfsp, &file, name, LFSP_O_WRONLY) => 0; + lfsp_file_seek(&lfsp, &file, SIZE/2, LFSP_SEEK_SET) => SIZE/2; + + for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + for (lfs_size_t k = 0; k < CHUNK; k++) { + chunk[k] = TEST_PRNG(&prng) & 0xff; + } + + lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK; + } + lfsp_file_close(&lfsp, &file) => 0; + } + + // can we list the directories? + lfsp_dir_t dir; + lfsp_dir_open(&lfsp, &dir, "/") => 0; + struct lfsp_info info; + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + for (lfs_size_t i = 0; i < COUNT; i++) { + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + char name[8]; + sprintf(name, "dir%03d", i); + assert(strcmp(info.name, name) == 0); + } + + lfsp_dir_read(&lfsp, &dir, &info) => 0; + lfsp_dir_close(&lfsp, &dir) => 0; + + // can we list the files? + for (lfs_size_t i = 0; i < COUNT; i++) { + char name[8]; + sprintf(name, "dir%03d", i); + lfsp_dir_t dir; + lfsp_dir_open(&lfsp, &dir, name) => 0; + struct lfsp_info info; + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + + lfsp_dir_read(&lfsp, &dir, &info) => 1; + assert(info.type == LFSP_TYPE_REG); + sprintf(name, "file%03d", i); + assert(strcmp(info.name, name) == 0); + assert(info.size == SIZE); + + lfsp_dir_read(&lfsp, &dir, &info) => 0; + lfsp_dir_close(&lfsp, &dir) => 0; + } + + // now can we read the files? + prng = 42; + for (lfs_size_t i = 0; i < COUNT; i++) { + lfsp_file_t file; + char name[16]; + sprintf(name, "dir%03d/file%03d", i, i); + lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0; + for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { + uint8_t chunk[CHUNK]; + lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK; + + for (lfs_size_t k = 0; k < CHUNK; k++) { + assert(chunk[k] == TEST_PRNG(&prng) & 0xff); + } + } + lfsp_file_close(&lfsp, &file) => 0; + } + + lfsp_unmount(&lfsp) => 0; +''' + + + +## incompatiblity tests ## + +# test that we fail to mount after a major version bump +[cases.test_compat_major_incompat] +in = 'lfs.c' +code = ''' + // create a superblock + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + + // bump the major version + // + // note we're messing around with internals to do this! this + // is not a user API + lfs_mount(&lfs, cfg) => 0; + lfs_mdir_t mdir; + lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; + lfs_superblock_t superblock = { + .version = LFS_DISK_VERSION + 0x00010000, + .block_size = lfs.cfg->block_size, + .block_count = lfs.cfg->block_count, + .name_max = lfs.name_max, + .file_max = lfs.file_max, + .attr_max = lfs.attr_max, + }; + lfs_superblock_tole32(&superblock); + lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), + &superblock})) => 0; + lfs_unmount(&lfs) => 0; + + // mount should now fail + lfs_mount(&lfs, cfg) => LFS_ERR_INVAL; +''' + +# test that we fail to mount after a minor version bump +[cases.test_compat_minor_incompat] +in = 'lfs.c' +code = ''' + // create a superblock + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + + // bump the minor version + // + // note we're messing around with internals to do this! this + // is not a user API + lfs_mount(&lfs, cfg) => 0; + lfs_mdir_t mdir; + lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; + lfs_superblock_t superblock = { + .version = LFS_DISK_VERSION + 0x00000001, + .block_size = lfs.cfg->block_size, + .block_count = lfs.cfg->block_count, + .name_max = lfs.name_max, + .file_max = lfs.file_max, + .attr_max = lfs.attr_max, + }; + lfs_superblock_tole32(&superblock); + lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), + &superblock})) => 0; + lfs_unmount(&lfs) => 0; + + // mount should now fail + lfs_mount(&lfs, cfg) => LFS_ERR_INVAL; +''' + +# test that we correctly bump the minor version +[cases.test_compat_minor_bump] +in = 'lfs.c' +if = 'LFS_DISK_VERSION_MINOR > 0' +code = ''' + // create a superblock + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; + lfs_file_open(&lfs, &file, "test", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_write(&lfs, &file, "testtest", 8) => 8; + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; + + // write an old minor version + // + // note we're messing around with internals to do this! this + // is not a user API + lfs_mount(&lfs, cfg) => 0; + lfs_mdir_t mdir; + lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; + lfs_superblock_t superblock = { + .version = LFS_DISK_VERSION - 0x00000001, + .block_size = lfs.cfg->block_size, + .block_count = lfs.cfg->block_count, + .name_max = lfs.name_max, + .file_max = lfs.file_max, + .attr_max = lfs.attr_max, + }; + lfs_superblock_tole32(&superblock); + lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( + {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), + &superblock})) => 0; + lfs_unmount(&lfs) => 0; + + // mount should still work + lfs_mount(&lfs, cfg) => 0; + lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0; + uint8_t buffer[8]; + lfs_file_read(&lfs, &file, buffer, 8) => 8; + assert(memcmp(buffer, "testtest", 8) == 0); + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; + + // if we write, we need to bump the minor version + lfs_mount(&lfs, cfg) => 0; + lfs_file_open(&lfs, &file, "test", LFS_O_WRONLY | LFS_O_TRUNC) => 0; + lfs_file_write(&lfs, &file, "teeeeest", 8) => 8; + lfs_file_close(&lfs, &file) => 0; + + // minor version should have changed + lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; + lfs_dir_get(&lfs, &mdir, LFS_MKTAG(0x7ff, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), + &superblock) + => LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)); + lfs_superblock_fromle32(&superblock); + assert((superblock.version >> 16) & 0xffff == LFS_DISK_VERSION_MAJOR); + assert((superblock.version >> 0) & 0xffff == LFS_DISK_VERSION_MINOR); + lfs_unmount(&lfs) => 0; + + // and of course mount should still work + lfs_mount(&lfs, cfg) => 0; + lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0; + lfs_file_read(&lfs, &file, buffer, 8) => 8; + assert(memcmp(buffer, "teeeeest", 8) == 0); + lfs_file_close(&lfs, &file) => 0; + + // minor version should have changed + lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; + lfs_dir_get(&lfs, &mdir, LFS_MKTAG(0x7ff, 0x3ff, 0), + LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), + &superblock) + => LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)); + lfs_superblock_fromle32(&superblock); + assert((superblock.version >> 16) & 0xffff == LFS_DISK_VERSION_MAJOR); + assert((superblock.version >> 0) & 0xffff == LFS_DISK_VERSION_MINOR); + lfs_unmount(&lfs) => 0; +''' diff --git a/tests/test_dirs.toml b/tests/test_dirs.toml index 7ff46e6..4262a1a 100644 --- a/tests/test_dirs.toml +++ b/tests/test_dirs.toml @@ -1,8 +1,11 @@ -[[case]] # root +[cases.test_dirs_root] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, ".") == 0); @@ -14,20 +17,25 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # many directory creation -define.N = 'range(0, 100, 3)' +[cases.test_dirs_many_creation] +defines.N = 'range(3, 100, 3)' +if = 'N < BLOCK_COUNT/2' code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "dir%03d", i); lfs_mkdir(&lfs, path) => 0; } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, ".") == 0); @@ -35,6 +43,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "dir%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -45,20 +54,25 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # many directory removal -define.N = 'range(3, 100, 11)' +[cases.test_dirs_many_removal] +defines.N = 'range(3, 100, 11)' +if = 'N < BLOCK_COUNT/2' code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "removeme%03d", i); lfs_mkdir(&lfs, path) => 0; } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, ".") == 0); @@ -66,6 +80,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "removeme%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -75,14 +90,15 @@ code = ''' lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs); - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "removeme%03d", i); lfs_remove(&lfs, path) => 0; } lfs_unmount(&lfs); - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -95,20 +111,25 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # many directory rename -define.N = 'range(3, 100, 11)' +[cases.test_dirs_many_rename] +defines.N = 'range(3, 100, 11)' +if = 'N < BLOCK_COUNT/2' code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "test%03d", i); lfs_mkdir(&lfs, path) => 0; } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, ".") == 0); @@ -116,6 +137,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "test%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -125,7 +147,7 @@ code = ''' lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs); - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 0; i < N; i++) { char oldpath[128]; char newpath[128]; @@ -135,7 +157,7 @@ code = ''' } lfs_unmount(&lfs); - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -144,6 +166,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "tedd%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -154,29 +177,35 @@ code = ''' lfs_unmount(&lfs); ''' -[[case]] # reentrant many directory creation/rename/removal -define.N = [5, 11] +[cases.test_dirs_many_reentrant] +defines.N = [5, 11] +if = 'BLOCK_COUNT >= 4*N' reentrant = true code = ''' - err = lfs_mount(&lfs, &cfg); + lfs_t lfs; + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "hi%03d", i); err = lfs_mkdir(&lfs, path); assert(err == 0 || err == LFS_ERR_EXIST); } for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "hello%03d", i); err = lfs_remove(&lfs, path); assert(err == 0 || err == LFS_ERR_NOENT); } + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, ".") == 0); @@ -184,6 +213,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "hi%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -209,6 +239,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "hello%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -218,6 +249,7 @@ code = ''' lfs_dir_close(&lfs, &dir) => 0; for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "hello%03d", i); lfs_remove(&lfs, path) => 0; } @@ -234,22 +266,28 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # file creation -define.N = 'range(3, 100, 11)' +[cases.test_dirs_file_creation] +defines.N = 'range(3, 100, 11)' +if = 'N < BLOCK_COUNT/2' code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "file%03d", i); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfs_file_close(&lfs, &file) => 0; } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, ".") == 0); @@ -257,6 +295,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "file%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_REG); @@ -267,22 +306,28 @@ code = ''' lfs_unmount(&lfs); ''' -[[case]] # file removal -define.N = 'range(0, 100, 3)' +[cases.test_dirs_file_removal] +defines.N = 'range(3, 100, 11)' +if = 'N < BLOCK_COUNT/2' code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "removeme%03d", i); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfs_file_close(&lfs, &file) => 0; } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, ".") == 0); @@ -290,6 +335,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "removeme%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_REG); @@ -299,14 +345,15 @@ code = ''' lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs); - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "removeme%03d", i); lfs_remove(&lfs, path) => 0; } lfs_unmount(&lfs); - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -319,22 +366,28 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # file rename -define.N = 'range(0, 100, 3)' +[cases.test_dirs_file_rename] +defines.N = 'range(3, 100, 11)' +if = 'N < BLOCK_COUNT/2' code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "test%03d", i); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfs_file_close(&lfs, &file) => 0; } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, ".") == 0); @@ -342,6 +395,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "test%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_REG); @@ -351,7 +405,7 @@ code = ''' lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs); - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 0; i < N; i++) { char oldpath[128]; char newpath[128]; @@ -361,7 +415,7 @@ code = ''' } lfs_unmount(&lfs); - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -370,6 +424,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "tedd%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_REG); @@ -380,29 +435,36 @@ code = ''' lfs_unmount(&lfs); ''' -[[case]] # reentrant file creation/rename/removal -define.N = [5, 25] +[cases.test_dirs_file_reentrant] +defines.N = [5, 25] +if = 'N < BLOCK_COUNT/2' reentrant = true code = ''' - err = lfs_mount(&lfs, &cfg); + lfs_t lfs; + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "hi%03d", i); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_close(&lfs, &file) => 0; } for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "hello%03d", i); err = lfs_remove(&lfs, path); assert(err == 0 || err == LFS_ERR_NOENT); } + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, ".") == 0); @@ -410,6 +472,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "hi%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_REG); @@ -435,6 +498,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "hello%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_REG); @@ -444,6 +508,7 @@ code = ''' lfs_dir_close(&lfs, &dir) => 0; for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "hello%03d", i); lfs_remove(&lfs, path) => 0; } @@ -460,24 +525,28 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # nested directories +[cases.test_dirs_nested] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "potato") => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "burito", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "potato/baked") => 0; lfs_mkdir(&lfs, "potato/sweet") => 0; lfs_mkdir(&lfs, "potato/fried") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "potato") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); info.type => LFS_TYPE_DIR; @@ -498,21 +567,21 @@ code = ''' lfs_unmount(&lfs) => 0; // try removing? - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY; lfs_unmount(&lfs) => 0; // try renaming? - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "potato", "coldpotato") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "coldpotato", "warmpotato") => 0; lfs_rename(&lfs, "warmpotato", "hotpotato") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_remove(&lfs, "potato") => LFS_ERR_NOENT; lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT; lfs_remove(&lfs, "warmpotato") => LFS_ERR_NOENT; @@ -520,7 +589,7 @@ code = ''' lfs_unmount(&lfs) => 0; // try cross-directory renaming - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "coldpotato") => 0; lfs_rename(&lfs, "hotpotato/baked", "coldpotato/baked") => 0; lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY; @@ -536,7 +605,7 @@ code = ''' lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "hotpotato") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -558,7 +627,7 @@ code = ''' lfs_unmount(&lfs) => 0; // final remove - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "hotpotato/baked") => 0; lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; @@ -568,7 +637,7 @@ code = ''' lfs_remove(&lfs, "hotpotato") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -584,17 +653,22 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # recursive remove -define.N = [10, 100] +[cases.test_dirs_recursive_remove] +defines.N = [10, 100] +if = 'N < BLOCK_COUNT/2' code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "prickly-pear") => 0; for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "prickly-pear/cactus%03d", i); lfs_mkdir(&lfs, path) => 0; } + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, ".") == 0); @@ -602,6 +676,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "cactus%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -611,7 +686,7 @@ code = ''' lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs); - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY; lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; @@ -622,6 +697,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { + char path[1024]; sprintf(path, "cactus%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -636,22 +712,24 @@ code = ''' lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT; lfs_unmount(&lfs) => 0; ''' -[[case]] # other error cases +[cases.test_dirs_other_errors] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "potato") => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "burito", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST; lfs_mkdir(&lfs, "burito") => LFS_ERR_EXIST; @@ -659,6 +737,7 @@ code = ''' LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; lfs_file_open(&lfs, &file, "potato", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "tomato") => LFS_ERR_NOENT; lfs_dir_open(&lfs, &dir, "burito") => LFS_ERR_NOTDIR; lfs_file_open(&lfs, &file, "tomato", LFS_O_RDONLY) => LFS_ERR_NOENT; @@ -678,6 +757,7 @@ code = ''' // check that errors did not corrupt directory lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, ".") == 0); @@ -696,7 +776,7 @@ code = ''' lfs_unmount(&lfs) => 0; // or on disk - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -715,13 +795,16 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # directory seek -define.COUNT = [4, 128, 132] +[cases.test_dirs_seek] +defines.COUNT = [4, 128, 132] +if = 'COUNT < BLOCK_COUNT/2' code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "hello") => 0; for (int i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "hello/kitty%03d", i); lfs_mkdir(&lfs, path) => 0; } @@ -729,8 +812,10 @@ code = ''' // try seeking to each dir entry for (int j = 0; j < COUNT; j++) { - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "hello") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -739,6 +824,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); for (int i = 0; i < j; i++) { + char path[1024]; sprintf(path, "kitty%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, path) == 0); @@ -748,13 +834,14 @@ code = ''' assert(pos >= 0); lfs_dir_seek(&lfs, &dir, pos) => 0; + char path[1024]; sprintf(path, "kitty%03d", j); lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, path) == 0); assert(info.type == LFS_TYPE_DIR); lfs_dir_rewind(&lfs, &dir) => 0; - sprintf(path, "kitty%03d", 0); + sprintf(path, "kitty%03u", 0); lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -776,8 +863,10 @@ code = ''' } // try seeking to end of dir - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "hello") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -786,6 +875,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); for (int i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "kitty%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, path) == 0); @@ -800,6 +890,7 @@ code = ''' lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_rewind(&lfs, &dir) => 0; + char path[1024]; sprintf(path, "kitty%03d", 0); lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -818,20 +909,25 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # root seek -define.COUNT = [4, 128, 132] +[cases.test_dirs_toot_seek] +defines.COUNT = [4, 128, 132] +if = 'COUNT < BLOCK_COUNT/2' code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "hi%03d", i); lfs_mkdir(&lfs, path) => 0; } lfs_unmount(&lfs) => 0; for (int j = 0; j < COUNT; j++) { - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -840,6 +936,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); for (int i = 0; i < j; i++) { + char path[1024]; sprintf(path, "hi%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, path) == 0); @@ -849,13 +946,14 @@ code = ''' assert(pos >= 0); lfs_dir_seek(&lfs, &dir, pos) => 0; + char path[1024]; sprintf(path, "hi%03d", j); lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, path) == 0); assert(info.type == LFS_TYPE_DIR); lfs_dir_rewind(&lfs, &dir) => 0; - sprintf(path, "hi%03d", 0); + sprintf(path, "hi%03u", 0); lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -877,8 +975,10 @@ code = ''' } // try seeking to end of dir - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -887,6 +987,7 @@ code = ''' assert(info.type == LFS_TYPE_DIR); for (int i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "hi%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, path) == 0); @@ -901,6 +1002,7 @@ code = ''' lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_rewind(&lfs, &dir) => 0; + char path[1024]; sprintf(path, "hi%03d", 0); lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); diff --git a/tests/test_entries.toml b/tests/test_entries.toml index 81e175f..7aa551e 100644 --- a/tests/test_entries.toml +++ b/tests/test_entries.toml @@ -2,19 +2,23 @@ # Note that these tests are intended for 512 byte inline sizes. They should # still pass with other inline sizes but wouldn't be testing anything. -define.LFS_CACHE_SIZE = 512 -if = 'LFS_CACHE_SIZE % LFS_PROG_SIZE == 0 && LFS_CACHE_SIZE == 512' +defines.CACHE_SIZE = 512 +if = 'CACHE_SIZE % PROG_SIZE == 0 && CACHE_SIZE == 512' -[[case]] # entry grow test +[cases.test_entries_grow] code = ''' uint8_t wbuffer[1024]; uint8_t rbuffer[1024]; - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // write hi0 20 + char path[1024]; + lfs_size_t size; sprintf(path, "hi0"); size = 20; + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; memset(wbuffer, 'c', size); @@ -94,16 +98,20 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # entry shrink test +[cases.test_entries_shrink] code = ''' uint8_t wbuffer[1024]; uint8_t rbuffer[1024]; - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // write hi0 20 + char path[1024]; + lfs_size_t size; sprintf(path, "hi0"); size = 20; + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; memset(wbuffer, 'c', size); @@ -183,16 +191,20 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # entry spill test +[cases.test_entries_spill] code = ''' uint8_t wbuffer[1024]; uint8_t rbuffer[1024]; - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // write hi0 200 + char path[1024]; + lfs_size_t size; sprintf(path, "hi0"); size = 200; + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; memset(wbuffer, 'c', size); @@ -256,16 +268,20 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # entry push spill test +[cases.test_entries_push_spill] code = ''' uint8_t wbuffer[1024]; uint8_t rbuffer[1024]; - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // write hi0 200 + char path[1024]; + lfs_size_t size; sprintf(path, "hi0"); size = 200; + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; memset(wbuffer, 'c', size); @@ -345,16 +361,20 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # entry push spill two test +[cases.test_entries_push_spill_two] code = ''' uint8_t wbuffer[1024]; uint8_t rbuffer[1024]; - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // write hi0 200 + char path[1024]; + lfs_size_t size; sprintf(path, "hi0"); size = 200; + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; memset(wbuffer, 'c', size); @@ -449,16 +469,20 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # entry drop test +[cases.test_entries_drop] code = ''' uint8_t wbuffer[1024]; uint8_t rbuffer[1024]; - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // write hi0 200 + char path[1024]; + lfs_size_t size; sprintf(path, "hi0"); size = 200; + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; memset(wbuffer, 'c', size); @@ -491,6 +515,7 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_remove(&lfs, "hi1") => 0; + struct lfs_info info; lfs_stat(&lfs, "hi1", &info) => LFS_ERR_NOENT; // read hi0 200 sprintf(path, "hi0"); size = 200; @@ -547,15 +572,18 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # create too big +[cases.test_entries_create_too_big] code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + char path[1024]; memset(path, 'm', 200); path[200] = '\0'; - size = 400; + lfs_size_t size = 400; + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; uint8_t wbuffer[1024]; @@ -572,15 +600,18 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # resize too big +[cases.test_entries_resize_too_big] code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + char path[1024]; memset(path, 'm', 200); path[200] = '\0'; - size = 40; + lfs_size_t size = 40; + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; uint8_t wbuffer[1024]; diff --git a/tests/test_evil.toml b/tests/test_evil.toml index 920d3a0..4acd5ef 100644 --- a/tests/test_evil.toml +++ b/tests/test_evil.toml @@ -3,16 +3,17 @@ # invalid pointer tests (outside of block_count) -[[case]] # invalid tail-pointer test -define.TAIL_TYPE = ['LFS_TYPE_HARDTAIL', 'LFS_TYPE_SOFTTAIL'] -define.INVALSET = [0x3, 0x1, 0x2] +[cases.test_evil_invalid_tail_pointer] +defines.TAIL_TYPE = ['LFS_TYPE_HARDTAIL', 'LFS_TYPE_SOFTTAIL'] +defines.INVALSET = [0x3, 0x1, 0x2] in = "lfs.c" code = ''' // create littlefs - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; // change tail-pointer to invalid pointers - lfs_init(&lfs, &cfg) => 0; + lfs_init(&lfs, cfg) => 0; lfs_mdir_t mdir; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( @@ -23,25 +24,27 @@ code = ''' lfs_deinit(&lfs) => 0; // test that mount fails gracefully - lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; + lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; ''' -[[case]] # invalid dir pointer test -define.INVALSET = [0x3, 0x1, 0x2] +[cases.test_evil_invalid_dir_pointer] +defines.INVALSET = [0x3, 0x1, 0x2] in = "lfs.c" code = ''' // create littlefs - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; // make a dir - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "dir_here") => 0; lfs_unmount(&lfs) => 0; // change the dir pointer to be invalid - lfs_init(&lfs, &cfg) => 0; + lfs_init(&lfs, cfg) => 0; lfs_mdir_t mdir; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; // make sure id 1 == our directory + uint8_t buffer[1024]; lfs_dir_get(&lfs, &mdir, LFS_MKTAG(0x700, 0x3ff, 0), LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("dir_here")), buffer) @@ -57,14 +60,17 @@ code = ''' // test that accessing our bad dir fails, note there's a number // of ways to access the dir, some can fail, but some don't - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + struct lfs_info info; lfs_stat(&lfs, "dir_here", &info) => 0; assert(strcmp(info.name, "dir_here") == 0); assert(info.type == LFS_TYPE_DIR); + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "dir_here") => LFS_ERR_CORRUPT; lfs_stat(&lfs, "dir_here/file_here", &info) => LFS_ERR_CORRUPT; lfs_dir_open(&lfs, &dir, "dir_here/dir_here") => LFS_ERR_CORRUPT; + lfs_file_t file; lfs_file_open(&lfs, &file, "dir_here/file_here", LFS_O_RDONLY) => LFS_ERR_CORRUPT; lfs_file_open(&lfs, &file, "dir_here/file_here", @@ -72,24 +78,27 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # invalid file pointer test +[cases.test_evil_invalid_file_pointer] in = "lfs.c" -define.SIZE = [10, 1000, 100000] # faked file size +defines.SIZE = [10, 1000, 100000] # faked file size code = ''' // create littlefs - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; // make a file - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "file_here", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; // change the file pointer to be invalid - lfs_init(&lfs, &cfg) => 0; + lfs_init(&lfs, cfg) => 0; lfs_mdir_t mdir; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; // make sure id 1 == our file + uint8_t buffer[1024]; lfs_dir_get(&lfs, &mdir, LFS_MKTAG(0x700, 0x3ff, 0), LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer) @@ -103,7 +112,8 @@ code = ''' // test that accessing our bad file fails, note there's a number // of ways to access the dir, some can fail, but some don't - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + struct lfs_info info; lfs_stat(&lfs, "file_here", &info) => 0; assert(strcmp(info.name, "file_here") == 0); assert(info.type == LFS_TYPE_REG); @@ -114,20 +124,22 @@ code = ''' lfs_file_close(&lfs, &file) => 0; // any allocs that traverse CTZ must unfortunately must fail - if (SIZE > 2*LFS_BLOCK_SIZE) { + if (SIZE > 2*BLOCK_SIZE) { lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT; } lfs_unmount(&lfs) => 0; ''' -[[case]] # invalid pointer in CTZ skip-list test -define.SIZE = ['2*LFS_BLOCK_SIZE', '3*LFS_BLOCK_SIZE', '4*LFS_BLOCK_SIZE'] +[cases.test_evil_invalid_ctz_pointer] # invalid pointer in CTZ skip-list test +defines.SIZE = ['2*BLOCK_SIZE', '3*BLOCK_SIZE', '4*BLOCK_SIZE'] in = "lfs.c" code = ''' // create littlefs - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; // make a file - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "file_here", LFS_O_WRONLY | LFS_O_CREAT) => 0; for (int i = 0; i < SIZE; i++) { @@ -137,10 +149,11 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; // change pointer in CTZ skip-list to be invalid - lfs_init(&lfs, &cfg) => 0; + lfs_init(&lfs, cfg) => 0; lfs_mdir_t mdir; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; // make sure id 1 == our file and get our CTZ structure + uint8_t buffer[4*BLOCK_SIZE]; lfs_dir_get(&lfs, &mdir, LFS_MKTAG(0x700, 0x3ff, 0), LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer) @@ -153,18 +166,19 @@ code = ''' => LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz)); lfs_ctz_fromle32(&ctz); // rewrite block to contain bad pointer - uint8_t bbuffer[LFS_BLOCK_SIZE]; - cfg.read(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0; + uint8_t bbuffer[BLOCK_SIZE]; + cfg->read(cfg, ctz.head, 0, bbuffer, BLOCK_SIZE) => 0; uint32_t bad = lfs_tole32(0xcccccccc); memcpy(&bbuffer[0], &bad, sizeof(bad)); memcpy(&bbuffer[4], &bad, sizeof(bad)); - cfg.erase(&cfg, ctz.head) => 0; - cfg.prog(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0; + cfg->erase(cfg, ctz.head) => 0; + cfg->prog(cfg, ctz.head, 0, bbuffer, BLOCK_SIZE) => 0; lfs_deinit(&lfs) => 0; // test that accessing our bad file fails, note there's a number // of ways to access the dir, some can fail, but some don't - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + struct lfs_info info; lfs_stat(&lfs, "file_here", &info) => 0; assert(strcmp(info.name, "file_here") == 0); assert(info.type == LFS_TYPE_REG); @@ -175,22 +189,23 @@ code = ''' lfs_file_close(&lfs, &file) => 0; // any allocs that traverse CTZ must unfortunately must fail - if (SIZE > 2*LFS_BLOCK_SIZE) { + if (SIZE > 2*BLOCK_SIZE) { lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT; } lfs_unmount(&lfs) => 0; ''' -[[case]] # invalid gstate pointer -define.INVALSET = [0x3, 0x1, 0x2] +[cases.test_evil_invalid_gstate_pointer] +defines.INVALSET = [0x3, 0x1, 0x2] in = "lfs.c" code = ''' // create littlefs - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; // create an invalid gstate - lfs_init(&lfs, &cfg) => 0; + lfs_init(&lfs, cfg) => 0; lfs_mdir_t mdir; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_fs_prepmove(&lfs, 1, (lfs_block_t [2]){ @@ -202,21 +217,22 @@ code = ''' // test that mount fails gracefully // mount may not fail, but our first alloc should fail when // we try to fix the gstate - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "should_fail") => LFS_ERR_CORRUPT; lfs_unmount(&lfs) => 0; ''' # cycle detection/recovery tests -[[case]] # metadata-pair threaded-list loop test +[cases.test_evil_mdir_loop] # metadata-pair threaded-list loop test in = "lfs.c" code = ''' // create littlefs - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; // change tail-pointer to point to ourself - lfs_init(&lfs, &cfg) => 0; + lfs_init(&lfs, cfg) => 0; lfs_mdir_t mdir; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( @@ -225,20 +241,21 @@ code = ''' lfs_deinit(&lfs) => 0; // test that mount fails gracefully - lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; + lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; ''' -[[case]] # metadata-pair threaded-list 2-length loop test +[cases.test_evil_mdir_loop2] # metadata-pair threaded-list 2-length loop test in = "lfs.c" code = ''' // create littlefs with child dir - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "child") => 0; lfs_unmount(&lfs) => 0; // find child - lfs_init(&lfs, &cfg) => 0; + lfs_init(&lfs, cfg) => 0; lfs_mdir_t mdir; lfs_block_t pair[2]; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; @@ -255,20 +272,21 @@ code = ''' lfs_deinit(&lfs) => 0; // test that mount fails gracefully - lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; + lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; ''' -[[case]] # metadata-pair threaded-list 1-length child loop test +[cases.test_evil_mdir_loop_child] # metadata-pair threaded-list 1-length child loop test in = "lfs.c" code = ''' // create littlefs with child dir - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "child") => 0; lfs_unmount(&lfs) => 0; // find child - lfs_init(&lfs, &cfg) => 0; + lfs_init(&lfs, cfg) => 0; lfs_mdir_t mdir; lfs_block_t pair[2]; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; @@ -284,5 +302,5 @@ code = ''' lfs_deinit(&lfs) => 0; // test that mount fails gracefully - lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; + lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; ''' diff --git a/tests/test_exhaustion.toml b/tests/test_exhaustion.toml index 569611c..2cf6aed 100644 --- a/tests/test_exhaustion.toml +++ b/tests/test_exhaustion.toml @@ -1,46 +1,50 @@ -[[case]] # test running a filesystem to exhaustion -define.LFS_ERASE_CYCLES = 10 -define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster -define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' -define.LFS_BADBLOCK_BEHAVIOR = [ - 'LFS_TESTBD_BADBLOCK_PROGERROR', - 'LFS_TESTBD_BADBLOCK_ERASEERROR', - 'LFS_TESTBD_BADBLOCK_READERROR', - 'LFS_TESTBD_BADBLOCK_PROGNOOP', - 'LFS_TESTBD_BADBLOCK_ERASENOOP', +# test running a filesystem to exhaustion +[cases.test_exhaustion_normal] +defines.ERASE_CYCLES = 10 +defines.BLOCK_COUNT = 256 # small bd so test runs faster +defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2' +defines.BADBLOCK_BEHAVIOR = [ + 'LFS_EMUBD_BADBLOCK_PROGERROR', + 'LFS_EMUBD_BADBLOCK_ERASEERROR', + 'LFS_EMUBD_BADBLOCK_READERROR', + 'LFS_EMUBD_BADBLOCK_PROGNOOP', + 'LFS_EMUBD_BADBLOCK_ERASENOOP', ] -define.FILES = 10 +defines.FILES = 10 code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "roadrunner") => 0; lfs_unmount(&lfs) => 0; uint32_t cycle = 0; while (true) { - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (uint32_t i = 0; i < FILES; i++) { // chose name, roughly random seed, and random 2^n size + char path[1024]; sprintf(path, "roadrunner/test%d", i); - srand(cycle * i); - size = 1 << ((rand() % 10)+2); + uint32_t prng = cycle * i; + lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (rand() % 26); + char c = 'a' + (TEST_PRNG(&prng) % 26); lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); assert(res == 1 || res == LFS_ERR_NOSPC); if (res == LFS_ERR_NOSPC) { - err = lfs_file_close(&lfs, &file); + int err = lfs_file_close(&lfs, &file); assert(err == 0 || err == LFS_ERR_NOSPC); lfs_unmount(&lfs) => 0; goto exhausted; } } - err = lfs_file_close(&lfs, &file); + int err = lfs_file_close(&lfs, &file); assert(err == 0 || err == LFS_ERR_NOSPC); if (err == LFS_ERR_NOSPC) { lfs_unmount(&lfs) => 0; @@ -50,13 +54,15 @@ code = ''' for (uint32_t i = 0; i < FILES; i++) { // check for errors + char path[1024]; sprintf(path, "roadrunner/test%d", i); - srand(cycle * i); - size = 1 << ((rand() % 10)+2); + uint32_t prng = cycle * i; + lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (rand() % 26); + char c = 'a' + (TEST_PRNG(&prng) % 26); char r; lfs_file_read(&lfs, &file, &r, 1) => 1; assert(r == c); @@ -71,10 +77,12 @@ code = ''' exhausted: // should still be readable - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (uint32_t i = 0; i < FILES; i++) { // check for errors + char path[1024]; sprintf(path, "roadrunner/test%d", i); + struct lfs_info info; lfs_stat(&lfs, path, &info) => 0; } lfs_unmount(&lfs) => 0; @@ -82,47 +90,51 @@ exhausted: LFS_WARN("completed %d cycles", cycle); ''' -[[case]] # test running a filesystem to exhaustion - # which also requires expanding superblocks -define.LFS_ERASE_CYCLES = 10 -define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster -define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' -define.LFS_BADBLOCK_BEHAVIOR = [ - 'LFS_TESTBD_BADBLOCK_PROGERROR', - 'LFS_TESTBD_BADBLOCK_ERASEERROR', - 'LFS_TESTBD_BADBLOCK_READERROR', - 'LFS_TESTBD_BADBLOCK_PROGNOOP', - 'LFS_TESTBD_BADBLOCK_ERASENOOP', +# test running a filesystem to exhaustion +# which also requires expanding superblocks +[cases.test_exhaustion_superblocks] +defines.ERASE_CYCLES = 10 +defines.BLOCK_COUNT = 256 # small bd so test runs faster +defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2' +defines.BADBLOCK_BEHAVIOR = [ + 'LFS_EMUBD_BADBLOCK_PROGERROR', + 'LFS_EMUBD_BADBLOCK_ERASEERROR', + 'LFS_EMUBD_BADBLOCK_READERROR', + 'LFS_EMUBD_BADBLOCK_PROGNOOP', + 'LFS_EMUBD_BADBLOCK_ERASENOOP', ] -define.FILES = 10 +defines.FILES = 10 code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; uint32_t cycle = 0; while (true) { - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (uint32_t i = 0; i < FILES; i++) { // chose name, roughly random seed, and random 2^n size + char path[1024]; sprintf(path, "test%d", i); - srand(cycle * i); - size = 1 << ((rand() % 10)+2); + uint32_t prng = cycle * i; + lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (rand() % 26); + char c = 'a' + (TEST_PRNG(&prng) % 26); lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); assert(res == 1 || res == LFS_ERR_NOSPC); if (res == LFS_ERR_NOSPC) { - err = lfs_file_close(&lfs, &file); + int err = lfs_file_close(&lfs, &file); assert(err == 0 || err == LFS_ERR_NOSPC); lfs_unmount(&lfs) => 0; goto exhausted; } } - err = lfs_file_close(&lfs, &file); + int err = lfs_file_close(&lfs, &file); assert(err == 0 || err == LFS_ERR_NOSPC); if (err == LFS_ERR_NOSPC) { lfs_unmount(&lfs) => 0; @@ -132,13 +144,15 @@ code = ''' for (uint32_t i = 0; i < FILES; i++) { // check for errors + char path[1024]; sprintf(path, "test%d", i); - srand(cycle * i); - size = 1 << ((rand() % 10)+2); + uint32_t prng = cycle * i; + lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (rand() % 26); + char c = 'a' + (TEST_PRNG(&prng) % 26); char r; lfs_file_read(&lfs, &file, &r, 1) => 1; assert(r == c); @@ -153,9 +167,11 @@ code = ''' exhausted: // should still be readable - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (uint32_t i = 0; i < FILES; i++) { // check for errors + char path[1024]; + struct lfs_info info; sprintf(path, "test%d", i); lfs_stat(&lfs, path, &info) => 0; } @@ -169,51 +185,55 @@ exhausted: # into increasing the block devices lifetime. This is something we can actually # check for. -[[case]] # wear-level test running a filesystem to exhaustion -define.LFS_ERASE_CYCLES = 20 -define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster -define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' -define.FILES = 10 +# wear-level test running a filesystem to exhaustion +[cases.test_exhuastion_wear_leveling] +defines.ERASE_CYCLES = 20 +defines.BLOCK_COUNT = 256 # small bd so test runs faster +defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2' +defines.FILES = 10 code = ''' uint32_t run_cycles[2]; - const uint32_t run_block_count[2] = {LFS_BLOCK_COUNT/2, LFS_BLOCK_COUNT}; + const uint32_t run_block_count[2] = {BLOCK_COUNT/2, BLOCK_COUNT}; for (int run = 0; run < 2; run++) { - for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) { - lfs_testbd_setwear(&cfg, b, - (b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0; + for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) { + lfs_emubd_setwear(cfg, b, + (b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0; } - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "roadrunner") => 0; lfs_unmount(&lfs) => 0; uint32_t cycle = 0; while (true) { - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (uint32_t i = 0; i < FILES; i++) { // chose name, roughly random seed, and random 2^n size + char path[1024]; sprintf(path, "roadrunner/test%d", i); - srand(cycle * i); - size = 1 << ((rand() % 10)+2); + uint32_t prng = cycle * i; + lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (rand() % 26); + char c = 'a' + (TEST_PRNG(&prng) % 26); lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); assert(res == 1 || res == LFS_ERR_NOSPC); if (res == LFS_ERR_NOSPC) { - err = lfs_file_close(&lfs, &file); + int err = lfs_file_close(&lfs, &file); assert(err == 0 || err == LFS_ERR_NOSPC); lfs_unmount(&lfs) => 0; goto exhausted; } } - err = lfs_file_close(&lfs, &file); + int err = lfs_file_close(&lfs, &file); assert(err == 0 || err == LFS_ERR_NOSPC); if (err == LFS_ERR_NOSPC) { lfs_unmount(&lfs) => 0; @@ -223,13 +243,15 @@ code = ''' for (uint32_t i = 0; i < FILES; i++) { // check for errors + char path[1024]; sprintf(path, "roadrunner/test%d", i); - srand(cycle * i); - size = 1 << ((rand() % 10)+2); + uint32_t prng = cycle * i; + lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (rand() % 26); + char c = 'a' + (TEST_PRNG(&prng) % 26); char r; lfs_file_read(&lfs, &file, &r, 1) => 1; assert(r == c); @@ -244,9 +266,11 @@ code = ''' exhausted: // should still be readable - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (uint32_t i = 0; i < FILES; i++) { // check for errors + char path[1024]; + struct lfs_info info; sprintf(path, "roadrunner/test%d", i); lfs_stat(&lfs, path, &info) => 0; } @@ -261,48 +285,52 @@ exhausted: LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); ''' -[[case]] # wear-level test + expanding superblock -define.LFS_ERASE_CYCLES = 20 -define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster -define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' -define.FILES = 10 +# wear-level test + expanding superblock +[cases.test_exhaustion_wear_leveling_superblocks] +defines.ERASE_CYCLES = 20 +defines.BLOCK_COUNT = 256 # small bd so test runs faster +defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2' +defines.FILES = 10 code = ''' uint32_t run_cycles[2]; - const uint32_t run_block_count[2] = {LFS_BLOCK_COUNT/2, LFS_BLOCK_COUNT}; + const uint32_t run_block_count[2] = {BLOCK_COUNT/2, BLOCK_COUNT}; for (int run = 0; run < 2; run++) { - for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) { - lfs_testbd_setwear(&cfg, b, - (b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0; + for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) { + lfs_emubd_setwear(cfg, b, + (b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0; } - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; uint32_t cycle = 0; while (true) { - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (uint32_t i = 0; i < FILES; i++) { // chose name, roughly random seed, and random 2^n size + char path[1024]; sprintf(path, "test%d", i); - srand(cycle * i); - size = 1 << ((rand() % 10)+2); + uint32_t prng = cycle * i; + lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (rand() % 26); + char c = 'a' + (TEST_PRNG(&prng) % 26); lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); assert(res == 1 || res == LFS_ERR_NOSPC); if (res == LFS_ERR_NOSPC) { - err = lfs_file_close(&lfs, &file); + int err = lfs_file_close(&lfs, &file); assert(err == 0 || err == LFS_ERR_NOSPC); lfs_unmount(&lfs) => 0; goto exhausted; } } - err = lfs_file_close(&lfs, &file); + int err = lfs_file_close(&lfs, &file); assert(err == 0 || err == LFS_ERR_NOSPC); if (err == LFS_ERR_NOSPC) { lfs_unmount(&lfs) => 0; @@ -312,13 +340,15 @@ code = ''' for (uint32_t i = 0; i < FILES; i++) { // check for errors + char path[1024]; sprintf(path, "test%d", i); - srand(cycle * i); - size = 1 << ((rand() % 10)+2); + uint32_t prng = cycle * i; + lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (rand() % 26); + char c = 'a' + (TEST_PRNG(&prng) % 26); char r; lfs_file_read(&lfs, &file, &r, 1) => 1; assert(r == c); @@ -333,9 +363,11 @@ code = ''' exhausted: // should still be readable - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (uint32_t i = 0; i < FILES; i++) { // check for errors + char path[1024]; + struct lfs_info info; sprintf(path, "test%d", i); lfs_stat(&lfs, path, &info) => 0; } @@ -350,44 +382,48 @@ exhausted: LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); ''' -[[case]] # test that we wear blocks roughly evenly -define.LFS_ERASE_CYCLES = 0xffffffff -define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster -define.LFS_BLOCK_CYCLES = [5, 4, 3, 2, 1] -define.CYCLES = 100 -define.FILES = 10 -if = 'LFS_BLOCK_CYCLES < CYCLES/10' +# test that we wear blocks roughly evenly +[cases.test_exhaustion_wear_distribution] +defines.ERASE_CYCLES = 0xffffffff +defines.BLOCK_COUNT = 256 # small bd so test runs faster +defines.BLOCK_CYCLES = [5, 4, 3, 2, 1] +defines.CYCLES = 100 +defines.FILES = 10 +if = 'BLOCK_CYCLES < CYCLES/10' code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "roadrunner") => 0; lfs_unmount(&lfs) => 0; uint32_t cycle = 0; while (cycle < CYCLES) { - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (uint32_t i = 0; i < FILES; i++) { // chose name, roughly random seed, and random 2^n size + char path[1024]; sprintf(path, "roadrunner/test%d", i); - srand(cycle * i); - size = 1 << 4; //((rand() % 10)+2); + uint32_t prng = cycle * i; + lfs_size_t size = 1 << 4; //((TEST_PRNG(&prng) % 10)+2); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (rand() % 26); + char c = 'a' + (TEST_PRNG(&prng) % 26); lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); assert(res == 1 || res == LFS_ERR_NOSPC); if (res == LFS_ERR_NOSPC) { - err = lfs_file_close(&lfs, &file); + int err = lfs_file_close(&lfs, &file); assert(err == 0 || err == LFS_ERR_NOSPC); lfs_unmount(&lfs) => 0; goto exhausted; } } - err = lfs_file_close(&lfs, &file); + int err = lfs_file_close(&lfs, &file); assert(err == 0 || err == LFS_ERR_NOSPC); if (err == LFS_ERR_NOSPC) { lfs_unmount(&lfs) => 0; @@ -397,13 +433,15 @@ code = ''' for (uint32_t i = 0; i < FILES; i++) { // check for errors + char path[1024]; sprintf(path, "roadrunner/test%d", i); - srand(cycle * i); - size = 1 << 4; //((rand() % 10)+2); + uint32_t prng = cycle * i; + lfs_size_t size = 1 << 4; //((TEST_PRNG(&prng) % 10)+2); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; for (lfs_size_t j = 0; j < size; j++) { - char c = 'a' + (rand() % 26); + char c = 'a' + (TEST_PRNG(&prng) % 26); char r; lfs_file_read(&lfs, &file, &r, 1) => 1; assert(r == c); @@ -418,9 +456,11 @@ code = ''' exhausted: // should still be readable - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (uint32_t i = 0; i < FILES; i++) { // check for errors + char path[1024]; + struct lfs_info info; sprintf(path, "roadrunner/test%d", i); lfs_stat(&lfs, path, &info) => 0; } @@ -429,12 +469,12 @@ exhausted: LFS_WARN("completed %d cycles", cycle); // check the wear on our block device - lfs_testbd_wear_t minwear = -1; - lfs_testbd_wear_t totalwear = 0; - lfs_testbd_wear_t maxwear = 0; + lfs_emubd_wear_t minwear = -1; + lfs_emubd_wear_t totalwear = 0; + lfs_emubd_wear_t maxwear = 0; // skip 0 and 1 as superblock movement is intentionally avoided - for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { - lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); + for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) { + lfs_emubd_wear_t wear = lfs_emubd_wear(cfg, b); printf("%08x: wear %d\n", b, wear); assert(wear >= 0); if (wear < minwear) { @@ -445,17 +485,17 @@ exhausted: } totalwear += wear; } - lfs_testbd_wear_t avgwear = totalwear / LFS_BLOCK_COUNT; + lfs_emubd_wear_t avgwear = totalwear / BLOCK_COUNT; LFS_WARN("max wear: %d cycles", maxwear); - LFS_WARN("avg wear: %d cycles", totalwear / LFS_BLOCK_COUNT); + LFS_WARN("avg wear: %d cycles", totalwear / (int)BLOCK_COUNT); LFS_WARN("min wear: %d cycles", minwear); // find standard deviation^2 - lfs_testbd_wear_t dev2 = 0; - for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { - lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); + lfs_emubd_wear_t dev2 = 0; + for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) { + lfs_emubd_wear_t wear = lfs_emubd_wear(cfg, b); assert(wear >= 0); - lfs_testbd_swear_t diff = wear - avgwear; + lfs_emubd_swear_t diff = wear - avgwear; dev2 += diff*diff; } dev2 /= totalwear; diff --git a/tests/test_files.toml b/tests/test_files.toml index 565e665..afb0811 100644 --- a/tests/test_files.toml +++ b/tests/test_files.toml @@ -1,17 +1,20 @@ -[[case]] # simple file test +[cases.test_files_simple] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "hello", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - size = strlen("Hello World!")+1; + lfs_size_t size = strlen("Hello World!")+1; + uint8_t buffer[1024]; strcpy((char*)buffer, "Hello World!"); lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0; lfs_file_read(&lfs, &file, buffer, size) => size; assert(strcmp((char*)buffer, "Hello World!") == 0); @@ -19,21 +22,24 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # larger files -define.SIZE = [32, 8192, 262144, 0, 7, 8193] -define.CHUNKSIZE = [31, 16, 33, 1, 1023] +[cases.test_files_large] +defines.SIZE = [32, 8192, 262144, 0, 7, 8193] +defines.CHUNKSIZE = [31, 16, 33, 1, 1023] code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; // write - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - srand(1); + uint32_t prng = 1; + uint8_t buffer[1024]; for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = rand() & 0xff; + buffer[b] = TEST_PRNG(&prng) & 0xff; } lfs_file_write(&lfs, &file, buffer, chunk) => chunk; } @@ -41,15 +47,15 @@ code = ''' lfs_unmount(&lfs) => 0; // read - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_size(&lfs, &file) => SIZE; - srand(1); + prng = 1; for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); lfs_file_read(&lfs, &file, buffer, chunk) => chunk; for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (rand() & 0xff)); + assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); } } lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; @@ -57,22 +63,25 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # rewriting files -define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] -define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] -define.CHUNKSIZE = [31, 16, 1] +[cases.test_files_rewrite] +defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] +defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] +defines.CHUNKSIZE = [31, 16, 1] code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; // write - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; + uint8_t buffer[1024]; lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - srand(1); + uint32_t prng = 1; for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = rand() & 0xff; + buffer[b] = TEST_PRNG(&prng) & 0xff; } lfs_file_write(&lfs, &file, buffer, chunk) => chunk; } @@ -80,15 +89,15 @@ code = ''' lfs_unmount(&lfs) => 0; // read - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_size(&lfs, &file) => SIZE1; - srand(1); + prng = 1; for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); lfs_file_read(&lfs, &file, buffer, chunk) => chunk; for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (rand() & 0xff)); + assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); } } lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; @@ -96,13 +105,13 @@ code = ''' lfs_unmount(&lfs) => 0; // rewrite - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY) => 0; - srand(2); + prng = 2; for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = rand() & 0xff; + buffer[b] = TEST_PRNG(&prng) & 0xff; } lfs_file_write(&lfs, &file, buffer, chunk) => chunk; } @@ -110,27 +119,27 @@ code = ''' lfs_unmount(&lfs) => 0; // read - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_size(&lfs, &file) => lfs_max(SIZE1, SIZE2); - srand(2); + prng = 2; for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); lfs_file_read(&lfs, &file, buffer, chunk) => chunk; for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (rand() & 0xff)); + assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); } } if (SIZE1 > SIZE2) { - srand(1); + prng = 1; for (lfs_size_t b = 0; b < SIZE2; b++) { - rand(); + TEST_PRNG(&prng); } for (lfs_size_t i = SIZE2; i < SIZE1; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); lfs_file_read(&lfs, &file, buffer, chunk) => chunk; for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (rand() & 0xff)); + assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); } } } @@ -139,22 +148,25 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # appending files -define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] -define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] -define.CHUNKSIZE = [31, 16, 1] +[cases.test_files_append] +defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] +defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] +defines.CHUNKSIZE = [31, 16, 1] code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; // write - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; + uint8_t buffer[1024]; lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - srand(1); + uint32_t prng = 1; for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = rand() & 0xff; + buffer[b] = TEST_PRNG(&prng) & 0xff; } lfs_file_write(&lfs, &file, buffer, chunk) => chunk; } @@ -162,15 +174,15 @@ code = ''' lfs_unmount(&lfs) => 0; // read - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_size(&lfs, &file) => SIZE1; - srand(1); + prng = 1; for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); lfs_file_read(&lfs, &file, buffer, chunk) => chunk; for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (rand() & 0xff)); + assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); } } lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; @@ -178,13 +190,13 @@ code = ''' lfs_unmount(&lfs) => 0; // append - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_APPEND) => 0; - srand(2); + prng = 2; for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = rand() & 0xff; + buffer[b] = TEST_PRNG(&prng) & 0xff; } lfs_file_write(&lfs, &file, buffer, chunk) => chunk; } @@ -192,23 +204,23 @@ code = ''' lfs_unmount(&lfs) => 0; // read - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_size(&lfs, &file) => SIZE1 + SIZE2; - srand(1); + prng = 1; for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); lfs_file_read(&lfs, &file, buffer, chunk) => chunk; for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (rand() & 0xff)); + assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); } } - srand(2); + prng = 2; for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); lfs_file_read(&lfs, &file, buffer, chunk) => chunk; for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (rand() & 0xff)); + assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); } } lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; @@ -216,22 +228,25 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # truncating files -define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] -define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] -define.CHUNKSIZE = [31, 16, 1] +[cases.test_files_truncate] +defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193] +defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193] +defines.CHUNKSIZE = [31, 16, 1] code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; // write - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; + uint8_t buffer[1024]; lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; - srand(1); + uint32_t prng = 1; for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = rand() & 0xff; + buffer[b] = TEST_PRNG(&prng) & 0xff; } lfs_file_write(&lfs, &file, buffer, chunk) => chunk; } @@ -239,15 +254,15 @@ code = ''' lfs_unmount(&lfs) => 0; // read - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_size(&lfs, &file) => SIZE1; - srand(1); + prng = 1; for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); lfs_file_read(&lfs, &file, buffer, chunk) => chunk; for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (rand() & 0xff)); + assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); } } lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; @@ -255,13 +270,13 @@ code = ''' lfs_unmount(&lfs) => 0; // truncate - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_TRUNC) => 0; - srand(2); + prng = 2; for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = rand() & 0xff; + buffer[b] = TEST_PRNG(&prng) & 0xff; } lfs_file_write(&lfs, &file, buffer, chunk) => chunk; } @@ -269,15 +284,15 @@ code = ''' lfs_unmount(&lfs) => 0; // read - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_size(&lfs, &file) => SIZE2; - srand(2); + prng = 2; for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); lfs_file_read(&lfs, &file, buffer, chunk) => chunk; for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (rand() & 0xff)); + assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); } } lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; @@ -285,33 +300,36 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # reentrant file writing -define.SIZE = [32, 0, 7, 2049] -define.CHUNKSIZE = [31, 16, 65] +[cases.test_files_reentrant_write] +defines.SIZE = [32, 0, 7, 2049] +defines.CHUNKSIZE = [31, 16, 65] reentrant = true code = ''' - err = lfs_mount(&lfs, &cfg); + lfs_t lfs; + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } + lfs_file_t file; + uint8_t buffer[1024]; err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY); assert(err == LFS_ERR_NOENT || err == 0); if (err == 0) { // can only be 0 (new file) or full size - size = lfs_file_size(&lfs, &file); + lfs_size_t size = lfs_file_size(&lfs, &file); assert(size == 0 || size == SIZE); lfs_file_close(&lfs, &file) => 0; } // write lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_CREAT) => 0; - srand(1); + uint32_t prng = 1; for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = rand() & 0xff; + buffer[b] = TEST_PRNG(&prng) & 0xff; } lfs_file_write(&lfs, &file, buffer, chunk) => chunk; } @@ -320,12 +338,12 @@ code = ''' // read lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_size(&lfs, &file) => SIZE; - srand(1); + prng = 1; for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); lfs_file_read(&lfs, &file, buffer, chunk) => chunk; for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (rand() & 0xff)); + assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); } } lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; @@ -333,8 +351,8 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # reentrant file writing with syncs -define = [ +[cases.test_files_reentrant_write_sync] +defines = [ # append (O(n)) {MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]}, # truncate (O(n^2)) @@ -344,24 +362,27 @@ define = [ ] reentrant = true code = ''' - err = lfs_mount(&lfs, &cfg); + lfs_t lfs; + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } + lfs_file_t file; + uint8_t buffer[1024]; err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY); assert(err == LFS_ERR_NOENT || err == 0); if (err == 0) { // with syncs we could be any size, but it at least must be valid data - size = lfs_file_size(&lfs, &file); + lfs_size_t size = lfs_file_size(&lfs, &file); assert(size <= SIZE); - srand(1); + uint32_t prng = 1; for (lfs_size_t i = 0; i < size; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, size-i); lfs_file_read(&lfs, &file, buffer, chunk) => chunk; for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (rand() & 0xff)); + assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); } } lfs_file_close(&lfs, &file) => 0; @@ -370,17 +391,17 @@ code = ''' // write lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_CREAT | MODE) => 0; - size = lfs_file_size(&lfs, &file); + lfs_size_t size = lfs_file_size(&lfs, &file); assert(size <= SIZE); - srand(1); + uint32_t prng = 1; lfs_size_t skip = (MODE == LFS_O_APPEND) ? size : 0; for (lfs_size_t b = 0; b < skip; b++) { - rand(); + TEST_PRNG(&prng); } for (lfs_size_t i = skip; i < SIZE; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); for (lfs_size_t b = 0; b < chunk; b++) { - buffer[b] = rand() & 0xff; + buffer[b] = TEST_PRNG(&prng) & 0xff; } lfs_file_write(&lfs, &file, buffer, chunk) => chunk; lfs_file_sync(&lfs, &file) => 0; @@ -390,12 +411,12 @@ code = ''' // read lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_size(&lfs, &file) => SIZE; - srand(1); + prng = 1; for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); lfs_file_read(&lfs, &file, buffer, chunk) => chunk; for (lfs_size_t b = 0; b < chunk; b++) { - assert(buffer[b] == (rand() & 0xff)); + assert(buffer[b] == (TEST_PRNG(&prng) & 0xff)); } } lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; @@ -403,19 +424,22 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # many files -define.N = 300 +[cases.test_files_many] +defines.N = 300 code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; // create N files of 7 bytes - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 0; i < N; i++) { + lfs_file_t file; + char path[1024]; sprintf(path, "file_%03d", i); lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; char wbuffer[1024]; - size = 7; - snprintf(wbuffer, size, "Hi %03d", i); + lfs_size_t size = 7; + sprintf(wbuffer, "Hi %03d", i); lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs_file_close(&lfs, &file) => 0; @@ -428,25 +452,28 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # many files with power cycle -define.N = 300 +[cases.test_files_many_power_cycle] +defines.N = 300 code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; // create N files of 7 bytes - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 0; i < N; i++) { + lfs_file_t file; + char path[1024]; sprintf(path, "file_%03d", i); lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; char wbuffer[1024]; - size = 7; - snprintf(wbuffer, size, "Hi %03d", i); + lfs_size_t size = 7; + sprintf(wbuffer, "Hi %03d", i); lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; char rbuffer[1024]; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_read(&lfs, &file, rbuffer, size) => size; assert(strcmp(rbuffer, wbuffer) == 0); @@ -455,22 +482,25 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # many files with power loss -define.N = 300 +[cases.test_files_many_power_loss] +defines.N = 300 reentrant = true code = ''' - err = lfs_mount(&lfs, &cfg); + lfs_t lfs; + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } // create N files of 7 bytes for (int i = 0; i < N; i++) { + lfs_file_t file; + char path[1024]; sprintf(path, "file_%03d", i); err = lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT); char wbuffer[1024]; - size = 7; - snprintf(wbuffer, size, "Hi %03d", i); + lfs_size_t size = 7; + sprintf(wbuffer, "Hi %03d", i); if ((lfs_size_t)lfs_file_size(&lfs, &file) != size) { lfs_file_write(&lfs, &file, wbuffer, size) => size; } diff --git a/tests/test_interspersed.toml b/tests/test_interspersed.toml index 87a0578..d7143f6 100644 --- a/tests/test_interspersed.toml +++ b/tests/test_interspersed.toml @@ -1,13 +1,15 @@ -[[case]] # interspersed file test -define.SIZE = [10, 100] -define.FILES = [4, 10, 26] +[cases.test_interspersed_files] +defines.SIZE = [10, 100] +defines.FILES = [4, 10, 26] code = ''' + lfs_t lfs; lfs_file_t files[FILES]; const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int j = 0; j < FILES; j++) { + char path[1024]; sprintf(path, "%c", alphas[j]); lfs_file_open(&lfs, &files[j], path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; @@ -23,7 +25,9 @@ code = ''' lfs_file_close(&lfs, &files[j]); } + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -31,6 +35,7 @@ code = ''' assert(strcmp(info.name, "..") == 0); assert(info.type == LFS_TYPE_DIR); for (int j = 0; j < FILES; j++) { + char path[1024]; sprintf(path, "%c", alphas[j]); lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, path) == 0); @@ -41,12 +46,14 @@ code = ''' lfs_dir_close(&lfs, &dir) => 0; for (int j = 0; j < FILES; j++) { + char path[1024]; sprintf(path, "%c", alphas[j]); lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0; } for (int i = 0; i < 10; i++) { for (int j = 0; j < FILES; j++) { + uint8_t buffer[1024]; lfs_file_read(&lfs, &files[j], buffer, 1) => 1; assert(buffer[0] == alphas[j]); } @@ -59,15 +66,18 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # interspersed remove file test -define.SIZE = [10, 100] -define.FILES = [4, 10, 26] +[cases.test_interspersed_remove_files] +defines.SIZE = [10, 100] +defines.FILES = [4, 10, 26] code = ''' + lfs_t lfs; const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int j = 0; j < FILES; j++) { + char path[1024]; sprintf(path, "%c", alphas[j]); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; for (int i = 0; i < SIZE; i++) { @@ -77,18 +87,22 @@ code = ''' } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "zzz", LFS_O_WRONLY | LFS_O_CREAT) => 0; for (int j = 0; j < FILES; j++) { lfs_file_write(&lfs, &file, (const void*)"~", 1) => 1; lfs_file_sync(&lfs, &file) => 0; + char path[1024]; sprintf(path, "%c", alphas[j]); lfs_remove(&lfs, path) => 0; } lfs_file_close(&lfs, &file); + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -104,6 +118,7 @@ code = ''' lfs_file_open(&lfs, &file, "zzz", LFS_O_RDONLY) => 0; for (int i = 0; i < FILES; i++) { + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, 1) => 1; assert(buffer[0] == '~'); } @@ -112,11 +127,12 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # remove inconveniently test -define.SIZE = [10, 100] +[cases.test_interspersed_remove_inconveniently] +defines.SIZE = [10, 100] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_t files[3]; lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &files[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0; @@ -140,7 +156,9 @@ code = ''' lfs_file_close(&lfs, &files[1]); lfs_file_close(&lfs, &files[2]); + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -161,6 +179,7 @@ code = ''' lfs_file_open(&lfs, &files[0], "e", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &files[1], "g", LFS_O_RDONLY) => 0; for (int i = 0; i < SIZE; i++) { + uint8_t buffer[1024]; lfs_file_read(&lfs, &files[0], buffer, 1) => 1; assert(buffer[0] == 'e'); lfs_file_read(&lfs, &files[1], buffer, 1) => 1; @@ -172,21 +191,23 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # reentrant interspersed file test -define.SIZE = [10, 100] -define.FILES = [4, 10, 26] +[cases.test_interspersed_reentrant_files] +defines.SIZE = [10, 100] +defines.FILES = [4, 10, 26] reentrant = true code = ''' + lfs_t lfs; lfs_file_t files[FILES]; const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; - err = lfs_mount(&lfs, &cfg); + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } for (int j = 0; j < FILES; j++) { + char path[1024]; sprintf(path, "%c", alphas[j]); lfs_file_open(&lfs, &files[j], path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; @@ -194,8 +215,8 @@ code = ''' for (int i = 0; i < SIZE; i++) { for (int j = 0; j < FILES; j++) { - size = lfs_file_size(&lfs, &files[j]); - assert((int)size >= 0); + lfs_ssize_t size = lfs_file_size(&lfs, &files[j]); + assert(size >= 0); if ((int)size <= i) { lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1; lfs_file_sync(&lfs, &files[j]) => 0; @@ -207,7 +228,9 @@ code = ''' lfs_file_close(&lfs, &files[j]); } + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/") => 0; + struct lfs_info info; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); assert(info.type == LFS_TYPE_DIR); @@ -215,6 +238,7 @@ code = ''' assert(strcmp(info.name, "..") == 0); assert(info.type == LFS_TYPE_DIR); for (int j = 0; j < FILES; j++) { + char path[1024]; sprintf(path, "%c", alphas[j]); lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, path) == 0); @@ -225,12 +249,14 @@ code = ''' lfs_dir_close(&lfs, &dir) => 0; for (int j = 0; j < FILES; j++) { + char path[1024]; sprintf(path, "%c", alphas[j]); lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0; } for (int i = 0; i < 10; i++) { for (int j = 0; j < FILES; j++) { + uint8_t buffer[1024]; lfs_file_read(&lfs, &files[j], buffer, 1) => 1; assert(buffer[0] == alphas[j]); } diff --git a/tests/test_move.toml b/tests/test_move.toml index bb3b713..0537f48 100644 --- a/tests/test_move.toml +++ b/tests/test_move.toml @@ -1,11 +1,13 @@ -[[case]] # move file +[cases.test_move_file] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "d") => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_write(&lfs, &file, "hola\n", 5) => 5; lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; @@ -13,11 +15,13 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -44,6 +48,7 @@ code = ''' lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 0; + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, 5) => 5; memcmp(buffer, "hola\n", 5) => 0; lfs_file_read(&lfs, &file, buffer, 8) => 8; @@ -55,31 +60,35 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # noop move, yes this is legal +[cases.test_move_nop] # yes this is legal code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "hi") => 0; lfs_rename(&lfs, "hi", "hi") => 0; lfs_mkdir(&lfs, "hi/hi") => 0; lfs_rename(&lfs, "hi/hi", "hi/hi") => 0; lfs_mkdir(&lfs, "hi/hi/hi") => 0; lfs_rename(&lfs, "hi/hi/hi", "hi/hi/hi") => 0; + struct lfs_info info; lfs_stat(&lfs, "hi/hi/hi", &info) => 0; assert(strcmp(info.name, "hi") == 0); assert(info.type == LFS_TYPE_DIR); lfs_unmount(&lfs) => 0; ''' -[[case]] # move file corrupt source +[cases.test_move_file_corrupt_source] in = "lfs.c" code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "d") => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_write(&lfs, &file, "hola\n", 5) => 5; lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; @@ -87,28 +96,30 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_unmount(&lfs) => 0; // corrupt the source - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_block_t block = dir.m.pair[0]; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; - uint8_t bbuffer[LFS_BLOCK_SIZE]; - cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - int off = LFS_BLOCK_SIZE-1; - while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { + uint8_t buffer[BLOCK_SIZE]; + cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + int off = BLOCK_SIZE-1; + while (off >= 0 && buffer[off] == ERASE_VALUE) { off -= 1; } - memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); - cfg.erase(&cfg, block) => 0; - cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - cfg.sync(&cfg) => 0; + memset(&buffer[off-3], BLOCK_SIZE, 3); + cfg->erase(cfg, block) => 0; + cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + cfg->sync(cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -146,16 +157,19 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # move file corrupt source and dest +# move file corrupt source and dest +[cases.test_move_file_corrupt_source_dest] in = "lfs.c" -if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit +if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "d") => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_write(&lfs, &file, "hola\n", 5) => 5; lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; @@ -163,44 +177,46 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_unmount(&lfs) => 0; // corrupt the source - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_block_t block = dir.m.pair[0]; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; - uint8_t bbuffer[LFS_BLOCK_SIZE]; - cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - int off = LFS_BLOCK_SIZE-1; - while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { + uint8_t buffer[BLOCK_SIZE]; + cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + int off = BLOCK_SIZE-1; + while (off >= 0 && buffer[off] == ERASE_VALUE) { off -= 1; } - memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); - cfg.erase(&cfg, block) => 0; - cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - cfg.sync(&cfg) => 0; + memset(&buffer[off-3], BLOCK_SIZE, 3); + cfg->erase(cfg, block) => 0; + cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + cfg->sync(cfg) => 0; // corrupt the destination - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "c") => 0; block = dir.m.pair[0]; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; - cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - off = LFS_BLOCK_SIZE-1; - while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { + cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + off = BLOCK_SIZE-1; + while (off >= 0 && buffer[off] == ERASE_VALUE) { off -= 1; } - memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); - cfg.erase(&cfg, block) => 0; - cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - cfg.sync(&cfg) => 0; + memset(&buffer[off-3], BLOCK_SIZE, 3); + cfg->erase(cfg, block) => 0; + cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + cfg->sync(cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -238,16 +254,18 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # move file after corrupt +[cases.test_move_file_after_corrupt] in = "lfs.c" -if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit +if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "d") => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_write(&lfs, &file, "hola\n", 5) => 5; lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; @@ -255,49 +273,51 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_unmount(&lfs) => 0; // corrupt the source - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_block_t block = dir.m.pair[0]; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; - uint8_t bbuffer[LFS_BLOCK_SIZE]; - cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - int off = LFS_BLOCK_SIZE-1; - while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { + uint8_t buffer[BLOCK_SIZE]; + cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + int off = BLOCK_SIZE-1; + while (off >= 0 && buffer[off] == ERASE_VALUE) { off -= 1; } - memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); - cfg.erase(&cfg, block) => 0; - cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - cfg.sync(&cfg) => 0; + memset(&buffer[off-3], BLOCK_SIZE, 3); + cfg->erase(cfg, block) => 0; + cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + cfg->sync(cfg) => 0; // corrupt the destination - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "c") => 0; block = dir.m.pair[0]; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; - cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - off = LFS_BLOCK_SIZE-1; - while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { + cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + off = BLOCK_SIZE-1; + while (off >= 0 && buffer[off] == ERASE_VALUE) { off -= 1; } - memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); - cfg.erase(&cfg, block) => 0; - cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - cfg.sync(&cfg) => 0; + memset(&buffer[off-3], BLOCK_SIZE, 3); + cfg->erase(cfg, block) => 0; + cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + cfg->sync(cfg) => 0; // continue move - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -335,13 +355,14 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # simple reentrant move file +[cases.test_move_reentrant_file] reentrant = true code = ''' - err = lfs_mount(&lfs, &cfg); + lfs_t lfs; + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } err = lfs_mkdir(&lfs, "a"); assert(!err || err == LFS_ERR_EXIST); @@ -354,9 +375,10 @@ code = ''' lfs_unmount(&lfs) => 0; while (true) { - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // there should never exist _2_ hello files int count = 0; + struct lfs_info info; if (lfs_stat(&lfs, "a/hello", &info) == 0) { assert(strcmp(info.name, "hello") == 0); assert(info.type == LFS_TYPE_REG); @@ -384,7 +406,7 @@ code = ''' assert(count <= 1); lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; if (lfs_stat(&lfs, "a/hello", &info) == 0 && info.size > 0) { lfs_rename(&lfs, "a/hello", "b/hello") => 0; } else if (lfs_stat(&lfs, "b/hello", &info) == 0) { @@ -397,6 +419,7 @@ code = ''' break; } else { // create file + lfs_file_t file; lfs_file_open(&lfs, &file, "a/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_write(&lfs, &file, "hola\n", 5) => 5; @@ -407,7 +430,9 @@ code = ''' lfs_unmount(&lfs) => 0; } - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -431,10 +456,12 @@ code = ''' lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_close(&lfs, &dir) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0; + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, 5) => 5; memcmp(buffer, "hola\n", 5) => 0; lfs_file_read(&lfs, &file, buffer, 8) => 8; @@ -445,10 +472,11 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # move dir +[cases.test_move_dir] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "c") => 0; @@ -459,11 +487,13 @@ code = ''' lfs_mkdir(&lfs, "a/hi/ohayo") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -510,11 +540,12 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # move dir corrupt source +[cases.test_move_dir_corrupt_source] in = "lfs.c" code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "c") => 0; @@ -525,28 +556,30 @@ code = ''' lfs_mkdir(&lfs, "a/hi/ohayo") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_unmount(&lfs) => 0; // corrupt the source - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_block_t block = dir.m.pair[0]; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; - uint8_t bbuffer[LFS_BLOCK_SIZE]; - cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - int off = LFS_BLOCK_SIZE-1; - while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { + uint8_t buffer[BLOCK_SIZE]; + cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + int off = BLOCK_SIZE-1; + while (off >= 0 && buffer[off] == ERASE_VALUE) { off -= 1; } - memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); - cfg.erase(&cfg, block) => 0; - cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - cfg.sync(&cfg) => 0; + memset(&buffer[off-3], BLOCK_SIZE, 3); + cfg->erase(cfg, block) => 0; + cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + cfg->sync(cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -593,12 +626,13 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # move dir corrupt source and dest +[cases.test_move_dir_corrupt_source_dest] in = "lfs.c" -if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit +if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "c") => 0; @@ -609,44 +643,46 @@ code = ''' lfs_mkdir(&lfs, "a/hi/ohayo") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_unmount(&lfs) => 0; // corrupt the source - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_block_t block = dir.m.pair[0]; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; - uint8_t bbuffer[LFS_BLOCK_SIZE]; - cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - int off = LFS_BLOCK_SIZE-1; - while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { + uint8_t buffer[BLOCK_SIZE]; + cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + int off = BLOCK_SIZE-1; + while (off >= 0 && buffer[off] == ERASE_VALUE) { off -= 1; } - memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); - cfg.erase(&cfg, block) => 0; - cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - cfg.sync(&cfg) => 0; + memset(&buffer[off-3], BLOCK_SIZE, 3); + cfg->erase(cfg, block) => 0; + cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + cfg->sync(cfg) => 0; // corrupt the destination - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "c") => 0; block = dir.m.pair[0]; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; - cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - off = LFS_BLOCK_SIZE-1; - while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { + cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + off = BLOCK_SIZE-1; + while (off >= 0 && buffer[off] == ERASE_VALUE) { off -= 1; } - memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); - cfg.erase(&cfg, block) => 0; - cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - cfg.sync(&cfg) => 0; + memset(&buffer[off-3], BLOCK_SIZE, 3); + cfg->erase(cfg, block) => 0; + cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + cfg->sync(cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -693,12 +729,13 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # move dir after corrupt +[cases.test_move_dir_after_corrupt] in = "lfs.c" -if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit +if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "c") => 0; @@ -709,49 +746,51 @@ code = ''' lfs_mkdir(&lfs, "a/hi/ohayo") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_unmount(&lfs) => 0; // corrupt the source - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_block_t block = dir.m.pair[0]; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; - uint8_t bbuffer[LFS_BLOCK_SIZE]; - cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - int off = LFS_BLOCK_SIZE-1; - while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { + uint8_t buffer[BLOCK_SIZE]; + cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + int off = BLOCK_SIZE-1; + while (off >= 0 && buffer[off] == ERASE_VALUE) { off -= 1; } - memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); - cfg.erase(&cfg, block) => 0; - cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - cfg.sync(&cfg) => 0; + memset(&buffer[off-3], BLOCK_SIZE, 3); + cfg->erase(cfg, block) => 0; + cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + cfg->sync(cfg) => 0; // corrupt the destination - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "c") => 0; block = dir.m.pair[0]; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; - cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - off = LFS_BLOCK_SIZE-1; - while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { + cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + off = BLOCK_SIZE-1; + while (off >= 0 && buffer[off] == ERASE_VALUE) { off -= 1; } - memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); - cfg.erase(&cfg, block) => 0; - cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - cfg.sync(&cfg) => 0; + memset(&buffer[off-3], BLOCK_SIZE, 3); + cfg->erase(cfg, block) => 0; + cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + cfg->sync(cfg) => 0; // continue move - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -798,13 +837,14 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # simple reentrant move dir +[cases.test_reentrant_dir] reentrant = true code = ''' - err = lfs_mount(&lfs, &cfg); + lfs_t lfs; + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } err = lfs_mkdir(&lfs, "a"); assert(!err || err == LFS_ERR_EXIST); @@ -817,9 +857,10 @@ code = ''' lfs_unmount(&lfs) => 0; while (true) { - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // there should never exist _2_ hi directories int count = 0; + struct lfs_info info; if (lfs_stat(&lfs, "a/hi", &info) == 0) { assert(strcmp(info.name, "hi") == 0); assert(info.type == LFS_TYPE_DIR); @@ -843,7 +884,7 @@ code = ''' assert(count <= 1); lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; if (lfs_stat(&lfs, "a/hi", &info) == 0) { lfs_rename(&lfs, "a/hi", "b/hi") => 0; } else if (lfs_stat(&lfs, "b/hi", &info) == 0) { @@ -868,7 +909,9 @@ code = ''' lfs_unmount(&lfs) => 0; } - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -915,14 +958,16 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # move state stealing +[cases.test_move_state_stealing] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "d") => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_write(&lfs, &file, "hola\n", 5) => 5; lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; @@ -930,21 +975,22 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "a/hello", "b/hello") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "b/hello", "c/hello") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_rename(&lfs, "c/hello", "d/hello") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0; + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, 5) => 5; memcmp(buffer, "hola\n", 5) => 0; lfs_file_read(&lfs, &file, buffer, 8) => 8; @@ -954,12 +1000,13 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_remove(&lfs, "b") => 0; lfs_remove(&lfs, "c") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + struct lfs_info info; lfs_stat(&lfs, "a", &info) => 0; lfs_stat(&lfs, "b", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "c", &info) => LFS_ERR_NOENT; @@ -979,12 +1026,16 @@ code = ''' ''' # Other specific corner cases -[[case]] # create + delete in same commit with neighbors + +# create + delete in same commit with neighbors +[cases.test_move_create_delete_same] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // littlefs keeps files sorted, so we know the order these will be in + lfs_file_t file; lfs_file_open(&lfs, &file, "/1.move_me", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_close(&lfs, &file) => 0; @@ -1024,6 +1075,8 @@ code = ''' lfs_file_close(&lfs, &files[2]) => 0; // check that nothing was corrupted + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -1051,6 +1104,7 @@ code = ''' lfs_dir_close(&lfs, &dir) => 0; lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0; + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, 7) => 7; assert(strcmp((char*)buffer, "test.4") == 0); lfs_file_close(&lfs, &file) => 0; @@ -1124,13 +1178,15 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -# Other specific corner cases -[[case]] # create + delete + delete in same commit with neighbors +# create + delete + delete in same commit with neighbors +[cases.test_move_create_delete_delete_same] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // littlefs keeps files sorted, so we know the order these will be in + lfs_file_t file; lfs_file_open(&lfs, &file, "/1.move_me", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_close(&lfs, &file) => 0; @@ -1175,6 +1231,8 @@ code = ''' lfs_file_close(&lfs, &files[2]) => 0; // check that nothing was corrupted + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -1202,6 +1260,7 @@ code = ''' lfs_dir_close(&lfs, &dir) => 0; lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0; + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, 7) => 7; assert(strcmp((char*)buffer, "test.4") == 0); lfs_file_close(&lfs, &file) => 0; @@ -1281,14 +1340,17 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # create + delete in different dirs with neighbors +# create + delete in different dirs with neighbors +[cases.test_move_create_delete_different] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // littlefs keeps files sorted, so we know the order these will be in lfs_mkdir(&lfs, "/dir.1") => 0; lfs_mkdir(&lfs, "/dir.2") => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "/dir.1/1.move_me", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_close(&lfs, &file) => 0; @@ -1340,6 +1402,8 @@ code = ''' lfs_file_close(&lfs, &files[3]) => 0; // check that nothing was corrupted + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -1397,6 +1461,7 @@ code = ''' lfs_dir_close(&lfs, &dir) => 0; lfs_file_open(&lfs, &file, "/dir.1/0.before", LFS_O_RDONLY) => 0; + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, 7) => 7; assert(strcmp((char*)buffer, "test.5") == 0); lfs_file_close(&lfs, &file) => 0; @@ -1518,17 +1583,20 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # move fix in relocation +# move fix in relocation +[cases.test_move_fix_relocation] in = "lfs.c" -define.RELOCATIONS = 'range(0x3+1)' -define.LFS_ERASE_CYCLES = 0xffffffff +defines.RELOCATIONS = 'range(4)' +defines.ERASE_CYCLES = 0xffffffff code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "/parent") => 0; lfs_mkdir(&lfs, "/parent/child") => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "/parent/1.move_me", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_write(&lfs, &file, "move me", @@ -1568,15 +1636,17 @@ code = ''' // force specific directories to relocate if (RELOCATIONS & 0x1) { + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/parent"); - lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; - lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; + lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; + lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_dir_close(&lfs, &dir) => 0; } if (RELOCATIONS & 0x2) { + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/parent/child"); - lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; - lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; + lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; + lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_dir_close(&lfs, &dir) => 0; } @@ -1593,6 +1663,8 @@ code = ''' lfs_file_close(&lfs, &files[3]) => 0; // check that nothing was corrupted + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "/parent") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -1637,6 +1709,7 @@ code = ''' lfs_dir_close(&lfs, &dir) => 0; lfs_file_open(&lfs, &file, "/parent/0.before", LFS_O_RDONLY) => 0; + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, 7) => 7; assert(strcmp((char*)buffer, "test.5") == 0); lfs_file_close(&lfs, &file) => 0; @@ -1655,18 +1728,21 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # move fix in relocation with predecessor +# move fix in relocation with predecessor +[cases.test_move_fix_relocation_predecessor] in = "lfs.c" -define.RELOCATIONS = 'range(0x7+1)' -define.LFS_ERASE_CYCLES = 0xffffffff +defines.RELOCATIONS = 'range(8)' +defines.ERASE_CYCLES = 0xffffffff code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "/parent") => 0; lfs_mkdir(&lfs, "/parent/child") => 0; lfs_mkdir(&lfs, "/parent/sibling") => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "/parent/sibling/1.move_me", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_write(&lfs, &file, "move me", @@ -1706,21 +1782,24 @@ code = ''' // force specific directories to relocate if (RELOCATIONS & 0x1) { + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/parent"); - lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; - lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; + lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; + lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_dir_close(&lfs, &dir) => 0; } if (RELOCATIONS & 0x2) { + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/parent/sibling"); - lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; - lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; + lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; + lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_dir_close(&lfs, &dir) => 0; } if (RELOCATIONS & 0x4) { + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "/parent/child"); - lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; - lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; + lfs_emubd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0; + lfs_emubd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_dir_close(&lfs, &dir) => 0; } @@ -1739,6 +1818,8 @@ code = ''' lfs_file_close(&lfs, &files[3]) => 0; // check that nothing was corrupted + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "/parent") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(strcmp(info.name, ".") == 0); @@ -1796,6 +1877,7 @@ code = ''' lfs_dir_close(&lfs, &dir) => 0; lfs_file_open(&lfs, &file, "/parent/sibling/0.before", LFS_O_RDONLY) => 0; + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, 7) => 7; assert(strcmp((char*)buffer, "test.5") == 0); lfs_file_close(&lfs, &file) => 0; diff --git a/tests/test_orphans.toml b/tests/test_orphans.toml index 241e273..b6b182e 100644 --- a/tests/test_orphans.toml +++ b/tests/test_orphans.toml @@ -1,9 +1,10 @@ -[[case]] # orphan test +[cases.test_orphans_normal] in = "lfs.c" -if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit +if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "parent") => 0; lfs_mkdir(&lfs, "parent/orphan") => 0; lfs_mkdir(&lfs, "parent/child") => 0; @@ -13,29 +14,31 @@ code = ''' // corrupt the child's most recent commit, this should be the update // to the linked-list entry, which should orphan the orphan. Note this // makes a lot of assumptions about the remove operation. - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; lfs_dir_open(&lfs, &dir, "parent/child") => 0; lfs_block_t block = dir.m.pair[0]; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; - uint8_t bbuffer[LFS_BLOCK_SIZE]; - cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - int off = LFS_BLOCK_SIZE-1; - while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { + uint8_t buffer[BLOCK_SIZE]; + cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + int off = BLOCK_SIZE-1; + while (off >= 0 && buffer[off] == ERASE_VALUE) { off -= 1; } - memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); - cfg.erase(&cfg, block) => 0; - cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; - cfg.sync(&cfg) => 0; + memset(&buffer[off-3], BLOCK_SIZE, 3); + cfg->erase(cfg, block) => 0; + cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0; + cfg->sync(cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + struct lfs_info info; lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "parent/child", &info) => 0; lfs_fs_size(&lfs) => 8; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "parent/child", &info) => 0; lfs_fs_size(&lfs) => 8; @@ -48,7 +51,7 @@ code = ''' lfs_fs_size(&lfs) => 8; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "parent/child", &info) => 0; lfs_stat(&lfs, "parent/otherchild", &info) => 0; @@ -56,43 +59,48 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # reentrant testing for orphans, basically just spam mkdir/remove +# reentrant testing for orphans, basically just spam mkdir/remove +[cases.test_orphans_reentrant] reentrant = true # TODO fix this case, caused by non-DAG trees -if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' -define = [ +if = '!(DEPTH == 3 && CACHE_SIZE != 64)' +defines = [ {FILES=6, DEPTH=1, CYCLES=20}, {FILES=26, DEPTH=1, CYCLES=20}, {FILES=3, DEPTH=3, CYCLES=20}, ] code = ''' - err = lfs_mount(&lfs, &cfg); + lfs_t lfs; + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } - srand(1); + uint32_t prng = 1; const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; - for (int i = 0; i < CYCLES; i++) { + for (unsigned i = 0; i < CYCLES; i++) { // create random path char full_path[256]; - for (int d = 0; d < DEPTH; d++) { - sprintf(&full_path[2*d], "/%c", alpha[rand() % FILES]); + for (unsigned d = 0; d < DEPTH; d++) { + sprintf(&full_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]); } // if it does not exist, we create it, else we destroy + struct lfs_info info; int res = lfs_stat(&lfs, full_path, &info); if (res == LFS_ERR_NOENT) { // create each directory in turn, ignore if dir already exists - for (int d = 0; d < DEPTH; d++) { + for (unsigned d = 0; d < DEPTH; d++) { + char path[1024]; strcpy(path, full_path); path[2*d+2] = '\0'; err = lfs_mkdir(&lfs, path); assert(!err || err == LFS_ERR_EXIST); } - for (int d = 0; d < DEPTH; d++) { + for (unsigned d = 0; d < DEPTH; d++) { + char path[1024]; strcpy(path, full_path); path[2*d+2] = '\0'; lfs_stat(&lfs, path, &info) => 0; @@ -106,6 +114,7 @@ code = ''' // try to delete path in reverse order, ignore if dir is not empty for (int d = DEPTH-1; d >= 0; d--) { + char path[1024]; strcpy(path, full_path); path[2*d+2] = '\0'; err = lfs_remove(&lfs, path); diff --git a/tests/test_paths.toml b/tests/test_paths.toml index a7474c0..97a519e 100644 --- a/tests/test_paths.toml +++ b/tests/test_paths.toml @@ -1,13 +1,16 @@ -[[case]] # simple path test +# simple path test +[cases.test_paths_normal] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/coldtea") => 0; + struct lfs_info info; lfs_stat(&lfs, "tea/hottea", &info) => 0; assert(strcmp(info.name, "hottea") == 0); lfs_stat(&lfs, "/tea/hottea", &info) => 0; @@ -21,15 +24,18 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # redundant slashes +# redundant slashes +[cases.test_paths_redundant_slashes] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/coldtea") => 0; + struct lfs_info info; lfs_stat(&lfs, "/tea/hottea", &info) => 0; assert(strcmp(info.name, "hottea") == 0); lfs_stat(&lfs, "//tea//hottea", &info) => 0; @@ -45,15 +51,18 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # dot path test +# dot path test +[cases.test_paths_dot] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/coldtea") => 0; + struct lfs_info info; lfs_stat(&lfs, "./tea/hottea", &info) => 0; assert(strcmp(info.name, "hottea") == 0); lfs_stat(&lfs, "/./tea/hottea", &info) => 0; @@ -71,10 +80,12 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # dot dot path test +# dot dot path test +[cases.test_paths_dot_dot] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0; @@ -84,6 +95,7 @@ code = ''' lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; + struct lfs_info info; lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0; assert(strcmp(info.name, "hottea") == 0); lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0; @@ -101,15 +113,18 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # trailing dot path test +# trailing dot path test +[cases.test_paths_trailing_dot] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/coldtea") => 0; + struct lfs_info info; lfs_stat(&lfs, "tea/hottea/", &info) => 0; assert(strcmp(info.name, "hottea") == 0); lfs_stat(&lfs, "tea/hottea/.", &info) => 0; @@ -123,11 +138,14 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # leading dot path test +# leading dot path test +[cases.test_paths_leading_dot] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, ".milk") => 0; + struct lfs_info info; lfs_stat(&lfs, ".milk", &info) => 0; strcmp(info.name, ".milk") => 0; lfs_stat(&lfs, "tea/.././.milk", &info) => 0; @@ -135,10 +153,12 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # root dot dot path test +# root dot dot path test +[cases.test_paths_root_dot_dot] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0; @@ -148,6 +168,7 @@ code = ''' lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; + struct lfs_info info; lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; strcmp(info.name, "hottea") => 0; @@ -159,10 +180,13 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # invalid path tests +# invalid path tests +[cases.test_paths_invalid] code = ''' - lfs_format(&lfs, &cfg); - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg); + lfs_mount(&lfs, cfg) => 0; + struct lfs_info info; lfs_stat(&lfs, "dirt", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "dirt/ground", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "dirt/ground/earth", &info) => LFS_ERR_NOENT; @@ -172,6 +196,7 @@ code = ''' lfs_remove(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT; + lfs_file_t file; lfs_file_open(&lfs, &file, "dirt/ground", LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NOENT; lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; @@ -180,15 +205,19 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # root operations +# root operations +[cases.test_paths_root] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + struct lfs_info info; lfs_stat(&lfs, "/", &info) => 0; assert(strcmp(info.name, "/") == 0); assert(info.type == LFS_TYPE_DIR); lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; + lfs_file_t file; lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; @@ -196,10 +225,13 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # root representations +# root representations +[cases.test_paths_root_reprs] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + struct lfs_info info; lfs_stat(&lfs, "/", &info) => 0; assert(strcmp(info.name, "/") == 0); assert(info.type == LFS_TYPE_DIR); @@ -221,10 +253,13 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # superblock conflict test +# superblock conflict test +[cases.test_paths_superblock_conflict] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + struct lfs_info info; lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; lfs_remove(&lfs, "littlefs") => LFS_ERR_NOENT; @@ -237,18 +272,22 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # max path test +# max path test +[cases.test_paths_max] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "coffee") => 0; lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; + char path[1024]; memset(path, 'w', LFS_NAME_MAX+1); path[LFS_NAME_MAX+1] = '\0'; lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NAMETOOLONG; @@ -261,19 +300,23 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # really big path test +# really big path test +[cases.test_paths_really_big] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_mkdir(&lfs, "coffee") => 0; lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; + char path[1024]; memset(path, 'w', LFS_NAME_MAX); path[LFS_NAME_MAX] = '\0'; lfs_mkdir(&lfs, path) => 0; lfs_remove(&lfs, path) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_close(&lfs, &file) => 0; diff --git a/tests/test_powerloss.toml b/tests/test_powerloss.toml new file mode 100644 index 0000000..06f8661 --- /dev/null +++ b/tests/test_powerloss.toml @@ -0,0 +1,182 @@ +# There are already a number of tests that test general operations under +# power-loss (see the reentrant attribute). These tests are for explicitly +# testing specific corner cases. + +# only a revision count +[cases.test_powerloss_only_rev] +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + + lfs_mount(&lfs, cfg) => 0; + lfs_mkdir(&lfs, "notebook") => 0; + lfs_file_t file; + lfs_file_open(&lfs, &file, "notebook/paper", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; + char buffer[256]; + strcpy(buffer, "hello"); + lfs_size_t size = strlen("hello"); + for (int i = 0; i < 5; i++) { + lfs_file_write(&lfs, &file, buffer, size) => size; + lfs_file_sync(&lfs, &file) => 0; + } + lfs_file_close(&lfs, &file) => 0; + + char rbuffer[256]; + lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; + for (int i = 0; i < 5; i++) { + lfs_file_read(&lfs, &file, rbuffer, size) => size; + assert(memcmp(rbuffer, buffer, size) == 0); + } + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; + + // get pair/rev count + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "notebook") => 0; + lfs_block_t pair[2] = {dir.m.pair[0], dir.m.pair[1]}; + uint32_t rev = dir.m.rev; + lfs_dir_close(&lfs, &dir) => 0; + lfs_unmount(&lfs) => 0; + + // write just the revision count + uint8_t bbuffer[BLOCK_SIZE]; + cfg->read(cfg, pair[1], 0, bbuffer, BLOCK_SIZE) => 0; + + memcpy(bbuffer, &(uint32_t){lfs_tole32(rev+1)}, sizeof(uint32_t)); + + cfg->erase(cfg, pair[1]) => 0; + cfg->prog(cfg, pair[1], 0, bbuffer, BLOCK_SIZE) => 0; + + lfs_mount(&lfs, cfg) => 0; + + // can read? + lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; + for (int i = 0; i < 5; i++) { + lfs_file_read(&lfs, &file, rbuffer, size) => size; + assert(memcmp(rbuffer, buffer, size) == 0); + } + lfs_file_close(&lfs, &file) => 0; + + // can write? + lfs_file_open(&lfs, &file, "notebook/paper", + LFS_O_WRONLY | LFS_O_APPEND) => 0; + strcpy(buffer, "goodbye"); + size = strlen("goodbye"); + for (int i = 0; i < 5; i++) { + lfs_file_write(&lfs, &file, buffer, size) => size; + lfs_file_sync(&lfs, &file) => 0; + } + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; + strcpy(buffer, "hello"); + size = strlen("hello"); + for (int i = 0; i < 5; i++) { + lfs_file_read(&lfs, &file, rbuffer, size) => size; + assert(memcmp(rbuffer, buffer, size) == 0); + } + strcpy(buffer, "goodbye"); + size = strlen("goodbye"); + for (int i = 0; i < 5; i++) { + lfs_file_read(&lfs, &file, rbuffer, size) => size; + assert(memcmp(rbuffer, buffer, size) == 0); + } + lfs_file_close(&lfs, &file) => 0; + + lfs_unmount(&lfs) => 0; +''' + +# partial prog, may not be byte in order! +[cases.test_powerloss_partial_prog] +if = "PROG_SIZE < BLOCK_SIZE" +defines.BYTE_OFF = ["0", "PROG_SIZE-1", "PROG_SIZE/2"] +defines.BYTE_VALUE = [0x33, 0xcc] +in = "lfs.c" +code = ''' + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + + lfs_mount(&lfs, cfg) => 0; + lfs_mkdir(&lfs, "notebook") => 0; + lfs_file_t file; + lfs_file_open(&lfs, &file, "notebook/paper", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; + char buffer[256]; + strcpy(buffer, "hello"); + lfs_size_t size = strlen("hello"); + for (int i = 0; i < 5; i++) { + lfs_file_write(&lfs, &file, buffer, size) => size; + lfs_file_sync(&lfs, &file) => 0; + } + lfs_file_close(&lfs, &file) => 0; + + char rbuffer[256]; + lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; + for (int i = 0; i < 5; i++) { + lfs_file_read(&lfs, &file, rbuffer, size) => size; + assert(memcmp(rbuffer, buffer, size) == 0); + } + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; + + // imitate a partial prog, value should not matter, if littlefs + // doesn't notice the partial prog testbd will assert + + // get offset to next prog + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; + lfs_dir_open(&lfs, &dir, "notebook") => 0; + lfs_block_t block = dir.m.pair[0]; + lfs_off_t off = dir.m.off; + lfs_dir_close(&lfs, &dir) => 0; + lfs_unmount(&lfs) => 0; + + // tweak byte + uint8_t bbuffer[BLOCK_SIZE]; + cfg->read(cfg, block, 0, bbuffer, BLOCK_SIZE) => 0; + + bbuffer[off + BYTE_OFF] = BYTE_VALUE; + + cfg->erase(cfg, block) => 0; + cfg->prog(cfg, block, 0, bbuffer, BLOCK_SIZE) => 0; + + lfs_mount(&lfs, cfg) => 0; + + // can read? + lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; + for (int i = 0; i < 5; i++) { + lfs_file_read(&lfs, &file, rbuffer, size) => size; + assert(memcmp(rbuffer, buffer, size) == 0); + } + lfs_file_close(&lfs, &file) => 0; + + // can write? + lfs_file_open(&lfs, &file, "notebook/paper", + LFS_O_WRONLY | LFS_O_APPEND) => 0; + strcpy(buffer, "goodbye"); + size = strlen("goodbye"); + for (int i = 0; i < 5; i++) { + lfs_file_write(&lfs, &file, buffer, size) => size; + lfs_file_sync(&lfs, &file) => 0; + } + lfs_file_close(&lfs, &file) => 0; + + lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; + strcpy(buffer, "hello"); + size = strlen("hello"); + for (int i = 0; i < 5; i++) { + lfs_file_read(&lfs, &file, rbuffer, size) => size; + assert(memcmp(rbuffer, buffer, size) == 0); + } + strcpy(buffer, "goodbye"); + size = strlen("goodbye"); + for (int i = 0; i < 5; i++) { + lfs_file_read(&lfs, &file, rbuffer, size) => size; + assert(memcmp(rbuffer, buffer, size) == 0); + } + lfs_file_close(&lfs, &file) => 0; + + lfs_unmount(&lfs) => 0; +''' diff --git a/tests/test_relocations.toml b/tests/test_relocations.toml index 71b1047..d20cb8c 100644 --- a/tests/test_relocations.toml +++ b/tests/test_relocations.toml @@ -1,15 +1,18 @@ # specific corner cases worth explicitly testing for -[[case]] # dangling split dir test -define.ITERATIONS = 20 -define.COUNT = 10 -define.LFS_BLOCK_CYCLES = [8, 1] +[cases.test_relocations_dangling_split_dir] +defines.ITERATIONS = 20 +defines.COUNT = 10 +defines.BLOCK_CYCLES = [8, 1] code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; // fill up filesystem so only ~16 blocks are left - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; + uint8_t buffer[512]; memset(buffer, 0, 512); - while (LFS_BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { + while (BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { lfs_file_write(&lfs, &file, buffer, 512) => 512; } lfs_file_close(&lfs, &file) => 0; @@ -17,18 +20,22 @@ code = ''' lfs_mkdir(&lfs, "child") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; - for (int j = 0; j < ITERATIONS; j++) { - for (int i = 0; i < COUNT; i++) { + lfs_mount(&lfs, cfg) => 0; + for (unsigned j = 0; j < ITERATIONS; j++) { + for (unsigned i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_close(&lfs, &file) => 0; } + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "child") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1; - for (int i = 0; i < COUNT; i++) { + for (unsigned i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "test%03d_loooooooooooooooooong_name", i); lfs_dir_read(&lfs, &dir, &info) => 1; strcmp(info.name, path) => 0; @@ -36,46 +43,54 @@ code = ''' lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_close(&lfs, &dir) => 0; - if (j == ITERATIONS-1) { + if (j == (unsigned)ITERATIONS-1) { break; } - for (int i = 0; i < COUNT; i++) { + for (unsigned i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); lfs_remove(&lfs, path) => 0; } } lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "child") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1; - for (int i = 0; i < COUNT; i++) { + for (unsigned i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "test%03d_loooooooooooooooooong_name", i); lfs_dir_read(&lfs, &dir, &info) => 1; strcmp(info.name, path) => 0; } lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_close(&lfs, &dir) => 0; - for (int i = 0; i < COUNT; i++) { + for (unsigned i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); lfs_remove(&lfs, path) => 0; } lfs_unmount(&lfs) => 0; ''' -[[case]] # outdated head test -define.ITERATIONS = 20 -define.COUNT = 10 -define.LFS_BLOCK_CYCLES = [8, 1] +[cases.test_relocations_outdated_head] +defines.ITERATIONS = 20 +defines.COUNT = 10 +defines.BLOCK_CYCLES = [8, 1] code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; // fill up filesystem so only ~16 blocks are left - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; + uint8_t buffer[512]; memset(buffer, 0, 512); - while (LFS_BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { + while (BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { lfs_file_write(&lfs, &file, buffer, 512) => 512; } lfs_file_close(&lfs, &file) => 0; @@ -83,18 +98,22 @@ code = ''' lfs_mkdir(&lfs, "child") => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; - for (int j = 0; j < ITERATIONS; j++) { - for (int i = 0; i < COUNT; i++) { + lfs_mount(&lfs, cfg) => 0; + for (unsigned j = 0; j < ITERATIONS; j++) { + for (unsigned i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_close(&lfs, &file) => 0; } + lfs_dir_t dir; + struct lfs_info info; lfs_dir_open(&lfs, &dir, "child") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1; - for (int i = 0; i < COUNT; i++) { + for (unsigned i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "test%03d_loooooooooooooooooong_name", i); lfs_dir_read(&lfs, &dir, &info) => 1; strcmp(info.name, path) => 0; @@ -110,7 +129,8 @@ code = ''' lfs_dir_rewind(&lfs, &dir) => 0; lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1; - for (int i = 0; i < COUNT; i++) { + for (unsigned i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "test%03d_loooooooooooooooooong_name", i); lfs_dir_read(&lfs, &dir, &info) => 1; strcmp(info.name, path) => 0; @@ -126,7 +146,8 @@ code = ''' lfs_dir_rewind(&lfs, &dir) => 0; lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1; - for (int i = 0; i < COUNT; i++) { + for (unsigned i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "test%03d_loooooooooooooooooong_name", i); lfs_dir_read(&lfs, &dir, &info) => 1; strcmp(info.name, path) => 0; @@ -135,7 +156,8 @@ code = ''' lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_close(&lfs, &dir) => 0; - for (int i = 0; i < COUNT; i++) { + for (unsigned i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); lfs_remove(&lfs, path) => 0; } @@ -143,45 +165,51 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # reentrant testing for relocations, this is the same as the - # orphan testing, except here we also set block_cycles so that - # almost every tree operation needs a relocation +# reentrant testing for relocations, this is the same as the +# orphan testing, except here we also set block_cycles so that +# almost every tree operation needs a relocation +[cases.test_relocations_reentrant] reentrant = true # TODO fix this case, caused by non-DAG trees -if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' -define = [ - {FILES=6, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, - {FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, - {FILES=3, DEPTH=3, CYCLES=20, LFS_BLOCK_CYCLES=1}, +# NOTE the second condition is required +if = '!(DEPTH == 3 && CACHE_SIZE != 64) && 2*FILES < BLOCK_COUNT' +defines = [ + {FILES=6, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1}, + {FILES=26, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1}, + {FILES=3, DEPTH=3, CYCLES=20, BLOCK_CYCLES=1}, ] code = ''' - err = lfs_mount(&lfs, &cfg); + lfs_t lfs; + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } - srand(1); + uint32_t prng = 1; const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; - for (int i = 0; i < CYCLES; i++) { + for (unsigned i = 0; i < CYCLES; i++) { // create random path char full_path[256]; - for (int d = 0; d < DEPTH; d++) { - sprintf(&full_path[2*d], "/%c", alpha[rand() % FILES]); + for (unsigned d = 0; d < DEPTH; d++) { + sprintf(&full_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]); } // if it does not exist, we create it, else we destroy + struct lfs_info info; int res = lfs_stat(&lfs, full_path, &info); if (res == LFS_ERR_NOENT) { // create each directory in turn, ignore if dir already exists - for (int d = 0; d < DEPTH; d++) { + for (unsigned d = 0; d < DEPTH; d++) { + char path[1024]; strcpy(path, full_path); path[2*d+2] = '\0'; err = lfs_mkdir(&lfs, path); assert(!err || err == LFS_ERR_EXIST); } - for (int d = 0; d < DEPTH; d++) { + for (unsigned d = 0; d < DEPTH; d++) { + char path[1024]; strcpy(path, full_path); path[2*d+2] = '\0'; lfs_stat(&lfs, path, &info) => 0; @@ -194,7 +222,8 @@ code = ''' assert(info.type == LFS_TYPE_DIR); // try to delete path in reverse order, ignore if dir is not empty - for (int d = DEPTH-1; d >= 0; d--) { + for (unsigned d = DEPTH-1; d+1 > 0; d--) { + char path[1024]; strcpy(path, full_path); path[2*d+2] = '\0'; err = lfs_remove(&lfs, path); @@ -207,44 +236,50 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # reentrant testing for relocations, but now with random renames! +# reentrant testing for relocations, but now with random renames! +[cases.test_relocations_reentrant_renames] reentrant = true # TODO fix this case, caused by non-DAG trees -if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' -define = [ - {FILES=6, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, - {FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, - {FILES=3, DEPTH=3, CYCLES=20, LFS_BLOCK_CYCLES=1}, +# NOTE the second condition is required +if = '!(DEPTH == 3 && CACHE_SIZE != 64) && 2*FILES < BLOCK_COUNT' +defines = [ + {FILES=6, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1}, + {FILES=26, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1}, + {FILES=3, DEPTH=3, CYCLES=20, BLOCK_CYCLES=1}, ] code = ''' - err = lfs_mount(&lfs, &cfg); + lfs_t lfs; + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } - srand(1); + uint32_t prng = 1; const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; - for (int i = 0; i < CYCLES; i++) { + for (unsigned i = 0; i < CYCLES; i++) { // create random path char full_path[256]; - for (int d = 0; d < DEPTH; d++) { - sprintf(&full_path[2*d], "/%c", alpha[rand() % FILES]); + for (unsigned d = 0; d < DEPTH; d++) { + sprintf(&full_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]); } // if it does not exist, we create it, else we destroy + struct lfs_info info; int res = lfs_stat(&lfs, full_path, &info); assert(!res || res == LFS_ERR_NOENT); if (res == LFS_ERR_NOENT) { // create each directory in turn, ignore if dir already exists - for (int d = 0; d < DEPTH; d++) { + for (unsigned d = 0; d < DEPTH; d++) { + char path[1024]; strcpy(path, full_path); path[2*d+2] = '\0'; err = lfs_mkdir(&lfs, path); assert(!err || err == LFS_ERR_EXIST); } - for (int d = 0; d < DEPTH; d++) { + for (unsigned d = 0; d < DEPTH; d++) { + char path[1024]; strcpy(path, full_path); path[2*d+2] = '\0'; lfs_stat(&lfs, path, &info) => 0; @@ -257,8 +292,8 @@ code = ''' // create new random path char new_path[256]; - for (int d = 0; d < DEPTH; d++) { - sprintf(&new_path[2*d], "/%c", alpha[rand() % FILES]); + for (unsigned d = 0; d < DEPTH; d++) { + sprintf(&new_path[2*d], "/%c", alpha[TEST_PRNG(&prng) % FILES]); } // if new path does not exist, rename, otherwise destroy @@ -266,7 +301,8 @@ code = ''' assert(!res || res == LFS_ERR_NOENT); if (res == LFS_ERR_NOENT) { // stop once some dir is renamed - for (int d = 0; d < DEPTH; d++) { + for (unsigned d = 0; d < DEPTH; d++) { + char path[1024]; strcpy(&path[2*d], &full_path[2*d]); path[2*d+2] = '\0'; strcpy(&path[128+2*d], &new_path[2*d]); @@ -278,7 +314,8 @@ code = ''' } } - for (int d = 0; d < DEPTH; d++) { + for (unsigned d = 0; d < DEPTH; d++) { + char path[1024]; strcpy(path, new_path); path[2*d+2] = '\0'; lfs_stat(&lfs, path, &info) => 0; @@ -290,7 +327,8 @@ code = ''' } else { // try to delete path in reverse order, // ignore if dir is not empty - for (int d = DEPTH-1; d >= 0; d--) { + for (unsigned d = DEPTH-1; d+1 > 0; d--) { + char path[1024]; strcpy(path, full_path); path[2*d+2] = '\0'; err = lfs_remove(&lfs, path); diff --git a/tests/test_seek.toml b/tests/test_seek.toml index 79d7728..b976057 100644 --- a/tests/test_seek.toml +++ b/tests/test_seek.toml @@ -1,6 +1,7 @@ -[[case]] # simple file seek -define = [ +# simple file seek +[cases.test_seek_read] +defines = [ {COUNT=132, SKIP=4}, {COUNT=132, SKIP=128}, {COUNT=200, SKIP=10}, @@ -9,11 +10,14 @@ define = [ {COUNT=4, SKIP=2}, ] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "kitty", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - size = strlen("kittycatcat"); + size_t size = strlen("kittycatcat"); + uint8_t buffer[1024]; memcpy(buffer, "kittycatcat", size); for (int j = 0; j < COUNT; j++) { lfs_file_write(&lfs, &file, buffer, size); @@ -21,7 +25,7 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY) => 0; lfs_soff_t pos = -1; @@ -68,8 +72,9 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # simple file seek and write -define = [ +# simple file seek and write +[cases.test_seek_write] +defines = [ {COUNT=132, SKIP=4}, {COUNT=132, SKIP=128}, {COUNT=200, SKIP=10}, @@ -78,11 +83,14 @@ define = [ {COUNT=4, SKIP=2}, ] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "kitty", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - size = strlen("kittycatcat"); + size_t size = strlen("kittycatcat"); + uint8_t buffer[1024]; memcpy(buffer, "kittycatcat", size); for (int j = 0; j < COUNT; j++) { lfs_file_write(&lfs, &file, buffer, size); @@ -90,7 +98,7 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; lfs_soff_t pos = -1; @@ -129,15 +137,18 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # boundary seek and writes -define.COUNT = 132 -define.OFFSETS = '"{512, 1020, 513, 1021, 511, 1019, 1441}"' +# boundary seek and writes +[cases.test_seek_boundary_write] +defines.COUNT = 132 code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "kitty", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - size = strlen("kittycatcat"); + size_t size = strlen("kittycatcat"); + uint8_t buffer[1024]; memcpy(buffer, "kittycatcat", size); for (int j = 0; j < COUNT; j++) { lfs_file_write(&lfs, &file, buffer, size); @@ -145,11 +156,11 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; size = strlen("hedgehoghog"); - const lfs_soff_t offsets[] = OFFSETS; + const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019, 1441}; for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { lfs_soff_t off = offsets[i]; @@ -183,8 +194,9 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # out of bounds seek -define = [ +# out of bounds seek +[cases.test_seek_out_of_bounds] +defines = [ {COUNT=132, SKIP=4}, {COUNT=132, SKIP=128}, {COUNT=200, SKIP=10}, @@ -193,18 +205,21 @@ define = [ {COUNT=4, SKIP=3}, ] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "kitty", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; - size = strlen("kittycatcat"); + size_t size = strlen("kittycatcat"); + uint8_t buffer[1024]; memcpy(buffer, "kittycatcat", size); for (int j = 0; j < COUNT; j++) { lfs_file_write(&lfs, &file, buffer, size); } lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; size = strlen("kittycatcat"); @@ -238,16 +253,20 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # inline write and seek -define.SIZE = [2, 4, 128, 132] +# inline write and seek +[cases.test_seek_inline_write] +defines.SIZE = [2, 4, 128, 132] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "tinykitty", LFS_O_RDWR | LFS_O_CREAT) => 0; int j = 0; int k = 0; + uint8_t buffer[1024]; memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26); for (unsigned i = 0; i < SIZE; i++) { lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1; @@ -305,16 +324,20 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # file seek and write with power-loss +# file seek and write with power-loss +[cases.test_seek_reentrant_write] # must be power-of-2 for quadratic probing to be exhaustive -define.COUNT = [4, 64, 128] +defines.COUNT = [4, 64, 128] reentrant = true code = ''' - err = lfs_mount(&lfs, &cfg); + lfs_t lfs; + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } + lfs_file_t file; + uint8_t buffer[1024]; err = lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY); assert(!err || err == LFS_ERR_NOENT); if (!err) { @@ -334,14 +357,14 @@ code = ''' if (lfs_file_size(&lfs, &file) == 0) { for (int j = 0; j < COUNT; j++) { strcpy((char*)buffer, "kittycatcat"); - size = strlen((char*)buffer); + size_t size = strlen((char*)buffer); lfs_file_write(&lfs, &file, buffer, size) => size; } } lfs_file_close(&lfs, &file) => 0; strcpy((char*)buffer, "doggodogdog"); - size = strlen((char*)buffer); + size_t size = strlen((char*)buffer); lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; lfs_file_size(&lfs, &file) => COUNT*size; diff --git a/tests/test_superblocks.toml b/tests/test_superblocks.toml index 407c845..689bbcd 100644 --- a/tests/test_superblocks.toml +++ b/tests/test_superblocks.toml @@ -1,41 +1,53 @@ -[[case]] # simple formatting test +# simple formatting test +[cases.test_superblocks_format] code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; ''' -[[case]] # mount/unmount +# mount/unmount +[cases.test_superblocks_mount] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_unmount(&lfs) => 0; ''' -[[case]] # reentrant format +# reentrant format +[cases.test_superblocks_reentrant_format] reentrant = true code = ''' - err = lfs_mount(&lfs, &cfg); + lfs_t lfs; + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } lfs_unmount(&lfs) => 0; ''' -[[case]] # invalid mount +# invalid mount +[cases.test_superblocks_invalid_mount] code = ''' - lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; + lfs_t lfs; + lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT; ''' -[[case]] # expanding superblock -define.LFS_BLOCK_CYCLES = [32, 33, 1] -define.N = [10, 100, 1000] +# expanding superblock +[cases.test_superblocks_expand] +defines.BLOCK_CYCLES = [32, 33, 1] +defines.N = [10, 100, 1000] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (int i = 0; i < N; i++) { + lfs_file_t file; lfs_file_open(&lfs, &file, "dummy", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfs_file_close(&lfs, &file) => 0; + struct lfs_info info; lfs_stat(&lfs, "dummy", &info) => 0; assert(strcmp(info.name, "dummy") == 0); assert(info.type == LFS_TYPE_REG); @@ -44,25 +56,30 @@ code = ''' lfs_unmount(&lfs) => 0; // one last check after power-cycle - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "dummy", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfs_file_close(&lfs, &file) => 0; + struct lfs_info info; lfs_stat(&lfs, "dummy", &info) => 0; assert(strcmp(info.name, "dummy") == 0); assert(info.type == LFS_TYPE_REG); lfs_unmount(&lfs) => 0; ''' -[[case]] # expanding superblock with power cycle -define.LFS_BLOCK_CYCLES = [32, 33, 1] -define.N = [10, 100, 1000] +# expanding superblock with power cycle +[cases.test_superblocks_expand_power_cycle] +defines.BLOCK_CYCLES = [32, 33, 1] +defines.N = [10, 100, 1000] code = ''' - lfs_format(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; for (int i = 0; i < N; i++) { - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; // remove lingering dummy? - err = lfs_stat(&lfs, "dummy", &info); + struct lfs_info info; + int err = lfs_stat(&lfs, "dummy", &info); assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); if (!err) { assert(strcmp(info.name, "dummy") == 0); @@ -70,6 +87,7 @@ code = ''' lfs_remove(&lfs, "dummy") => 0; } + lfs_file_t file; lfs_file_open(&lfs, &file, "dummy", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfs_file_close(&lfs, &file) => 0; @@ -80,26 +98,30 @@ code = ''' } // one last check after power-cycle - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + struct lfs_info info; lfs_stat(&lfs, "dummy", &info) => 0; assert(strcmp(info.name, "dummy") == 0); assert(info.type == LFS_TYPE_REG); lfs_unmount(&lfs) => 0; ''' -[[case]] # reentrant expanding superblock -define.LFS_BLOCK_CYCLES = [2, 1] -define.N = 24 +# reentrant expanding superblock +[cases.test_superblocks_reentrant_expand] +defines.BLOCK_CYCLES = [2, 1] +defines.N = 24 reentrant = true code = ''' - err = lfs_mount(&lfs, &cfg); + lfs_t lfs; + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } for (int i = 0; i < N; i++) { // remove lingering dummy? + struct lfs_info info; err = lfs_stat(&lfs, "dummy", &info); assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); if (!err) { @@ -108,6 +130,7 @@ code = ''' lfs_remove(&lfs, "dummy") => 0; } + lfs_file_t file; lfs_file_open(&lfs, &file, "dummy", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfs_file_close(&lfs, &file) => 0; @@ -119,7 +142,8 @@ code = ''' lfs_unmount(&lfs) => 0; // one last check after power-cycle - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + struct lfs_info info; lfs_stat(&lfs, "dummy", &info) => 0; assert(strcmp(info.name, "dummy") == 0); assert(info.type == LFS_TYPE_REG); diff --git a/tests/test_truncate.toml b/tests/test_truncate.toml index 850d7aa..a0da50e 100644 --- a/tests/test_truncate.toml +++ b/tests/test_truncate.toml @@ -1,14 +1,18 @@ -[[case]] # simple truncate -define.MEDIUMSIZE = [32, 2048] -define.LARGESIZE = 8192 +# simple truncate +[cases.test_truncate_simple] +defines.MEDIUMSIZE = [32, 2048] +defines.LARGESIZE = 8192 code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "baldynoop", LFS_O_WRONLY | LFS_O_CREAT) => 0; + uint8_t buffer[1024]; strcpy((char*)buffer, "hair"); - size = strlen((char*)buffer); + size_t size = strlen((char*)buffer); for (lfs_off_t j = 0; j < LARGESIZE; j += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -17,7 +21,7 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; lfs_file_size(&lfs, &file) => LARGESIZE; @@ -27,7 +31,7 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDONLY) => 0; lfs_file_size(&lfs, &file) => MEDIUMSIZE; @@ -42,17 +46,21 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # truncate and read -define.MEDIUMSIZE = [32, 2048] -define.LARGESIZE = 8192 +# truncate and read +[cases.test_truncate_read] +defines.MEDIUMSIZE = [32, 2048] +defines.LARGESIZE = 8192 code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "baldyread", LFS_O_WRONLY | LFS_O_CREAT) => 0; + uint8_t buffer[1024]; strcpy((char*)buffer, "hair"); - size = strlen((char*)buffer); + size_t size = strlen((char*)buffer); for (lfs_off_t j = 0; j < LARGESIZE; j += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -61,7 +69,7 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDWR) => 0; lfs_file_size(&lfs, &file) => LARGESIZE; @@ -78,7 +86,7 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDONLY) => 0; lfs_file_size(&lfs, &file) => MEDIUMSIZE; @@ -93,14 +101,18 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # write, truncate, and read +# write, truncate, and read +[cases.test_truncate_write_read] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "sequence", LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0; - size = lfs_min(lfs.cfg->cache_size, sizeof(buffer)/2); + uint8_t buffer[1024]; + size_t size = lfs_min(lfs.cfg->cache_size, sizeof(buffer)/2); lfs_size_t qsize = size / 4; uint8_t *wb = buffer; uint8_t *rb = buffer + size; @@ -145,17 +157,21 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # truncate and write -define.MEDIUMSIZE = [32, 2048] -define.LARGESIZE = 8192 +# truncate and write +[cases.test_truncate_write] +defines.MEDIUMSIZE = [32, 2048] +defines.LARGESIZE = 8192 code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "baldywrite", LFS_O_WRONLY | LFS_O_CREAT) => 0; + uint8_t buffer[1024]; strcpy((char*)buffer, "hair"); - size = strlen((char*)buffer); + size_t size = strlen((char*)buffer); for (lfs_off_t j = 0; j < LARGESIZE; j += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -164,7 +180,7 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0; lfs_file_size(&lfs, &file) => LARGESIZE; @@ -181,7 +197,7 @@ code = ''' lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDONLY) => 0; lfs_file_size(&lfs, &file) => MEDIUMSIZE; @@ -196,26 +212,30 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # truncate write under powerloss -define.SMALLSIZE = [4, 512] -define.MEDIUMSIZE = [32, 1024] -define.LARGESIZE = 2048 +# truncate write under powerloss +[cases.test_truncate_reentrant_write] +defines.SMALLSIZE = [4, 512] +defines.MEDIUMSIZE = [32, 1024] +defines.LARGESIZE = 2048 reentrant = true code = ''' - err = lfs_mount(&lfs, &cfg); + lfs_t lfs; + int err = lfs_mount(&lfs, cfg); if (err) { - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; } + lfs_file_t file; err = lfs_file_open(&lfs, &file, "baldy", LFS_O_RDONLY); assert(!err || err == LFS_ERR_NOENT); if (!err) { - size = lfs_file_size(&lfs, &file); + size_t size = lfs_file_size(&lfs, &file); assert(size == 0 || - size == LARGESIZE || - size == MEDIUMSIZE || - size == SMALLSIZE); + size == (size_t)LARGESIZE || + size == (size_t)MEDIUMSIZE || + size == (size_t)SMALLSIZE); for (lfs_off_t j = 0; j < size; j += 4) { + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, 4) => 4; assert(memcmp(buffer, "hair", 4) == 0 || memcmp(buffer, "bald", 4) == 0 || @@ -227,8 +247,9 @@ code = ''' lfs_file_open(&lfs, &file, "baldy", LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; lfs_file_size(&lfs, &file) => 0; + uint8_t buffer[1024]; strcpy((char*)buffer, "hair"); - size = strlen((char*)buffer); + size_t size = strlen((char*)buffer); for (lfs_off_t j = 0; j < LARGESIZE; j += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -262,12 +283,14 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # more aggressive general truncation tests -define.CONFIG = 'range(6)' -define.SMALLSIZE = 32 -define.MEDIUMSIZE = 2048 -define.LARGESIZE = 8192 +# more aggressive general truncation tests +[cases.test_truncate_aggressive] +defines.CONFIG = 'range(6)' +defines.SMALLSIZE = 32 +defines.MEDIUMSIZE = 2048 +defines.LARGESIZE = 8192 code = ''' + lfs_t lfs; #define COUNT 5 const struct { lfs_off_t startsizes[COUNT]; @@ -312,16 +335,19 @@ code = ''' const lfs_off_t *hotsizes = configs[CONFIG].hotsizes; const lfs_off_t *coldsizes = configs[CONFIG].coldsizes; - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (unsigned i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "hairyhead%d", i); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; + uint8_t buffer[1024]; strcpy((char*)buffer, "hair"); - size = strlen((char*)buffer); + size_t size = strlen((char*)buffer); for (lfs_off_t j = 0; j < startsizes[i]; j += size) { lfs_file_write(&lfs, &file, buffer, size) => size; } @@ -340,21 +366,25 @@ code = ''' lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (unsigned i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "hairyhead%d", i); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_RDWR) => 0; lfs_file_size(&lfs, &file) => hotsizes[i]; - size = strlen("hair"); + size_t size = strlen("hair"); lfs_off_t j = 0; for (; j < startsizes[i] && j < hotsizes[i]; j += size) { + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, size) => size; memcmp(buffer, "hair", size) => 0; } for (; j < hotsizes[i]; j += size) { + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, size) => size; memcmp(buffer, "\0\0\0\0", size) => 0; } @@ -367,22 +397,26 @@ code = ''' lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; for (unsigned i = 0; i < COUNT; i++) { + char path[1024]; sprintf(path, "hairyhead%d", i); + lfs_file_t file; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_size(&lfs, &file) => coldsizes[i]; - size = strlen("hair"); + size_t size = strlen("hair"); lfs_off_t j = 0; for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i]; j += size) { + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, size) => size; memcmp(buffer, "hair", size) => 0; } for (; j < coldsizes[i]; j += size) { + uint8_t buffer[1024]; lfs_file_read(&lfs, &file, buffer, size) => size; memcmp(buffer, "\0\0\0\0", size) => 0; } @@ -393,16 +427,20 @@ code = ''' lfs_unmount(&lfs) => 0; ''' -[[case]] # noop truncate -define.MEDIUMSIZE = [32, 2048] +# noop truncate +[cases.test_truncate_nop] +defines.MEDIUMSIZE = [32, 2048] code = ''' - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; + lfs_t lfs; + lfs_format(&lfs, cfg) => 0; + lfs_mount(&lfs, cfg) => 0; + lfs_file_t file; lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR | LFS_O_CREAT) => 0; + uint8_t buffer[1024]; strcpy((char*)buffer, "hair"); - size = strlen((char*)buffer); + size_t size = strlen((char*)buffer); for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { lfs_file_write(&lfs, &file, buffer, size) => size; @@ -426,7 +464,7 @@ code = ''' lfs_unmount(&lfs) => 0; // still there after reboot? - lfs_mount(&lfs, &cfg) => 0; + lfs_mount(&lfs, cfg) => 0; lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; lfs_file_size(&lfs, &file) => MEDIUMSIZE; for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { |