Files
littlefs/tests/t5_dirs.toml
T
Christopher Haster 97f867b28d Added powerloss testing over lfsr_mkdir, fixed grm bugs
The grm bugs were mostly issues with:

1. Not maintaining the on-disk grm state in RAM (lfs->grm) correctly,
   this needs to be updated correctly after every commit or littlefs
   gets a confused.

2. lfsr_fs_fixgrm got a bit confused when it was missed when changing
   the no-rm encoding from 0 to -2. Added some inline functions to help
   avoid this in the future.

3. Leaking information due to mixing fixed sized and variable sized
   encodings of the grm delta in places. This is a bit tricky to write
   an assert for as we don't parse the full grm when we see a no-rm grm.
2023-07-18 21:40:43 -05:00

2068 lines
67 KiB
TOML

# Directory tests
[cases.t5_dirs_mkdir]
defines.REMOUNT = [false, true]
code = '''
lfs_t lfs;
lfsr_format(&lfs, cfg) => 0;
lfsr_mount(&lfs, cfg) => 0;
// make a directory
lfsr_mkdir(&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 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_unmount(&lfs) => 0;
'''
# test that noent errors work
[cases.t5_dirs_noent]
defines.REMOUNT = [false, true]
code = '''
lfs_t lfs;
lfsr_format(&lfs, cfg) => 0;
lfsr_mount(&lfs, cfg) => 0;
// make a directory
lfsr_mkdir(&lfs, "ardvark") => 0;
// 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_unmount(&lfs) => 0;
'''
# test that creating the same directory twice errors
[cases.t5_dirs_mkdir_exists]
defines.REMOUNT = [false, true]
code = '''
lfs_t lfs;
lfsr_format(&lfs, cfg) => 0;
lfsr_mount(&lfs, cfg) => 0;
// make a directory
lfsr_mkdir(&lfs, "ardvark") => 0;
// 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_unmount(&lfs) => 0;
'''
# test that creating a directory with an invalid path errors
[cases.t5_dirs_mkdir_noent]
defines.REMOUNT = [false, true]
code = '''
lfs_t lfs;
lfsr_format(&lfs, cfg) => 0;
lfsr_mount(&lfs, cfg) => 0;
// make a directory
lfsr_mkdir(&lfs, "ardvark") => 0;
// 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_unmount(&lfs) => 0;
'''
[cases.t5_dirs_mkdir_siblings]
defines.REMOUNT = [false, true]
code = '''
lfs_t lfs;
lfsr_format(&lfs, cfg) => 0;
lfsr_mount(&lfs, cfg) => 0;
// make some directories
lfsr_mkdir(&lfs, "ardvark") => 0;
lfsr_mkdir(&lfs, "batman") => 0;
lfsr_mkdir(&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 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_unmount(&lfs) => 0;
'''
[cases.t5_dirs_mkdir_children]
defines.REMOUNT = [false, true]
code = '''
lfs_t lfs;
lfsr_format(&lfs, cfg) => 0;
lfsr_mount(&lfs, cfg) => 0;
// make some directories
lfsr_mkdir(&lfs, "ardvark") => 0;
lfsr_mkdir(&lfs, "ardvark/batman") => 0;
lfsr_mkdir(&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 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_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_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_unmount(&lfs) => 0;
'''
[cases.t5_dirs_mkdir_many]
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
defines.REMOUNT = [false, true]
code = '''
lfs_t lfs;
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);
lfsr_mkdir(&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 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_unmount(&lfs) => 0;
'''
[cases.t5_dirs_mkdir_many_2layers]
defines.N = [1, 2, 4, 8, 16, 32]
defines.REMOUNT = [false, true]
code = '''
lfs_t lfs;
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);
lfsr_mkdir(&lfs, name) => 0;
// containing this many directories
for (lfs_size_t j = 0; j < N; j++) {
sprintf(name, "dir%04d/child%04d", i, j);
lfsr_mkdir(&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 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;
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_unmount(&lfs) => 0;
'''
[cases.t5_dirs_mkdir_many_3layers]
defines.N = [1, 2, 4, 8]
defines.REMOUNT = [false, true]
code = '''
lfs_t lfs;
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);
lfsr_mkdir(&lfs, name) => 0;
// containing this many directories
for (lfs_size_t j = 0; j < N; j++) {
sprintf(name, "dir%04d/child%04d", i, j);
lfsr_mkdir(&lfs, name) => 0;
// containing this many directories
for (lfs_size_t k = 0; k < N; k++) {
sprintf(name, "dir%04d/child%04d/grandchild%04d", i, j, k);
lfsr_mkdir(&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 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;
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;
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_unmount(&lfs) => 0;
'''
[cases.t5_dirs_mkdir_many_linkedlist]
defines.N = [1, 2, 4, 8, 16, 32, 64]
defines.REMOUNT = [false, true]
code = '''
lfs_t lfs;
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);
lfsr_mkdir(&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 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_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.SAMPLES = 10
# -1 => all pseudo-random seeds
# n => reproduce a specific seed
defines.SEED = -1
code = '''
// iterate through severals seeds that we can reproduce easily
for (uint32_t seed = (SEED == -1 ? 1 : SEED);
(SEED == -1 ? seed < SAMPLES+1 : seed == SEED);
seed++) {
printf("--- seed: %d ---\n", seed);
// reset lfs here each iteration
lfs_t lfs;
lfsr_format(&lfs, cfg) => 0;
lfsr_mount(&lfs, cfg) => 0;
if (PARENT) {
lfsr_mkdir(&lfs, "parent") => 0;
}
// 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 (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;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
break;
}
}
// create a directory here
char name[256];
sprintf(name, "%s/dir%04d", (PARENT ? "parent" : ""), x);
lfsr_mkdir(&lfs, name) => 0;
next:;
}
// 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 ? "parent" : ""), 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 ? "parent" : "/")) => 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;
// 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]
code = '''
lfs_t lfs;
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
lfsr_mkdir(&lfs, "a_SNmwMTHH") => 0;
lfsr_mkdir(&lfs, "b_skvjpWJH") => 0;
lfsr_mkdir(&lfs, "c_OnOQhVPH") => 0;
lfsr_mkdir(&lfs, "d_puMpPjRH") => 0;
lfsr_mkdir(&lfs, "e_LptKHkHH") => 0;
lfsr_mkdir(&lfs, "f_lUoVuhJH") => 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 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_unmount(&lfs) => 0;
'''
# these will also collide with the root
[cases.t5_dirs_did_zero]
defines.REMOUNT = [false, true]
code = '''
lfs_t lfs;
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);
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, cfg) => 0;
// grm should be zero here
assert(lfs.grm[0] == 0);
}
// make directories
lfsr_mkdir(&lfs, "a_IplRNrPH") => 0;
lfsr_mkdir(&lfs, "b_iUwOsqRH") => 0;
lfsr_mkdir(&lfs, "c_UPNtkpHH") => 0;
lfsr_mkdir(&lfs, "d_jKLUSLJH") => 0;
lfsr_mkdir(&lfs, "e_VNunKMPH") => 0;
lfsr_mkdir(&lfs, "f_vknsvNRH") => 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 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_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]
code = '''
lfs_t lfs;
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
lfsr_mkdir(&lfs, "a_iomlVKPH") => 0;
lfsr_mkdir(&lfs, "b_IJvqkHRH") => 0;
lfsr_mkdir(&lfs, "c_uOOJsIHH") => 0;
lfsr_mkdir(&lfs, "d_JTMkKuJH") => 0;
lfsr_mkdir(&lfs, "e_vQtPStPH") => 0;
lfsr_mkdir(&lfs, "f_VtoMnwRH") => 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 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_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]
code = '''
lfs_t lfs;
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
lfsr_mkdir(&lfs, "a_IOtUptRH") => 0;
lfsr_mkdir(&lfs, "b_nquQsKHH") => 0;
lfsr_mkdir(&lfs, "c_vwQtKjHH") => 0;
lfsr_mkdir(&lfs, "d_sVrvrWHH") => 0;
lfsr_mkdir(&lfs, "e_thrRIsRH") => 0;
lfsr_mkdir(&lfs, "f_pNtQTPJH") => 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 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_unmount(&lfs) => 0;
'''
[cases.t5_dirs_mkdir_many_pl]
defines.N = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
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);
int err = lfsr_mkdir(&lfs, name);
assert(!err || err == LFS_ERR_EXIST);
}
// 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_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;
# }
#'''
#