Files
littlefs/tests/test_dseek.toml
T
Christopher Haster da4e86abac 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.
2023-08-04 14:17:42 -05:00

1340 lines
40 KiB
TOML

# 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;
'''