Added explicit test over directory ordering
It turned out the previous version had a subtle ordering bug when names where the same length that went unnoticed for years. And at this point is probably baked into the on-disk format permanently. This redesign, with a named-ordered btree, relies quite a bit more on name ordering, so it's unlikely the same mistake would make it through without breaking something. And sure enough this bug was unintentionally fixed at some point. But still, better safe than sorry. Added tests over character ordering and length ordering. Open to more ordering tests in the future. Found by andriyndev
This commit is contained in:
@@ -1396,6 +1396,230 @@ code = '''
|
||||
'''
|
||||
|
||||
|
||||
# test some common ordering mistakes
|
||||
[cases.test_dirs_ordering]
|
||||
# ORDER=0 => inorder
|
||||
# ORDER=1 => reversed
|
||||
# ORDER=2 => random
|
||||
defines.ORDER = [0, 1, 2]
|
||||
defines.REMOUNT = [false, true]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, CFG) => 0;
|
||||
lfsr_mount(&lfs, CFG) => 0;
|
||||
|
||||
if (ORDER == 0) {
|
||||
lfsr_mkdir(&lfs, "a") => 0;
|
||||
lfsr_mkdir(&lfs, "b") => 0;
|
||||
lfsr_mkdir(&lfs, "c") => 0;
|
||||
lfsr_mkdir(&lfs, "d") => 0;
|
||||
lfsr_mkdir(&lfs, "e") => 0;
|
||||
lfsr_mkdir(&lfs, "f") => 0;
|
||||
} else if (ORDER == 1) {
|
||||
lfsr_mkdir(&lfs, "f") => 0;
|
||||
lfsr_mkdir(&lfs, "e") => 0;
|
||||
lfsr_mkdir(&lfs, "d") => 0;
|
||||
lfsr_mkdir(&lfs, "c") => 0;
|
||||
lfsr_mkdir(&lfs, "b") => 0;
|
||||
lfsr_mkdir(&lfs, "a") => 0;
|
||||
} else if (ORDER == 2) {
|
||||
// "random", trust me
|
||||
lfsr_mkdir(&lfs, "e") => 0;
|
||||
lfsr_mkdir(&lfs, "c") => 0;
|
||||
lfsr_mkdir(&lfs, "b") => 0;
|
||||
lfsr_mkdir(&lfs, "d") => 0;
|
||||
lfsr_mkdir(&lfs, "f") => 0;
|
||||
lfsr_mkdir(&lfs, "a") => 0;
|
||||
}
|
||||
|
||||
// remount?
|
||||
if (REMOUNT) {
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
lfsr_mount(&lfs, CFG) => 0;
|
||||
// grm should be zero here
|
||||
assert(lfs.grm_g[0] == 0);
|
||||
}
|
||||
|
||||
// check that our mkdirs worked
|
||||
struct lfs_info info;
|
||||
lfsr_stat(&lfs, "a", &info) => 0;
|
||||
assert(strcmp(info.name, "a") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_stat(&lfs, "b", &info) => 0;
|
||||
assert(strcmp(info.name, "b") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_stat(&lfs, "c", &info) => 0;
|
||||
assert(strcmp(info.name, "c") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_stat(&lfs, "d", &info) => 0;
|
||||
assert(strcmp(info.name, "d") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_stat(&lfs, "e", &info) => 0;
|
||||
assert(strcmp(info.name, "e") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_stat(&lfs, "f", &info) => 0;
|
||||
assert(strcmp(info.name, "f") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
|
||||
// check the directory order
|
||||
lfsr_dir_t dir;
|
||||
lfsr_dir_open(&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, "a") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, "b") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, "c") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, "d") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, "e") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, "f") == 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_dirs_ordering_length]
|
||||
# ORDER=0 => inorder
|
||||
# ORDER=1 => reversed
|
||||
# ORDER=2 => random
|
||||
defines.ORDER = [0, 1, 2]
|
||||
defines.REMOUNT = [false, true]
|
||||
code = '''
|
||||
lfs_t lfs;
|
||||
lfsr_format(&lfs, CFG) => 0;
|
||||
lfsr_mount(&lfs, CFG) => 0;
|
||||
|
||||
if (ORDER == 0) {
|
||||
lfsr_mkdir(&lfs, "a") => 0;
|
||||
lfsr_mkdir(&lfs, "aa") => 0;
|
||||
lfsr_mkdir(&lfs, "aaa") => 0;
|
||||
lfsr_mkdir(&lfs, "aaaa") => 0;
|
||||
lfsr_mkdir(&lfs, "aaaaa") => 0;
|
||||
lfsr_mkdir(&lfs, "aaaaaa") => 0;
|
||||
} else if (ORDER == 1) {
|
||||
lfsr_mkdir(&lfs, "aaaaaa") => 0;
|
||||
lfsr_mkdir(&lfs, "aaaaa") => 0;
|
||||
lfsr_mkdir(&lfs, "aaaa") => 0;
|
||||
lfsr_mkdir(&lfs, "aaa") => 0;
|
||||
lfsr_mkdir(&lfs, "aa") => 0;
|
||||
lfsr_mkdir(&lfs, "a") => 0;
|
||||
} else if (ORDER == 2) {
|
||||
// "random", trust me
|
||||
lfsr_mkdir(&lfs, "aaaaa") => 0;
|
||||
lfsr_mkdir(&lfs, "aaa") => 0;
|
||||
lfsr_mkdir(&lfs, "aa") => 0;
|
||||
lfsr_mkdir(&lfs, "aaaa") => 0;
|
||||
lfsr_mkdir(&lfs, "aaaaaa") => 0;
|
||||
lfsr_mkdir(&lfs, "a") => 0;
|
||||
}
|
||||
|
||||
// remount?
|
||||
if (REMOUNT) {
|
||||
lfsr_unmount(&lfs) => 0;
|
||||
lfsr_mount(&lfs, CFG) => 0;
|
||||
// grm should be zero here
|
||||
assert(lfs.grm_g[0] == 0);
|
||||
}
|
||||
|
||||
// check that our mkdirs worked
|
||||
struct lfs_info info;
|
||||
lfsr_stat(&lfs, "a", &info) => 0;
|
||||
assert(strcmp(info.name, "a") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_stat(&lfs, "aa", &info) => 0;
|
||||
assert(strcmp(info.name, "aa") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_stat(&lfs, "aaa", &info) => 0;
|
||||
assert(strcmp(info.name, "aaa") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_stat(&lfs, "aaaa", &info) => 0;
|
||||
assert(strcmp(info.name, "aaaa") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_stat(&lfs, "aaaaa", &info) => 0;
|
||||
assert(strcmp(info.name, "aaaaa") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_stat(&lfs, "aaaaaa", &info) => 0;
|
||||
assert(strcmp(info.name, "aaaaaa") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
|
||||
// check the directory order
|
||||
lfsr_dir_t dir;
|
||||
lfsr_dir_open(&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, "a") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, "aa") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, "aaa") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, "aaaa") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, "aaaaa") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
assert(info.size == 0);
|
||||
lfsr_dir_read(&lfs, &dir, &info) => 0;
|
||||
assert(strcmp(info.name, "aaaaaa") == 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 that did collisions don't cause issues
|
||||
[cases.test_dirs_did_collisions]
|
||||
defines.REMOUNT = [false, true]
|
||||
|
||||
Reference in New Issue
Block a user