Files
littlefs/tests/t5_dirs.toml
T
Christopher Haster b1187595d6 Added support for recursive removes in directories
"Recursion" here just refers to the ability to remove entries in a
directory while iterating over it. This is very useful when you just
want a directory gone, and can be extended to a "true" recursive remove
straightforwardly. This mainly tests that mid/rid updates in opened
mdirs are correct.

To make this work, we need to update opened dirs differently than files,
since opened dirs do not get marked as removed when its rid is removed
and contain an additional position in the dir that needs to be updated.

To keep track of the different types, littlefs now contains 2
linked-lists for opened mdirs. Maybe these should be correctly typed,
but by hiding the specific types behind an array of mdir linked-lists,
we can more efficiently iterate over both lists when necessary.

We should probably compare this approach to the type-tagged approach in
the previous littlefs implementation, but I think the idea of an array
of type-hidden linked-lists just didn't come to me then. There was also
a bit more room in the mdir structs to hide a 1-bit type field. The mdir
structs here are getting pretty squeezed since they are used everywhere.
2023-07-25 12:54:49 -05:00

3972 lines
128 KiB
TOML

# Directory tests
## mkdir tests
[cases.t5_dirs_mkdir]
defines.REMOUNT = [false, true]
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;
}
// make a directory
err = lfsr_mkdir(&lfs, "ardvark");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our mkdir worked with stat
struct lfs_info info;
lfsr_stat(&lfs, "ardvark", &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
// and with dir_read
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);
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 that noent errors work
[cases.t5_dirs_noent]
defines.REMOUNT = [false, true]
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;
}
// make a directory
err = lfsr_mkdir(&lfs, "ardvark");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// try to read a nonsense path
struct lfs_info info;
lfsr_stat(&lfs, "no", &info) => LFS_ERR_NOENT;
lfsr_dir_t dir;
lfsr_dir_open(&lfs, &dir, "no") => LFS_ERR_NOENT;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// and check that this didn't interfere with our original directory
lfsr_stat(&lfs, "ardvark", &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_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);
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 that creating the same directory twice errors
[cases.t5_dirs_mkdir_exists]
defines.REMOUNT = [false, true]
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;
}
// make a directory
err = lfsr_mkdir(&lfs, "ardvark");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// make the same directory, should error
lfsr_mkdir(&lfs, "ardvark") => LFS_ERR_EXIST;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// and check that this didn't interfere with our original directory
struct lfs_info info;
lfsr_stat(&lfs, "ardvark", &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
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);
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 what happens if we try to make root
[cases.t5_dirs_mkdir_root]
defines.REMOUNT = [false, true]
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;
}
// try to make root, which doesn't make sense
lfsr_mkdir(&lfs, "/") => LFS_ERR_EXIST;
// make a directory
err = lfsr_mkdir(&lfs, "ardvark");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// try to make root, which doesn't make sense
lfsr_mkdir(&lfs, "/") => LFS_ERR_EXIST;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// and check that this didn't interfere with our original directory
struct lfs_info info;
lfsr_stat(&lfs, "ardvark", &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
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);
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 that creating a directory with an invalid path errors
[cases.t5_dirs_mkdir_noent]
defines.REMOUNT = [false, true]
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;
}
// make a directory
err = lfsr_mkdir(&lfs, "ardvark");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// make a nonsense directory, should error
lfsr_mkdir(&lfs, "no/hmm") => LFS_ERR_NOENT;
// make a nonsense child directory, should error
lfsr_mkdir(&lfs, "ardvark/no/hmm") => LFS_ERR_NOENT;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// and check that this didn't interfere with our original directory
struct lfs_info info;
lfsr_stat(&lfs, "ardvark", &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
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);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
lfsr_unmount(&lfs) => 0;
'''
[cases.t5_dirs_mkdir_siblings]
defines.REMOUNT = [false, true]
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;
}
// make some directories
err = lfsr_mkdir(&lfs, "ardvark");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "batman");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "cantaloupe");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our mkdir worked
struct lfs_info info;
lfsr_stat(&lfs, "ardvark", &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "batman", &info) => 0;
assert(strcmp(info.name, "batman") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "cantaloupe", &info) => 0;
assert(strcmp(info.name, "cantaloupe") == 0);
assert(info.type == LFS_TYPE_DIR);
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);
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) => 0;
assert(strcmp(info.name, "batman") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "cantaloupe") == 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.t5_dirs_mkdir_children]
defines.REMOUNT = [false, true]
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;
}
// make some directories
err = lfsr_mkdir(&lfs, "ardvark");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "ardvark/batman");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "ardvark/batman/cantaloupe");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our mkdirs worked
struct lfs_info info;
lfsr_stat(&lfs, "ardvark", &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "ardvark/batman", &info) => 0;
assert(strcmp(info.name, "batman") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "ardvark/batman/cantaloupe", &info) => 0;
assert(strcmp(info.name, "cantaloupe") == 0);
assert(info.type == LFS_TYPE_DIR);
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);
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_dir_open(&lfs, &dir, "/ardvark") => 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, "batman") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
lfsr_dir_open(&lfs, &dir, "/ardvark/batman") => 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, "cantaloupe") == 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.t5_dirs_mkdir_many]
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
defines.REMOUNT = [false, true]
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;
}
// make this many directories
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
// check that our mkdir worked
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
}
lfsr_dir_t dir;
lfsr_dir_open(&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_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;
lfsr_unmount(&lfs) => 0;
'''
[cases.t5_dirs_mkdir_many_backwards]
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
defines.REMOUNT = [false, true]
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;
}
// make this many directories
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", (int)(N-1-i));
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
// check that our mkdir worked
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
}
lfsr_dir_t dir;
lfsr_dir_open(&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_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;
lfsr_unmount(&lfs) => 0;
'''
[cases.t5_dirs_mkdir_many_2layers]
defines.N = [1, 2, 4, 8, 16]
defines.REMOUNT = [false, true]
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;
}
// make this many directories
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// containing this many directories
for (lfs_size_t j = 0; j < N; j++) {
sprintf(name, "dir%04d/child%04d", i, j);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
}
// check that our mkdirs worked
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
for (lfs_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "dir%04d/child%04d", i, j);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
sprintf(name, "child%04d", j);
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
}
}
lfsr_dir_t dir;
lfsr_dir_open(&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_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;
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
lfsr_dir_open(&lfs, &dir, name) => 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 j = 0; j < N; j++) {
char name[256];
sprintf(name, "child%04d", 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.t5_dirs_mkdir_many_3layers]
defines.N = [1, 2, 4]
defines.REMOUNT = [false, true]
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;
}
// make this many directories
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// containing this many directories
for (lfs_size_t j = 0; j < N; j++) {
sprintf(name, "dir%04d/child%04d", i, j);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// containing this many directories
for (lfs_size_t k = 0; k < N; k++) {
sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
}
}
// check that our mkdirs worked
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
for (lfs_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "dir%04d/child%04d", i, j);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
sprintf(name, "child%04d", j);
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
for (lfs_size_t k = 0; k < N; k++) {
char name[256];
sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
sprintf(name, "grandchild%04d", k);
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
}
}
}
lfsr_dir_t dir;
lfsr_dir_open(&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_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;
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
lfsr_dir_open(&lfs, &dir, name) => 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 j = 0; j < N; j++) {
char name[256];
sprintf(name, "child%04d", 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;
for (lfs_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "dir%04d/child%04d", i, j);
lfsr_dir_open(&lfs, &dir, name) => 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 k = 0; k < N; k++) {
char name[256];
sprintf(name, "grandchild%04d", k);
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.t5_dirs_mkdir_many_linkedlist]
defines.N = [1, 2, 4, 8, 16, 32, 64]
defines.REMOUNT = [false, true]
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;
}
// create this many directory in a sort of linked-list by nesting
char name[4096];
memset(name, 0, sizeof(name));
for (lfs_size_t i = 0; i < N; i++) {
sprintf(&name[strlen(name)], "/dir%04d", i);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
// check that our mkdir worked
memset(name, 0, sizeof(name));
for (lfs_size_t i = 0; i < N; i++) {
sprintf(&name[strlen(name)], "/dir%04d", 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);
}
memset(name, 0, sizeof(name));
for (lfs_size_t i = 0; i < N; i++) {
sprintf(&name[strlen(name)], "/dir%04d", i);
lfsr_dir_t dir;
lfsr_dir_open(&lfs, &dir, name) => 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);
if (i < N-1) {
char name2[256];
sprintf(name2, "dir%04d", i+1);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, name2) == 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.t5_dirs_mkdir_fuzz]
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
defines.PARENT = [false, true]
defines.REMOUNT = [false, true]
defines.SEED = 'range(10)'
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));
}
// set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
lfs_size_t sim_size = 0;
uint32_t prng = SEED;
for (lfs_size_t i = 0; i < N; i++) {
// choose a pseudo-random number, truncate to 4 decimals
lfs_size_t x = TEST_PRNG(&prng) % 1000;
// insert into our sim
for (lfs_size_t j = 0;; j++) {
if (j >= sim_size || sim[j] >= x) {
// already seen? skip
if (j < sim_size && sim[j] == x) {
goto next;
}
// insert
memmove(&sim[j+1], &sim[j],
(sim_size-j)*sizeof(lfs_size_t));
sim_size += 1;
sim[j] = x;
break;
}
}
// create a directory here
char name[256];
sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), x);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
next:;
}
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// test that our directories match our simulation
for (lfs_size_t j = 0; j < sim_size; j++) {
char name[256];
sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), sim[j]);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
char name2[256];
sprintf(name2, "dir%04d", sim[j]);
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 j = 0; j < sim_size; j++) {
char name[256];
sprintf(name, "dir%04d", sim[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;
// clean up sim/lfs
free(sim);
lfsr_unmount(&lfs) => 0;
'''
# test that did collisions don't cause issues
[cases.t5_dirs_did_collisions]
defines.REMOUNT = [false, true]
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;
}
assert(lfs_crc32c(0, "a_SNmwMTHH", 10) == 0x12345678);
assert(lfs_crc32c(0, "b_skvjpWJH", 10) == 0x12345678);
assert(lfs_crc32c(0, "c_OnOQhVPH", 10) == 0x12345678);
assert(lfs_crc32c(0, "d_puMpPjRH", 10) == 0x12345678);
assert(lfs_crc32c(0, "e_LptKHkHH", 10) == 0x12345678);
assert(lfs_crc32c(0, "f_lUoVuhJH", 10) == 0x12345678);
// make directories
err = lfsr_mkdir(&lfs, "a_SNmwMTHH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "b_skvjpWJH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "c_OnOQhVPH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "d_puMpPjRH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "e_LptKHkHH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "f_lUoVuhJH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our mkdirs worked
struct lfs_info info;
lfsr_stat(&lfs, "a_SNmwMTHH", &info) => 0;
assert(strcmp(info.name, "a_SNmwMTHH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "b_skvjpWJH", &info) => 0;
assert(strcmp(info.name, "b_skvjpWJH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "c_OnOQhVPH", &info) => 0;
assert(strcmp(info.name, "c_OnOQhVPH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "d_puMpPjRH", &info) => 0;
assert(strcmp(info.name, "d_puMpPjRH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "e_LptKHkHH", &info) => 0;
assert(strcmp(info.name, "e_LptKHkHH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "f_lUoVuhJH", &info) => 0;
assert(strcmp(info.name, "f_lUoVuhJH") == 0);
assert(info.type == LFS_TYPE_DIR);
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);
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, "a_SNmwMTHH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "b_skvjpWJH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "c_OnOQhVPH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "d_puMpPjRH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "e_LptKHkHH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "f_lUoVuhJH") == 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;
'''
# these will also collide with the root
[cases.t5_dirs_did_zero]
defines.REMOUNT = [false, true]
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;
}
assert(lfs_crc32c(0, "a_IplRNrPH", 10) == 0x00000000);
assert(lfs_crc32c(0, "b_iUwOsqRH", 10) == 0x00000000);
assert(lfs_crc32c(0, "c_UPNtkpHH", 10) == 0x00000000);
assert(lfs_crc32c(0, "d_jKLUSLJH", 10) == 0x00000000);
assert(lfs_crc32c(0, "e_VNunKMPH", 10) == 0x00000000);
assert(lfs_crc32c(0, "f_vknsvNRH", 10) == 0x00000000);
// make directories
err = lfsr_mkdir(&lfs, "a_IplRNrPH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "b_iUwOsqRH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "c_UPNtkpHH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "d_jKLUSLJH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "e_VNunKMPH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "f_vknsvNRH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our mkdirs worked
struct lfs_info info;
lfsr_stat(&lfs, "a_IplRNrPH", &info) => 0;
assert(strcmp(info.name, "a_IplRNrPH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "b_iUwOsqRH", &info) => 0;
assert(strcmp(info.name, "b_iUwOsqRH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "c_UPNtkpHH", &info) => 0;
assert(strcmp(info.name, "c_UPNtkpHH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "d_jKLUSLJH", &info) => 0;
assert(strcmp(info.name, "d_jKLUSLJH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "e_VNunKMPH", &info) => 0;
assert(strcmp(info.name, "e_VNunKMPH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "f_vknsvNRH", &info) => 0;
assert(strcmp(info.name, "f_vknsvNRH") == 0);
assert(info.type == LFS_TYPE_DIR);
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);
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, "a_IplRNrPH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "b_iUwOsqRH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "c_UPNtkpHH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "d_jKLUSLJH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "e_VNunKMPH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "f_vknsvNRH") == 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;
'''
# these will need to rollover from 0xffffffff -> 0x00000000 correctly
#
# note this is true even if you truncate
[cases.t5_dirs_did_ones]
defines.REMOUNT = [false, true]
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;
}
assert(lfs_crc32c(0, "a_iomlVKPH", 10) == 0xffffffff);
assert(lfs_crc32c(0, "b_IJvqkHRH", 10) == 0xffffffff);
assert(lfs_crc32c(0, "c_uOOJsIHH", 10) == 0xffffffff);
assert(lfs_crc32c(0, "d_JTMkKuJH", 10) == 0xffffffff);
assert(lfs_crc32c(0, "e_vQtPStPH", 10) == 0xffffffff);
assert(lfs_crc32c(0, "f_VtoMnwRH", 10) == 0xffffffff);
// make directories
err = lfsr_mkdir(&lfs, "a_iomlVKPH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "b_IJvqkHRH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "c_uOOJsIHH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "d_JTMkKuJH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "e_vQtPStPH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "f_VtoMnwRH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our mkdirs worked
struct lfs_info info;
lfsr_stat(&lfs, "a_iomlVKPH", &info) => 0;
assert(strcmp(info.name, "a_iomlVKPH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "b_IJvqkHRH", &info) => 0;
assert(strcmp(info.name, "b_IJvqkHRH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "c_uOOJsIHH", &info) => 0;
assert(strcmp(info.name, "c_uOOJsIHH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "d_JTMkKuJH", &info) => 0;
assert(strcmp(info.name, "d_JTMkKuJH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "e_vQtPStPH", &info) => 0;
assert(strcmp(info.name, "e_vQtPStPH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "f_VtoMnwRH", &info) => 0;
assert(strcmp(info.name, "f_VtoMnwRH") == 0);
assert(info.type == LFS_TYPE_DIR);
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);
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, "a_iomlVKPH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "b_IJvqkHRH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "c_uOOJsIHH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "d_JTMkKuJH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "e_vQtPStPH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "f_VtoMnwRH") == 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;
'''
# these test some boundary conditions on the underlying leb128 encoding,
# if the leb128 disk-size is not calculated correctly these can cause
# issues
[cases.t5_dirs_did_leb128_boundaries]
defines.REMOUNT = [false, true]
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;
}
assert(lfs_crc32c(0, "a_IOtUptRH", 10) == 0x0000007f);
assert(lfs_crc32c(0, "b_nquQsKHH", 10) == 0x00000080);
assert(lfs_crc32c(0, "c_vwQtKjHH", 10) == 0x00000081);
assert(lfs_crc32c(0, "d_sVrvrWHH", 10) == 0x00003fff);
assert(lfs_crc32c(0, "e_thrRIsRH", 10) == 0x00004000);
assert(lfs_crc32c(0, "f_pNtQTPJH", 10) == 0x00004001);
// make directories
err = lfsr_mkdir(&lfs, "a_IOtUptRH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "b_nquQsKHH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "c_vwQtKjHH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "d_sVrvrWHH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "e_thrRIsRH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "f_pNtQTPJH");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our mkdirs worked
struct lfs_info info;
lfsr_stat(&lfs, "a_IOtUptRH", &info) => 0;
assert(strcmp(info.name, "a_IOtUptRH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "b_nquQsKHH", &info) => 0;
assert(strcmp(info.name, "b_nquQsKHH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "c_vwQtKjHH", &info) => 0;
assert(strcmp(info.name, "c_vwQtKjHH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "d_sVrvrWHH", &info) => 0;
assert(strcmp(info.name, "d_sVrvrWHH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "e_thrRIsRH", &info) => 0;
assert(strcmp(info.name, "e_thrRIsRH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "f_pNtQTPJH", &info) => 0;
assert(strcmp(info.name, "f_pNtQTPJH") == 0);
assert(info.type == LFS_TYPE_DIR);
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);
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, "a_IOtUptRH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "b_nquQsKHH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "c_vwQtKjHH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "d_sVrvrWHH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "e_thrRIsRH") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "f_pNtQTPJH") == 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;
'''
## dir remove tests
[cases.t5_dirs_rm]
defines.REMOUNT = [false, true]
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;
}
// make a directory
err = lfsr_mkdir(&lfs, "ardvark");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our mkdir worked with stat
struct lfs_info info;
lfsr_stat(&lfs, "ardvark", &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
// and with dir_read
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);
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;
// and remove the directory
lfsr_remove(&lfs, "ardvark") => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that remove worked with stat
lfsr_stat(&lfs, "ardvark", &info) => LFS_ERR_NOENT;
// and with dir_read
lfsr_dir_open(&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) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
lfsr_unmount(&lfs) => 0;
'''
# test that noent errors work
[cases.t5_dirs_rm_noent]
defines.REMOUNT = [false, true]
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;
}
// make a directory
err = lfsr_mkdir(&lfs, "ardvark");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// try to remove a nonsense directory
lfsr_remove(&lfs, "no") => LFS_ERR_NOENT;
// try to remove a directory in a nonsense directory
lfsr_remove(&lfs, "no/ardvark") => LFS_ERR_NOENT;
// try to remove a nonsense child directory
lfsr_remove(&lfs, "ardvark/no") => LFS_ERR_NOENT;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// and check that this didn't interfere with our original directory
struct lfs_info info;
lfsr_stat(&lfs, "ardvark", &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
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);
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 that we catch removing of a non-empty directory
[cases.t5_dirs_rm_notempty]
defines.REMOUNT = [false, true]
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;
}
// make a directory
err = lfsr_mkdir(&lfs, "ardvark");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// fill it with stuff
err = lfsr_mkdir(&lfs, "ardvark/banana");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// try to remove the parent directory
lfsr_remove(&lfs, "ardvark") => LFS_ERR_NOTEMPTY;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// and check that this didn't interfere with our original directory
struct lfs_info info;
lfsr_stat(&lfs, "ardvark", &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "ardvark/banana", &info) => 0;
assert(strcmp(info.name, "banana") == 0);
assert(info.type == LFS_TYPE_DIR);
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);
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_dir_open(&lfs, &dir, "ardvark") => 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, "banana") == 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;
'''
## TODO make this work eventually
#
## test what happens if we try to remove root
#[cases.t5_dirs_rm_root]
#defines.REMOUNT = [false, true]
#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;
# }
#
# // try to remove root, which doesn't really make sense
# lfsr_remove(&lfs, "/") => LFS_ERR_INVAL;
#
# // make a directory
# err = lfsr_mkdir(&lfs, "ardvark");
# assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
#
# // try to remove root, which doesn't really make sense
# //
# // it doesn't really matter which error returns first, so accept both
# err = lfsr_remove(&lfs, "/");
# assert(err == LFS_ERR_NOTEMPTY || err == LFS_ERR_INVAL);
#
# // remount?
# if (REMOUNT) {
# lfsr_unmount(&lfs) => 0;
# lfsr_mount(&lfs, cfg) => 0;
# // grm should be zero here
# assert(lfs.grm[0] == 0);
# }
#
# // and check that this didn't interfere with our original directory
# struct lfs_info info;
# lfsr_stat(&lfs, "ardvark", &info) => 0;
# assert(strcmp(info.name, "ardvark") == 0);
# assert(info.type == LFS_TYPE_DIR);
#
# 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);
# lfsr_dir_read(&lfs, &dir, &info) => 0;
# assert(strcmp(info.name, "..") == 0);
# assert(info.type == LFS_TYPE_DIR);
# lfsr_dir_read(&lfs, &dir, &info) => 0;
# assert(strcmp(info.name, "ardvark") == 0);
# assert(info.type == LFS_TYPE_DIR);
# lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
# lfsr_dir_close(&lfs, &dir) => 0;
#
# lfsr_unmount(&lfs) => 0;
#'''
[cases.t5_dirs_rm_siblings]
defines.REMOUNT = [false, true]
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;
}
// make some directories
err = lfsr_mkdir(&lfs, "ardvark");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "batman");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "cantaloupe");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our mkdir worked
struct lfs_info info;
lfsr_stat(&lfs, "ardvark", &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "batman", &info) => 0;
assert(strcmp(info.name, "batman") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "cantaloupe", &info) => 0;
assert(strcmp(info.name, "cantaloupe") == 0);
assert(info.type == LFS_TYPE_DIR);
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);
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) => 0;
assert(strcmp(info.name, "batman") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "cantaloupe") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// now remove each directory
lfsr_remove(&lfs, "ardvark") => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our remove worked
lfsr_stat(&lfs, "ardvark", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "batman", &info) => 0;
assert(strcmp(info.name, "batman") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "cantaloupe", &info) => 0;
assert(strcmp(info.name, "cantaloupe") == 0);
assert(info.type == LFS_TYPE_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);
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, "batman") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "cantaloupe") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// remove another
lfsr_remove(&lfs, "batman") => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our remove worked
lfsr_stat(&lfs, "ardvark", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "batman", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "cantaloupe", &info) => 0;
assert(strcmp(info.name, "cantaloupe") == 0);
assert(info.type == LFS_TYPE_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);
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, "cantaloupe") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// remove another
lfsr_remove(&lfs, "cantaloupe") => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our remove worked
lfsr_stat(&lfs, "ardvark", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "batman", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "cantaloupe", &info) => LFS_ERR_NOENT;
lfsr_dir_open(&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) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
lfsr_unmount(&lfs) => 0;
'''
[cases.t5_dirs_rm_children]
defines.REMOUNT = [false, true]
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;
}
// make some directories
err = lfsr_mkdir(&lfs, "ardvark");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "ardvark/batman");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
err = lfsr_mkdir(&lfs, "ardvark/batman/cantaloupe");
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our mkdirs worked
struct lfs_info info;
lfsr_stat(&lfs, "ardvark", &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "ardvark/batman", &info) => 0;
assert(strcmp(info.name, "batman") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "ardvark/batman/cantaloupe", &info) => 0;
assert(strcmp(info.name, "cantaloupe") == 0);
assert(info.type == LFS_TYPE_DIR);
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);
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_dir_open(&lfs, &dir, "/ardvark") => 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, "batman") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
lfsr_dir_open(&lfs, &dir, "/ardvark/batman") => 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, "cantaloupe") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// now remove each directory
lfsr_remove(&lfs, "ardvark/batman/cantaloupe") => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our remove worked
lfsr_stat(&lfs, "ardvark", &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "ardvark/batman", &info) => 0;
assert(strcmp(info.name, "batman") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "ardvark/batman/cantaloupe", &info) => LFS_ERR_NOENT;
lfsr_dir_open(&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_dir_open(&lfs, &dir, "/ardvark") => 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, "batman") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
lfsr_dir_open(&lfs, &dir, "/ardvark/batman") => 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;
// remove another
lfsr_remove(&lfs, "ardvark/batman") => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our remove worked
lfsr_stat(&lfs, "ardvark", &info) => 0;
assert(strcmp(info.name, "ardvark") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_stat(&lfs, "ardvark/batman", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "ardvark/batman/cantaloupe", &info) => LFS_ERR_NOENT;
lfsr_dir_open(&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_dir_open(&lfs, &dir, "/ardvark") => 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;
// remove another
lfsr_remove(&lfs, "ardvark") => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// check that our remove worked
lfsr_stat(&lfs, "ardvark", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "ardvark/batman", &info) => LFS_ERR_NOENT;
lfsr_stat(&lfs, "ardvark/batman/cantaloupe", &info) => LFS_ERR_NOENT;
lfsr_dir_open(&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) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
lfsr_unmount(&lfs) => 0;
'''
[cases.t5_dirs_rm_many]
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
defines.REMAINING = [64, 2, 1, 0]
defines.REMOUNT = [false, true]
if = [
'N > REMAINING',
# this test sort of fights against itself when powerloss testing,
# limit it to a _very_ small number of entries for this reason
'!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;
}
// make this many directories
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
// check that our mkdir worked
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
}
lfsr_dir_t dir;
lfsr_dir_open(&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_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 some number of directories
for (lfs_size_t i = 0; i < N-REMAINING; i++) {
char name[256];
sprintf(name, "dir%04d", i);
lfsr_remove(&lfs, name) => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
// check that our removes worked
for (lfs_size_t i = 0; i < N-REMAINING; i++) {
char name[256];
sprintf(name, "dir%04d", i);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT;
}
for (lfs_size_t i = 0; i < REMAINING; i++) {
char name[256];
sprintf(name, "dir%04d", (int)(N-REMAINING + i));
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_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);
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 < REMAINING; i++) {
char name[256];
sprintf(name, "dir%04d", (int)(N-REMAINING + 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.t5_dirs_rm_many_backwards]
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
defines.REMAINING = [64, 2, 1, 0]
defines.REMOUNT = [false, true]
if = [
'N > REMAINING',
# this test sort of fights against itself when powerloss testing,
# limit it to a _very_ small number of entries for this reason
'!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;
}
// make this many directories
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", (int)(N-1-i));
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
// check that our mkdir worked
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
}
lfsr_dir_t dir;
lfsr_dir_open(&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_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 some number of directories
for (lfs_size_t i = 0; i < N-REMAINING; i++) {
char name[256];
sprintf(name, "dir%04d", (int)(N-1-i));
lfsr_remove(&lfs, name) => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
// check that our removes worked
for (lfs_size_t i = 0; i < N-REMAINING; i++) {
char name[256];
sprintf(name, "dir%04d", (int)(N-1-i));
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT;
}
for (lfs_size_t i = 0; i < REMAINING; i++) {
char name[256];
sprintf(name, "dir%04d", i);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_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);
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 < REMAINING; 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;
lfsr_unmount(&lfs) => 0;
'''
[cases.t5_dirs_rm_many_2layers]
defines.N = [1, 2, 4, 8, 16]
defines.REMAINING = [2, 1, 0]
defines.REMOUNT = [false, true]
if = [
'N > REMAINING',
# this test sort of fights against itself when powerloss testing,
# limit it to a _very_ small number of entries for this reason
'!TEST_PL || N <= 4',
]
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;
}
// make this many directories
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// containing this many directories
for (lfs_size_t j = 0; j < N; j++) {
sprintf(name, "dir%04d/child%04d", i, j);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
}
// check that our mkdirs worked
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
for (lfs_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "dir%04d/child%04d", i, j);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
sprintf(name, "child%04d", j);
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
}
}
lfsr_dir_t dir;
lfsr_dir_open(&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_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;
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
lfsr_dir_open(&lfs, &dir, name) => 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 j = 0; j < N; j++) {
char name[256];
sprintf(name, "child%04d", 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;
}
// now remove some number of directories
for (lfs_size_t i = 0; i < N; i++) {
for (lfs_size_t j = 0; j < N; j++) {
if (i < N-REMAINING || j < N-REMAINING) {
char name[256];
sprintf(name, "dir%04d/child%04d", i, j);
lfsr_remove(&lfs, name) => 0;
}
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
if (i < N-REMAINING) {
char name[256];
sprintf(name, "dir%04d", i);
lfsr_remove(&lfs, name) => 0;
}
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
// check that our removes worked
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
struct lfs_info info;
if (i < N-REMAINING) {
lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT;
} else {
lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
for (lfs_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "dir%04d/child%04d", i, j);
struct lfs_info info;
if (j < N-REMAINING) {
lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT;
} else {
lfsr_stat(&lfs, name, &info) => 0;
sprintf(name, "child%04d", j);
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_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);
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 < REMAINING; i++) {
char name[256];
sprintf(name, "dir%04d", (int)(N-REMAINING + 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;
for (lfs_size_t i = 0; i < REMAINING; i++) {
char name[256];
sprintf(name, "dir%04d", (int)(N-REMAINING + i));
lfsr_dir_open(&lfs, &dir, name) => 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 j = 0; j < REMAINING; j++) {
char name[256];
sprintf(name, "child%04d", (int)(N-REMAINING + 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.t5_dirs_rm_many_3layers]
defines.N = [1, 2, 4]
defines.REMAINING = [2, 1, 0]
defines.REMOUNT = [false, true]
if = [
'N > REMAINING',
# this test sort of fights against itself when powerloss testing,
# limit it to a _very_ small number of entries for this reason
'!TEST_PL || N <= 2',
]
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;
}
// make this many directories
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// containing this many directories
for (lfs_size_t j = 0; j < N; j++) {
sprintf(name, "dir%04d/child%04d", i, j);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// containing this many directories
for (lfs_size_t k = 0; k < N; k++) {
sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
}
}
// check that our mkdirs worked
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
for (lfs_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "dir%04d/child%04d", i, j);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
sprintf(name, "child%04d", j);
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
for (lfs_size_t k = 0; k < N; k++) {
char name[256];
sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
sprintf(name, "grandchild%04d", k);
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
}
}
}
lfsr_dir_t dir;
lfsr_dir_open(&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_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;
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
lfsr_dir_open(&lfs, &dir, name) => 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 j = 0; j < N; j++) {
char name[256];
sprintf(name, "child%04d", 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;
for (lfs_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "dir%04d/child%04d", i, j);
lfsr_dir_open(&lfs, &dir, name) => 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 k = 0; k < N; k++) {
char name[256];
sprintf(name, "grandchild%04d", k);
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 some number of directories
for (lfs_size_t i = 0; i < N; i++) {
for (lfs_size_t j = 0; j < N; j++) {
for (lfs_size_t k = 0; k < N; k++) {
if (i < N-REMAINING || j < N-REMAINING || k < N-REMAINING) {
char name[256];
sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k);
lfsr_remove(&lfs, name) => 0;
}
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
if (i < N-REMAINING || j < N-REMAINING) {
char name[256];
sprintf(name, "dir%04d/child%04d", i, j);
lfsr_remove(&lfs, name) => 0;
}
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
if (i < N-REMAINING) {
char name[256];
sprintf(name, "dir%04d", i);
lfsr_remove(&lfs, name) => 0;
}
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
// check that our removes worked
for (lfs_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "dir%04d", i);
struct lfs_info info;
if (i < N-REMAINING) {
lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT;
} else {
lfsr_stat(&lfs, name, &info) => 0;
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
for (lfs_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "dir%04d/child%04d", i, j);
struct lfs_info info;
if (j < N-REMAINING) {
lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT;
} else {
lfsr_stat(&lfs, name, &info) => 0;
sprintf(name, "child%04d", j);
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_DIR);
for (lfs_size_t k = 0; k < N; k++) {
char name[256];
sprintf(name, "dir%04d/child%04d/grandchild%04d",
i, j, k);
struct lfs_info info;
if (k < N-REMAINING) {
lfsr_stat(&lfs, name, &info) => LFS_ERR_NOENT;
} else {
lfsr_stat(&lfs, name, &info) => 0;
sprintf(name, "grandchild%04d", k);
assert(strcmp(info.name, name) == 0);
assert(info.type == LFS_TYPE_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);
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 < REMAINING; i++) {
char name[256];
sprintf(name, "dir%04d", (int)(N-REMAINING + 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;
for (lfs_size_t i = 0; i < REMAINING; i++) {
char name[256];
sprintf(name, "dir%04d", (int)(N-REMAINING + i));
lfsr_dir_open(&lfs, &dir, name) => 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 j = 0; j < REMAINING; j++) {
char name[256];
sprintf(name, "child%04d", (int)(N-REMAINING + 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;
}
for (lfs_size_t i = 0; i < REMAINING; i++) {
for (lfs_size_t j = 0; j < REMAINING; j++) {
char name[256];
sprintf(name, "dir%04d/child%04d",
(int)(N-REMAINING + i),
(int)(N-REMAINING + j));
lfsr_dir_open(&lfs, &dir, name) => 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 k = 0; k < REMAINING; k++) {
char name[256];
sprintf(name, "grandchild%04d", (int)(N-REMAINING + k));
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.t5_dirs_rm_many_linkedlist]
defines.N = [1, 2, 4, 8, 16, 32, 64]
defines.REMAINING = [16, 2, 1, 0]
defines.REMOUNT = [false, true]
if = [
'N > REMAINING',
# this test sort of fights against itself when powerloss testing,
# limit it to a _very_ small number of entries for this reason
'!TEST_PL || 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;
}
// create this many directory in a sort of linked-list by nesting
char name[4096];
memset(name, 0, sizeof(name));
for (lfs_size_t i = 0; i < N; i++) {
sprintf(&name[strlen(name)], "/dir%04d", i);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
// check that our mkdir worked
memset(name, 0, sizeof(name));
for (lfs_size_t i = 0; i < N; i++) {
sprintf(&name[strlen(name)], "/dir%04d", 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);
}
memset(name, 0, sizeof(name));
for (lfs_size_t i = 0; i < N; i++) {
sprintf(&name[strlen(name)], "/dir%04d", i);
lfsr_dir_t dir;
lfsr_dir_open(&lfs, &dir, name) => 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);
if (i < N-1) {
char name2[256];
sprintf(name2, "dir%04d", i+1);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, name2) == 0);
assert(info.type == LFS_TYPE_DIR);
}
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
}
// now remove some number of directories
for (lfs_size_t i = 0; i < N-REMAINING; i++) {
lfsr_remove(&lfs, name) => 0;
name[strlen(name) - strlen("/dir....")] = '\0';
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
}
// check that our remove worked
memset(name, 0, sizeof(name));
for (lfs_size_t i = 0; i < REMAINING; i++) {
sprintf(&name[strlen(name)], "/dir%04d", 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);
}
memset(name, 0, sizeof(name));
for (lfs_size_t i = 0; i < REMAINING; i++) {
sprintf(&name[strlen(name)], "/dir%04d", i);
lfsr_dir_t dir;
lfsr_dir_open(&lfs, &dir, name) => 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);
if (i < REMAINING-1) {
char name2[256];
sprintf(name2, "dir%04d", i+1);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, name2) == 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 deleting entries in a directory while
# iterating over the directory
#
# This is a useful feature, but it's unintuitive that this should have
# well-defined behavior, so make sure to test for it
[cases.t5_dirs_rm_many_recursive]
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
defines.PARENT = [false, true]
# this test sort of fights against itself when powerloss testing,
# limit it to a _very_ small number of entries for this reason
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;
}
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;
'''
[cases.t5_dirs_rm_fuzz]
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
defines.PARENT = [false, true]
defines.REMOUNT = [false, true]
defines.SEED = 'range(10)'
# limit powerloss testing due to time
if = '!TEST_PL || N <= 64'
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));
}
// set up a simulation to compare against
lfs_size_t *sim = malloc(N*sizeof(lfs_size_t));
lfs_size_t sim_size = 0;
uint32_t prng = SEED;
for (lfs_size_t i = 0; i < N; i++) {
// choose a pseudo-random op, either mkdir or rmdir
uint8_t op = TEST_PRNG(&prng) % 2;
if (op == 0 || sim_size == 0) {
// choose a pseudo-random number, truncate to 4 decimals
lfs_size_t x = TEST_PRNG(&prng) % 1000;
// insert into our sim
for (lfs_size_t j = 0;; j++) {
if (j >= sim_size || sim[j] >= x) {
// already seen? skip
if (j < sim_size && sim[j] == x) {
goto next;
}
// insert
memmove(&sim[j+1], &sim[j],
(sim_size-j)*sizeof(lfs_size_t));
sim_size += 1;
sim[j] = x;
break;
}
}
// create a directory here
char name[256];
sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), x);
err = lfsr_mkdir(&lfs, name);
assert(!err || (TEST_PL && err == LFS_ERR_EXIST));
} else {
// choose a pseudo-random entry to delete
lfs_size_t j = TEST_PRNG(&prng) % sim_size;
lfs_size_t x = sim[j];
// delete from our sim
memmove(&sim[j], &sim[j+1],
(sim_size-(j+1))*sizeof(lfs_size_t));
sim_size -= 1;
// remove this directory
char name[256];
sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), x);
lfsr_remove(&lfs, name) => 0;
}
next:;
}
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// test that our directories match our simulation
for (lfs_size_t j = 0; j < sim_size; j++) {
char name[256];
sprintf(name, "%s/dir%04d", (PARENT ? "pricklypear" : ""), sim[j]);
struct lfs_info info;
lfsr_stat(&lfs, name, &info) => 0;
char name2[256];
sprintf(name2, "dir%04d", sim[j]);
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 j = 0; j < sim_size; j++) {
char name[256];
sprintf(name, "dir%04d", sim[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;
// clean up sim/lfs
free(sim);
lfsr_unmount(&lfs) => 0;
'''
#[cases.test_dirs_root]
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_t dir;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# struct lfs_info info;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_dirs_many_creation]
#defines.N = 'range(3, 100, 3)'
#if = 'N < BLOCK_COUNT/2'
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "dir%03d", i);
# lfs_mkdir(&lfs, path) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_t dir;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# struct lfs_info info;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "dir%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, path) == 0);
# }
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_dirs_many_removal]
#defines.N = 'range(3, 100, 11)'
#if = 'N < BLOCK_COUNT/2'
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "removeme%03d", i);
# lfs_mkdir(&lfs, path) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_t dir;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# struct lfs_info info;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "removeme%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, path) == 0);
# }
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs);
#
# lfs_mount(&lfs, cfg) => 0;
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "removeme%03d", i);
# lfs_remove(&lfs, path) => 0;
# }
# lfs_unmount(&lfs);
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_dirs_many_rename]
#defines.N = 'range(3, 100, 11)'
#if = 'N < BLOCK_COUNT/2'
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "test%03d", i);
# lfs_mkdir(&lfs, path) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_t dir;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# struct lfs_info info;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "test%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, path) == 0);
# }
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs);
#
# lfs_mount(&lfs, cfg) => 0;
# for (int i = 0; i < N; i++) {
# char oldpath[128];
# char newpath[128];
# sprintf(oldpath, "test%03d", i);
# sprintf(newpath, "tedd%03d", i);
# lfs_rename(&lfs, oldpath, newpath) => 0;
# }
# lfs_unmount(&lfs);
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "tedd%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, path) == 0);
# }
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs);
#'''
#
#[cases.test_dirs_many_reentrant]
#defines.N = [5, 11]
#if = 'BLOCK_COUNT >= 4*N'
#reentrant = true
#code = '''
# lfs_t lfs;
# int err = lfs_mount(&lfs, cfg);
# if (err) {
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# }
#
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "hi%03d", i);
# err = lfs_mkdir(&lfs, path);
# assert(err == 0 || err == LFS_ERR_EXIST);
# }
#
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "hello%03d", i);
# err = lfs_remove(&lfs, path);
# assert(err == 0 || err == LFS_ERR_NOENT);
# }
#
# lfs_dir_t dir;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# struct lfs_info info;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "hi%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, path) == 0);
# }
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
#
# for (int i = 0; i < N; i++) {
# char oldpath[128];
# char newpath[128];
# sprintf(oldpath, "hi%03d", i);
# sprintf(newpath, "hello%03d", i);
# // YES this can overwrite an existing newpath
# lfs_rename(&lfs, oldpath, newpath) => 0;
# }
#
# lfs_dir_open(&lfs, &dir, "/") => 0;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "hello%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, path) == 0);
# }
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
#
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "hello%03d", i);
# lfs_remove(&lfs, path) => 0;
# }
#
# lfs_dir_open(&lfs, &dir, "/") => 0;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_dirs_file_creation]
#defines.N = 'range(3, 100, 11)'
#if = 'N < BLOCK_COUNT/2'
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "file%03d", i);
# lfs_file_t file;
# lfs_file_open(&lfs, &file, path,
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
# lfs_file_close(&lfs, &file) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_t dir;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# struct lfs_info info;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "file%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_REG);
# assert(strcmp(info.name, path) == 0);
# }
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs);
#'''
#
#[cases.test_dirs_file_removal]
#defines.N = 'range(3, 100, 11)'
#if = 'N < BLOCK_COUNT/2'
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "removeme%03d", i);
# lfs_file_t file;
# lfs_file_open(&lfs, &file, path,
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
# lfs_file_close(&lfs, &file) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_t dir;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# struct lfs_info info;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "removeme%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_REG);
# assert(strcmp(info.name, path) == 0);
# }
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs);
#
# lfs_mount(&lfs, cfg) => 0;
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "removeme%03d", i);
# lfs_remove(&lfs, path) => 0;
# }
# lfs_unmount(&lfs);
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_dirs_file_rename]
#defines.N = 'range(3, 100, 11)'
#if = 'N < BLOCK_COUNT/2'
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "test%03d", i);
# lfs_file_t file;
# lfs_file_open(&lfs, &file, path,
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
# lfs_file_close(&lfs, &file) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_t dir;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# struct lfs_info info;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "test%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_REG);
# assert(strcmp(info.name, path) == 0);
# }
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs);
#
# lfs_mount(&lfs, cfg) => 0;
# for (int i = 0; i < N; i++) {
# char oldpath[128];
# char newpath[128];
# sprintf(oldpath, "test%03d", i);
# sprintf(newpath, "tedd%03d", i);
# lfs_rename(&lfs, oldpath, newpath) => 0;
# }
# lfs_unmount(&lfs);
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "tedd%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_REG);
# assert(strcmp(info.name, path) == 0);
# }
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs);
#'''
#
#[cases.test_dirs_file_reentrant]
#defines.N = [5, 25]
#if = 'N < BLOCK_COUNT/2'
#reentrant = true
#code = '''
# lfs_t lfs;
# int err = lfs_mount(&lfs, cfg);
# if (err) {
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# }
#
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "hi%03d", i);
# lfs_file_t file;
# lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0;
# lfs_file_close(&lfs, &file) => 0;
# }
#
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "hello%03d", i);
# err = lfs_remove(&lfs, path);
# assert(err == 0 || err == LFS_ERR_NOENT);
# }
#
# lfs_dir_t dir;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# struct lfs_info info;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "hi%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_REG);
# assert(strcmp(info.name, path) == 0);
# }
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
#
# for (int i = 0; i < N; i++) {
# char oldpath[128];
# char newpath[128];
# sprintf(oldpath, "hi%03d", i);
# sprintf(newpath, "hello%03d", i);
# // YES this can overwrite an existing newpath
# lfs_rename(&lfs, oldpath, newpath) => 0;
# }
#
# lfs_dir_open(&lfs, &dir, "/") => 0;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "hello%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_REG);
# assert(strcmp(info.name, path) == 0);
# }
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
#
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "hello%03d", i);
# lfs_remove(&lfs, path) => 0;
# }
#
# lfs_dir_open(&lfs, &dir, "/") => 0;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_dirs_nested]
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# lfs_mkdir(&lfs, "potato") => 0;
# lfs_file_t file;
# lfs_file_open(&lfs, &file, "burito",
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_mkdir(&lfs, "potato/baked") => 0;
# lfs_mkdir(&lfs, "potato/sweet") => 0;
# lfs_mkdir(&lfs, "potato/fried") => 0;
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_t dir;
# lfs_dir_open(&lfs, &dir, "potato") => 0;
# struct lfs_info info;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, ".") == 0);
# info.type => LFS_TYPE_DIR;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, "..") == 0);
# info.type => LFS_TYPE_DIR;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, "baked") == 0);
# info.type => LFS_TYPE_DIR;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, "fried") == 0);
# info.type => LFS_TYPE_DIR;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, "sweet") == 0);
# info.type => LFS_TYPE_DIR;
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs) => 0;
#
# // try removing?
# lfs_mount(&lfs, cfg) => 0;
# lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY;
# lfs_unmount(&lfs) => 0;
#
# // try renaming?
# lfs_mount(&lfs, cfg) => 0;
# lfs_rename(&lfs, "potato", "coldpotato") => 0;
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_rename(&lfs, "coldpotato", "warmpotato") => 0;
# lfs_rename(&lfs, "warmpotato", "hotpotato") => 0;
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_remove(&lfs, "potato") => LFS_ERR_NOENT;
# lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT;
# lfs_remove(&lfs, "warmpotato") => LFS_ERR_NOENT;
# lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
# lfs_unmount(&lfs) => 0;
#
# // try cross-directory renaming
# lfs_mount(&lfs, cfg) => 0;
# lfs_mkdir(&lfs, "coldpotato") => 0;
# lfs_rename(&lfs, "hotpotato/baked", "coldpotato/baked") => 0;
# lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY;
# lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY;
# lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
# lfs_rename(&lfs, "hotpotato/fried", "coldpotato/fried") => 0;
# lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY;
# lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY;
# lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
# lfs_rename(&lfs, "hotpotato/sweet", "coldpotato/sweet") => 0;
# lfs_rename(&lfs, "coldpotato", "hotpotato") => 0;
# lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT;
# lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_open(&lfs, &dir, "hotpotato") => 0;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, ".") == 0);
# info.type => LFS_TYPE_DIR;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, "..") == 0);
# info.type => LFS_TYPE_DIR;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, "baked") == 0);
# info.type => LFS_TYPE_DIR;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, "fried") == 0);
# info.type => LFS_TYPE_DIR;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, "sweet") == 0);
# info.type => LFS_TYPE_DIR;
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs) => 0;
#
# // final remove
# lfs_mount(&lfs, cfg) => 0;
# lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
# lfs_remove(&lfs, "hotpotato/baked") => 0;
# lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
# lfs_remove(&lfs, "hotpotato/fried") => 0;
# lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
# lfs_remove(&lfs, "hotpotato/sweet") => 0;
# lfs_remove(&lfs, "hotpotato") => 0;
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, ".") == 0);
# info.type => LFS_TYPE_DIR;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, "..") == 0);
# info.type => LFS_TYPE_DIR;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, "burito") == 0);
# info.type => LFS_TYPE_REG;
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_dirs_recursive_remove]
#defines.N = [10, 100]
#if = 'N < BLOCK_COUNT/2'
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# lfs_mkdir(&lfs, "prickly-pear") => 0;
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "prickly-pear/cactus%03d", i);
# lfs_mkdir(&lfs, path) => 0;
# }
# lfs_dir_t dir;
# lfs_dir_open(&lfs, &dir, "prickly-pear") => 0;
# struct lfs_info info;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "cactus%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, path) == 0);
# }
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs);
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY;
#
# lfs_dir_open(&lfs, &dir, "prickly-pear") => 0;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# for (int i = 0; i < N; i++) {
# char path[1024];
# sprintf(path, "cactus%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, path) == 0);
# sprintf(path, "prickly-pear/%s", info.name);
# lfs_remove(&lfs, path) => 0;
# }
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
#
# lfs_remove(&lfs, "prickly-pear") => 0;
# lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT;
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_dirs_other_errors]
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# lfs_mkdir(&lfs, "potato") => 0;
# lfs_file_t file;
# lfs_file_open(&lfs, &file, "burito",
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
#
# lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST;
# lfs_mkdir(&lfs, "burito") => LFS_ERR_EXIST;
# lfs_file_open(&lfs, &file, "burito",
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST;
# lfs_file_open(&lfs, &file, "potato",
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST;
# lfs_dir_t dir;
# lfs_dir_open(&lfs, &dir, "tomato") => LFS_ERR_NOENT;
# lfs_dir_open(&lfs, &dir, "burito") => LFS_ERR_NOTDIR;
# lfs_file_open(&lfs, &file, "tomato", LFS_O_RDONLY) => LFS_ERR_NOENT;
# lfs_file_open(&lfs, &file, "potato", LFS_O_RDONLY) => LFS_ERR_ISDIR;
# lfs_file_open(&lfs, &file, "tomato", LFS_O_WRONLY) => LFS_ERR_NOENT;
# lfs_file_open(&lfs, &file, "potato", LFS_O_WRONLY) => LFS_ERR_ISDIR;
# lfs_file_open(&lfs, &file, "potato",
# LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR;
#
# lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST;
# lfs_file_open(&lfs, &file, "/",
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST;
# lfs_file_open(&lfs, &file, "/", LFS_O_RDONLY) => LFS_ERR_ISDIR;
# lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY) => LFS_ERR_ISDIR;
# lfs_file_open(&lfs, &file, "/",
# LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR;
#
# // check that errors did not corrupt directory
# lfs_dir_open(&lfs, &dir, "/") => 0;
# struct lfs_info info;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_REG);
# assert(strcmp(info.name, "burito") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "potato") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
#
# lfs_unmount(&lfs) => 0;
#
# // or on disk
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, ".") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "..") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_REG);
# assert(strcmp(info.name, "burito") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(info.type == LFS_TYPE_DIR);
# assert(strcmp(info.name, "potato") == 0);
# lfs_dir_read(&lfs, &dir, &info) => 0;
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_dirs_seek]
#defines.COUNT = [4, 128, 132]
#if = 'COUNT < BLOCK_COUNT/2'
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# lfs_mkdir(&lfs, "hello") => 0;
# for (int i = 0; i < COUNT; i++) {
# char path[1024];
# sprintf(path, "hello/kitty%03d", i);
# lfs_mkdir(&lfs, path) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# for (int j = 2; j < COUNT; j++) {
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_t dir;
# lfs_dir_open(&lfs, &dir, "hello") => 0;
# struct lfs_info info;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, ".") == 0);
# assert(info.type == LFS_TYPE_DIR);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, "..") == 0);
# assert(info.type == LFS_TYPE_DIR);
#
# lfs_soff_t pos;
# for (int i = 0; i < j; i++) {
# char path[1024];
# sprintf(path, "kitty%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, path) == 0);
# assert(info.type == LFS_TYPE_DIR);
# pos = lfs_dir_tell(&lfs, &dir);
# assert(pos >= 0);
# }
#
# lfs_dir_seek(&lfs, &dir, pos) => 0;
# char path[1024];
# sprintf(path, "kitty%03d", j);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, path) == 0);
# assert(info.type == LFS_TYPE_DIR);
#
# lfs_dir_rewind(&lfs, &dir) => 0;
# sprintf(path, "kitty%03u", 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, ".") == 0);
# assert(info.type == LFS_TYPE_DIR);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, "..") == 0);
# assert(info.type == LFS_TYPE_DIR);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, path) == 0);
# assert(info.type == LFS_TYPE_DIR);
#
# lfs_dir_seek(&lfs, &dir, pos) => 0;
# sprintf(path, "kitty%03d", j);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, path) == 0);
# assert(info.type == LFS_TYPE_DIR);
#
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs) => 0;
# }
#'''
#
#[cases.test_dirs_toot_seek]
#defines.COUNT = [4, 128, 132]
#if = 'COUNT < BLOCK_COUNT/2'
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# for (int i = 0; i < COUNT; i++) {
# char path[1024];
# sprintf(path, "hi%03d", i);
# lfs_mkdir(&lfs, path) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# for (int j = 2; j < COUNT; j++) {
# lfs_mount(&lfs, cfg) => 0;
# lfs_dir_t dir;
# lfs_dir_open(&lfs, &dir, "/") => 0;
# struct lfs_info info;
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, ".") == 0);
# assert(info.type == LFS_TYPE_DIR);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, "..") == 0);
# assert(info.type == LFS_TYPE_DIR);
#
# lfs_soff_t pos;
# for (int i = 0; i < j; i++) {
# char path[1024];
# sprintf(path, "hi%03d", i);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, path) == 0);
# assert(info.type == LFS_TYPE_DIR);
# pos = lfs_dir_tell(&lfs, &dir);
# assert(pos >= 0);
# }
#
# lfs_dir_seek(&lfs, &dir, pos) => 0;
# char path[1024];
# sprintf(path, "hi%03d", j);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, path) == 0);
# assert(info.type == LFS_TYPE_DIR);
#
# lfs_dir_rewind(&lfs, &dir) => 0;
# sprintf(path, "hi%03u", 0);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, ".") == 0);
# assert(info.type == LFS_TYPE_DIR);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, "..") == 0);
# assert(info.type == LFS_TYPE_DIR);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, path) == 0);
# assert(info.type == LFS_TYPE_DIR);
#
# lfs_dir_seek(&lfs, &dir, pos) => 0;
# sprintf(path, "hi%03d", j);
# lfs_dir_read(&lfs, &dir, &info) => 1;
# assert(strcmp(info.name, path) == 0);
# assert(info.type == LFS_TYPE_DIR);
#
# lfs_dir_close(&lfs, &dir) => 0;
# lfs_unmount(&lfs) => 0;
# }
#'''
#