Files
littlefs/tests/test_kv.toml
T
Christopher Haster 1f824a029b Renamed LFS3_T_COMPACT -> LFS3_T_COMPACTMETA (and gc_compactmeta_thresh)
- LFS3_T_COMPACT -> LFS3_T_COMPACTMETA
- gc_compact_thresh -> gc_compactmeta_thresh

And friends:

  LFS3_M_COMPACTMETA   0x00000800  Compact metadata logs
  LFS3_GC_COMPACTMETA  0x00000800  Compact metadata logs
  LFS3_I_COMPACTMETA   0x00000800  Filesystem may have uncompacted metadata
  LFS3_T_COMPACTMETA   0x00000800  Compact metadata logs

---

This does two things:

1. Highlights that LFS3_T_COMPACTMETA only interacts with metadata logs,
   and has no effect on data blocks.

2. Better matches the verb+noun names used for other gc/traversal flags
   (REPOPGBMAP, CKMETA, etc).

It is a bit more of a mouthful, but I'm not sure that's entirely a bad
thing. These are pretty low-level flags.
2025-10-23 23:54:57 -05:00

1601 lines
52 KiB
TOML

# Tests over the simple key-value API
after = ['test_files', 'test_fsync', 'test_stickynotes']
## General set/get tests
# test some simple kv operations
[cases.test_kv_set]
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// create some kv files
const char *a = "One 18.25 ounce package chocolate cake mix.";
lfs3_set(&lfs3, "a", a, strlen(a)) => 0;
const char *b = "One can prepared coconut pecan frosting.";
lfs3_set(&lfs3, "b", b, strlen(b)) => 0;
const char *c = "Three slash four cup vegetable oil.";
lfs3_set(&lfs3, "c", c, strlen(c)) => 0;
for (int remount = 0; remount < 2; remount++) {
// remount?
if (remount) {
lfs3_unmount(&lfs3) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
}
// try getting the file sizes
lfs3_size(&lfs3, "a") => strlen(a);
lfs3_size(&lfs3, "b") => strlen(b);
lfs3_size(&lfs3, "c") => strlen(c);
// try reading the files
uint8_t rbuf[256];
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf)) => strlen(a);
assert(memcmp(rbuf, a, strlen(a)) == 0);
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf)) => strlen(b);
assert(memcmp(rbuf, b, strlen(b)) == 0);
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf)) => strlen(c);
assert(memcmp(rbuf, c, strlen(c)) == 0);
}
lfs3_unmount(&lfs3) => 0;
'''
# test truncated get calls still work
[cases.test_kv_set_trunc]
defines.BUFSIZE = [1, 4, 7]
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// create some kv files
const char *a = "One 18.25 ounce package chocolate cake mix.";
lfs3_set(&lfs3, "a", a, strlen(a)) => 0;
const char *b = "One can prepared coconut pecan frosting.";
lfs3_set(&lfs3, "b", b, strlen(b)) => 0;
const char *c = "Three slash four cup vegetable oil.";
lfs3_set(&lfs3, "c", c, strlen(c)) => 0;
for (int remount = 0; remount < 2; remount++) {
// remount?
if (remount) {
lfs3_unmount(&lfs3) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
}
// try getting the file sizes
lfs3_size(&lfs3, "a") => strlen(a);
lfs3_size(&lfs3, "b") => strlen(b);
lfs3_size(&lfs3, "c") => strlen(c);
// mark rbuf so we can detect overflow
uint8_t rbuf[256];
rbuf[BUFSIZE] = '!';
// try reading truncated files
lfs3_get(&lfs3, "a", rbuf, BUFSIZE) => BUFSIZE;
assert(memcmp(rbuf, a, BUFSIZE) == 0);
assert(rbuf[BUFSIZE] == '!');
lfs3_get(&lfs3, "b", rbuf, BUFSIZE) => BUFSIZE;
assert(memcmp(rbuf, b, BUFSIZE) == 0);
assert(rbuf[BUFSIZE] == '!');
lfs3_get(&lfs3, "c", rbuf, BUFSIZE) => BUFSIZE;
assert(memcmp(rbuf, c, BUFSIZE) == 0);
assert(rbuf[BUFSIZE] == '!');
// try reading the full files
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf)) => strlen(a);
assert(memcmp(rbuf, a, strlen(a)) == 0);
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf)) => strlen(b);
assert(memcmp(rbuf, b, strlen(b)) == 0);
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf)) => strlen(c);
assert(memcmp(rbuf, c, strlen(c)) == 0);
}
lfs3_unmount(&lfs3) => 0;
'''
# test ENOENT works
[cases.test_kv_set_noent]
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// try getting the file sizes
lfs3_size(&lfs3, "a") => LFS3_ERR_NOENT;
lfs3_size(&lfs3, "b") => LFS3_ERR_NOENT;
lfs3_size(&lfs3, "c") => LFS3_ERR_NOENT;
// try reading files
uint8_t rbuf[256];
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf)) => LFS3_ERR_NOENT;
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf)) => LFS3_ERR_NOENT;
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf)) => LFS3_ERR_NOENT;
lfs3_unmount(&lfs3) => 0;
'''
# test that updating kv files works
[cases.test_kv_set_update]
# update based on this mask
defines.MASK = 'range(0x8)'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// create some kv files
const char *a = "One 18.25 ounce package chocolate cake mix.";
lfs3_set(&lfs3, "a", a, strlen(a)) => 0;
const char *b = "One can prepared coconut pecan frosting.";
lfs3_set(&lfs3, "b", b, strlen(b)) => 0;
const char *c = "Three slash four cup vegetable oil.";
lfs3_set(&lfs3, "c", c, strlen(c)) => 0;
// rewrite some kv files
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
if (MASK & 0x1) {
lfs3_set(&lfs3, "a", a_, strlen(a_)) => 0;
}
const char *b_ = "Three slash four cup butter or margarine.";
if (MASK & 0x2) {
lfs3_set(&lfs3, "b", b_, strlen(b_)) => 0;
}
const char *c_ = "One and two third cups granulated sugar.";
if (MASK & 0x4) {
lfs3_set(&lfs3, "c", c_, strlen(c_)) => 0;
}
for (int remount = 0; remount < 2; remount++) {
// remount?
if (remount) {
lfs3_unmount(&lfs3) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
}
// try getting the file sizes
if (MASK & 0x1) {
lfs3_size(&lfs3, "a") => strlen(a_);
} else {
lfs3_size(&lfs3, "a") => strlen(a);
}
if (MASK & 0x2) {
lfs3_size(&lfs3, "b") => strlen(b_);
} else {
lfs3_size(&lfs3, "b") => strlen(b);
}
if (MASK & 0x4) {
lfs3_size(&lfs3, "c") => strlen(c_);
} else {
lfs3_size(&lfs3, "c") => strlen(c);
}
// try reading files
uint8_t rbuf[256];
if (MASK & 0x1) {
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf)) => strlen(a_);
assert(memcmp(rbuf, a_, strlen(a_)) == 0);
} else {
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf)) => strlen(a);
assert(memcmp(rbuf, a, strlen(a)) == 0);
}
if (MASK & 0x2) {
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf)) => strlen(b_);
assert(memcmp(rbuf, b_, strlen(b_)) == 0);
} else {
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf)) => strlen(b);
assert(memcmp(rbuf, b, strlen(b)) == 0);
}
if (MASK & 0x4) {
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf)) => strlen(c_);
assert(memcmp(rbuf, c_, strlen(c_)) == 0);
} else {
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf)) => strlen(c);
assert(memcmp(rbuf, c, strlen(c)) == 0);
}
}
lfs3_unmount(&lfs3) => 0;
'''
# test removing simple kv files
#
# surprise! this is the normal file remove function
#
[cases.test_kv_remove]
# remove based on this mask
defines.MASK = 'range(0x8)'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// create some kv files
const char *a = "One 18.25 ounce package chocolate cake mix.";
lfs3_set(&lfs3, "a", a, strlen(a)) => 0;
const char *b = "One can prepared coconut pecan frosting.";
lfs3_set(&lfs3, "b", b, strlen(b)) => 0;
const char *c = "Three slash four cup vegetable oil.";
lfs3_set(&lfs3, "c", c, strlen(c)) => 0;
// remove some kv files
if (MASK & 0x1) {
lfs3_remove(&lfs3, "a") => 0;
}
if (MASK & 0x2) {
lfs3_remove(&lfs3, "b") => 0;
}
if (MASK & 0x4) {
lfs3_remove(&lfs3, "c") => 0;
}
for (int remount = 0; remount < 2; remount++) {
// remount?
if (remount) {
lfs3_unmount(&lfs3) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
}
// try getting the file sizes
if (MASK & 0x1) {
lfs3_size(&lfs3, "a") => LFS3_ERR_NOENT;
} else {
lfs3_size(&lfs3, "a") => strlen(a);
}
if (MASK & 0x2) {
lfs3_size(&lfs3, "b") => LFS3_ERR_NOENT;
} else {
lfs3_size(&lfs3, "b") => strlen(b);
}
if (MASK & 0x4) {
lfs3_size(&lfs3, "c") => LFS3_ERR_NOENT;
} else {
lfs3_size(&lfs3, "c") => strlen(c);
}
// try reading the full files
uint8_t rbuf[256];
if (MASK & 0x1) {
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf))
=> LFS3_ERR_NOENT;
} else {
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf))
=> strlen(a);
assert(memcmp(rbuf, a, strlen(a)) == 0);
}
if (MASK & 0x2) {
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf))
=> LFS3_ERR_NOENT;
} else {
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf))
=> strlen(b);
assert(memcmp(rbuf, b, strlen(b)) == 0);
}
if (MASK & 0x4) {
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf))
=> LFS3_ERR_NOENT;
} else {
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf))
=> strlen(c);
assert(memcmp(rbuf, c, strlen(c)) == 0);
}
}
lfs3_unmount(&lfs3) => 0;
'''
# test setting a file to zero size
#
# this is _not_ the same as removing
#
[cases.test_kv_set_zero]
# zero based on this mask
defines.MASK = 'range(0x8)'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// create some kv files
const char *a = "One 18.25 ounce package chocolate cake mix.";
lfs3_set(&lfs3, "a", a, strlen(a)) => 0;
const char *b = "One can prepared coconut pecan frosting.";
lfs3_set(&lfs3, "b", b, strlen(b)) => 0;
const char *c = "Three slash four cup vegetable oil.";
lfs3_set(&lfs3, "c", c, strlen(c)) => 0;
// set zero some kv files
if (MASK & 0x1) {
lfs3_set(&lfs3, "a", (const uint8_t*)1, 0) => 0;
}
if (MASK & 0x2) {
lfs3_set(&lfs3, "b", (const uint8_t*)1, 0) => 0;
}
if (MASK & 0x4) {
lfs3_set(&lfs3, "c", (const uint8_t*)1, 0) => 0;
}
for (int remount = 0; remount < 2; remount++) {
// remount?
if (remount) {
lfs3_unmount(&lfs3) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
}
// try getting the file sizes
if (MASK & 0x1) {
lfs3_size(&lfs3, "a") => 0;
} else {
lfs3_size(&lfs3, "a") => strlen(a);
}
if (MASK & 0x2) {
lfs3_size(&lfs3, "b") => 0;
} else {
lfs3_size(&lfs3, "b") => strlen(b);
}
if (MASK & 0x4) {
lfs3_size(&lfs3, "c") => 0;
} else {
lfs3_size(&lfs3, "c") => strlen(c);
}
// try reading the full files
uint8_t rbuf[256];
if (MASK & 0x1) {
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf))
=> 0;
} else {
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf))
=> strlen(a);
assert(memcmp(rbuf, a, strlen(a)) == 0);
}
if (MASK & 0x2) {
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf))
=> 0;
} else {
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf))
=> strlen(b);
assert(memcmp(rbuf, b, strlen(b)) == 0);
}
if (MASK & 0x4) {
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf))
=> 0;
} else {
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf))
=> strlen(c);
assert(memcmp(rbuf, c, strlen(c)) == 0);
}
}
lfs3_unmount(&lfs3) => 0;
'''
# test setting a file to zero size + null
#
# this can trip up naive internal logic
#
[cases.test_kv_set_null]
# zero based on this mask
defines.MASK = 'range(0x8)'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// create some kv files
const char *a = "One 18.25 ounce package chocolate cake mix.";
lfs3_set(&lfs3, "a", a, strlen(a)) => 0;
const char *b = "One can prepared coconut pecan frosting.";
lfs3_set(&lfs3, "b", b, strlen(b)) => 0;
const char *c = "Three slash four cup vegetable oil.";
lfs3_set(&lfs3, "c", c, strlen(c)) => 0;
// set zero some kv files
if (MASK & 0x1) {
lfs3_set(&lfs3, "a", NULL, 0) => 0;
}
if (MASK & 0x2) {
lfs3_set(&lfs3, "b", NULL, 0) => 0;
}
if (MASK & 0x4) {
lfs3_set(&lfs3, "c", NULL, 0) => 0;
}
for (int remount = 0; remount < 2; remount++) {
// remount?
if (remount) {
lfs3_unmount(&lfs3) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
}
// try getting the file sizes
if (MASK & 0x1) {
lfs3_size(&lfs3, "a") => 0;
} else {
lfs3_size(&lfs3, "a") => strlen(a);
}
if (MASK & 0x2) {
lfs3_size(&lfs3, "b") => 0;
} else {
lfs3_size(&lfs3, "b") => strlen(b);
}
if (MASK & 0x4) {
lfs3_size(&lfs3, "c") => 0;
} else {
lfs3_size(&lfs3, "c") => strlen(c);
}
// try reading the full files
uint8_t rbuf[256];
if (MASK & 0x1) {
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf))
=> 0;
} else {
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf))
=> strlen(a);
assert(memcmp(rbuf, a, strlen(a)) == 0);
}
if (MASK & 0x2) {
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf))
=> 0;
} else {
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf))
=> strlen(b);
assert(memcmp(rbuf, b, strlen(b)) == 0);
}
if (MASK & 0x4) {
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf))
=> 0;
} else {
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf))
=> strlen(c);
assert(memcmp(rbuf, c, strlen(c)) == 0);
}
}
lfs3_unmount(&lfs3) => 0;
'''
# test creating a bunch of kv files
[cases.test_kv_many]
defines.N = [40, 400]
defines.SIZE = 4
defines.COMPACTMETA = [false, true]
defines.GC_FLAGS = 'LFS3_GC_COMPACTMETA'
defines.GC_STEPS = -1
defines.GC_COMPACTMETA_THRESH = 'BLOCK_SIZE/2'
if = 'LFS3_IFDEF_GC(true, !COMPACTMETA)'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// create N kv files
uint32_t prng = 42;
for (lfs3_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "key%03x", i);
uint8_t wbuf[SIZE];
for (lfs3_size_t j = 0; j < SIZE; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfs3_set(&lfs3, name, wbuf, SIZE) => 0;
}
// try compacting?
#ifdef LFS3_GC
if (COMPACTMETA) {
lfs3_fs_gc(&lfs3) => 0;
}
#endif
for (int remount = 0; remount < 2; remount++) {
// remount?
if (remount) {
lfs3_unmount(&lfs3) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
}
// try getting the file sizes
for (lfs3_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "key%03x", i);
lfs3_size(&lfs3, name) => SIZE;
}
// try reading the files
prng = 42;
for (lfs3_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "key%03x", i);
uint8_t wbuf[SIZE];
for (lfs3_size_t j = 0; j < SIZE; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
}
uint8_t rbuf[256];
lfs3_get(&lfs3, name, rbuf, sizeof(rbuf)) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
}
}
lfs3_unmount(&lfs3) => 0;
'''
# fuzz kv files
[cases.test_kv_fuzz]
defines.N = 10
defines.SIZE = 4
defines.OPS = ['4*N', '40*N']
defines.SEED = 'range(20)'
fuzz = 'SEED'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// set up a simulation to compare against
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
memset(sim_prngs, 0, N*sizeof(uint32_t));
uint32_t prng = SEED;
for (lfs3_size_t i = 0; i < OPS; i++) {
// choose which operation to do
uint8_t op = TEST_PRNG(&prng) % 2;
// create a kv file?
if (op == 0) {
// choose a kv file
lfs3_size_t x = TEST_PRNG(&prng) % N;
// choose a prng
uint32_t wprng = TEST_PRNG(&prng);
// create the file
char name[256];
sprintf(name, "key%03x", x);
uint32_t wprng_ = wprng;
uint8_t wbuf[SIZE];
for (lfs3_size_t j = 0; j < SIZE; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfs3_set(&lfs3, name, wbuf, SIZE) => 0;
// update our sim
sim_prngs[x] = wprng;
// remove a kv file?
} else if (op == 1) {
// choose a kv file
lfs3_size_t x = TEST_PRNG(&prng) % N;
// remove the file
char name[256];
sprintf(name, "key%03x", x);
if (sim_prngs[x]) {
lfs3_remove(&lfs3, name) => 0;
} else {
lfs3_remove(&lfs3, name) => LFS3_ERR_NOENT;
}
// update our sim
sim_prngs[x] = 0;
}
}
for (int remount = 0; remount < 2; remount++) {
// remount?
if (remount) {
lfs3_unmount(&lfs3) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
}
// try getting each file size
for (lfs3_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "key%03x", j);
if (sim_prngs[j]) {
lfs3_size(&lfs3, name) => SIZE;
} else {
lfs3_size(&lfs3, name) => LFS3_ERR_NOENT;
}
}
// try reading each file
for (lfs3_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "key%03x", j);
if (sim_prngs[j]) {
uint32_t wprng_ = sim_prngs[j];
uint8_t wbuf[SIZE];
for (lfs3_size_t i = 0; i < SIZE; i++) {
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
uint8_t rbuf[256];
lfs3_get(&lfs3, name, rbuf, sizeof(rbuf)) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
} else {
uint8_t rbuf[256];
lfs3_get(&lfs3, name, rbuf, sizeof(rbuf))
=> LFS3_ERR_NOENT;
}
}
}
// clean up sim/lfs3
free(sim_prngs);
lfs3_unmount(&lfs3) => 0;
'''
# test creating a bunch of kv files
[cases.test_kv_many_big]
defines.N = 40
# size is more an upper limit here
defines.SIZE = 40000
defines.COMPACTMETA = [false, true]
defines.GC_FLAGS = 'LFS3_GC_COMPACTMETA'
defines.GC_STEPS = -1
defines.GC_COMPACTMETA_THRESH = 'BLOCK_SIZE/2'
if = 'LFS3_IFDEF_GC(true, !COMPACTMETA)'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// create N kv files
uint32_t prng = 42;
for (lfs3_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "key%03x", i);
// choose a random size, bias towards zero
lfs3_off_t size = lfs3_abs(
(TEST_PRNG(&prng) % SIZE)
+ (TEST_PRNG(&prng) % SIZE)
- SIZE);
uint8_t wbuf[SIZE];
for (lfs3_size_t j = 0; j < size; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
}
lfs3_set(&lfs3, name, wbuf, size) => 0;
}
// try compacting?
#ifdef LFS3_GC
if (COMPACTMETA) {
lfs3_fs_gc(&lfs3) => 0;
}
#endif
for (int remount = 0; remount < 2; remount++) {
// remount?
if (remount) {
lfs3_unmount(&lfs3) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
}
// try getting the file sizes
prng = 42;
for (lfs3_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "key%03x", i);
lfs3_off_t size = lfs3_abs(
(TEST_PRNG(&prng) % SIZE)
+ (TEST_PRNG(&prng) % SIZE)
- SIZE);
for (lfs3_size_t j = 0; j < size; j++) {
TEST_PRNG(&prng);
}
lfs3_size(&lfs3, name) => size;
}
// try reading the files
prng = 42;
for (lfs3_size_t i = 0; i < N; i++) {
char name[256];
sprintf(name, "key%03x", i);
lfs3_off_t size = lfs3_abs(
(TEST_PRNG(&prng) % SIZE)
+ (TEST_PRNG(&prng) % SIZE)
- SIZE);
uint8_t wbuf[SIZE];
for (lfs3_size_t j = 0; j < size; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&prng) % 26);
}
uint8_t rbuf[SIZE];
lfs3_get(&lfs3, name, rbuf, sizeof(rbuf)) => size;
assert(memcmp(rbuf, wbuf, size) == 0);
}
}
lfs3_unmount(&lfs3) => 0;
'''
# fuzz kv files
[cases.test_kv_fuzz_big]
defines.N = 10
# size is more an upper limit here
defines.SIZE = 40000
defines.OPS = ['4*N', '40*N']
defines.SEED = 'range(20)'
fuzz = 'SEED'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// set up a simulation to compare against
lfs3_off_t *sim_sizes = malloc(N*sizeof(lfs3_off_t));
memset(sim_sizes, 0, N*sizeof(lfs3_off_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
memset(sim_prngs, 0, N*sizeof(uint32_t));
uint32_t prng = SEED;
for (lfs3_size_t i = 0; i < OPS; i++) {
// choose which operation to do
uint8_t op = TEST_PRNG(&prng) % 2;
// create a kv file?
if (op == 0) {
// choose a kv file
lfs3_size_t x = TEST_PRNG(&prng) % N;
// choose a size, bias towards zero
lfs3_off_t size = lfs3_abs(
(TEST_PRNG(&prng) % SIZE)
+ (TEST_PRNG(&prng) % SIZE)
- SIZE);
// choose a prng
uint32_t wprng = TEST_PRNG(&prng);
// create the file
char name[256];
sprintf(name, "key%03x", x);
uint32_t wprng_ = wprng;
uint8_t wbuf[SIZE];
for (lfs3_size_t j = 0; j < size; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfs3_set(&lfs3, name, wbuf, size) => 0;
// update our sim
sim_sizes[x] = size;
sim_prngs[x] = wprng;
// remove a kv file?
} else if (op == 1) {
// choose a kv file
lfs3_size_t x = TEST_PRNG(&prng) % N;
// remove the file
char name[256];
sprintf(name, "key%03x", x);
if (sim_prngs[x]) {
lfs3_remove(&lfs3, name) => 0;
} else {
lfs3_remove(&lfs3, name) => LFS3_ERR_NOENT;
}
// update our sim
sim_prngs[x] = 0;
}
}
for (int remount = 0; remount < 2; remount++) {
// remount?
if (remount) {
lfs3_unmount(&lfs3) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
}
// try getting each file size
for (lfs3_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "key%03x", j);
if (sim_prngs[j]) {
lfs3_size(&lfs3, name) => sim_sizes[j];
} else {
lfs3_size(&lfs3, name) => LFS3_ERR_NOENT;
}
}
// try reading each file
for (lfs3_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "key%03x", j);
if (sim_prngs[j]) {
uint32_t wprng_ = sim_prngs[j];
uint8_t wbuf[SIZE];
for (lfs3_size_t i = 0; i < sim_sizes[j]; i++) {
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
uint8_t rbuf[SIZE];
lfs3_get(&lfs3, name, rbuf, sizeof(rbuf)) => sim_sizes[j];
assert(memcmp(rbuf, wbuf, sim_sizes[j]) == 0);
} else {
uint8_t rbuf[SIZE];
lfs3_get(&lfs3, name, rbuf, sizeof(rbuf))
=> LFS3_ERR_NOENT;
}
}
}
// clean up sim/lfs3
free(sim_sizes);
free(sim_prngs);
lfs3_unmount(&lfs3) => 0;
'''
# test kv files can be read as normal files
[cases.test_kv_interop_reads]
ifndef = 'LFS3_KVONLY'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// create some kv files
const char *a = "One 18.25 ounce package chocolate cake mix.";
lfs3_set(&lfs3, "a", a, strlen(a)) => 0;
const char *b = "One can prepared coconut pecan frosting.";
lfs3_set(&lfs3, "b", b, strlen(b)) => 0;
const char *c = "Three slash four cup vegetable oil.";
lfs3_set(&lfs3, "c", c, strlen(c)) => 0;
for (int remount = 0; remount < 2; remount++) {
// remount?
if (remount) {
lfs3_unmount(&lfs3) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
}
// try getting the file sizes
lfs3_size(&lfs3, "a") => strlen(a);
lfs3_size(&lfs3, "b") => strlen(b);
lfs3_size(&lfs3, "c") => strlen(c);
// try reading the files
uint8_t rbuf[256];
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf)) => strlen(a);
assert(memcmp(rbuf, a, strlen(a)) == 0);
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf)) => strlen(b);
assert(memcmp(rbuf, b, strlen(b)) == 0);
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf)) => strlen(c);
assert(memcmp(rbuf, c, strlen(c)) == 0);
// check our files with stat
struct lfs3_info info;
lfs3_stat(&lfs3, "a", &info) => 0;
assert(strcmp(info.name, "a") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(a));
lfs3_stat(&lfs3, "b", &info) => 0;
assert(strcmp(info.name, "b") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(b));
lfs3_stat(&lfs3, "c", &info) => 0;
assert(strcmp(info.name, "c") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(c));
// and with dir read
lfs3_dir_t dir;
lfs3_dir_open(&lfs3, &dir, "/") => 0;
lfs3_dir_read(&lfs3, &dir, &info) => 0;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS3_TYPE_DIR);
assert(info.size == 0);
lfs3_dir_read(&lfs3, &dir, &info) => 0;
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS3_TYPE_DIR);
assert(info.size == 0);
lfs3_dir_read(&lfs3, &dir, &info) => 0;
assert(strcmp(info.name, "a") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(a));
lfs3_dir_read(&lfs3, &dir, &info) => 0;
assert(strcmp(info.name, "b") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(b));
lfs3_dir_read(&lfs3, &dir, &info) => 0;
assert(strcmp(info.name, "c") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(c));
lfs3_dir_read(&lfs3, &dir, &info) => LFS3_ERR_NOENT;
lfs3_dir_close(&lfs3, &dir) => 0;
// try reading our files
lfs3_file_t file_a;
lfs3_file_t file_b;
lfs3_file_t file_c;
lfs3_file_open(&lfs3, &file_a, "a", LFS3_O_RDONLY) => 0;
lfs3_file_open(&lfs3, &file_b, "b", LFS3_O_RDONLY) => 0;
lfs3_file_open(&lfs3, &file_c, "c", LFS3_O_RDONLY) => 0;
// is size correct?
lfs3_file_size(&lfs3, &file_a) => strlen(a);
lfs3_file_size(&lfs3, &file_b) => strlen(b);
lfs3_file_size(&lfs3, &file_c) => strlen(c);
// try reading
lfs3_file_read(&lfs3, &file_a, rbuf, sizeof(rbuf)) => strlen(a);
assert(memcmp(rbuf, a, strlen(a)) == 0);
lfs3_file_read(&lfs3, &file_b, rbuf, sizeof(rbuf)) => strlen(b);
assert(memcmp(rbuf, b, strlen(b)) == 0);
lfs3_file_read(&lfs3, &file_c, rbuf, sizeof(rbuf)) => strlen(c);
assert(memcmp(rbuf, c, strlen(c)) == 0);
lfs3_file_close(&lfs3, &file_a) => 0;
lfs3_file_close(&lfs3, &file_b) => 0;
lfs3_file_close(&lfs3, &file_c) => 0;
}
lfs3_unmount(&lfs3) => 0;
'''
# test normal files can be read a kv files
[cases.test_kv_interop_writes]
ifndef = 'LFS3_KVONLY'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// create some kv files
const char *a = "One 18.25 ounce package chocolate cake mix.";
lfs3_file_t file_a;
lfs3_file_open(&lfs3, &file_a, "a",
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
lfs3_file_write(&lfs3, &file_a, a, strlen(a)) => strlen(a);
lfs3_file_close(&lfs3, &file_a) => 0;
const char *b = "One can prepared coconut pecan frosting.";
lfs3_file_t file_b;
lfs3_file_open(&lfs3, &file_b, "b",
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
lfs3_file_write(&lfs3, &file_b, b, strlen(b)) => strlen(b);
lfs3_file_close(&lfs3, &file_b) => 0;
const char *c = "Three slash four cup vegetable oil.";
lfs3_file_t file_c;
lfs3_file_open(&lfs3, &file_c, "c",
LFS3_O_WRONLY | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
lfs3_file_write(&lfs3, &file_c, c, strlen(c)) => strlen(c);
lfs3_file_close(&lfs3, &file_c) => 0;
for (int remount = 0; remount < 2; remount++) {
// remount?
if (remount) {
lfs3_unmount(&lfs3) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
}
// try getting the file sizes
lfs3_size(&lfs3, "a") => strlen(a);
lfs3_size(&lfs3, "b") => strlen(b);
lfs3_size(&lfs3, "c") => strlen(c);
// try reading the files
uint8_t rbuf[256];
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf)) => strlen(a);
assert(memcmp(rbuf, a, strlen(a)) == 0);
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf)) => strlen(b);
assert(memcmp(rbuf, b, strlen(b)) == 0);
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf)) => strlen(c);
assert(memcmp(rbuf, c, strlen(c)) == 0);
}
lfs3_unmount(&lfs3) => 0;
'''
# test kv files broadcast sync updates
[cases.test_kv_interop_sync]
defines.STICKYNOTES = [false, true]
ifndef = 'LFS3_KVONLY'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// open some files
const char *a = "One 18.25 ounce package chocolate cake mix.";
lfs3_file_t file_a;
lfs3_file_open(&lfs3, &file_a, "a",
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
lfs3_file_write(&lfs3, &file_a, a, strlen(a)) => strlen(a);
const char *b = "One can prepared coconut pecan frosting.";
lfs3_file_t file_b;
lfs3_file_open(&lfs3, &file_b, "b",
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
lfs3_file_write(&lfs3, &file_b, b, strlen(b)) => strlen(b);
const char *c = "Three slash four cup vegetable oil.";
lfs3_file_t file_c;
lfs3_file_open(&lfs3, &file_c, "c",
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL) => 0;
lfs3_file_write(&lfs3, &file_c, c, strlen(c)) => strlen(c);
// sync to create if creating
if (!STICKYNOTES) {
lfs3_file_sync(&lfs3, &file_a) => 0;
lfs3_file_sync(&lfs3, &file_b) => 0;
lfs3_file_sync(&lfs3, &file_c) => 0;
}
// set the new values
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
lfs3_set(&lfs3, "a", a_, strlen(a_)) => 0;
const char *b_ = "Three slash four cup butter or margarine.";
lfs3_set(&lfs3, "b", b_, strlen(b_)) => 0;
const char *c_ = "One and two third cups granulated sugar.";
lfs3_set(&lfs3, "c", c_, strlen(c_)) => 0;
// files should have been created
struct lfs3_info info;
lfs3_stat(&lfs3, "a", &info) => 0;
assert(strcmp(info.name, "a") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(a_));
lfs3_stat(&lfs3, "b", &info) => 0;
assert(strcmp(info.name, "b") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(b_));
lfs3_stat(&lfs3, "c", &info) => 0;
assert(strcmp(info.name, "c") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(c_));
// try getting the file sizes
lfs3_size(&lfs3, "a") => strlen(a_);
lfs3_size(&lfs3, "b") => strlen(b_);
lfs3_size(&lfs3, "c") => strlen(c_);
// try reading files
uint8_t rbuf[256];
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf)) => strlen(a_);
assert(memcmp(rbuf, a_, strlen(a_)) == 0);
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf)) => strlen(b_);
assert(memcmp(rbuf, b_, strlen(b_)) == 0);
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf)) => strlen(c_);
assert(memcmp(rbuf, c_, strlen(c_)) == 0);
// opened files should be updated
lfs3_file_rewind(&lfs3, &file_a) => 0;
lfs3_file_read(&lfs3, &file_a, rbuf, sizeof(rbuf)) => strlen(a_);
assert(memcmp(rbuf, a_, strlen(a_)) == 0);
lfs3_file_rewind(&lfs3, &file_b) => 0;
lfs3_file_read(&lfs3, &file_b, rbuf, sizeof(rbuf)) => strlen(b_);
assert(memcmp(rbuf, b_, strlen(b_)) == 0);
lfs3_file_rewind(&lfs3, &file_c) => 0;
lfs3_file_read(&lfs3, &file_c, rbuf, sizeof(rbuf)) => strlen(c_);
assert(memcmp(rbuf, c_, strlen(c_)) == 0);
lfs3_file_close(&lfs3, &file_a) => 0;
lfs3_file_close(&lfs3, &file_b) => 0;
lfs3_file_close(&lfs3, &file_c) => 0;
lfs3_unmount(&lfs3) => 0;
'''
# test kv files don't interfere with desync files
[cases.test_kv_interop_desync]
defines.STICKYNOTES = [false, true]
ifndef = 'LFS3_KVONLY'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// open some files desync
const char *a = "One 18.25 ounce package chocolate cake mix.";
lfs3_file_t file_a;
lfs3_file_open(&lfs3, &file_a, "a",
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
lfs3_file_write(&lfs3, &file_a, a, strlen(a)) => strlen(a);
const char *b = "One can prepared coconut pecan frosting.";
lfs3_file_t file_b;
lfs3_file_open(&lfs3, &file_b, "b",
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
lfs3_file_write(&lfs3, &file_b, b, strlen(b)) => strlen(b);
const char *c = "Three slash four cup vegetable oil.";
lfs3_file_t file_c;
lfs3_file_open(&lfs3, &file_c, "c",
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
lfs3_file_write(&lfs3, &file_c, c, strlen(c)) => strlen(c);
// sync to create if creating
if (!STICKYNOTES) {
lfs3_file_sync(&lfs3, &file_a) => 0;
lfs3_file_sync(&lfs3, &file_b) => 0;
lfs3_file_sync(&lfs3, &file_c) => 0;
// but then desync again!
lfs3_file_desync(&lfs3, &file_a) => 0;
lfs3_file_desync(&lfs3, &file_b) => 0;
lfs3_file_desync(&lfs3, &file_c) => 0;
}
// set the new values
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
lfs3_set(&lfs3, "a", a_, strlen(a_)) => 0;
const char *b_ = "Three slash four cup butter or margarine.";
lfs3_set(&lfs3, "b", b_, strlen(b_)) => 0;
const char *c_ = "One and two third cups granulated sugar.";
lfs3_set(&lfs3, "c", c_, strlen(c_)) => 0;
// files should have been created
struct lfs3_info info;
lfs3_stat(&lfs3, "a", &info) => 0;
assert(strcmp(info.name, "a") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(a_));
lfs3_stat(&lfs3, "b", &info) => 0;
assert(strcmp(info.name, "b") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(b_));
lfs3_stat(&lfs3, "c", &info) => 0;
assert(strcmp(info.name, "c") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(c_));
// try getting the file sizes
lfs3_size(&lfs3, "a") => strlen(a_);
lfs3_size(&lfs3, "b") => strlen(b_);
lfs3_size(&lfs3, "c") => strlen(c_);
// try reading files
uint8_t rbuf[256];
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf)) => strlen(a_);
assert(memcmp(rbuf, a_, strlen(a_)) == 0);
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf)) => strlen(b_);
assert(memcmp(rbuf, b_, strlen(b_)) == 0);
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf)) => strlen(c_);
assert(memcmp(rbuf, c_, strlen(c_)) == 0);
// opened files should _not_ be updated
lfs3_file_rewind(&lfs3, &file_a) => 0;
lfs3_file_read(&lfs3, &file_a, rbuf, sizeof(rbuf)) => strlen(a);
assert(memcmp(rbuf, a, strlen(a)) == 0);
lfs3_file_rewind(&lfs3, &file_b) => 0;
lfs3_file_read(&lfs3, &file_b, rbuf, sizeof(rbuf)) => strlen(b);
assert(memcmp(rbuf, b, strlen(b)) == 0);
lfs3_file_rewind(&lfs3, &file_c) => 0;
lfs3_file_read(&lfs3, &file_c, rbuf, sizeof(rbuf)) => strlen(c);
assert(memcmp(rbuf, c, strlen(c)) == 0);
lfs3_file_close(&lfs3, &file_a) => 0;
lfs3_file_close(&lfs3, &file_b) => 0;
lfs3_file_close(&lfs3, &file_c) => 0;
lfs3_unmount(&lfs3) => 0;
'''
# test kv files work with resyncing files
[cases.test_kv_interop_resync]
defines.STICKYNOTES = [false, true]
ifndef = 'LFS3_KVONLY'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// open some files desync
const char *a = "One 18.25 ounce package chocolate cake mix.";
lfs3_file_t file_a;
lfs3_file_open(&lfs3, &file_a, "a",
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
lfs3_file_write(&lfs3, &file_a, a, strlen(a)) => strlen(a);
const char *b = "One can prepared coconut pecan frosting.";
lfs3_file_t file_b;
lfs3_file_open(&lfs3, &file_b, "b",
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
lfs3_file_write(&lfs3, &file_b, b, strlen(b)) => strlen(b);
const char *c = "Three slash four cup vegetable oil.";
lfs3_file_t file_c;
lfs3_file_open(&lfs3, &file_c, "c",
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_EXCL | LFS3_O_DESYNC) => 0;
lfs3_file_write(&lfs3, &file_c, c, strlen(c)) => strlen(c);
// sync to create if creating
if (!STICKYNOTES) {
lfs3_file_sync(&lfs3, &file_a) => 0;
lfs3_file_sync(&lfs3, &file_b) => 0;
lfs3_file_sync(&lfs3, &file_c) => 0;
// but then desync again!
lfs3_file_desync(&lfs3, &file_a) => 0;
lfs3_file_desync(&lfs3, &file_b) => 0;
lfs3_file_desync(&lfs3, &file_c) => 0;
}
// set the new values
const char *a_ = "Four large eggs. One cup semi-sweet chocolate chips.";
lfs3_set(&lfs3, "a", a_, strlen(a_)) => 0;
const char *b_ = "Three slash four cup butter or margarine.";
lfs3_set(&lfs3, "b", b_, strlen(b_)) => 0;
const char *c_ = "One and two third cups granulated sugar.";
lfs3_set(&lfs3, "c", c_, strlen(c_)) => 0;
// files should have been created
struct lfs3_info info;
lfs3_stat(&lfs3, "a", &info) => 0;
assert(strcmp(info.name, "a") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(a_));
lfs3_stat(&lfs3, "b", &info) => 0;
assert(strcmp(info.name, "b") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(b_));
lfs3_stat(&lfs3, "c", &info) => 0;
assert(strcmp(info.name, "c") == 0);
assert(info.type == LFS3_TYPE_REG);
assert(info.size == strlen(c_));
// try getting the file sizes
lfs3_size(&lfs3, "a") => strlen(a_);
lfs3_size(&lfs3, "b") => strlen(b_);
lfs3_size(&lfs3, "c") => strlen(c_);
// try reading files
uint8_t rbuf[256];
lfs3_get(&lfs3, "a", rbuf, sizeof(rbuf)) => strlen(a_);
assert(memcmp(rbuf, a_, strlen(a_)) == 0);
lfs3_get(&lfs3, "b", rbuf, sizeof(rbuf)) => strlen(b_);
assert(memcmp(rbuf, b_, strlen(b_)) == 0);
lfs3_get(&lfs3, "c", rbuf, sizeof(rbuf)) => strlen(c_);
assert(memcmp(rbuf, c_, strlen(c_)) == 0);
// opened files should _not_ be updated
lfs3_file_rewind(&lfs3, &file_a) => 0;
lfs3_file_read(&lfs3, &file_a, rbuf, sizeof(rbuf)) => strlen(a);
assert(memcmp(rbuf, a, strlen(a)) == 0);
lfs3_file_rewind(&lfs3, &file_b) => 0;
lfs3_file_read(&lfs3, &file_b, rbuf, sizeof(rbuf)) => strlen(b);
assert(memcmp(rbuf, b, strlen(b)) == 0);
lfs3_file_rewind(&lfs3, &file_c) => 0;
lfs3_file_read(&lfs3, &file_c, rbuf, sizeof(rbuf)) => strlen(c);
assert(memcmp(rbuf, c, strlen(c)) == 0);
// but if we resync they should be updated
lfs3_file_resync(&lfs3, &file_a) => 0;
lfs3_file_resync(&lfs3, &file_b) => 0;
lfs3_file_resync(&lfs3, &file_c) => 0;
lfs3_file_rewind(&lfs3, &file_a) => 0;
lfs3_file_read(&lfs3, &file_a, rbuf, sizeof(rbuf)) => strlen(a_);
assert(memcmp(rbuf, a_, strlen(a_)) == 0);
lfs3_file_rewind(&lfs3, &file_b) => 0;
lfs3_file_read(&lfs3, &file_b, rbuf, sizeof(rbuf)) => strlen(b_);
assert(memcmp(rbuf, b_, strlen(b_)) == 0);
lfs3_file_rewind(&lfs3, &file_c) => 0;
lfs3_file_read(&lfs3, &file_c, rbuf, sizeof(rbuf)) => strlen(c_);
assert(memcmp(rbuf, c_, strlen(c_)) == 0);
lfs3_file_close(&lfs3, &file_a) => 0;
lfs3_file_close(&lfs3, &file_b) => 0;
lfs3_file_close(&lfs3, &file_c) => 0;
lfs3_unmount(&lfs3) => 0;
'''
# fuzz kv files and normal files
[cases.test_kv_interop_fuzz]
defines.STICKYNOTES = [false, true]
defines.N = 10
defines.SIZE = 4
defines.OPS = ['4*N', '40*N']
defines.SEED = 'range(20)'
fuzz = 'SEED'
ifndef = 'LFS3_KVONLY'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// set up a simulation to compare against
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
memset(sim_prngs, 0, N*sizeof(uint32_t));
// keep track of opened files
lfs3_file_t **sim_files = malloc(N*sizeof(lfs3_file_t*));
memset(sim_files, 0, N*sizeof(lfs3_file_t*));
uint32_t prng = SEED;
for (lfs3_size_t i = 0; i < OPS; i++) {
// choose which operation to do
uint8_t op = TEST_PRNG(&prng) % 3;
// create a kv file?
if (op == 0) {
// choose a kv file
lfs3_size_t x = TEST_PRNG(&prng) % N;
// choose a prng
uint32_t wprng = TEST_PRNG(&prng);
// create the file
char name[256];
sprintf(name, "key%03x", x);
uint32_t wprng_ = wprng;
uint8_t wbuf[SIZE];
for (lfs3_size_t j = 0; j < SIZE; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfs3_set(&lfs3, name, wbuf, SIZE) => 0;
// update our sim
sim_prngs[x] = wprng;
// remove a kv file?
} else if (op == 1) {
// choose a kv file
lfs3_size_t x = TEST_PRNG(&prng) % N;
// remove the file
char name[256];
sprintf(name, "key%03x", x);
if (sim_prngs[x]) {
lfs3_remove(&lfs3, name) => 0;
} else {
lfs3_remove(&lfs3, name) => LFS3_ERR_NOENT;
}
// update our sim
sim_prngs[x] = 0;
if (sim_files[x]) {
lfs3_file_close(&lfs3, sim_files[x]) => 0;
free(sim_files[x]);
}
sim_files[x] = NULL;
// open a normal file?
} else if (op == 2) {
// choose a file
lfs3_size_t x = TEST_PRNG(&prng) % N;
// choose a prng
uint32_t wprng = TEST_PRNG(&prng);
// close if open
if (sim_files[x]) {
lfs3_file_close(&lfs3, sim_files[x]) => 0;
free(sim_files[x]);
}
// create/open the file
sim_files[x] = malloc(sizeof(lfs3_file_t));
char name[256];
sprintf(name, "key%03x", x);
uint32_t wprng_ = wprng;
uint8_t wbuf[SIZE];
for (lfs3_size_t j = 0; j < SIZE; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfs3_file_open(&lfs3, sim_files[x], name,
LFS3_O_RDWR | LFS3_O_CREAT) => 0;
lfs3_file_write(&lfs3, sim_files[x], wbuf, SIZE) => SIZE;
lfs3_file_sync(&lfs3, sim_files[x]) => 0;
// update our sim
sim_prngs[x] = wprng;
}
}
// try getting each file size
for (lfs3_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "key%03x", j);
if (sim_prngs[j]) {
lfs3_size(&lfs3, name) => SIZE;
} else {
lfs3_size(&lfs3, name) => LFS3_ERR_NOENT;
}
}
// try reading each file
for (lfs3_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "key%03x", j);
if (sim_prngs[j]) {
uint32_t wprng_ = sim_prngs[j];
uint8_t wbuf[SIZE];
for (lfs3_size_t i = 0; i < SIZE; i++) {
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
uint8_t rbuf[256];
lfs3_get(&lfs3, name, rbuf, sizeof(rbuf)) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
} else {
uint8_t rbuf[256];
lfs3_get(&lfs3, name, rbuf, sizeof(rbuf))
=> LFS3_ERR_NOENT;
}
}
// try reading the opened file handles
for (lfs3_size_t j = 0; j < N; j++) {
if (sim_files[j]) {
lfs3_file_rewind(&lfs3, sim_files[j]) => 0;
uint32_t wprng_ = sim_prngs[j];
uint8_t wbuf[SIZE];
for (lfs3_size_t i = 0; i < SIZE; i++) {
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
uint8_t rbuf[256];
lfs3_file_read(&lfs3, sim_files[j], rbuf, sizeof(rbuf)) => SIZE;
assert(memcmp(rbuf, wbuf, SIZE) == 0);
}
}
// clean up sim/files
free(sim_prngs);
for (lfs3_size_t j = 0; j < N; j++) {
if (sim_files[j]) {
lfs3_file_close(&lfs3, sim_files[j]) => 0;
free(sim_files[j]);
}
}
free(sim_files);
lfs3_unmount(&lfs3) => 0;
'''
# fuzz kv files and normal files
[cases.test_kv_interop_fuzz_big]
defines.STICKYNOTES = [false, true]
defines.N = 10
# size is more an upper limit here
defines.SIZE = 40000
defines.OPS = ['4*N', '40*N']
defines.SEED = 'range(20)'
fuzz = 'SEED'
ifndef = 'LFS3_KVONLY'
code = '''
lfs3_t lfs3;
lfs3_format(&lfs3, LFS3_F_RDWR, CFG) => 0;
lfs3_mount(&lfs3, LFS3_M_RDWR, CFG) => 0;
// set up a simulation to compare against
lfs3_off_t *sim_sizes = malloc(N*sizeof(lfs3_off_t));
memset(sim_sizes, 0, N*sizeof(lfs3_off_t));
uint32_t *sim_prngs = malloc(N*sizeof(uint32_t));
memset(sim_prngs, 0, N*sizeof(uint32_t));
// keep track of opened files
lfs3_file_t **sim_files = malloc(N*sizeof(lfs3_file_t*));
memset(sim_files, 0, N*sizeof(lfs3_file_t*));
uint32_t prng = SEED;
for (lfs3_size_t i = 0; i < OPS; i++) {
// choose which operation to do
uint8_t op = TEST_PRNG(&prng) % 3;
// create a kv file?
if (op == 0) {
// choose a kv file
lfs3_size_t x = TEST_PRNG(&prng) % N;
// choose a size, bias towards zero
lfs3_off_t size = lfs3_abs(
(TEST_PRNG(&prng) % SIZE)
+ (TEST_PRNG(&prng) % SIZE)
- SIZE);
// choose a prng
uint32_t wprng = TEST_PRNG(&prng);
// create the file
char name[256];
sprintf(name, "key%03x", x);
uint32_t wprng_ = wprng;
uint8_t wbuf[SIZE];
for (lfs3_size_t j = 0; j < size; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfs3_set(&lfs3, name, wbuf, size) => 0;
// update our sim
sim_sizes[x] = size;
sim_prngs[x] = wprng;
// remove a kv file?
} else if (op == 1) {
// choose a kv file
lfs3_size_t x = TEST_PRNG(&prng) % N;
// remove the file
char name[256];
sprintf(name, "key%03x", x);
if (sim_prngs[x]) {
lfs3_remove(&lfs3, name) => 0;
} else {
lfs3_remove(&lfs3, name) => LFS3_ERR_NOENT;
}
// update our sim
sim_prngs[x] = 0;
if (sim_files[x]) {
lfs3_file_close(&lfs3, sim_files[x]) => 0;
free(sim_files[x]);
}
sim_files[x] = NULL;
// open a normal file?
} else if (op == 2) {
// choose a file
lfs3_size_t x = TEST_PRNG(&prng) % N;
// choose a size, bias towards zero
lfs3_off_t size = lfs3_abs(
(TEST_PRNG(&prng) % SIZE)
+ (TEST_PRNG(&prng) % SIZE)
- SIZE);
// choose a prng
uint32_t wprng = TEST_PRNG(&prng);
// close if open
if (sim_files[x]) {
lfs3_file_close(&lfs3, sim_files[x]) => 0;
free(sim_files[x]);
}
// create/open the file
sim_files[x] = malloc(sizeof(lfs3_file_t));
char name[256];
sprintf(name, "key%03x", x);
uint32_t wprng_ = wprng;
uint8_t wbuf[SIZE];
for (lfs3_size_t j = 0; j < size; j++) {
wbuf[j] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
lfs3_file_open(&lfs3, sim_files[x], name,
LFS3_O_RDWR | LFS3_O_CREAT | LFS3_O_TRUNC) => 0;
lfs3_file_write(&lfs3, sim_files[x], wbuf, size) => size;
lfs3_file_sync(&lfs3, sim_files[x]) => 0;
// update our sim
sim_sizes[x] = size;
sim_prngs[x] = wprng;
}
}
// try getting each file size
for (lfs3_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "key%03x", j);
if (sim_prngs[j]) {
lfs3_size(&lfs3, name) => sim_sizes[j];
} else {
lfs3_size(&lfs3, name) => LFS3_ERR_NOENT;
}
}
// try reading each file
for (lfs3_size_t j = 0; j < N; j++) {
char name[256];
sprintf(name, "key%03x", j);
if (sim_prngs[j]) {
uint32_t wprng_ = sim_prngs[j];
uint8_t wbuf[SIZE];
for (lfs3_size_t i = 0; i < sim_sizes[j]; i++) {
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
uint8_t rbuf[SIZE];
lfs3_get(&lfs3, name, rbuf, sizeof(rbuf)) => sim_sizes[j];
assert(memcmp(rbuf, wbuf, sim_sizes[j]) == 0);
} else {
uint8_t rbuf[SIZE];
lfs3_get(&lfs3, name, rbuf, sizeof(rbuf))
=> LFS3_ERR_NOENT;
}
}
// try reading the opened file handles
for (lfs3_size_t j = 0; j < N; j++) {
if (sim_files[j]) {
lfs3_file_rewind(&lfs3, sim_files[j]) => 0;
uint32_t wprng_ = sim_prngs[j];
uint8_t wbuf[SIZE];
for (lfs3_size_t i = 0; i < sim_sizes[j]; i++) {
wbuf[i] = 'a' + (TEST_PRNG(&wprng_) % 26);
}
uint8_t rbuf[SIZE];
lfs3_file_read(&lfs3, sim_files[j], rbuf, sizeof(rbuf))
=> sim_sizes[j];
assert(memcmp(rbuf, wbuf, sim_sizes[j]) == 0);
}
}
// clean up sim/files
free(sim_prngs);
for (lfs3_size_t j = 0; j < N; j++) {
if (sim_files[j]) {
lfs3_file_close(&lfs3, sim_files[j]) => 0;
free(sim_files[j]);
}
}
free(sim_files);
lfs3_unmount(&lfs3) => 0;
'''