From da4e86abac3df336234c58a83fc13650b45813d5 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Fri, 4 Aug 2023 14:14:18 -0500 Subject: [PATCH] Split test_dirs into test_dtree and test_dseek - test_dtree - Pure directory creation/deletion/move functionality testing. This ends up testing the core of littlefs file entry manipulation, since directories is all we need for that. - test_dseek - Tests more of the corner cases specific to directory iteration and seeking. This involves an annoying amount of interactions with concurrent updates to the filesystem that are complicated to test for. Also generally renaming the "fstree" concept to "dtree". This only changes dbglfs.py as far as I'm aware. It's useful to have a name for this thing and "directory tree" fits a bit better than "filesystem tree" which could be ambiguous when we also have the "metadata tree" as a different concept. --- scripts/dbglfs.py | 18 +- tests/test_dseek.toml | 1339 +++++++++++++++++++ tests/{test_dirs.toml => test_dtree.toml} | 1420 +-------------------- 3 files changed, 1393 insertions(+), 1384 deletions(-) create mode 100644 tests/test_dseek.toml rename tests/{test_dirs.toml => test_dtree.toml} (82%) diff --git a/scripts/dbglfs.py b/scripts/dbglfs.py index 5ee8401f..3798ee4c 100755 --- a/scripts/dbglfs.py +++ b/scripts/dbglfs.py @@ -888,14 +888,14 @@ def main(disk, mroots=None, *, if grmed_dir_dids != grmed_dstart_dids: corrupted = True - # are we going to end up rendering the fstree? - fstree = args.get('fstree') or not ( + # are we going to end up rendering the dtree? + dtree = args.get('dtree') or not ( args.get('config') or args.get('gstate')) # do a pass to find the width that fits file names+tree, this # may not terminate! It's up to the user to use -Z in that case f_width = 0 - if fstree: + if dtree: def rec_f_width(did, depth): depth_ = 0 width_ = 0 @@ -930,7 +930,7 @@ def main(disk, mroots=None, *, w_width = (m.ceil(m.log10(max(1, mweight)+1)) + 2*m.ceil(m.log10(max(1, rweight)+1)) + 2) - if fstree: + if dtree: print('%-11s %-*s %-*s %s' % ( 'mdir', w_width, 'ids', @@ -1054,8 +1054,8 @@ def main(disk, mroots=None, *, w_width, '', line)) - # print fstree? - if fstree: + # print dtree? + if dtree: # only show mdir on change pmid = None # recursively print directories @@ -1110,7 +1110,7 @@ def main(disk, mroots=None, *, if did_ not in grmed_dir_dids: notes.append('orphaned') - # print human readable fstree entry + # print human readable dtree entry print('%s%12s %*s %-*s %s%s%s' % ( '\x1b[90m' if color and (grmed or tag == TAG_DSTART) else '', @@ -1238,9 +1238,9 @@ if __name__ == "__main__": action='store_true', help="Show the gdelta that xors into the global-state.") parser.add_argument( - '-f', '--fstree', + '-t', '--dtree', '--tree', action='store_true', - help="Show the filesystem tree (default).") + help="Show the directory tree (default).") parser.add_argument( '-A', '--attrs', action='store_true', diff --git a/tests/test_dseek.toml b/tests/test_dseek.toml new file mode 100644 index 00000000..42cbd80c --- /dev/null +++ b/tests/test_dseek.toml @@ -0,0 +1,1339 @@ +# Test the annoying subtle corner cases of directory seeking+reading +# +# Note there may be some overlap with test_dtree, since some dir operations +# are needed to validate the directory tree works +after = 'test_dtree' + + +# test some dir functions + +[cases.test_dseek_tell] +defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] +defines.PARENT = [false, true] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + if (PARENT) { + lfsr_mkdir(&lfs, "pricklypear") => 0; + } + + // make this many directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + lfsr_mkdir(&lfs, name) => 0; + } + + // read our directory + // + // Note tell's value is not guaranteed! We can test the exact value only + // because these tests are tightly bound to the current littlefs version. + // + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + lfsr_dir_tell(&lfs, &dir) => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_tell(&lfs, &dir) => 1; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t i = 0; i < N; i++) { + lfsr_dir_tell(&lfs, &dir) => 2 + i; + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_tell(&lfs, &dir) => 2 + N; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_tell(&lfs, &dir) => 2 + N; + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +[cases.test_dseek_rewind] +defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] +defines.PARENT = [false, true] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + if (PARENT) { + lfsr_mkdir(&lfs, "pricklypear") => 0; + } + + // make this many directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + lfsr_mkdir(&lfs, name) => 0; + } + + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + + // read our directory once + lfsr_dir_tell(&lfs, &dir) => 0;; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_tell(&lfs, &dir) => 1; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t i = 0; i < N; i++) { + lfsr_dir_tell(&lfs, &dir) => 2 + i; + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_tell(&lfs, &dir) => 2 + N; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_tell(&lfs, &dir) => 2 + N; + + // now read it again + lfsr_dir_rewind(&lfs, &dir) => 0; + lfsr_dir_tell(&lfs, &dir) => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_tell(&lfs, &dir) => 1; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t i = 0; i < N; i++) { + lfsr_dir_tell(&lfs, &dir) => 2 + i; + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_tell(&lfs, &dir) => 2 + N; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_tell(&lfs, &dir) => 2 + N; + + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +[cases.test_dseek_seek] +defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] +defines.PARENT = [false, true] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + if (PARENT) { + lfsr_mkdir(&lfs, "pricklypear") => 0; + } + + // make this many directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + lfsr_mkdir(&lfs, name) => 0; + } + + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + + // read our directory once + lfsr_dir_tell(&lfs, &dir) => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_tell(&lfs, &dir) => 1; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t i = 0; i < N; i++) { + lfsr_dir_tell(&lfs, &dir) => 2 + i; + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_tell(&lfs, &dir) => 2 + N; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_tell(&lfs, &dir) => 2 + N; + + // now try to seek to each entry explicitly + lfsr_dir_seek(&lfs, &dir, 0) => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_seek(&lfs, &dir, 1) => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t i = 0; i < N; i++) { + lfsr_dir_seek(&lfs, &dir, 2 + i) => 0; + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_seek(&lfs, &dir, 2 + N) => 0; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_seek(&lfs, &dir, 2 + N) => 0; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +# test we don't ever get extra entries back after we reach +# the end of a directory +[cases.test_dseek_read_idempotent] +defines.PARENT = [false, true] +# bit 0x2 = left neighbor +# bit 0x1 = right neighbor +defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] +# neighbors only make sense if we have a parent +if = 'PARENT || NEIGHBORS == 0' +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + if (PARENT) { + lfsr_mkdir(&lfs, "pricklypear") => 0; + + if (NEIGHBORS & 0x2) { + assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); + lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; + lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; + } + + if (NEIGHBORS & 0x1) { + assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); + lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; + lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; + } + } + + char name[256]; + sprintf(name, "%s/ardvark", (PARENT ? "pricklypear" : "")); + lfsr_mkdir(&lfs, name) => 0; + + // read to the end + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_tell(&lfs, &dir) => 3; + + // reading again should still return noent + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + // seeking past the end of the directory should still return noent + lfsr_dir_seek(&lfs, &dir, 3) => 0; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + lfsr_dir_seek(&lfs, &dir, 4) => 0; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + lfsr_dir_seek(&lfs, &dir, 1000) => 0; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + // but we should be able to read again + lfsr_dir_rewind(&lfs, &dir) => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "ardvark") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +# test dir read works when under filesystem modifications +# +# this is a bit complex and subtle + +[cases.test_dseek_read_with_mkdirs] +defines.N = 5 +# where in the dir read do we mkdir? +defines.I = 'range(6)' +# where do we mkdir? +defines.J = 'range(6)' +defines.PARENT = [false, true] +# bit 0x2 = left neighbor +# bit 0x1 = right neighbor +defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] +# 0 => don't seek +# 1 => seek +# 2 => rewind then seek +defines.SEEK = [0, 1, 2] +# neighbors only make sense if we have a parent +if = 'PARENT || NEIGHBORS == 0' +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + if (PARENT) { + lfsr_mkdir(&lfs, "pricklypear") => 0; + + if (NEIGHBORS & 0x2) { + assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); + lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; + lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; + } + + if (NEIGHBORS & 0x1) { + assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); + lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; + lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; + } + } + + // create our directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i+1); + lfsr_mkdir(&lfs, name) => 0; + } + + // start reading + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + + // read until I + for (lfs_size_t i = 0; i < I; i++) { + char name[256]; + sprintf(name, "dir%04d", i+1); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + // make a dir at J + char name[256]; + sprintf(name, "%s/dir%04d_", (PARENT ? "pricklypear" : ""), (int)J); + lfsr_mkdir(&lfs, name) => 0; + + // seek after mkdir? this tests that the internal position is + // updated correctly + if (SEEK) { + lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); + assert(off >= 0); + if (SEEK >= 2) { + lfsr_dir_rewind(&lfs, &dir) => 0; + } + lfsr_dir_seek(&lfs, &dir, off) => 0; + } + + // we should be able to keep reading, though we may pick up J + for (lfs_size_t i = I + (I >= J ? 1 : 0); i < N+1; i++) { + char name[256]; + sprintf(name, "dir%04d%s", i+1 - (i >= J ? 1 : 0), (i == J ? "_" : "")); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +[cases.test_dseek_read_with_rms] +defines.N = 5 +# where in the dir read do we rm? +defines.I = 'range(5)' +# where do we rm? +defines.J = 'range(5)' +defines.PARENT = [false, true] +# bit 0x2 = left neighbor +# bit 0x1 = right neighbor +defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] +# 0 => don't seek +# 1 => seek +# 2 => rewind then seek +defines.SEEK = [0, 1, 2] +# neighbors only make sense if we have a parent +if = 'PARENT || NEIGHBORS == 0' +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + if (PARENT) { + lfsr_mkdir(&lfs, "pricklypear") => 0; + + if (NEIGHBORS & 0x2) { + assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); + lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; + lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; + } + + if (NEIGHBORS & 0x1) { + assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); + lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; + lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; + } + } + + // create our directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + lfsr_mkdir(&lfs, name) => 0; + } + + // start reading + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + + // read until I + for (lfs_size_t i = 0; i < I; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + // remove the dir at J + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)J); + lfsr_remove(&lfs, name) => 0; + + // seek after remove? this tests that the internal position is + // updated correctly + if (SEEK) { + lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); + assert(off >= 0); + if (SEEK >= 2) { + lfsr_dir_rewind(&lfs, &dir) => 0; + } + lfsr_dir_seek(&lfs, &dir, off) => 0; + } + + // we should be able to keep reading + for (lfs_size_t i = I; i < N; i++) { + if (i == J) { + continue; + } + + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +[cases.test_dseek_read_with_mvs] +defines.N = 5 +# where in the dir read do we rm? +defines.I = 'range(5)' +# where do we rm? +defines.J = 'range(5)' +defines.K = 'range(5)' +defines.BEFORE = [false, true] +# 0 => no +# 1 => yes +# 2 => yes, and rename to new parent +defines.PARENT = [0, 1, 2] +# bit 0x2 = left neighbor +# bit 0x1 = right neighbor +defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] +# 0 => don't seek +# 1 => seek +# 2 => rewind then seek +defines.SEEK = [0, 1, 2] +# neighbors only make sense if we have a parent +if = 'PARENT || NEIGHBORS == 0' +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + if (PARENT) { + lfsr_mkdir(&lfs, "pricklypear") => 0; + if (PARENT >= 2) { + lfsr_mkdir(&lfs, "quiabentia") => 0; + } + + if (NEIGHBORS & 0x2) { + assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); + lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; + lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; + } + + if (NEIGHBORS & 0x1) { + assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); + lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; + lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; + } + } + + // create our directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + lfsr_mkdir(&lfs, name) => 0; + } + + // start reading + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + + // read until I + for (lfs_size_t i = 0; i < I; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + // rename the dir at J + char old_name[256]; + sprintf(old_name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)J); + char new_name[256]; + sprintf(new_name, "%s/%smved%04d", + (PARENT == 1 ? "pricklypear" + : PARENT >= 2 ? "quiabentia" + : ""), + (BEFORE ? "0" : ""), + (int)J); + lfsr_rename(&lfs, old_name, new_name) => 0; + + // seek after remove? this tests that the internal position is + // updated correctly + if (SEEK) { + lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); + assert(off >= 0); + if (SEEK >= 2) { + lfsr_dir_rewind(&lfs, &dir) => 0; + } + lfsr_dir_seek(&lfs, &dir, off) => 0; + } + + // we should be able to keep reading + for (lfs_size_t i = I; i < N; i++) { + if (i == J) { + continue; + } + + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + int err = lfsr_dir_read(&lfs, &dir, &info); + assert(err == LFS_ERR_NOENT || (!BEFORE && PARENT < 2)); + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +# dir reads with 2x ops have better chances of catching bugs that depend on +# invalid dir states + +[cases.test_dseek_read_with_2_mkdirs] +defines.N = 5 +# where in the dir read do we mkdir? +defines.I = 'range(6)' +# where do we mkdir? +defines.J = 'range(6)' +defines.K = 'range(6)' +defines.PARENT = [false, true] +# bit 0x2 = left neighbor +# bit 0x1 = right neighbor +defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] +# 0 => don't seek +# 1 => seek +# 2 => rewind then seek +defines.SEEK = [0, 1, 2] +if = [ + 'J != K', + # neighbors only make sense if we have a parent + 'PARENT || NEIGHBORS == 0', +] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + if (PARENT) { + lfsr_mkdir(&lfs, "pricklypear") => 0; + + if (NEIGHBORS & 0x2) { + assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); + lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; + } + + if (NEIGHBORS & 0x1) { + assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); + lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; + } + } + + // create our directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i+1); + lfsr_mkdir(&lfs, name) => 0; + } + + // start reading + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + + // read until I + for (lfs_size_t i = 0; i < I; i++) { + char name[256]; + sprintf(name, "dir%04d", i+1); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + // make a dir at J + char name[256]; + sprintf(name, "%s/dir%04d_", (PARENT ? "pricklypear" : ""), (int)J); + lfsr_mkdir(&lfs, name) => 0; + + // make a dir at K + sprintf(name, "%s/dir%04d_", (PARENT ? "pricklypear" : ""), (int)K); + lfsr_mkdir(&lfs, name) => 0; + + // seek after mkdir? this tests that the internal position is + // updated correctly + if (SEEK) { + lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); + assert(off >= 0); + if (SEEK >= 2) { + lfsr_dir_rewind(&lfs, &dir) => 0; + } + lfsr_dir_seek(&lfs, &dir, off) => 0; + } + + // we should be able to keep reading, though we may pick up J + for (lfs_size_t i = I + (I >= J ? 1 : 0) + (I >= K ? 1 : 0); i < N+2; i++) { + char name[256]; + sprintf(name, "dir%04d%s", + i+1 - (i >= J + (J >= K ? 1 : 0) ? 1 : 0) + - (i >= K + (K >= J ? 1 : 0) ? 1 : 0), + (i == J + (J > K ? 1 : 0) || i == K + (K > J ? 1 : 0) + ? "_" : "")); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +[cases.test_dseek_read_with_2_rms] +defines.N = 5 +# where in the dir read do we rm? +defines.I = 'range(5)' +# where do we rm? +defines.J = 'range(5)' +defines.K = 'range(5)' +defines.PARENT = [false, true] +# bit 0x2 = left neighbor +# bit 0x1 = right neighbor +defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] +# 0 => don't seek +# 1 => seek +# 2 => rewind then seek +defines.SEEK = [0, 1, 2] +if = [ + 'J != K', + # neighbors only make sense if we have a parent + 'PARENT || NEIGHBORS == 0', +] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + if (PARENT) { + lfsr_mkdir(&lfs, "pricklypear") => 0; + + if (NEIGHBORS & 0x2) { + assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); + lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; + lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; + } + + if (NEIGHBORS & 0x1) { + assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); + lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; + lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; + } + } + + // create our directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + lfsr_mkdir(&lfs, name) => 0; + } + + // start reading + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + + // read until I + for (lfs_size_t i = 0; i < I; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + // remove the dir at J + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)J); + lfsr_remove(&lfs, name) => 0; + + // remove the dir at K + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)K); + lfsr_remove(&lfs, name) => 0; + + // seek after remove? this tests that the internal position is + // updated correctly + if (SEEK) { + lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); + assert(off >= 0); + if (SEEK >= 2) { + lfsr_dir_rewind(&lfs, &dir) => 0; + } + lfsr_dir_seek(&lfs, &dir, off) => 0; + } + + // we should be able to keep reading + for (lfs_size_t i = I; i < N; i++) { + if (i == J || i == K) { + continue; + } + + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +[cases.test_dseek_read_with_2_mvs] +defines.N = 5 +# where in the dir read do we rm? +defines.I = 'range(5)' +# where do we rm? +defines.J = 'range(5)' +defines.K = 'range(5)' +defines.BEFORE = [false, true] +# 0 => no +# 1 => yes +# 2 => yes, and rename to new parent +defines.PARENT = [0, 1, 2] +# bit 0x2 = left neighbor +# bit 0x1 = right neighbor +defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] +# 0 => don't seek +# 1 => seek +# 2 => rewind then seek +defines.SEEK = [0, 1, 2] +# neighbors only make sense if we have a parent +if = [ + 'J != K', + # neighbors only make sense if we have a parent + 'PARENT || NEIGHBORS == 0', +] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + if (PARENT) { + lfsr_mkdir(&lfs, "pricklypear") => 0; + if (PARENT >= 2) { + lfsr_mkdir(&lfs, "quiabentia") => 0; + } + + if (NEIGHBORS & 0x2) { + assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); + lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; + lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; + } + + if (NEIGHBORS & 0x1) { + assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); + lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; + lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; + } + } + + // create our directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + lfsr_mkdir(&lfs, name) => 0; + } + + // start reading + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + + // read until I + for (lfs_size_t i = 0; i < I; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + // rename the dir at J + char old_name[256]; + sprintf(old_name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)J); + char new_name[256]; + sprintf(new_name, "%s/%smved%04d", + (PARENT == 1 ? "pricklypear" + : PARENT >= 2 ? "quiabentia" + : ""), + (BEFORE ? "0" : ""), + (int)J); + lfsr_rename(&lfs, old_name, new_name) => 0; + + // rename the dir at K + sprintf(old_name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)K); + sprintf(new_name, "%s/%smved%04d", + (PARENT == 1 ? "pricklypear" + : PARENT >= 2 ? "quiabentia" + : ""), + (BEFORE ? "0" : ""), + (int)K); + lfsr_rename(&lfs, old_name, new_name) => 0; + + // seek after remove? this tests that the internal position is + // updated correctly + if (SEEK) { + lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); + assert(off >= 0); + if (SEEK >= 2) { + lfsr_dir_rewind(&lfs, &dir) => 0; + } + lfsr_dir_seek(&lfs, &dir, off) => 0; + } + + // we should be able to keep reading + for (lfs_size_t i = I; i < N; i++) { + if (i == J || i == K) { + continue; + } + + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + int err = lfsr_dir_read(&lfs, &dir, &info); + assert(err == LFS_ERR_NOENT || (!BEFORE && PARENT < 2)); + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +# test removing the directory we are iterating over +[cases.test_dseek_read_rm] +defines.N = 5 +# where in the dir read do we remove? +defines.I = 'range(6)' +# bit 0x2 = left neighbor +# bit 0x1 = right neighbor +defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] +# 0 => don't seek +# 1 => seek +# 2 => rewind then seek +defines.SEEK = [0, 1, 2] +code = ''' + lfs_t lfs; + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + + lfsr_mkdir(&lfs, "pricklypear") => 0; + + if (NEIGHBORS & 0x2) { + assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); + lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; + lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; + } + + if (NEIGHBORS & 0x1) { + assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); + lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; + lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; + } + + // create our directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "pricklypear/dir%04d", i+1); + lfsr_mkdir(&lfs, name) => 0; + } + + // start reading + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, "pricklypear") => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + + // read until I + for (lfs_size_t i = 0; i < I; i++) { + char name[256]; + sprintf(name, "dir%04d", i+1); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + // remove the directory + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "pricklypear/dir%04d", i+1); + lfsr_remove(&lfs, name) => 0; + } + lfsr_remove(&lfs, "pricklypear") => 0; + + // seek after mkdir? + if (SEEK) { + lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); + assert(off >= 0); + if (SEEK >= 2) { + lfsr_dir_rewind(&lfs, &dir) => 0; + } + lfsr_dir_seek(&lfs, &dir, off) => 0; + } + + // try to read, but this should return an error + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + + + +## Recursive tests + +# Recursive here just refers to removing entries in a directory while +# iterating over the directory +# +# This is a useful feature, but it's unintuitive if this should have +# well-defined behavior, so make sure to test for it +[cases.test_dseek_recursive_rm] +defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] +defines.PARENT = [false, true] +# 0 => don't seek +# 1 => seek +# 2 => rewind then seek +defines.SEEK = [0, 1, 2] +# limit powerloss testing due to time +if = '!TEST_PL || N <= 32' +reentrant = true +code = ''' + // format once per test + lfs_t lfs; + int err = lfsr_mount(&lfs, CFG); + if (err) { + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + } + + if (PARENT) { + err = lfsr_mkdir(&lfs, "pricklypear"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + } + + // make this many directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + err = lfsr_mkdir(&lfs, name); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + } + + // check that our mkdir worked + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + struct lfs_info info; + lfsr_stat(&lfs, name, &info) => 0; + char name2[256]; + sprintf(name2, "dir%04d", i); + assert(strcmp(info.name, name2) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + // now remove directories recursively + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + + char path[1024]; + sprintf(path, "%s/%s", (PARENT ? "pricklypear" : ""), info.name); + lfsr_remove(&lfs, path) => 0; + + // seek between removes? this tests that the internal position is + // updated correctly + if (SEEK) { + lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); + assert(off >= 0); + if (SEEK >= 2) { + lfsr_dir_rewind(&lfs, &dir) => 0; + } + lfsr_dir_seek(&lfs, &dir, off) => 0; + } + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + // check that our removes worked + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + struct lfs_info info; + lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT; + } + + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + +# Recursive here just refers to renaming entries in a directory while +# iterating over the directory +# +# This is a useful feature, but it's unintuitive if this should have +# well-defined behavior, so make sure to test for it +[cases.test_dseek_recursive_mv] +defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] +defines.BEFORE = [false, true] +# 0 => no +# 1 => yes +# 2 => yes, and rename to new parent +defines.PARENT = [0, 1, 2] +# 0 => don't seek +# 1 => seek +# 2 => rewind then seek +defines.SEEK = [0, 1, 2] +# limit powerloss testing due to time +if = '!TEST_PL || N <= 32' +reentrant = true +code = ''' + // format once per test + lfs_t lfs; + int err = lfsr_mount(&lfs, CFG); + if (err) { + lfsr_format(&lfs, CFG) => 0; + lfsr_mount(&lfs, CFG) => 0; + } + + if (PARENT) { + err = lfsr_mkdir(&lfs, "pricklypear"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + if (PARENT >= 2) { + err = lfsr_mkdir(&lfs, "quiabentia"); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + } + } + + // check if we have already started renaming, in case of powerloss + struct lfs_info info; + err = lfsr_stat(&lfs, + (PARENT == 1 ? (BEFORE + ? "pricklypear/0mved0000" + : "pricklypear/mved0000") + : PARENT >= 2 ? (BEFORE + ? "quiabentia/0mved0000" + : "quiabentia/mved0000") + : (BEFORE + ? "/0mved0000" + : "/mved0000")), &info); + if (err == LFS_ERR_NOENT) { + // make this many directories + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + err = lfsr_mkdir(&lfs, name); + assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); + } + + // check that our mkdir worked + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + struct lfs_info info; + lfsr_stat(&lfs, name, &info) => 0; + char name2[256]; + sprintf(name2, "dir%04d", i); + assert(strcmp(info.name, name2) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + struct lfs_info info; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "dir%04d", i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + } + + // now rename directories recursively + lfsr_dir_t dir; + lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t i = 0;; i++) { + int err = lfsr_dir_read(&lfs, &dir, &info); + assert(!err || err == LFS_ERR_NOENT); + // reached the end? + if (err == LFS_ERR_NOENT) { + break; + } + // skip already moved? + if (memcmp(info.name, "dir", strlen("dir")) != 0) { + continue; + } + assert(i < 2*N); + assert(info.type == LFS_TYPE_DIR); + + char old_path[1024]; + sprintf(old_path, "%s/%s", (PARENT ? "pricklypear" : ""), info.name); + char new_path[1024]; + sprintf(new_path, "%s/%smved%s", + (PARENT == 1 ? "pricklypear" + : PARENT >= 2 ? "quiabentia" + : ""), + (BEFORE ? "0" : ""), + &info.name[strlen("dir")]); + err = lfsr_rename(&lfs, old_path, new_path); + assert(!err || (TEST_PL && err == LFS_ERR_NOENT)); + + // seek between renames? this tests that the internal position is + // updated correctly + if (SEEK) { + lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); + assert(off >= 0); + if (SEEK >= 2) { + lfsr_dir_rewind(&lfs, &dir) => 0; + } + lfsr_dir_seek(&lfs, &dir, off) => 0; + } + } + lfsr_dir_close(&lfs, &dir) => 0; + + // check that our renames worked + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); + struct lfs_info info; + lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT; + + sprintf(name, "%s/%smved%04d", + (PARENT == 1 ? "pricklypear" + : PARENT >= 2 ? "quiabentia" + : ""), + (BEFORE ? "0" : ""), + i); + lfsr_stat(&lfs, name, &info) => 0; + char name2[256]; + sprintf(name2, "%smved%04d", (BEFORE ? "0" : ""), i); + assert(strcmp(info.name, name2) == 0); + assert(info.type == LFS_TYPE_DIR); + } + + lfsr_dir_open(&lfs, &dir, + (PARENT == 1 ? "pricklypear" + : PARENT >= 2 ? "quiabentia" + : "/")) => 0; + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, ".") == 0); + assert(info.type == LFS_TYPE_DIR); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, "..") == 0); + assert(info.type == LFS_TYPE_DIR); + for (lfs_size_t i = 0; i < N; i++) { + char name[256]; + sprintf(name, "%smved%04d", (BEFORE ? "0" : ""), i); + lfsr_dir_read(&lfs, &dir, &info) => 0; + assert(strcmp(info.name, name) == 0); + assert(info.type == LFS_TYPE_DIR); + } + lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; + lfsr_dir_close(&lfs, &dir) => 0; + + lfsr_unmount(&lfs) => 0; +''' + diff --git a/tests/test_dirs.toml b/tests/test_dtree.toml similarity index 82% rename from tests/test_dirs.toml rename to tests/test_dtree.toml index 417083bb..f05351fb 100644 --- a/tests/test_dirs.toml +++ b/tests/test_dtree.toml @@ -3,7 +3,7 @@ after = ['test_mtree', 'test_alloc'] ## mkdir tests -[cases.test_dirs_mkdir] +[cases.test_dtree_mkdir] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -52,7 +52,7 @@ code = ''' ''' # test that noent errors work -[cases.test_dirs_noent] +[cases.test_dtree_noent] defines.REMOUNT = [false, true] code = ''' lfs_t lfs; @@ -99,7 +99,7 @@ code = ''' ''' # test that stat on root works -[cases.test_dirs_stat_root] +[cases.test_dtree_stat_root] defines.REMOUNT = [false, true] code = ''' lfs_t lfs; @@ -146,7 +146,7 @@ code = ''' ''' # test that creating the same directory twice errors -[cases.test_dirs_mkdir_exists] +[cases.test_dtree_mkdir_exists] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -197,7 +197,7 @@ code = ''' ''' # test what happens if we try to make root -[cases.test_dirs_mkdir_root] +[cases.test_dtree_mkdir_root] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -253,7 +253,7 @@ code = ''' ''' # test that creating a directory with an invalid path errors -[cases.test_dirs_mkdir_noent] +[cases.test_dtree_mkdir_noent] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -306,7 +306,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mkdir_siblings] +[cases.test_dtree_mkdir_siblings] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -369,7 +369,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mkdir_children] +[cases.test_dtree_mkdir_children] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -452,7 +452,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mkdir_many] +[cases.test_dtree_mkdir_many] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.REMOUNT = [false, true] # limit powerloss testing due to time @@ -515,7 +515,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mkdir_many_backwards] +[cases.test_dtree_mkdir_many_backwards] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.REMOUNT = [false, true] # limit powerloss testing due to time @@ -578,7 +578,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mkdir_many_2layers] +[cases.test_dtree_mkdir_many_2layers] defines.N = [1, 2, 4, 8, 16] defines.REMOUNT = [false, true] # limit powerloss testing due to time @@ -679,7 +679,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mkdir_many_3layers] +[cases.test_dtree_mkdir_many_3layers] defines.N = [1, 2, 4] defines.REMOUNT = [false, true] # limit powerloss testing due to time @@ -818,7 +818,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mkdir_many_linkedlist] +[cases.test_dtree_mkdir_many_linkedlist] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.REMOUNT = [false, true] # limit powerloss testing due to time @@ -888,7 +888,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mkdir_fuzz] +[cases.test_dtree_mkdir_fuzz] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.PARENT = [false, true] defines.REMOUNT = [false, true] @@ -989,7 +989,7 @@ code = ''' # test that did collisions don't cause issues -[cases.test_dirs_did_collisions] +[cases.test_dtree_did_collisions] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -1084,7 +1084,7 @@ code = ''' ''' # these will also collide with the root -[cases.test_dirs_did_zero] +[cases.test_dtree_did_zero] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -1181,7 +1181,7 @@ code = ''' # these will need to rollover from 0xffffffff -> 0x00000000 correctly # # note this is true even if you truncate -[cases.test_dirs_did_ones] +[cases.test_dtree_did_ones] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -1278,7 +1278,7 @@ code = ''' # these test some boundary conditions on the underlying leb128 encoding, # if the leb128 disk-size is not calculated correctly these can cause # issues -[cases.test_dirs_did_leb128_boundaries] +[cases.test_dtree_did_leb128_boundaries] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -1375,7 +1375,7 @@ code = ''' ## dir remove tests -[cases.test_dirs_rm] +[cases.test_dtree_rm] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -1449,7 +1449,7 @@ code = ''' ''' # test that noent errors work -[cases.test_dirs_rm_noent] +[cases.test_dtree_rm_noent] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -1506,7 +1506,7 @@ code = ''' ''' # test that we catch removing of a non-empty directory -[cases.test_dirs_rm_notempty] +[cases.test_dtree_rm_notempty] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -1577,7 +1577,7 @@ code = ''' ''' # test what happens if we try to remove root -[cases.test_dirs_rm_root] +[cases.test_dtree_rm_root] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -1633,7 +1633,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_rm_siblings] +[cases.test_dtree_rm_siblings] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -1789,7 +1789,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_rm_children] +[cases.test_dtree_rm_children] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -1995,7 +1995,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_rm_many] +[cases.test_dtree_rm_many] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.REMAINING = [64, 2, 1, 0] defines.REMOUNT = [false, true] @@ -2110,7 +2110,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_rm_many_backwards] +[cases.test_dtree_rm_many_backwards] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.REMAINING = [64, 2, 1, 0] defines.REMOUNT = [false, true] @@ -2225,7 +2225,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_rm_many_2layers] +[cases.test_dtree_rm_many_2layers] defines.N = [1, 2, 4, 8, 16] defines.REMAINING = [2, 1, 0] defines.REMOUNT = [false, true] @@ -2429,7 +2429,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_rm_many_3layers] +[cases.test_dtree_rm_many_3layers] defines.N = [1, 2, 4] defines.REMAINING = [2, 1, 0] defines.REMOUNT = [false, true] @@ -2727,7 +2727,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_rm_many_linkedlist] +[cases.test_dtree_rm_many_linkedlist] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.REMAINING = [16, 2, 1, 0] defines.REMOUNT = [false, true] @@ -2850,7 +2850,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_rm_fuzz] +[cases.test_dtree_rm_fuzz] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.PARENT = [false, true] defines.REMOUNT = [false, true] @@ -2970,7 +2970,7 @@ code = ''' ## dir rename tests -[cases.test_dirs_mv] +[cases.test_dtree_mv] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -3056,7 +3056,7 @@ code = ''' ''' # test that we can rename, and replace, other directories -[cases.test_dirs_mv_replace] +[cases.test_dtree_mv_replace] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -3141,7 +3141,7 @@ code = ''' ''' # test that we can rename to ourselves -[cases.test_dirs_mv_noop] +[cases.test_dtree_mv_noop] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -3220,7 +3220,7 @@ code = ''' ''' # test that we catch replacing an invalid path -[cases.test_dirs_mv_noent] +[cases.test_dtree_mv_noent] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -3280,7 +3280,7 @@ code = ''' ''' # test that we catch replacing a non-empty directory -[cases.test_dirs_mv_notempty] +[cases.test_dtree_mv_notempty] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -3358,7 +3358,7 @@ code = ''' ''' # test what happens if we try to rename root -[cases.test_dirs_mv_root] +[cases.test_dtree_mv_root] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -3411,7 +3411,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mv_siblings] +[cases.test_dtree_mv_siblings] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -3607,7 +3607,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mv_children] +[cases.test_dtree_mv_children] defines.REMOUNT = [false, true] reentrant = true code = ''' @@ -3889,7 +3889,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mv_many] +[cases.test_dtree_mv_many] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.BEFORE = [false, true] defines.REMOUNT = [false, true] @@ -4004,7 +4004,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mv_many_backwards] +[cases.test_dtree_mv_many_backwards] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.BEFORE = [false, true] defines.REMOUNT = [false, true] @@ -4119,7 +4119,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mv_many_2layers] +[cases.test_dtree_mv_many_2layers] defines.N = [1, 2, 4, 8, 16] defines.BEFORE = [false, true] defines.REMOUNT = [false, true] @@ -4324,7 +4324,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mv_many_3layers] +[cases.test_dtree_mv_many_3layers] defines.N = [1, 2, 4] defines.BEFORE = [false, true] defines.REMOUNT = [false, true] @@ -4626,7 +4626,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mv_many_linkedlist] +[cases.test_dtree_mv_many_linkedlist] defines.N = [1, 2, 4, 8, 16, 32, 64] defines.BEFORE = [false, true] defines.REMOUNT = [false, true] @@ -4762,7 +4762,7 @@ code = ''' lfsr_unmount(&lfs) => 0; ''' -[cases.test_dirs_mv_fuzz] +[cases.test_dtree_mv_fuzz] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.PARENT = [false, true] defines.REMOUNT = [false, true] @@ -4903,7 +4903,7 @@ code = ''' ''' # test all of the operations together -[cases.test_dirs_general_fuzz] +[cases.test_dtree_general_fuzz] defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] defines.PARENT = [false, true] defines.REMOUNT = [false, true] @@ -5058,1336 +5058,6 @@ code = ''' ''' -## Test seeking and stuff - -[cases.test_dirs_tell] -defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] -defines.PARENT = [false, true] -code = ''' - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - - if (PARENT) { - lfsr_mkdir(&lfs, "pricklypear") => 0; - } - - // make this many directories - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); - lfsr_mkdir(&lfs, name) => 0; - } - - // read our directory - // - // Note tell's value is not guaranteed! We can test the exact value only - // because these tests are tightly bound to the current littlefs version. - // - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - lfsr_dir_tell(&lfs, &dir) => 0; - struct lfs_info info; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_tell(&lfs, &dir) => 1; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - for (lfs_size_t i = 0; i < N; i++) { - lfsr_dir_tell(&lfs, &dir) => 2 + i; - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - lfsr_dir_tell(&lfs, &dir) => 2 + N; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_tell(&lfs, &dir) => 2 + N; - lfsr_dir_close(&lfs, &dir) => 0; - - lfsr_unmount(&lfs) => 0; -''' - -[cases.test_dirs_rewind] -defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] -defines.PARENT = [false, true] -code = ''' - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - - if (PARENT) { - lfsr_mkdir(&lfs, "pricklypear") => 0; - } - - // make this many directories - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); - lfsr_mkdir(&lfs, name) => 0; - } - - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - - // read our directory once - lfsr_dir_tell(&lfs, &dir) => 0;; - struct lfs_info info; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_tell(&lfs, &dir) => 1; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - for (lfs_size_t i = 0; i < N; i++) { - lfsr_dir_tell(&lfs, &dir) => 2 + i; - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - lfsr_dir_tell(&lfs, &dir) => 2 + N; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_tell(&lfs, &dir) => 2 + N; - - // now read it again - lfsr_dir_rewind(&lfs, &dir) => 0; - lfsr_dir_tell(&lfs, &dir) => 0; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_tell(&lfs, &dir) => 1; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - for (lfs_size_t i = 0; i < N; i++) { - lfsr_dir_tell(&lfs, &dir) => 2 + i; - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - lfsr_dir_tell(&lfs, &dir) => 2 + N; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_tell(&lfs, &dir) => 2 + N; - - lfsr_dir_close(&lfs, &dir) => 0; - - lfsr_unmount(&lfs) => 0; -''' - -[cases.test_dirs_seek] -defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] -defines.PARENT = [false, true] -code = ''' - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - - if (PARENT) { - lfsr_mkdir(&lfs, "pricklypear") => 0; - } - - // make this many directories - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); - lfsr_mkdir(&lfs, name) => 0; - } - - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - - // read our directory once - lfsr_dir_tell(&lfs, &dir) => 0; - struct lfs_info info; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_tell(&lfs, &dir) => 1; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - for (lfs_size_t i = 0; i < N; i++) { - lfsr_dir_tell(&lfs, &dir) => 2 + i; - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - lfsr_dir_tell(&lfs, &dir) => 2 + N; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_tell(&lfs, &dir) => 2 + N; - - // now try to seek to each entry explicitly - lfsr_dir_seek(&lfs, &dir, 0) => 0; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_seek(&lfs, &dir, 1) => 0; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - for (lfs_size_t i = 0; i < N; i++) { - lfsr_dir_seek(&lfs, &dir, 2 + i) => 0; - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - lfsr_dir_seek(&lfs, &dir, 2 + N) => 0; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_seek(&lfs, &dir, 2 + N) => 0; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - - lfsr_dir_close(&lfs, &dir) => 0; - - lfsr_unmount(&lfs) => 0; -''' - -[cases.test_dirs_read_idempotent] -defines.PARENT = [false, true] -# bit 0x2 = left neighbor -# bit 0x1 = right neighbor -defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] -# neighbors only make sense if we have a parent -if = 'PARENT || NEIGHBORS == 0' -code = ''' - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - - if (PARENT) { - lfsr_mkdir(&lfs, "pricklypear") => 0; - - if (NEIGHBORS & 0x2) { - assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); - lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; - lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; - } - - if (NEIGHBORS & 0x1) { - assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); - lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; - lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; - } - } - - char name[256]; - sprintf(name, "%s/ardvark", (PARENT ? "pricklypear" : "")); - lfsr_mkdir(&lfs, name) => 0; - - // read to the end - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - - struct lfs_info info; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "ardvark") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_tell(&lfs, &dir) => 3; - - // reading again should still return noent - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - - // seeking past the end of the directory should still return noent - lfsr_dir_seek(&lfs, &dir, 3) => 0; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - - lfsr_dir_seek(&lfs, &dir, 4) => 0; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - - lfsr_dir_seek(&lfs, &dir, 1000) => 0; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - - // but we should be able to read again - lfsr_dir_rewind(&lfs, &dir) => 0; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "ardvark") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - - lfsr_dir_close(&lfs, &dir) => 0; - - lfsr_unmount(&lfs) => 0; -''' - -[cases.test_dirs_read_with_mkdirs] -defines.N = 5 -# where in the dir read do we mkdir? -defines.I = 'range(6)' -# where do we mkdir? -defines.J = 'range(6)' -defines.PARENT = [false, true] -# bit 0x2 = left neighbor -# bit 0x1 = right neighbor -defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] -# 0 => don't seek -# 1 => seek -# 2 => rewind then seek -defines.SEEK = [0, 1, 2] -# neighbors only make sense if we have a parent -if = 'PARENT || NEIGHBORS == 0' -code = ''' - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - - if (PARENT) { - lfsr_mkdir(&lfs, "pricklypear") => 0; - - if (NEIGHBORS & 0x2) { - assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); - lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; - lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; - } - - if (NEIGHBORS & 0x1) { - assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); - lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; - lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; - } - } - - // create our directories - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i+1); - lfsr_mkdir(&lfs, name) => 0; - } - - // start reading - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - struct lfs_info info; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - - // read until I - for (lfs_size_t i = 0; i < I; i++) { - char name[256]; - sprintf(name, "dir%04d", i+1); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - // make a dir at J - char name[256]; - sprintf(name, "%s/dir%04d_", (PARENT ? "pricklypear" : ""), (int)J); - lfsr_mkdir(&lfs, name) => 0; - - // seek after mkdir? this tests that the internal position is - // updated correctly - if (SEEK) { - lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); - assert(off >= 0); - if (SEEK >= 2) { - lfsr_dir_rewind(&lfs, &dir) => 0; - } - lfsr_dir_seek(&lfs, &dir, off) => 0; - } - - // we should be able to keep reading, though we may pick up J - for (lfs_size_t i = I + (I >= J ? 1 : 0); i < N+1; i++) { - char name[256]; - sprintf(name, "dir%04d%s", i+1 - (i >= J ? 1 : 0), (i == J ? "_" : "")); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_close(&lfs, &dir) => 0; - - lfsr_unmount(&lfs) => 0; -''' - -[cases.test_dirs_read_with_rms] -defines.N = 5 -# where in the dir read do we rm? -defines.I = 'range(5)' -# where do we rm? -defines.J = 'range(5)' -defines.PARENT = [false, true] -# bit 0x2 = left neighbor -# bit 0x1 = right neighbor -defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] -# 0 => don't seek -# 1 => seek -# 2 => rewind then seek -defines.SEEK = [0, 1, 2] -# neighbors only make sense if we have a parent -if = 'PARENT || NEIGHBORS == 0' -code = ''' - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - - if (PARENT) { - lfsr_mkdir(&lfs, "pricklypear") => 0; - - if (NEIGHBORS & 0x2) { - assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); - lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; - lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; - } - - if (NEIGHBORS & 0x1) { - assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); - lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; - lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; - } - } - - // create our directories - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); - lfsr_mkdir(&lfs, name) => 0; - } - - // start reading - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - struct lfs_info info; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - - // read until I - for (lfs_size_t i = 0; i < I; i++) { - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - // remove the dir at J - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)J); - lfsr_remove(&lfs, name) => 0; - - // seek after remove? this tests that the internal position is - // updated correctly - if (SEEK) { - lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); - assert(off >= 0); - if (SEEK >= 2) { - lfsr_dir_rewind(&lfs, &dir) => 0; - } - lfsr_dir_seek(&lfs, &dir, off) => 0; - } - - // we should be able to keep reading - for (lfs_size_t i = I; i < N; i++) { - if (i == J) { - continue; - } - - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_close(&lfs, &dir) => 0; - - lfsr_unmount(&lfs) => 0; -''' - -[cases.test_dirs_read_with_mvs] -defines.N = 5 -# where in the dir read do we rm? -defines.I = 'range(5)' -# where do we rm? -defines.J = 'range(5)' -defines.K = 'range(5)' -defines.BEFORE = [false, true] -# 0 => no -# 1 => yes -# 2 => yes, and rename to new parent -defines.PARENT = [0, 1, 2] -# bit 0x2 = left neighbor -# bit 0x1 = right neighbor -defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] -# 0 => don't seek -# 1 => seek -# 2 => rewind then seek -defines.SEEK = [0, 1, 2] -# neighbors only make sense if we have a parent -if = 'PARENT || NEIGHBORS == 0' -code = ''' - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - - if (PARENT) { - lfsr_mkdir(&lfs, "pricklypear") => 0; - if (PARENT >= 2) { - lfsr_mkdir(&lfs, "quiabentia") => 0; - } - - if (NEIGHBORS & 0x2) { - assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); - lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; - lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; - } - - if (NEIGHBORS & 0x1) { - assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); - lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; - lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; - } - } - - // create our directories - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); - lfsr_mkdir(&lfs, name) => 0; - } - - // start reading - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - struct lfs_info info; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - - // read until I - for (lfs_size_t i = 0; i < I; i++) { - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - // rename the dir at J - char old_name[256]; - sprintf(old_name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)J); - char new_name[256]; - sprintf(new_name, "%s/%smved%04d", - (PARENT == 1 ? "pricklypear" - : PARENT >= 2 ? "quiabentia" - : ""), - (BEFORE ? "0" : ""), - (int)J); - lfsr_rename(&lfs, old_name, new_name) => 0; - - // seek after remove? this tests that the internal position is - // updated correctly - if (SEEK) { - lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); - assert(off >= 0); - if (SEEK >= 2) { - lfsr_dir_rewind(&lfs, &dir) => 0; - } - lfsr_dir_seek(&lfs, &dir, off) => 0; - } - - // we should be able to keep reading - for (lfs_size_t i = I; i < N; i++) { - if (i == J) { - continue; - } - - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - int err = lfsr_dir_read(&lfs, &dir, &info); - assert(err == LFS_ERR_NOENT || (!BEFORE && PARENT < 2)); - lfsr_dir_close(&lfs, &dir) => 0; - - lfsr_unmount(&lfs) => 0; -''' - -# dir reads with 2x ops have better chances of catching bugs that depend on -# invalid dir states - -[cases.test_dirs_read_with_2_mkdirs] -defines.N = 5 -# where in the dir read do we mkdir? -defines.I = 'range(6)' -# where do we mkdir? -defines.J = 'range(6)' -defines.K = 'range(6)' -defines.PARENT = [false, true] -# bit 0x2 = left neighbor -# bit 0x1 = right neighbor -defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] -# 0 => don't seek -# 1 => seek -# 2 => rewind then seek -defines.SEEK = [0, 1, 2] -if = [ - 'J != K', - # neighbors only make sense if we have a parent - 'PARENT || NEIGHBORS == 0', -] -code = ''' - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - - if (PARENT) { - lfsr_mkdir(&lfs, "pricklypear") => 0; - - if (NEIGHBORS & 0x2) { - assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); - lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; - } - - if (NEIGHBORS & 0x1) { - assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); - lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; - } - } - - // create our directories - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i+1); - lfsr_mkdir(&lfs, name) => 0; - } - - // start reading - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - struct lfs_info info; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - - // read until I - for (lfs_size_t i = 0; i < I; i++) { - char name[256]; - sprintf(name, "dir%04d", i+1); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - // make a dir at J - char name[256]; - sprintf(name, "%s/dir%04d_", (PARENT ? "pricklypear" : ""), (int)J); - lfsr_mkdir(&lfs, name) => 0; - - // make a dir at K - sprintf(name, "%s/dir%04d_", (PARENT ? "pricklypear" : ""), (int)K); - lfsr_mkdir(&lfs, name) => 0; - - // seek after mkdir? this tests that the internal position is - // updated correctly - if (SEEK) { - lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); - assert(off >= 0); - if (SEEK >= 2) { - lfsr_dir_rewind(&lfs, &dir) => 0; - } - lfsr_dir_seek(&lfs, &dir, off) => 0; - } - - // we should be able to keep reading, though we may pick up J - for (lfs_size_t i = I + (I >= J ? 1 : 0) + (I >= K ? 1 : 0); i < N+2; i++) { - char name[256]; - sprintf(name, "dir%04d%s", - i+1 - (i >= J + (J >= K ? 1 : 0) ? 1 : 0) - - (i >= K + (K >= J ? 1 : 0) ? 1 : 0), - (i == J + (J > K ? 1 : 0) || i == K + (K > J ? 1 : 0) - ? "_" : "")); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_close(&lfs, &dir) => 0; - - lfsr_unmount(&lfs) => 0; -''' - -[cases.test_dirs_read_with_2_rms] -defines.N = 5 -# where in the dir read do we rm? -defines.I = 'range(5)' -# where do we rm? -defines.J = 'range(5)' -defines.K = 'range(5)' -defines.PARENT = [false, true] -# bit 0x2 = left neighbor -# bit 0x1 = right neighbor -defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] -# 0 => don't seek -# 1 => seek -# 2 => rewind then seek -defines.SEEK = [0, 1, 2] -if = [ - 'J != K', - # neighbors only make sense if we have a parent - 'PARENT || NEIGHBORS == 0', -] -code = ''' - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - - if (PARENT) { - lfsr_mkdir(&lfs, "pricklypear") => 0; - - if (NEIGHBORS & 0x2) { - assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); - lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; - lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; - } - - if (NEIGHBORS & 0x1) { - assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); - lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; - lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; - } - } - - // create our directories - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); - lfsr_mkdir(&lfs, name) => 0; - } - - // start reading - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - struct lfs_info info; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - - // read until I - for (lfs_size_t i = 0; i < I; i++) { - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - // remove the dir at J - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)J); - lfsr_remove(&lfs, name) => 0; - - // remove the dir at K - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)K); - lfsr_remove(&lfs, name) => 0; - - // seek after remove? this tests that the internal position is - // updated correctly - if (SEEK) { - lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); - assert(off >= 0); - if (SEEK >= 2) { - lfsr_dir_rewind(&lfs, &dir) => 0; - } - lfsr_dir_seek(&lfs, &dir, off) => 0; - } - - // we should be able to keep reading - for (lfs_size_t i = I; i < N; i++) { - if (i == J || i == K) { - continue; - } - - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_close(&lfs, &dir) => 0; - - lfsr_unmount(&lfs) => 0; -''' - -[cases.test_dirs_read_with_2_mvs] -defines.N = 5 -# where in the dir read do we rm? -defines.I = 'range(5)' -# where do we rm? -defines.J = 'range(5)' -defines.K = 'range(5)' -defines.BEFORE = [false, true] -# 0 => no -# 1 => yes -# 2 => yes, and rename to new parent -defines.PARENT = [0, 1, 2] -# bit 0x2 = left neighbor -# bit 0x1 = right neighbor -defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] -# 0 => don't seek -# 1 => seek -# 2 => rewind then seek -defines.SEEK = [0, 1, 2] -# neighbors only make sense if we have a parent -if = [ - 'J != K', - # neighbors only make sense if we have a parent - 'PARENT || NEIGHBORS == 0', -] -code = ''' - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - - if (PARENT) { - lfsr_mkdir(&lfs, "pricklypear") => 0; - if (PARENT >= 2) { - lfsr_mkdir(&lfs, "quiabentia") => 0; - } - - if (NEIGHBORS & 0x2) { - assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); - lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; - lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; - } - - if (NEIGHBORS & 0x1) { - assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); - lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; - lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; - } - } - - // create our directories - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); - lfsr_mkdir(&lfs, name) => 0; - } - - // start reading - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - struct lfs_info info; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - - // read until I - for (lfs_size_t i = 0; i < I; i++) { - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - // rename the dir at J - char old_name[256]; - sprintf(old_name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)J); - char new_name[256]; - sprintf(new_name, "%s/%smved%04d", - (PARENT == 1 ? "pricklypear" - : PARENT >= 2 ? "quiabentia" - : ""), - (BEFORE ? "0" : ""), - (int)J); - lfsr_rename(&lfs, old_name, new_name) => 0; - - // rename the dir at K - sprintf(old_name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), (int)K); - sprintf(new_name, "%s/%smved%04d", - (PARENT == 1 ? "pricklypear" - : PARENT >= 2 ? "quiabentia" - : ""), - (BEFORE ? "0" : ""), - (int)K); - lfsr_rename(&lfs, old_name, new_name) => 0; - - // seek after remove? this tests that the internal position is - // updated correctly - if (SEEK) { - lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); - assert(off >= 0); - if (SEEK >= 2) { - lfsr_dir_rewind(&lfs, &dir) => 0; - } - lfsr_dir_seek(&lfs, &dir, off) => 0; - } - - // we should be able to keep reading - for (lfs_size_t i = I; i < N; i++) { - if (i == J || i == K) { - continue; - } - - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - int err = lfsr_dir_read(&lfs, &dir, &info); - assert(err == LFS_ERR_NOENT || (!BEFORE && PARENT < 2)); - lfsr_dir_close(&lfs, &dir) => 0; - - lfsr_unmount(&lfs) => 0; -''' - -# test removing the directory we are iterating over -[cases.test_dirs_read_rm] -defines.N = 5 -# where in the dir read do we remove? -defines.I = 'range(6)' -# bit 0x2 = left neighbor -# bit 0x1 = right neighbor -defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3] -# 0 => don't seek -# 1 => seek -# 2 => rewind then seek -defines.SEEK = [0, 1, 2] -code = ''' - lfs_t lfs; - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - - lfsr_mkdir(&lfs, "pricklypear") => 0; - - if (NEIGHBORS & 0x2) { - assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000); - lfsr_mkdir(&lfs, "a_IplRNrPH") => 0; - lfsr_mkdir(&lfs, "a_IplRNrPH/a_child") => 0; - } - - if (NEIGHBORS & 0x1) { - assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff); - lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0; - lfsr_mkdir(&lfs, "f_VtoMnwRH/f_child") => 0; - } - - // create our directories - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "pricklypear/dir%04d", i+1); - lfsr_mkdir(&lfs, name) => 0; - } - - // start reading - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, "pricklypear") => 0; - struct lfs_info info; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - - // read until I - for (lfs_size_t i = 0; i < I; i++) { - char name[256]; - sprintf(name, "dir%04d", i+1); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - // remove the directory - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "pricklypear/dir%04d", i+1); - lfsr_remove(&lfs, name) => 0; - } - lfsr_remove(&lfs, "pricklypear") => 0; - - // seek after mkdir? - if (SEEK) { - lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); - assert(off >= 0); - if (SEEK >= 2) { - lfsr_dir_rewind(&lfs, &dir) => 0; - } - lfsr_dir_seek(&lfs, &dir, off) => 0; - } - - // try to read, but this should return an error - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_close(&lfs, &dir) => 0; - - lfsr_unmount(&lfs) => 0; -''' - - - -## Recursive tests - -# Recursive here just refers to removing entries in a directory while -# iterating over the directory -# -# This is a useful feature, but it's unintuitive if this should have -# well-defined behavior, so make sure to test for it -[cases.test_dirs_recursive_rm] -defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] -defines.PARENT = [false, true] -# 0 => don't seek -# 1 => seek -# 2 => rewind then seek -defines.SEEK = [0, 1, 2] -# limit powerloss testing due to time -if = '!TEST_PL || N <= 32' -reentrant = true -code = ''' - // format once per test - lfs_t lfs; - int err = lfsr_mount(&lfs, CFG); - if (err) { - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - } - - if (PARENT) { - err = lfsr_mkdir(&lfs, "pricklypear"); - assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); - } - - // make this many directories - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); - err = lfsr_mkdir(&lfs, name); - assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); - } - - // check that our mkdir worked - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); - struct lfs_info info; - lfsr_stat(&lfs, name, &info) => 0; - char name2[256]; - sprintf(name2, "dir%04d", i); - assert(strcmp(info.name, name2) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - struct lfs_info info; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_close(&lfs, &dir) => 0; - - // now remove directories recursively - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - - char path[1024]; - sprintf(path, "%s/%s", (PARENT ? "pricklypear" : ""), info.name); - lfsr_remove(&lfs, path) => 0; - - // seek between removes? this tests that the internal position is - // updated correctly - if (SEEK) { - lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); - assert(off >= 0); - if (SEEK >= 2) { - lfsr_dir_rewind(&lfs, &dir) => 0; - } - lfsr_dir_seek(&lfs, &dir, off) => 0; - } - } - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_close(&lfs, &dir) => 0; - - // check that our removes worked - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); - struct lfs_info info; - lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT; - } - - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_close(&lfs, &dir) => 0; - - lfsr_unmount(&lfs) => 0; -''' - -# Recursive here just refers to renaming entries in a directory while -# iterating over the directory -# -# This is a useful feature, but it's unintuitive if this should have -# well-defined behavior, so make sure to test for it -[cases.test_dirs_recursive_mv] -defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512] -defines.BEFORE = [false, true] -# 0 => no -# 1 => yes -# 2 => yes, and rename to new parent -defines.PARENT = [0, 1, 2] -# 0 => don't seek -# 1 => seek -# 2 => rewind then seek -defines.SEEK = [0, 1, 2] -# limit powerloss testing due to time -if = '!TEST_PL || N <= 32' -reentrant = true -code = ''' - // format once per test - lfs_t lfs; - int err = lfsr_mount(&lfs, CFG); - if (err) { - lfsr_format(&lfs, CFG) => 0; - lfsr_mount(&lfs, CFG) => 0; - } - - if (PARENT) { - err = lfsr_mkdir(&lfs, "pricklypear"); - assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); - if (PARENT >= 2) { - err = lfsr_mkdir(&lfs, "quiabentia"); - assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); - } - } - - // check if we have already started renaming, in case of powerloss - struct lfs_info info; - err = lfsr_stat(&lfs, - (PARENT == 1 ? (BEFORE - ? "pricklypear/0mved0000" - : "pricklypear/mved0000") - : PARENT >= 2 ? (BEFORE - ? "quiabentia/0mved0000" - : "quiabentia/mved0000") - : (BEFORE - ? "/0mved0000" - : "/mved0000")), &info); - if (err == LFS_ERR_NOENT) { - // make this many directories - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); - err = lfsr_mkdir(&lfs, name); - assert(!err || (TEST_PL && err == LFS_ERR_EXIST)); - } - - // check that our mkdir worked - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); - struct lfs_info info; - lfsr_stat(&lfs, name, &info) => 0; - char name2[256]; - sprintf(name2, "dir%04d", i); - assert(strcmp(info.name, name2) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - struct lfs_info info; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "dir%04d", i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_close(&lfs, &dir) => 0; - } - - // now rename directories recursively - lfsr_dir_t dir; - lfsr_dir_open(&lfs, &dir, (PARENT ? "pricklypear" : "/")) => 0; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - for (lfs_size_t i = 0;; i++) { - int err = lfsr_dir_read(&lfs, &dir, &info); - assert(!err || err == LFS_ERR_NOENT); - // reached the end? - if (err == LFS_ERR_NOENT) { - break; - } - // skip already moved? - if (memcmp(info.name, "dir", strlen("dir")) != 0) { - continue; - } - assert(i < 2*N); - assert(info.type == LFS_TYPE_DIR); - - char old_path[1024]; - sprintf(old_path, "%s/%s", (PARENT ? "pricklypear" : ""), info.name); - char new_path[1024]; - sprintf(new_path, "%s/%smved%s", - (PARENT == 1 ? "pricklypear" - : PARENT >= 2 ? "quiabentia" - : ""), - (BEFORE ? "0" : ""), - &info.name[strlen("dir")]); - err = lfsr_rename(&lfs, old_path, new_path); - assert(!err || (TEST_PL && err == LFS_ERR_NOENT)); - - // seek between renames? this tests that the internal position is - // updated correctly - if (SEEK) { - lfs_ssize_t off = lfsr_dir_tell(&lfs, &dir); - assert(off >= 0); - if (SEEK >= 2) { - lfsr_dir_rewind(&lfs, &dir) => 0; - } - lfsr_dir_seek(&lfs, &dir, off) => 0; - } - } - lfsr_dir_close(&lfs, &dir) => 0; - - // check that our renames worked - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), i); - struct lfs_info info; - lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT; - - sprintf(name, "%s/%smved%04d", - (PARENT == 1 ? "pricklypear" - : PARENT >= 2 ? "quiabentia" - : ""), - (BEFORE ? "0" : ""), - i); - lfsr_stat(&lfs, name, &info) => 0; - char name2[256]; - sprintf(name2, "%smved%04d", (BEFORE ? "0" : ""), i); - assert(strcmp(info.name, name2) == 0); - assert(info.type == LFS_TYPE_DIR); - } - - lfsr_dir_open(&lfs, &dir, - (PARENT == 1 ? "pricklypear" - : PARENT >= 2 ? "quiabentia" - : "/")) => 0; - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, ".") == 0); - assert(info.type == LFS_TYPE_DIR); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, "..") == 0); - assert(info.type == LFS_TYPE_DIR); - for (lfs_size_t i = 0; i < N; i++) { - char name[256]; - sprintf(name, "%smved%04d", (BEFORE ? "0" : ""), i); - lfsr_dir_read(&lfs, &dir, &info) => 0; - assert(strcmp(info.name, name) == 0); - assert(info.type == LFS_TYPE_DIR); - } - lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT; - lfsr_dir_close(&lfs, &dir) => 0; - - lfsr_unmount(&lfs) => 0; -''' - - - - - #[cases.test_dirs_root] #code = '''