bd4a5e5ab3
The main idea here is that diverse tests are better than many similar tests. Sure, if we throw fuzz tests at the system all day we'll eventually find more bugs, but if a developer is in the loop that time is going to be better spent writing specific tests targeting the fragile parts of the system. And don't worry, we can still throw fuzz tests at the system all day by specifying explicit seeds with -DSEED=blah. Changes: - Limited dir-related powerloss fuzz testing to N <= 16. These tests were the biggest culprit of excessive test runtime, requiring O(n^2) redundant operations to recover from powerlosses (they just replay the full sequence on powerloss). - As a tradeoff, bumped most fuzz tests to a minimum of 20 seeds. The big exception being the test_fwrite tests, which are heavily parameterized and already take the most time to run. Each parameter combination also multiplies the effective number of seeds, so increasing the number of base seeds will probably have diminishing returns. - Limited test_fwrite_reversed to SIZE <= 4*1024*CHUNK. Writing a file backwards is just about the worst way you could write a file, since all buffering/coalescing expect writes to eventually make forward progress. On the flip side, because it's uncommon, writing a file backwards is also a great way to find bugs. But at some point a compromise needs to be made. Impacted test runtimes: case otime ntime dtime test_btree_push_fuzz 0.3 0.5 +0.2 (+60.2%) test_btree_push_sparse_fuzz 0.4 3.3 +2.9 (+720.4%) test_btree_update_fuzz 0.4 0.9 +0.6 (+141.6%) test_btree_update_sparse_fuzz 0.5 4.5 +4.1 (+857.4%) test_btree_pop_fuzz 0.6 2.3 +1.7 (+314.7%) test_btree_pop_sparse_fuzz 1.2 5.7 +4.4 (+356.2%) test_btree_split_fuzz 0.5 1.4 +0.8 (+150.2%) test_btree_split_sparse_fuzz 0.4 5.6 +5.1 (+1163.2%) test_btree_find_fuzz 0.5 0.7 +0.2 (+50.7%) test_btree_find_sparse_fuzz 1.0 3.0 +2.0 (+189.8%) test_btree_traversal_fuzz 0.6 2.3 +1.6 (+260.4%) test_dirs_mkdir_many 3.3 2.1 -1.3 (-37.8%) test_dirs_mkdir_many_backwards 3.5 2.1 -1.4 (-39.9%) test_dirs_mkdir_fuzz 115.3 106.4 -8.9 (-7.7%) test_dirs_rm_many 283.9 76.8 -207.0 (-72.9%) test_dirs_rm_many_backwards 216.1 80.6 -135.5 (-62.7%) test_dirs_rm_fuzz 647.0 68.5 -578.5 (-89.4%) test_dirs_mv_many 14.2 15.4 +1.1 (+7.9%) test_dirs_mv_many_backwards 16.5 14.5 -2.1 (-12.5%) test_dirs_mv_fuzz 1932.5 156.7 -1775.8 (-91.9%) test_dirs_general_fuzz 561.9 74.5 -487.4 (-86.7%) test_dread_recursive_rm 336.6 46.2 -290.4 (-86.3%) test_dread_recursive_mv 55.5 44.6 -11.0 (-19.8%) test_fsync_rrrr_fuzz 0.4 0.3 -0.1 (-18.4%) test_fsync_wrrr_fuzz 8.0 12.4 +4.5 (+56.0%) test_fsync_wwww_fuzz 13.2 33.4 +20.2 (+152.6%) test_fsync_wwrr_fuzz 5.4 50.9 +45.5 (+841.6%) test_fsync_rwrw_fuzz 2.4 8.4 +6.0 (+253.9%) test_fsync_rwrw_sparse_fuzz 3.2 7.5 +4.2 (+129.9%) test_fsync_rwtfrwtf_sparse_fuzz 6.1 8.5 +2.4 (+39.3%) test_fsync_drrr_fuzz 11.8 9.2 -2.6 (-21.8%) test_fsync_wddd_fuzz 9.3 11.9 +2.6 (+28.0%) test_fsync_rwdrwd_fuzz 1.6 33.1 +31.5 (+1963.4%) test_fsync_rwdrwd_sparse_fuzz 0.3 1.8 +1.4 (+418.8%) test_fsync_rwtfdrwtfd_sparse_fuzz 0.3 1.1 +0.8 (+260.2%) test_fwrite_reversed 728.5 345.2 -383.3 (-52.6%) TOTAL 7587.5 3792.3 -3795.2 (-50.0%)
1809 lines
54 KiB
TOML
1809 lines
54 KiB
TOML
# Test the annoying subtle corner cases of directory seeking+reading
|
|
#
|
|
# Note there may be some overlap with test_dirs, since some dir operations
|
|
# are needed to validate the directory tree works
|
|
after = 'test_dirs'
|
|
|
|
|
|
# test some dir functions
|
|
|
|
[cases.test_dread_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%03x", ((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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_tell(&lfs, &dir) => 1;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
lfsr_dir_tell(&lfs, &dir) => 2 + i;
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
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_dread_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%03x", ((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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_tell(&lfs, &dir) => 1;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
lfsr_dir_tell(&lfs, &dir) => 2 + i;
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_tell(&lfs, &dir) => 1;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
lfsr_dir_tell(&lfs, &dir) => 2 + i;
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
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_dread_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%03x", ((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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_tell(&lfs, &dir) => 1;
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
lfsr_dir_tell(&lfs, &dir) => 2 + i;
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
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);
|
|
assert(info.size == 0);
|
|
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);
|
|
assert(info.size == 0);
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
lfsr_dir_seek(&lfs, &dir, 2 + i) => 0;
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
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_dread_read_idempotent]
|
|
defines.PARENT = [false, true]
|
|
# NEIGHBORS&0x2 = left neighbor
|
|
# NEIGHBORS&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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "ardvark") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "ardvark") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# test neighbor changes don't mess with an unrelated dir read
|
|
[cases.test_dread_read_neighbor_mkdirs]
|
|
defines.N = 5
|
|
# where in the dir read do we mkdir?
|
|
defines.I = 'range(6)'
|
|
defines.PARENT = true
|
|
# NEIGHBORS&0x2 = left neighbor
|
|
# NEIGHBORS&0x1 = right neighbor
|
|
defines.NEIGHBORS = [0x1, 0x2, 0x3]
|
|
# more neighbors ensures mdir splits which can be its own source
|
|
# of problems
|
|
defines.NEIGHBOR_N = [1, 10, 100]
|
|
# SEEK=0 => don't seek
|
|
# SEEK=1 => seek
|
|
# SEEK=2 => rewind then seek
|
|
# SEEK=3 => seek with offset before mutation
|
|
# SEEK=4 => rewind then seek with offset before mutation
|
|
defines.SEEK = [0, 1, 2, 3, 4]
|
|
# 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;
|
|
}
|
|
|
|
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%03x", ((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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
|
|
// read until I
|
|
for (lfs_size_t i = 0; i < I; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
// since modification is unrelated, the dir position should go unchanged
|
|
lfs_soff_t off = lfsr_dir_tell(&lfs, &dir);
|
|
assert(off == I+2);
|
|
|
|
// make unrelated dirs
|
|
if (NEIGHBORS & 0x2) {
|
|
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
|
char name[256];
|
|
sprintf(name, "a_IplRNrPH/a_%03x", i);
|
|
lfsr_mkdir(&lfs, name) => 0;
|
|
}
|
|
}
|
|
|
|
if (NEIGHBORS & 0x1) {
|
|
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
|
char name[256];
|
|
sprintf(name, "f_VtoMnwRH/f_%03x", i);
|
|
lfsr_mkdir(&lfs, name) => 0;
|
|
}
|
|
}
|
|
|
|
// seek after mkdir?
|
|
if (SEEK) {
|
|
// note dir pos after reaching end of dir can be anything
|
|
lfs_soff_t off_ = lfsr_dir_tell(&lfs, &dir);
|
|
assert(off_ >= 0);
|
|
if (I < N) {
|
|
assert(off_ == off);
|
|
}
|
|
|
|
if (SEEK == 2 || SEEK == 4) {
|
|
lfsr_dir_rewind(&lfs, &dir) => 0;
|
|
}
|
|
|
|
if (SEEK == 3 || SEEK == 4) {
|
|
lfsr_dir_seek(&lfs, &dir, off) => 0;
|
|
} else {
|
|
lfsr_dir_seek(&lfs, &dir, off_) => 0;
|
|
}
|
|
}
|
|
|
|
// we should be able to keep reading where we left off
|
|
for (lfs_size_t i = I; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_dread_read_neighbor_rms]
|
|
defines.N = 5
|
|
# where in the dir read do we mkdir?
|
|
defines.I = 'range(6)'
|
|
defines.PARENT = true
|
|
# NEIGHBORS&0x2 = left neighbor
|
|
# NEIGHBORS&0x1 = right neighbor
|
|
defines.NEIGHBORS = [0x1, 0x2, 0x3]
|
|
# more neighbors ensures mdir splits which can be its own source
|
|
# of problems
|
|
defines.NEIGHBOR_N = [1, 10, 100]
|
|
# SEEK=0 => don't seek
|
|
# SEEK=1 => seek
|
|
# SEEK=2 => rewind then seek
|
|
# SEEK=3 => seek with offset before mutation
|
|
# SEEK=4 => rewind then seek with offset before mutation
|
|
defines.SEEK = [0, 1, 2, 3, 4]
|
|
# 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;
|
|
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
|
char name[256];
|
|
sprintf(name, "a_IplRNrPH/a_%03x", i);
|
|
lfsr_mkdir(&lfs, name) => 0;
|
|
}
|
|
}
|
|
|
|
if (NEIGHBORS & 0x1) {
|
|
assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff);
|
|
lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0;
|
|
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
|
char name[256];
|
|
sprintf(name, "f_VtoMnwRH/f_%03x", i);
|
|
lfsr_mkdir(&lfs, name) => 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// create our directories
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "%s/dir%03x", ((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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
|
|
// read until I
|
|
for (lfs_size_t i = 0; i < I; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
// since modification is unrelated, the dir position should go unchanged
|
|
lfs_soff_t off = lfsr_dir_tell(&lfs, &dir);
|
|
assert(off == I+2);
|
|
|
|
// remove unrelated dirs
|
|
if (NEIGHBORS & 0x2) {
|
|
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
|
char name[256];
|
|
sprintf(name, "a_IplRNrPH/a_%03x", i);
|
|
lfsr_remove(&lfs, name) => 0;
|
|
}
|
|
}
|
|
|
|
if (NEIGHBORS & 0x1) {
|
|
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
|
char name[256];
|
|
sprintf(name, "f_VtoMnwRH/f_%03x", i);
|
|
lfsr_remove(&lfs, name) => 0;
|
|
}
|
|
}
|
|
|
|
// seek after mkdir?
|
|
if (SEEK) {
|
|
// note dir pos after reaching end of dir can be anything
|
|
lfs_soff_t off_ = lfsr_dir_tell(&lfs, &dir);
|
|
assert(off_ >= 0);
|
|
if (I < N) {
|
|
assert(off_ == off);
|
|
}
|
|
|
|
if (SEEK == 2 || SEEK == 4) {
|
|
lfsr_dir_rewind(&lfs, &dir) => 0;
|
|
}
|
|
|
|
if (SEEK == 3 || SEEK == 4) {
|
|
lfsr_dir_seek(&lfs, &dir, off) => 0;
|
|
} else {
|
|
lfsr_dir_seek(&lfs, &dir, off_) => 0;
|
|
}
|
|
}
|
|
|
|
// we should be able to keep reading where we left off
|
|
for (lfs_size_t i = I; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_dread_read_neighbor_mvs]
|
|
defines.N = 5
|
|
# where in the dir read do we mkdir?
|
|
defines.I = 'range(6)'
|
|
defines.PARENT = true
|
|
# NEIGHBORS&0x2 = left neighbor
|
|
# NEIGHBORS&0x1 = right neighbor
|
|
defines.NEIGHBORS = [0x1, 0x2, 0x3]
|
|
# more neighbors ensures mdir splits which can be its own source
|
|
# of problems
|
|
defines.NEIGHBOR_N = [1, 10, 100]
|
|
# SEEK=0 => don't seek
|
|
# SEEK=1 => seek
|
|
# SEEK=2 => rewind then seek
|
|
# SEEK=3 => seek with offset before mutation
|
|
# SEEK=4 => rewind then seek with offset before mutation
|
|
defines.SEEK = [0, 1, 2, 3, 4]
|
|
# 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;
|
|
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
|
char name[256];
|
|
sprintf(name, "a_IplRNrPH/a_%03x", i);
|
|
lfsr_mkdir(&lfs, name) => 0;
|
|
}
|
|
}
|
|
|
|
if (NEIGHBORS & 0x1) {
|
|
assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff);
|
|
lfsr_mkdir(&lfs, "f_VtoMnwRH") => 0;
|
|
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
|
char name[256];
|
|
sprintf(name, "f_VtoMnwRH/f_%03x", i);
|
|
lfsr_mkdir(&lfs, name) => 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// create our directories
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "%s/dir%03x", ((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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
|
|
// read until I
|
|
for (lfs_size_t i = 0; i < I; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
// since modification is unrelated, the dir position should go unchanged
|
|
lfs_soff_t off = lfsr_dir_tell(&lfs, &dir);
|
|
assert(off == I+2);
|
|
|
|
// rename unrelated dirs
|
|
if (NEIGHBORS & 0x2) {
|
|
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
|
char name[256];
|
|
sprintf(name, "a_IplRNrPH/a_%03x", i);
|
|
char name_[256];
|
|
sprintf(name_, "a_IplRNrPH/b_%03x", i);
|
|
lfsr_rename(&lfs, name, name_) => 0;
|
|
}
|
|
}
|
|
|
|
if (NEIGHBORS & 0x1) {
|
|
for (lfs_size_t i = 0; i < NEIGHBOR_N; i++) {
|
|
char name[256];
|
|
sprintf(name, "f_VtoMnwRH/f_%03x", i);
|
|
char name_[256];
|
|
sprintf(name_, "f_VtoMnwRH/b_%03x", i);
|
|
lfsr_rename(&lfs, name, name_) => 0;
|
|
}
|
|
}
|
|
|
|
// seek after mkdir?
|
|
if (SEEK) {
|
|
// note dir pos after reaching end of dir can be anything
|
|
lfs_soff_t off_ = lfsr_dir_tell(&lfs, &dir);
|
|
assert(off_ >= 0);
|
|
if (I < N) {
|
|
assert(off_ == off);
|
|
}
|
|
|
|
if (SEEK == 2 || SEEK == 4) {
|
|
lfsr_dir_rewind(&lfs, &dir) => 0;
|
|
}
|
|
|
|
if (SEEK == 3 || SEEK == 4) {
|
|
lfsr_dir_seek(&lfs, &dir, off) => 0;
|
|
} else {
|
|
lfsr_dir_seek(&lfs, &dir, off_) => 0;
|
|
}
|
|
}
|
|
|
|
// we should be able to keep reading where we left off
|
|
for (lfs_size_t i = I; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
# test dir read has somewhat reasonable behaviour when the dir is modified
|
|
[cases.test_dread_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]
|
|
# NEIGHBORS&0x2 = left neighbor
|
|
# NEIGHBORS&0x1 = right neighbor
|
|
defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3]
|
|
# SEEK=0 => don't seek
|
|
# SEEK=1 => seek
|
|
# 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%03x", ((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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
|
|
// read until I
|
|
for (lfs_size_t i = 0; i < I; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i+1);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
// make a dir at J
|
|
char name[256];
|
|
sprintf(name, "%s/dir%03x_", ((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%03x%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);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_dread_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]
|
|
# NEIGHBORS&0x2 = left neighbor
|
|
# NEIGHBORS&0x1 = right neighbor
|
|
defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3]
|
|
# SEEK=0 => don't seek
|
|
# SEEK=1 => seek
|
|
# 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%03x", ((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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
|
|
// read until I
|
|
for (lfs_size_t i = 0; i < I; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
// remove the dir at J
|
|
char name[256];
|
|
sprintf(name, "%s/dir%03x", ((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%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_dread_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]
|
|
# PARENT=0 => no
|
|
# PARENT=1 => yes
|
|
# PARENT=2 => yes, and rename to new parent
|
|
defines.PARENT = [0, 1, 2]
|
|
# NEIGHBORS&0x2 = left neighbor
|
|
# NEIGHBORS&0x1 = right neighbor
|
|
defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3]
|
|
# SEEK=0 => don't seek
|
|
# SEEK=1 => seek
|
|
# 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%03x", ((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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
|
|
// read until I
|
|
for (lfs_size_t i = 0; i < I; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
// rename the dir at J
|
|
char old_name[256];
|
|
sprintf(old_name, "%s/dir%03x", ((PARENT) ? "pricklypear" : ""), (int)J);
|
|
char new_name[256];
|
|
sprintf(new_name, "%s/%smved%03x",
|
|
((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%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
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_dread_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]
|
|
# NEIGHBORS&0x2 = left neighbor
|
|
# NEIGHBORS&0x1 = right neighbor
|
|
defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3]
|
|
# SEEK=0 => don't seek
|
|
# SEEK=1 => seek
|
|
# 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%03x", ((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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
|
|
// read until I
|
|
for (lfs_size_t i = 0; i < I; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i+1);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
// make a dir at J
|
|
char name[256];
|
|
sprintf(name, "%s/dir%03x_", ((PARENT) ? "pricklypear" : ""), (int)J);
|
|
lfsr_mkdir(&lfs, name) => 0;
|
|
|
|
// make a dir at K
|
|
sprintf(name, "%s/dir%03x_", ((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%03x%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);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_dread_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]
|
|
# NEIGHBORS&0x2 = left neighbor
|
|
# NEIGHBORS&0x1 = right neighbor
|
|
defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3]
|
|
# SEEK=0 => don't seek
|
|
# SEEK=1 => seek
|
|
# 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%03x", ((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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
|
|
// read until I
|
|
for (lfs_size_t i = 0; i < I; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
// remove the dir at J
|
|
char name[256];
|
|
sprintf(name, "%s/dir%03x", ((PARENT) ? "pricklypear" : ""), (int)J);
|
|
lfsr_remove(&lfs, name) => 0;
|
|
|
|
// remove the dir at K
|
|
sprintf(name, "%s/dir%03x", ((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%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|
|
[cases.test_dread_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]
|
|
# PARENT=0 => no
|
|
# PARENT=1 => yes
|
|
# PARENT=2 => yes, and rename to new parent
|
|
defines.PARENT = [0, 1, 2]
|
|
# NEIGHBORS&0x2 = left neighbor
|
|
# NEIGHBORS&0x1 = right neighbor
|
|
defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3]
|
|
# SEEK=0 => don't seek
|
|
# SEEK=1 => seek
|
|
# 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%03x", ((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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
|
|
// read until I
|
|
for (lfs_size_t i = 0; i < I; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
// rename the dir at J
|
|
char old_name[256];
|
|
sprintf(old_name, "%s/dir%03x", ((PARENT) ? "pricklypear" : ""), (int)J);
|
|
char new_name[256];
|
|
sprintf(new_name, "%s/%smved%03x",
|
|
((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%03x", ((PARENT) ? "pricklypear" : ""), (int)K);
|
|
sprintf(new_name, "%s/%smved%03x",
|
|
((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%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
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_dread_read_rm]
|
|
defines.N = 5
|
|
# where in the dir read do we remove?
|
|
defines.I = 'range(6)'
|
|
# NEIGHBORS&0x2 = left neighbor
|
|
# NEIGHBORS&0x1 = right neighbor
|
|
defines.NEIGHBORS = [0x0, 0x1, 0x2, 0x3]
|
|
# SEEK=0 => don't seek
|
|
# SEEK=1 => seek
|
|
# 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%03x", 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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
|
|
// read until I
|
|
for (lfs_size_t i = 0; i < I; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i+1);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
// remove the directory
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "pricklypear/dir%03x", 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_dread_recursive_rm]
|
|
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
|
|
defines.PARENT = [false, true]
|
|
# SEEK=0 => don't seek
|
|
# SEEK=1 => seek
|
|
# SEEK=2 => rewind then seek
|
|
defines.SEEK = [0, 1, 2]
|
|
# limit powerloss testing due to time
|
|
if = '!TEST_PLS || N <= 16'
|
|
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_PLS && err == LFS_ERR_EXIST));
|
|
}
|
|
|
|
// make this many directories
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "%s/dir%03x", ((PARENT) ? "pricklypear" : ""), i);
|
|
err = lfsr_mkdir(&lfs, name);
|
|
assert(!err || (TEST_PLS && 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%03x", ((PARENT) ? "pricklypear" : ""), i);
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, name, &info) => 0;
|
|
char name2[256];
|
|
sprintf(name2, "dir%03x", i);
|
|
assert(strcmp(info.name, name2) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
|
|
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%03x", ((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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
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_dread_recursive_mv]
|
|
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
|
|
defines.BEFORE = [false, true]
|
|
# PARENT=0 => no
|
|
# PARENT=1 => yes
|
|
# PARENT=2 => yes, and rename to new parent
|
|
defines.PARENT = [0, 1, 2]
|
|
# SEEK=0 => don't seek
|
|
# SEEK=1 => seek
|
|
# SEEK=2 => rewind then seek
|
|
defines.SEEK = [0, 1, 2]
|
|
# limit powerloss testing due to time
|
|
if = '!TEST_PLS || N <= 16'
|
|
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_PLS && err == LFS_ERR_EXIST));
|
|
if (PARENT >= 2) {
|
|
err = lfsr_mkdir(&lfs, "quiabentia");
|
|
assert(!err || (TEST_PLS && 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/0mved000"
|
|
: "pricklypear/mved000")
|
|
: (PARENT >= 2) ? ((BEFORE)
|
|
? "quiabentia/0mved000"
|
|
: "quiabentia/mved000")
|
|
: ((BEFORE)
|
|
? "/0mved000"
|
|
: "/mved000")), &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%03x", ((PARENT) ? "pricklypear" : ""), i);
|
|
err = lfsr_mkdir(&lfs, name);
|
|
assert(!err || (TEST_PLS && 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%03x", ((PARENT) ? "pricklypear" : ""), i);
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, name, &info) => 0;
|
|
char name2[256];
|
|
sprintf(name2, "dir%03x", i);
|
|
assert(strcmp(info.name, name2) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "dir%03x", i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
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);
|
|
assert(info.size == 0);
|
|
|
|
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_PLS && 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%03x", ((PARENT) ? "pricklypear" : ""), i);
|
|
struct lfs_info info;
|
|
lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT;
|
|
|
|
sprintf(name, "%s/%smved%03x",
|
|
((PARENT == 1) ? "pricklypear"
|
|
: (PARENT >= 2) ? "quiabentia"
|
|
: ""),
|
|
((BEFORE) ? "0" : ""),
|
|
i);
|
|
lfsr_stat(&lfs, name, &info) => 0;
|
|
char name2[256];
|
|
sprintf(name2, "%smved%03x", ((BEFORE) ? "0" : ""), i);
|
|
assert(strcmp(info.name, name2) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
|
|
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);
|
|
assert(info.size == 0);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, "..") == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
for (lfs_size_t i = 0; i < N; i++) {
|
|
char name[256];
|
|
sprintf(name, "%smved%03x", ((BEFORE) ? "0" : ""), i);
|
|
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
|
assert(strcmp(info.name, name) == 0);
|
|
assert(info.type == LFS_TYPE_DIR);
|
|
assert(info.size == 0);
|
|
}
|
|
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
|
|
lfsr_dir_close(&lfs, &dir) => 0;
|
|
|
|
lfsr_unmount(&lfs) => 0;
|
|
'''
|
|
|