Files
littlefs/tests/test_ftree.toml
T
Christopher Haster 582dc5f1b2 Added some tests, quick seek impl, fixed bugs
Turns out it's hard to test file holes without seek.

It's interesting to note most of seek's buffer flush work actually
occurs lazily in lfsr_file_write, so lfsr_file_seek turns out to be a
relatively simple function.
2023-10-14 00:09:27 -05:00

1666 lines
51 KiB
TOML

# Test basic file operations
after = ['test_dtree']
# test creation/deletion
[cases.test_ftree_create]
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 a file
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfsr_file_close(&lfs, &file) => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
}
// check our file with stat
struct lfs_info info;
lfsr_stat(&lfs, "hello", &info) => 0;
assert(strcmp(info.name, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == 0);
// 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, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == 0);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// try reading our file
lfsr_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
// is size correct?
lfsr_file_size(&lfs, &file) => 0;
// try reading
uint8_t rbuf[8192];
lfsr_file_read(&lfs, &file, rbuf, sizeof(rbuf)) => 0;
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
'''
# test we can write some data, should be inlined
[cases.test_ftree_hello]
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 a file
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
uint8_t wbuf[8192];
strcpy((char*)wbuf, "Hello World!");
lfs_size_t wsize = strlen((const char*)wbuf);
lfsr_file_write(&lfs, &file, wbuf, wsize) => wsize;
lfsr_file_close(&lfs, &file) => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
}
// check our file with stat
struct lfs_info info;
lfsr_stat(&lfs, "hello", &info) => 0;
assert(strcmp(info.name, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == wsize);
// 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, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == wsize);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// try reading our file
lfsr_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
// is size correct?
lfsr_file_size(&lfs, &file) => wsize;
// try reading
uint8_t rbuf[8192];
memset(rbuf, 0xaa, sizeof(rbuf));
lfsr_file_read(&lfs, &file, rbuf, sizeof(rbuf)) => wsize;
assert(memcmp(rbuf, wbuf, wsize) == 0);
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
'''
# test we can rewrite a file
[cases.test_ftree_trunc]
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 a file
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
uint8_t wbuf[8192];
strcpy((char*)wbuf, "Oh no!");
lfs_size_t wsize = strlen((const char*)wbuf);
lfsr_file_write(&lfs, &file, wbuf, wsize) => wsize;
lfsr_file_close(&lfs, &file) => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
}
// rewrite the file
lfsr_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
strcpy((char*)wbuf, "Hello World!");
wsize = strlen((const char*)wbuf);
lfsr_file_write(&lfs, &file, wbuf, wsize) => wsize;
lfsr_file_close(&lfs, &file) => 0;
// check our file with stat
struct lfs_info info;
lfsr_stat(&lfs, "hello", &info) => 0;
assert(strcmp(info.name, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == wsize);
// 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, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == wsize);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// try reading our file
lfsr_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
// is size correct?
lfsr_file_size(&lfs, &file) => wsize;
// try reading
uint8_t rbuf[8192];
memset(rbuf, 0xaa, sizeof(rbuf));
lfsr_file_read(&lfs, &file, rbuf, sizeof(rbuf)) => wsize;
assert(memcmp(rbuf, wbuf, wsize) == 0);
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
'''
# check for LFS_F_EXCL errors
[cases.test_ftree_excl]
defines.REMOUNT = [false, true]
code = '''
lfs_t lfs;
lfsr_format(&lfs, CFG) => 0;
lfsr_mount(&lfs, CFG) => 0;
// create a file
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
uint8_t wbuf[8192];
strcpy((char*)wbuf, "Hello World!");
lfs_size_t wsize = strlen((const char*)wbuf);
lfsr_file_write(&lfs, &file, wbuf, wsize) => wsize;
lfsr_file_close(&lfs, &file) => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
}
// try to recreate file, this should error
lfsr_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
}
// check our file with stat
struct lfs_info info;
lfsr_stat(&lfs, "hello", &info) => 0;
assert(strcmp(info.name, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == wsize);
// 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, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == wsize);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// try reading our file
lfsr_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
// is size correct?
lfsr_file_size(&lfs, &file) => wsize;
// try reading
uint8_t rbuf[8192];
memset(rbuf, 0xaa, sizeof(rbuf));
lfsr_file_read(&lfs, &file, rbuf, sizeof(rbuf)) => wsize;
assert(memcmp(rbuf, wbuf, wsize) == 0);
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
'''
# a file is not a directory
[cases.test_ftree_file_not_dir]
defines.REMOUNT = [false, true]
code = '''
lfs_t lfs;
lfsr_format(&lfs, CFG) => 0;
lfsr_mount(&lfs, CFG) => 0;
// create a file
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
uint8_t wbuf[8192];
strcpy((char*)wbuf, "Hello World!");
lfs_size_t wsize = strlen((const char*)wbuf);
lfsr_file_write(&lfs, &file, wbuf, wsize) => wsize;
lfsr_file_close(&lfs, &file) => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
}
// try to open our file as a directory
lfsr_dir_t dir;
lfsr_dir_open(&lfs, &dir, "hello") => LFS_ERR_NOTDIR;
// try to create a directory on top of our file
lfsr_mkdir(&lfs, "hello") => LFS_ERR_EXIST;
// try to rename a directory onto our file
lfsr_mkdir(&lfs, "not_hello") => 0;
lfsr_rename(&lfs, "not_hello", "hello") => LFS_ERR_ISDIR;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
}
// check our file with stat
struct lfs_info info;
lfsr_stat(&lfs, "hello", &info) => 0;
assert(strcmp(info.name, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == wsize);
// 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) => 0;
assert(strcmp(info.name, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == wsize);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "not_hello") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// try reading our file
lfsr_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
// is size correct?
lfsr_file_size(&lfs, &file) => wsize;
// try reading
uint8_t rbuf[8192];
memset(rbuf, 0xaa, sizeof(rbuf));
lfsr_file_read(&lfs, &file, rbuf, sizeof(rbuf)) => wsize;
assert(memcmp(rbuf, wbuf, wsize) == 0);
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
'''
# a directory is not a file
[cases.test_ftree_dir_not_file]
defines.REMOUNT = [false, true]
code = '''
lfs_t lfs;
lfsr_format(&lfs, CFG) => 0;
lfsr_mount(&lfs, CFG) => 0;
// create a directory
lfsr_mkdir(&lfs, "hello") => 0;
// try reading our directory as a file
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => LFS_ERR_ISDIR;
// try writing our directory as a file
lfsr_file_open(&lfs, &file, "hello", LFS_O_WRONLY) => LFS_ERR_ISDIR;
lfsr_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_TRUNC) => LFS_ERR_ISDIR;
lfsr_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR;
lfsr_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => LFS_ERR_ISDIR;
// try rename a file on top of our directory
lfsr_file_open(&lfs, &file, "not_hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
uint8_t wbuf[8192];
strcpy((char*)wbuf, "Hello World!");
lfs_size_t wsize = strlen((const char*)wbuf);
lfsr_file_write(&lfs, &file, wbuf, wsize) => wsize;
lfsr_file_close(&lfs, &file) => 0;
lfsr_rename(&lfs, "not_hello", "hello") => LFS_ERR_ISDIR;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
}
// check our dir with stat
struct lfs_info info;
lfsr_stat(&lfs, "hello", &info) => 0;
assert(strcmp(info.name, "hello") == 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, "hello") == 0);
assert(info.type == LFS_TYPE_DIR);
lfsr_dir_read(&lfs, &dir, &info) => 0;
assert(strcmp(info.name, "not_hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == wsize);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// did we corrupt our renaming file?
// try reading our file
lfsr_file_open(&lfs, &file, "not_hello", LFS_O_RDONLY) => 0;
// is size correct?
lfsr_file_size(&lfs, &file) => wsize;
// try reading
uint8_t rbuf[8192];
memset(rbuf, 0xaa, sizeof(rbuf));
lfsr_file_read(&lfs, &file, rbuf, sizeof(rbuf)) => wsize;
assert(memcmp(rbuf, wbuf, wsize) == 0);
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
'''
# try writing larger files?
#
# at 2*CACHE_SIZE we need an inlined tree
# ? single block?
# at 2*BLOCK_SIZE we need a b-tree
#
[cases.test_ftree_more]
defines.SIZE = ['CACHE_SIZE/2', '2*CACHE_SIZE']
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 a file
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
uint8_t wbuf[8192];
uint32_t prng = 42;
for (lfs_size_t i = 0; i < SIZE; i++) {
wbuf[i] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_write(&lfs, &file, wbuf, SIZE) => SIZE;
lfsr_file_close(&lfs, &file) => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
}
// check our file with stat
struct lfs_info info;
lfsr_stat(&lfs, "hello", &info) => 0;
assert(strcmp(info.name, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
// 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, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// try reading our file
lfsr_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
// is size correct?
lfsr_file_size(&lfs, &file) => SIZE;
// try reading
uint8_t rbuf[8192];
memset(rbuf, 0xaa, sizeof(rbuf));
lfsr_file_read(&lfs, &file, rbuf, sizeof(rbuf)) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
'''
# more complex writing patterns to inlined files
# write files incrementally
[cases.test_ftree_incr]
defines.SIZE = ['CACHE_SIZE/2', '2*CACHE_SIZE']
defines.CHUNK = ['CACHE_SIZE/2', '4', '1']
defines.SYNC = [false, true]
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 a file, truncating in case of powerloss
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
uint8_t wbuf[8192];
uint32_t prng = 42;
for (lfs_size_t i = 0; i < SIZE; i++) {
wbuf[i] = 'a' + (TEST_PRNG(&prng) % 26);
}
for (lfs_size_t i = 0; i < SIZE; i += CHUNK) {
lfsr_file_write(&lfs, &file, &wbuf[i], CHUNK) => CHUNK;
// sync?
if (SYNC) {
lfsr_file_sync(&lfs, &file) => 0;
}
// remount?
if (REMOUNT) {
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
// note the switch to append here
lfsr_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_APPEND) => 0;
}
}
lfsr_file_close(&lfs, &file) => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
}
// check our file with stat
struct lfs_info info;
lfsr_stat(&lfs, "hello", &info) => 0;
assert(strcmp(info.name, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
// 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, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// try reading our file
lfsr_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
// is size correct?
lfsr_file_size(&lfs, &file) => SIZE;
// try reading
uint8_t rbuf[8192];
memset(rbuf, 0xaa, sizeof(rbuf));
lfsr_file_read(&lfs, &file, rbuf, sizeof(rbuf)) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
'''
# overwrite files
[cases.test_ftree_overwrite]
defines.SIZE = ['CACHE_SIZE/2', '2*CACHE_SIZE']
defines.CHUNK = ['CACHE_SIZE/2', '4', '1']
# bit 0 => first chunk
# bit 1 => middle chunk
# bit 2 => last chunk
defines.MASK = [0, 1, 2, 3, 4, 5, 6, 7]
# 0 => in-order
# 1 => reversed
defines.ORDER = [0, 1]
defines.SYNC = [false, true]
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 a file, truncating in case of powerloss
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
// simulate our file in ram
uint8_t sim[8192];
uint32_t prng = 42;
for (lfs_size_t i = 0; i < SIZE; i++) {
sim[i] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_write(&lfs, &file, sim, SIZE) => SIZE;
// sync?
if (SYNC) {
lfsr_file_sync(&lfs, &file) => 0;
}
// remount?
if (REMOUNT) {
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
lfsr_file_open(&lfs, &file, "hello", LFS_O_WRONLY) => 0;
}
// write first chunk?
if (MASK & 1) {
if (ORDER == 0) {
for (lfs_size_t i = 0; i < CHUNK; i++) {
sim[i] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
lfsr_file_write(&lfs, &file, &sim[0], CHUNK) => CHUNK;
} else {
for (lfs_size_t i = 0; i < CHUNK; i++) {
sim[SIZE-CHUNK+i] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_seek(&lfs, &file, SIZE-CHUNK, LFS_SEEK_SET) => SIZE-CHUNK;
lfsr_file_write(&lfs, &file, &sim[SIZE-CHUNK], CHUNK) => CHUNK;
}
}
// sync?
if (SYNC) {
lfsr_file_sync(&lfs, &file) => 0;
}
// remount?
if (REMOUNT) {
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
lfsr_file_open(&lfs, &file, "hello", LFS_O_WRONLY) => 0;
}
// write second chunk?
if (MASK & 2) {
for (lfs_size_t i = 0; i < CHUNK; i++) {
sim[SIZE/2-CHUNK/2+i] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_seek(&lfs, &file, SIZE/2 - CHUNK/2, LFS_SEEK_SET)
=> SIZE/2 - CHUNK/2;
lfsr_file_write(&lfs, &file, &sim[SIZE/2-CHUNK/2], CHUNK) => CHUNK;
}
// sync?
if (SYNC) {
lfsr_file_sync(&lfs, &file) => 0;
}
// remount?
if (REMOUNT) {
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
lfsr_file_open(&lfs, &file, "hello", LFS_O_WRONLY) => 0;
}
// write third chunk?
if (MASK & 4) {
if (ORDER == 0) {
for (lfs_size_t i = 0; i < CHUNK; i++) {
sim[SIZE-CHUNK+i] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_seek(&lfs, &file, SIZE-CHUNK, LFS_SEEK_SET) => SIZE-CHUNK;
lfsr_file_write(&lfs, &file, &sim[SIZE-CHUNK], CHUNK) => CHUNK;
} else {
for (lfs_size_t i = 0; i < CHUNK; i++) {
sim[i] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
lfsr_file_write(&lfs, &file, &sim[0], CHUNK) => CHUNK;
}
}
lfsr_file_close(&lfs, &file) => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
}
// check our file with stat
struct lfs_info info;
lfsr_stat(&lfs, "hello", &info) => 0;
assert(strcmp(info.name, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
// 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, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// try reading our file
lfsr_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
// is size correct?
lfsr_file_size(&lfs, &file) => SIZE;
// try reading
uint8_t rbuf[8192];
memset(rbuf, 0xaa, sizeof(rbuf));
lfsr_file_read(&lfs, &file, rbuf, sizeof(rbuf)) => SIZE;
// does our file match our simulation?
assert(memcmp(rbuf, sim, SIZE) == 0);
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
'''
# similar to overwrite files, but without underlying data
[cases.test_ftree_holes]
defines.SIZE = ['CACHE_SIZE/2', '2*CACHE_SIZE']
defines.CHUNK = ['CACHE_SIZE/2', '4', '1']
# bit 0 => first chunk
# bit 1 => middle chunk
# bit 2 => last chunk
defines.MASK = [4, 5, 6, 7] # TODO 0 1 2 3 ? need truncate?
# 0 => in-order
# 1 => reversed
defines.ORDER = [0] # TODO 1?
defines.SYNC = [false, true]
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 a file, truncating in case of powerloss
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
// simulate our file in ram
uint8_t sim[8192];
uint32_t prng = 42;
memset(sim, 0, SIZE);
// sync?
if (SYNC) {
lfsr_file_sync(&lfs, &file) => 0;
}
// remount?
if (REMOUNT) {
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
lfsr_file_open(&lfs, &file, "hello", LFS_O_WRONLY) => 0;
}
// write first chunk?
if (MASK & 1) {
if (ORDER == 0) {
for (lfs_size_t i = 0; i < CHUNK; i++) {
sim[i] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
lfsr_file_write(&lfs, &file, &sim[0], CHUNK) => CHUNK;
} else {
for (lfs_size_t i = 0; i < CHUNK; i++) {
sim[SIZE-CHUNK+i] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_seek(&lfs, &file, SIZE-CHUNK, LFS_SEEK_SET) => SIZE-CHUNK;
lfsr_file_write(&lfs, &file, &sim[SIZE-CHUNK], CHUNK) => CHUNK;
}
}
// sync?
if (SYNC) {
lfsr_file_sync(&lfs, &file) => 0;
}
// remount?
if (REMOUNT) {
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
lfsr_file_open(&lfs, &file, "hello", LFS_O_WRONLY) => 0;
}
// write second chunk?
if (MASK & 2) {
for (lfs_size_t i = 0; i < CHUNK; i++) {
sim[SIZE/2-CHUNK/2+i] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_seek(&lfs, &file, SIZE/2 - CHUNK/2, LFS_SEEK_SET)
=> SIZE/2 - CHUNK/2;
lfsr_file_write(&lfs, &file, &sim[SIZE/2-CHUNK/2], CHUNK) => CHUNK;
}
// sync?
if (SYNC) {
lfsr_file_sync(&lfs, &file) => 0;
}
// remount?
if (REMOUNT) {
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
lfsr_file_open(&lfs, &file, "hello", LFS_O_WRONLY) => 0;
}
// write third chunk?
if (MASK & 4) {
if (ORDER == 0) {
for (lfs_size_t i = 0; i < CHUNK; i++) {
sim[SIZE-CHUNK+i] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_seek(&lfs, &file, SIZE-CHUNK, LFS_SEEK_SET) => SIZE-CHUNK;
lfsr_file_write(&lfs, &file, &sim[SIZE-CHUNK], CHUNK) => CHUNK;
} else {
for (lfs_size_t i = 0; i < CHUNK; i++) {
sim[i] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0;
lfsr_file_write(&lfs, &file, &sim[0], CHUNK) => CHUNK;
}
}
lfsr_file_close(&lfs, &file) => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
}
// check our file with stat
struct lfs_info info;
lfsr_stat(&lfs, "hello", &info) => 0;
assert(strcmp(info.name, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
// 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, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// try reading our file
lfsr_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
// is size correct?
lfsr_file_size(&lfs, &file) => SIZE;
// try reading
uint8_t rbuf[8192];
memset(rbuf, 0xaa, sizeof(rbuf));
lfsr_file_read(&lfs, &file, rbuf, sizeof(rbuf)) => SIZE;
// does our file match our simulation?
assert(memcmp(rbuf, sim, SIZE) == 0);
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
'''
# writing any data structure backwards always reveals issues
[cases.test_ftree_reversed_overwrite]
defines.SIZE = ['CACHE_SIZE/2', '2*CACHE_SIZE']
defines.CHUNK = ['CACHE_SIZE/2', '4', '1']
defines.SYNC = [false, true]
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 a file, truncating in case of powerloss
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
// simulate our file in ram
uint8_t sim[8192];
uint32_t prng = 42;
for (lfs_size_t i = 0; i < SIZE; i++) {
sim[i] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_write(&lfs, &file, sim, SIZE) => SIZE;
// sync?
if (SYNC) {
lfsr_file_sync(&lfs, &file) => 0;
}
// remount?
if (REMOUNT) {
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
lfsr_file_open(&lfs, &file, "hello", LFS_O_WRONLY) => 0;
}
// write to file incrementally and backwards
for (lfs_size_t i = 0; i < SIZE; i += CHUNK) {
for (lfs_size_t j = 0; j < CHUNK; j++) {
sim[SIZE-i-CHUNK+j] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_seek(&lfs, &file, SIZE-i-CHUNK, LFS_SEEK_SET) => SIZE-i-CHUNK;
lfsr_file_write(&lfs, &file, &sim[SIZE-i-CHUNK], CHUNK) => CHUNK;
// sync?
if (SYNC) {
lfsr_file_sync(&lfs, &file) => 0;
}
// remount?
if (REMOUNT) {
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
lfsr_file_open(&lfs, &file, "hello", LFS_O_WRONLY) => 0;
}
}
lfsr_file_close(&lfs, &file) => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
}
// check our file with stat
struct lfs_info info;
lfsr_stat(&lfs, "hello", &info) => 0;
assert(strcmp(info.name, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
// 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, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// try reading our file
lfsr_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
// is size correct?
lfsr_file_size(&lfs, &file) => SIZE;
// try reading
uint8_t rbuf[8192];
memset(rbuf, 0xaa, sizeof(rbuf));
lfsr_file_read(&lfs, &file, rbuf, sizeof(rbuf)) => SIZE;
// does our file match our simulation?
assert(memcmp(rbuf, sim, SIZE) == 0);
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
'''
# writing any data structure backwards always reveals issues
[cases.test_ftree_reversed_holes]
defines.SIZE = ['CACHE_SIZE/2', '2*CACHE_SIZE']
defines.CHUNK = ['CACHE_SIZE/2', '4', '1']
defines.SYNC = [false, true]
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 a file, truncating in case of powerloss
lfsr_file_t file;
lfsr_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
// simulate our file in ram
uint8_t sim[8192];
uint32_t prng = 42;
memset(sim, 0, SIZE);
// sync?
if (SYNC) {
lfsr_file_sync(&lfs, &file) => 0;
}
// remount?
if (REMOUNT) {
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
lfsr_file_open(&lfs, &file, "hello", LFS_O_WRONLY) => 0;
}
// write to file incrementally and backwards
for (lfs_size_t i = 0; i < SIZE; i += CHUNK) {
for (lfs_size_t j = 0; j < CHUNK; j++) {
sim[SIZE-i-CHUNK+j] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfsr_file_seek(&lfs, &file, SIZE-i-CHUNK, LFS_SEEK_SET) => SIZE-i-CHUNK;
lfsr_file_write(&lfs, &file, &sim[SIZE-i-CHUNK], CHUNK) => CHUNK;
// sync?
if (SYNC) {
lfsr_file_sync(&lfs, &file) => 0;
}
// remount?
if (REMOUNT) {
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
lfsr_file_open(&lfs, &file, "hello", LFS_O_WRONLY) => 0;
}
}
lfsr_file_close(&lfs, &file) => 0;
// remount?
if (REMOUNT) {
lfsr_unmount(&lfs) => 0;
lfsr_mount(&lfs, CFG) => 0;
}
// check our file with stat
struct lfs_info info;
lfsr_stat(&lfs, "hello", &info) => 0;
assert(strcmp(info.name, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
// 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, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
assert(info.size == SIZE);
lfsr_dir_read(&lfs, &dir, &info) => LFS_ERR_NOENT;
lfsr_dir_close(&lfs, &dir) => 0;
// try reading our file
lfsr_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
// is size correct?
lfsr_file_size(&lfs, &file) => SIZE;
// try reading
uint8_t rbuf[8192];
memset(rbuf, 0xaa, sizeof(rbuf));
lfsr_file_read(&lfs, &file, rbuf, sizeof(rbuf)) => SIZE;
// does our file match our simulation?
assert(memcmp(rbuf, sim, SIZE) == 0);
lfsr_file_close(&lfs, &file) => 0;
lfsr_unmount(&lfs) => 0;
'''
#
#[cases.test_files_simple]
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_t file;
# lfs_file_open(&lfs, &file, "hello",
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
# lfs_size_t size = strlen("Hello World!")+1;
# uint8_t buffer[1024];
# strcpy((char*)buffer, "Hello World!");
# lfs_file_write(&lfs, &file, buffer, size) => size;
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
# lfs_file_read(&lfs, &file, buffer, size) => size;
# assert(strcmp((char*)buffer, "Hello World!") == 0);
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_files_large]
#defines.SIZE = [32, 8192, 262144, 0, 7, 8193]
#defines.CHUNKSIZE = [31, 16, 33, 1, 1023]
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
#
# // write
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_t file;
# lfs_file_open(&lfs, &file, "avacado",
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
# uint32_t prng = 1;
# uint8_t buffer[1024];
# for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
# for (lfs_size_t b = 0; b < chunk; b++) {
# buffer[b] = TEST_PRNG(&prng) & 0xff;
# }
# lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
# }
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#
# // read
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
# lfs_file_size(&lfs, &file) => SIZE;
# prng = 1;
# for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
# lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
# for (lfs_size_t b = 0; b < chunk; b++) {
# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
# }
# }
# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_files_rewrite]
#defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
#defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
#defines.CHUNKSIZE = [31, 16, 1]
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
#
# // write
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_t file;
# uint8_t buffer[1024];
# lfs_file_open(&lfs, &file, "avacado",
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
# uint32_t prng = 1;
# for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
# for (lfs_size_t b = 0; b < chunk; b++) {
# buffer[b] = TEST_PRNG(&prng) & 0xff;
# }
# lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
# }
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#
# // read
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
# lfs_file_size(&lfs, &file) => SIZE1;
# prng = 1;
# for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
# lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
# for (lfs_size_t b = 0; b < chunk; b++) {
# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
# }
# }
# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#
# // rewrite
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY) => 0;
# prng = 2;
# for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
# for (lfs_size_t b = 0; b < chunk; b++) {
# buffer[b] = TEST_PRNG(&prng) & 0xff;
# }
# lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
# }
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#
# // read
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
# lfs_file_size(&lfs, &file) => lfs_max(SIZE1, SIZE2);
# prng = 2;
# for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
# lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
# for (lfs_size_t b = 0; b < chunk; b++) {
# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
# }
# }
# if (SIZE1 > SIZE2) {
# prng = 1;
# for (lfs_size_t b = 0; b < SIZE2; b++) {
# TEST_PRNG(&prng);
# }
# for (lfs_size_t i = SIZE2; i < SIZE1; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
# lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
# for (lfs_size_t b = 0; b < chunk; b++) {
# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
# }
# }
# }
# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_files_append]
#defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
#defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
#defines.CHUNKSIZE = [31, 16, 1]
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
#
# // write
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_t file;
# uint8_t buffer[1024];
# lfs_file_open(&lfs, &file, "avacado",
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
# uint32_t prng = 1;
# for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
# for (lfs_size_t b = 0; b < chunk; b++) {
# buffer[b] = TEST_PRNG(&prng) & 0xff;
# }
# lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
# }
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#
# // read
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
# lfs_file_size(&lfs, &file) => SIZE1;
# prng = 1;
# for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
# lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
# for (lfs_size_t b = 0; b < chunk; b++) {
# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
# }
# }
# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#
# // append
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_APPEND) => 0;
# prng = 2;
# for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
# for (lfs_size_t b = 0; b < chunk; b++) {
# buffer[b] = TEST_PRNG(&prng) & 0xff;
# }
# lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
# }
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#
# // read
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
# lfs_file_size(&lfs, &file) => SIZE1 + SIZE2;
# prng = 1;
# for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
# lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
# for (lfs_size_t b = 0; b < chunk; b++) {
# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
# }
# }
# prng = 2;
# for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
# lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
# for (lfs_size_t b = 0; b < chunk; b++) {
# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
# }
# }
# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_files_truncate]
#defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
#defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
#defines.CHUNKSIZE = [31, 16, 1]
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
#
# // write
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_t file;
# uint8_t buffer[1024];
# lfs_file_open(&lfs, &file, "avacado",
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
# uint32_t prng = 1;
# for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
# for (lfs_size_t b = 0; b < chunk; b++) {
# buffer[b] = TEST_PRNG(&prng) & 0xff;
# }
# lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
# }
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#
# // read
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
# lfs_file_size(&lfs, &file) => SIZE1;
# prng = 1;
# for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i);
# lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
# for (lfs_size_t b = 0; b < chunk; b++) {
# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
# }
# }
# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#
# // truncate
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_TRUNC) => 0;
# prng = 2;
# for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
# for (lfs_size_t b = 0; b < chunk; b++) {
# buffer[b] = TEST_PRNG(&prng) & 0xff;
# }
# lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
# }
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#
# // read
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
# lfs_file_size(&lfs, &file) => SIZE2;
# prng = 2;
# for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i);
# lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
# for (lfs_size_t b = 0; b < chunk; b++) {
# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
# }
# }
# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_files_reentrant_write]
#defines.SIZE = [32, 0, 7, 2049]
#defines.CHUNKSIZE = [31, 16, 65]
#reentrant = true
#code = '''
# lfs_t lfs;
# int err = lfs_mount(&lfs, cfg);
# if (err) {
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# }
#
# lfs_file_t file;
# uint8_t buffer[1024];
# err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY);
# assert(err == LFS_ERR_NOENT || err == 0);
# if (err == 0) {
# // can only be 0 (new file) or full size
# lfs_size_t size = lfs_file_size(&lfs, &file);
# assert(size == 0 || size == SIZE);
# lfs_file_close(&lfs, &file) => 0;
# }
#
# // write
# lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_CREAT) => 0;
# uint32_t prng = 1;
# for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
# for (lfs_size_t b = 0; b < chunk; b++) {
# buffer[b] = TEST_PRNG(&prng) & 0xff;
# }
# lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
# }
# lfs_file_close(&lfs, &file) => 0;
#
# // read
# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
# lfs_file_size(&lfs, &file) => SIZE;
# prng = 1;
# for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
# lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
# for (lfs_size_t b = 0; b < chunk; b++) {
# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
# }
# }
# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_files_reentrant_write_sync]
#defines = [
# # append (O(n))
# {MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]},
# # truncate (O(n^2))
# {MODE='LFS_O_TRUNC', SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]},
# # rewrite (O(n^2))
# {MODE=0, SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]},
#]
#reentrant = true
#code = '''
# lfs_t lfs;
# int err = lfs_mount(&lfs, cfg);
# if (err) {
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# }
#
# lfs_file_t file;
# uint8_t buffer[1024];
# err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY);
# assert(err == LFS_ERR_NOENT || err == 0);
# if (err == 0) {
# // with syncs we could be any size, but it at least must be valid data
# lfs_size_t size = lfs_file_size(&lfs, &file);
# assert(size <= SIZE);
# uint32_t prng = 1;
# for (lfs_size_t i = 0; i < size; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, size-i);
# lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
# for (lfs_size_t b = 0; b < chunk; b++) {
# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
# }
# }
# lfs_file_close(&lfs, &file) => 0;
# }
#
# // write
# lfs_file_open(&lfs, &file, "avacado",
# LFS_O_WRONLY | LFS_O_CREAT | MODE) => 0;
# lfs_size_t size = lfs_file_size(&lfs, &file);
# assert(size <= SIZE);
# uint32_t prng = 1;
# lfs_size_t skip = (MODE == LFS_O_APPEND) ? size : 0;
# for (lfs_size_t b = 0; b < skip; b++) {
# TEST_PRNG(&prng);
# }
# for (lfs_size_t i = skip; i < SIZE; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
# for (lfs_size_t b = 0; b < chunk; b++) {
# buffer[b] = TEST_PRNG(&prng) & 0xff;
# }
# lfs_file_write(&lfs, &file, buffer, chunk) => chunk;
# lfs_file_sync(&lfs, &file) => 0;
# }
# lfs_file_close(&lfs, &file) => 0;
#
# // read
# lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
# lfs_file_size(&lfs, &file) => SIZE;
# prng = 1;
# for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
# lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
# lfs_file_read(&lfs, &file, buffer, chunk) => chunk;
# for (lfs_size_t b = 0; b < chunk; b++) {
# assert(buffer[b] == (TEST_PRNG(&prng) & 0xff));
# }
# }
# lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0;
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_files_many]
#defines.N = 300
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
# // create N files of 7 bytes
# lfs_mount(&lfs, cfg) => 0;
# for (int i = 0; i < N; i++) {
# lfs_file_t file;
# char path[1024];
# sprintf(path, "file_%03d", i);
# lfs_file_open(&lfs, &file, path,
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
# char wbuffer[1024];
# lfs_size_t size = 7;
# sprintf(wbuffer, "Hi %03d", i);
# lfs_file_write(&lfs, &file, wbuffer, size) => size;
# lfs_file_close(&lfs, &file) => 0;
#
# char rbuffer[1024];
# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
# lfs_file_read(&lfs, &file, rbuffer, size) => size;
# assert(strcmp(rbuffer, wbuffer) == 0);
# lfs_file_close(&lfs, &file) => 0;
# }
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_files_many_power_cycle]
#defines.N = 300
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
# // create N files of 7 bytes
# lfs_mount(&lfs, cfg) => 0;
# for (int i = 0; i < N; i++) {
# lfs_file_t file;
# char path[1024];
# sprintf(path, "file_%03d", i);
# lfs_file_open(&lfs, &file, path,
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
# char wbuffer[1024];
# lfs_size_t size = 7;
# sprintf(wbuffer, "Hi %03d", i);
# lfs_file_write(&lfs, &file, wbuffer, size) => size;
# lfs_file_close(&lfs, &file) => 0;
# lfs_unmount(&lfs) => 0;
#
# char rbuffer[1024];
# lfs_mount(&lfs, cfg) => 0;
# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
# lfs_file_read(&lfs, &file, rbuffer, size) => size;
# assert(strcmp(rbuffer, wbuffer) == 0);
# lfs_file_close(&lfs, &file) => 0;
# }
# lfs_unmount(&lfs) => 0;
#'''
#
#[cases.test_files_many_power_loss]
#defines.N = 300
#reentrant = true
#code = '''
# lfs_t lfs;
# int err = lfs_mount(&lfs, cfg);
# if (err) {
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# }
# // create N files of 7 bytes
# for (int i = 0; i < N; i++) {
# lfs_file_t file;
# char path[1024];
# sprintf(path, "file_%03d", i);
# err = lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT);
# char wbuffer[1024];
# lfs_size_t size = 7;
# sprintf(wbuffer, "Hi %03d", i);
# if ((lfs_size_t)lfs_file_size(&lfs, &file) != size) {
# lfs_file_write(&lfs, &file, wbuffer, size) => size;
# }
# lfs_file_close(&lfs, &file) => 0;
#
# char rbuffer[1024];
# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
# lfs_file_read(&lfs, &file, rbuffer, size) => size;
# assert(strcmp(rbuffer, wbuffer) == 0);
# lfs_file_close(&lfs, &file) => 0;
# }
# lfs_unmount(&lfs) => 0;
#'''