Ported tests to new framework

This mostly required names for each test case, declarations of
previously-implicit variables since the new test framework is more
conservative with what it declares (the small extra effort to add
declarations is well worth the simplicity and improved readability),
and tweaks to work with not-really-constant defines.

Also renamed test_ -> test, replacing the old ./scripts/test.py,
unfortunately git seems to have had a hard time with this.
This commit is contained in:
Christopher Haster
2022-05-14 02:55:17 -05:00
parent d679fbb389
commit 0781f50edb
21 changed files with 2538 additions and 2818 deletions

View File

@@ -32,7 +32,7 @@ DEP := $(SRC:%.c=$(BUILDDIR)%.d)
ASM := $(SRC:%.c=$(BUILDDIR)%.s) ASM := $(SRC:%.c=$(BUILDDIR)%.s)
CGI := $(SRC:%.c=$(BUILDDIR)%.ci) CGI := $(SRC:%.c=$(BUILDDIR)%.ci)
TESTS ?= $(wildcard tests_/*.toml) TESTS ?= $(wildcard tests/*.toml)
TEST_SRC ?= $(SRC) \ TEST_SRC ?= $(SRC) \
$(filter-out $(wildcard bd/*.*.c),$(wildcard bd/*.c)) \ $(filter-out $(wildcard bd/*.*.c),$(wildcard bd/*.c)) \
runners/test_runner.c runners/test_runner.c
@@ -53,10 +53,11 @@ override CFLAGS += -g3
override CFLAGS += -I. override CFLAGS += -I.
override CFLAGS += -std=c99 -Wall -pedantic override CFLAGS += -std=c99 -Wall -pedantic
override CFLAGS += -Wextra -Wshadow -Wjump-misses-init -Wundef override CFLAGS += -Wextra -Wshadow -Wjump-misses-init -Wundef
override CFLAGS += -ftrack-macro-expansion=0
override TESTFLAGS_ += -b override TESTFLAGS += -b
# forward -j flag # forward -j flag
override TESTFLAGS_ += $(filter -j%,$(MAKEFLAGS)) override TESTFLAGS += $(filter -j%,$(MAKEFLAGS))
ifdef VERBOSE ifdef VERBOSE
override TESTFLAGS += -v override TESTFLAGS += -v
override CALLSFLAGS += -v override CALLSFLAGS += -v
@@ -65,15 +66,14 @@ override DATAFLAGS += -v
override STACKFLAGS += -v override STACKFLAGS += -v
override STRUCTSFLAGS += -v override STRUCTSFLAGS += -v
override COVERAGEFLAGS += -v override COVERAGEFLAGS += -v
override TESTFLAGS_ += -v override TESTFLAGS += -v
override TESTCFLAGS_ += -v override TESTCFLAGS += -v
endif endif
ifdef EXEC ifdef EXEC
override TESTFLAGS_ += --exec="$(EXEC)" override TESTFLAGS += --exec="$(EXEC)"
endif endif
ifdef COVERAGE ifdef COVERAGE
override TESTFLAGS += --coverage override TESTFLAGS += --coverage
override TESTFLAGS_ += --coverage
endif endif
ifdef BUILDDIR ifdef BUILDDIR
override TESTFLAGS += --build-dir="$(BUILDDIR:/=)" override TESTFLAGS += --build-dir="$(BUILDDIR:/=)"
@@ -112,23 +112,16 @@ tags:
calls: $(CGI) calls: $(CGI)
./scripts/calls.py $^ $(CALLSFLAGS) ./scripts/calls.py $^ $(CALLSFLAGS)
.PHONY: test
test:
./scripts/test.py $(TESTFLAGS)
.SECONDEXPANSION:
test%: tests/test$$(firstword $$(subst \#, ,%)).toml
./scripts/test.py $@ $(TESTFLAGS)
.PHONY: test_runner .PHONY: test_runner
test_runner: $(BUILDDIR)runners/test_runner test_runner: $(BUILDDIR)runners/test_runner
.PHONY: test_ .PHONY: test
test_: test_runner test: test_runner
./scripts/test_.py --runner=$(BUILDDIR)runners/test_runner $(TESTFLAGS_) ./scripts/test.py --runner=$(BUILDDIR)runners/test_runner $(TESTFLAGS)
.PHONY: test_list .PHONY: test_list
test_list: test_runner test_list: test_runner
./scripts/test_.py --runner=$(BUILDDIR)runners/test_runner $(TESTFLAGS_) -l ./scripts/test.py --runner=$(BUILDDIR)runners/test_runner $(TESTFLAGS) -l
.PHONY: code .PHONY: code
code: $(OBJ) code: $(OBJ)
@@ -199,10 +192,10 @@ $(BUILDDIR)%.a.c: $(BUILDDIR)%.c
./scripts/explode_asserts.py $< -o $@ ./scripts/explode_asserts.py $< -o $@
$(BUILDDIR)%.t.c: %.toml $(BUILDDIR)%.t.c: %.toml
./scripts/test_.py -c $< $(TESTCFLAGS_) -o $@ ./scripts/test.py -c $< $(TESTCFLAGS) -o $@
$(BUILDDIR)%.t.c: %.c $(TESTS) $(BUILDDIR)%.t.c: %.c $(TESTS)
./scripts/test_.py -c $(TESTS) -s $< $(TESTCFLAGS_) -o $@ ./scripts/test.py -c $(TESTS) -s $< $(TESTCFLAGS) -o $@
# clean everything # clean everything
.PHONY: clean .PHONY: clean
@@ -215,7 +208,6 @@ clean:
rm -f $(CGI) rm -f $(CGI)
rm -f $(DEP) rm -f $(DEP)
rm -f $(ASM) rm -f $(ASM)
rm -f $(BUILDDIR)tests/*.toml.*
rm -f $(TEST_TSRC) rm -f $(TEST_TSRC)
rm -f $(TEST_TASRC) rm -f $(TEST_TASRC)
rm -f $(TEST_TAOBJ) rm -f $(TEST_TAOBJ)

View File

@@ -10,17 +10,17 @@
// test geometries // test geometries
struct test_geometry { struct test_geometry {
const char *name; const char *name;
uintmax_t defines[TEST_GEOMETRY_DEFINE_COUNT]; intmax_t defines[TEST_GEOMETRY_DEFINE_COUNT];
}; };
const struct test_geometry test_geometries[TEST_GEOMETRY_COUNT] const struct test_geometry test_geometries[TEST_GEOMETRY_COUNT]
= TEST_GEOMETRIES; = TEST_GEOMETRIES;
// test define lookup and management // test define lookup and management
const uintmax_t *test_override_defines; const intmax_t *test_override_defines;
uintmax_t (*const *test_case_defines)(void); intmax_t (*const *test_case_defines)(void);
const uintmax_t *test_geometry_defines; const intmax_t *test_geometry_defines;
const uintmax_t test_default_defines[TEST_PREDEFINE_COUNT] const intmax_t test_default_defines[TEST_PREDEFINE_COUNT]
= TEST_DEFAULTS; = TEST_DEFAULTS;
uint8_t test_override_predefine_map[TEST_PREDEFINE_COUNT]; uint8_t test_override_predefine_map[TEST_PREDEFINE_COUNT];
@@ -37,7 +37,7 @@ const char *const *test_define_names;
size_t test_define_count; size_t test_define_count;
uintmax_t test_predefine(size_t define) { intmax_t test_predefine(size_t define) {
if (test_override_defines if (test_override_defines
&& test_override_predefine_map[define] != 0xff) { && test_override_predefine_map[define] != 0xff) {
return test_override_defines[test_override_predefine_map[define]]; return test_override_defines[test_override_predefine_map[define]];
@@ -52,7 +52,7 @@ uintmax_t test_predefine(size_t define) {
} }
} }
uintmax_t test_define(size_t define) { intmax_t test_define(size_t define) {
if (test_override_defines if (test_override_defines
&& test_override_define_map[define] != 0xff) { && test_override_define_map[define] != 0xff) {
return test_override_defines[test_override_define_map[define]]; return test_override_defines[test_override_define_map[define]];
@@ -73,7 +73,7 @@ static void test_define_geometry(const struct test_geometry *geometry) {
static void test_define_overrides( static void test_define_overrides(
const char *const *override_names, const char *const *override_names,
const uintmax_t *override_defines, const intmax_t *override_defines,
size_t override_count) { size_t override_count) {
test_override_defines = override_defines; test_override_defines = override_defines;
test_override_names = override_names; test_override_names = override_names;
@@ -583,7 +583,7 @@ int main(int argc, char **argv) {
void (*op)(void) = run; void (*op)(void) = run;
static const char **override_names = NULL; static const char **override_names = NULL;
static uintmax_t *override_defines = NULL; static intmax_t *override_defines = NULL;
static size_t override_count = 0; static size_t override_count = 0;
static size_t override_cap = 0; static size_t override_cap = 0;
@@ -685,10 +685,10 @@ int main(int argc, char **argv) {
override_names = realloc(override_names, override_cap override_names = realloc(override_names, override_cap
* sizeof(const char *)); * sizeof(const char *));
override_defines = realloc(override_defines, override_cap override_defines = realloc(override_defines, override_cap
* sizeof(uintmax_t)); * sizeof(intmax_t));
} }
// parse into string key/uintmax_t value, cannibalizing the // parse into string key/intmax_t value, cannibalizing the
// arg in the process // arg in the process
char *sep = strchr(optarg, '='); char *sep = strchr(optarg, '=');
char *parsed = NULL; char *parsed = NULL;

View File

@@ -19,7 +19,7 @@ struct test_case {
test_types_t types; test_types_t types;
size_t permutations; size_t permutations;
uintmax_t (*const *const *defines)(void); intmax_t (*const *const *defines)(void);
bool (*filter)(void); bool (*filter)(void);
void (*run)(struct lfs_config *cfg); void (*run)(struct lfs_config *cfg);
@@ -43,8 +43,8 @@ extern const size_t test_suite_count;
// access generated test defines // access generated test defines
uintmax_t test_predefine(size_t define); intmax_t test_predefine(size_t define);
uintmax_t test_define(size_t define); intmax_t test_define(size_t define);
// a few preconfigured defines that control how tests run // a few preconfigured defines that control how tests run
#define READ_SIZE test_predefine(0) #define READ_SIZE test_predefine(0)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,27 +1,30 @@
# allocator tests # allocator tests
# note for these to work there are a number constraints on the device geometry # note for these to work there are a number constraints on the device geometry
if = 'LFS_BLOCK_CYCLES == -1' if = 'BLOCK_CYCLES == -1'
[[case]] # parallel allocation test # parallel allocation test
define.FILES = 3 [cases.parallel_allocation]
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' defines.FILES = 3
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
code = ''' code = '''
const char *names[FILES] = {"bacon", "eggs", "pancakes"}; const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_file_t files[FILES]; lfs_file_t files[FILES];
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_open(&lfs, &files[n], path, lfs_file_open(&lfs, &files[n], path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
} }
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
size = strlen(names[n]); size_t size = strlen(names[n]);
for (lfs_size_t i = 0; i < SIZE; i += size) { for (lfs_size_t i = 0; i < SIZE; i += size) {
lfs_file_write(&lfs, &files[n], names[n], size) => size; lfs_file_write(&lfs, &files[n], names[n], size) => size;
} }
@@ -31,12 +34,15 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
size = strlen(names[n]); size_t size = strlen(names[n]);
for (lfs_size_t i = 0; i < SIZE; i += size) { for (lfs_size_t i = 0; i < SIZE; i += size) {
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, size) => size;
assert(memcmp(buffer, names[n], size) == 0); assert(memcmp(buffer, names[n], size) == 0);
} }
@@ -45,23 +51,28 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # serial allocation test # serial allocation test
define.FILES = 3 [cases.serial_allocation]
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' defines.FILES = 3
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
code = ''' code = '''
const char *names[FILES] = {"bacon", "eggs", "pancakes"}; const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
size = strlen(names[n]); size_t size = strlen(names[n]);
uint8_t buffer[1024];
memcpy(buffer, names[n], size); memcpy(buffer, names[n], size);
for (int i = 0; i < SIZE; i += size) { for (int i = 0; i < SIZE; i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
@@ -70,12 +81,15 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
} }
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
size = strlen(names[n]); size_t size = strlen(names[n]);
for (int i = 0; i < SIZE; i += size) { for (int i = 0; i < SIZE; i += size) {
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, size) => size;
assert(memcmp(buffer, names[n], size) == 0); assert(memcmp(buffer, names[n], size) == 0);
} }
@@ -84,29 +98,32 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # parallel allocation reuse test # parallel allocation reuse test
define.FILES = 3 [cases.parallel_allocation_reuse]
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' defines.FILES = 3
define.CYCLES = [1, 10] defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
defines.CYCLES = [1, 10]
code = ''' code = '''
const char *names[FILES] = {"bacon", "eggs", "pancakes"}; const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_file_t files[FILES]; lfs_file_t files[FILES];
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
for (int c = 0; c < CYCLES; c++) { for (int c = 0; c < CYCLES; c++) {
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_open(&lfs, &files[n], path, lfs_file_open(&lfs, &files[n], path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
} }
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
size = strlen(names[n]); size_t size = strlen(names[n]);
for (int i = 0; i < SIZE; i += size) { for (int i = 0; i < SIZE; i += size) {
lfs_file_write(&lfs, &files[n], names[n], size) => size; lfs_file_write(&lfs, &files[n], names[n], size) => size;
} }
@@ -116,12 +133,15 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
size = strlen(names[n]); size_t size = strlen(names[n]);
for (int i = 0; i < SIZE; i += size) { for (int i = 0; i < SIZE; i += size) {
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, size) => size;
assert(memcmp(buffer, names[n], size) == 0); assert(memcmp(buffer, names[n], size) == 0);
} }
@@ -129,8 +149,9 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
} }
@@ -139,26 +160,31 @@ code = '''
} }
''' '''
[[case]] # serial allocation reuse test # serial allocation reuse test
define.FILES = 3 [cases.serial_allocation_reuse]
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)' defines.FILES = 3
define.CYCLES = [1, 10] defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
defines.CYCLES = [1, 10]
code = ''' code = '''
const char *names[FILES] = {"bacon", "eggs", "pancakes"}; const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
for (int c = 0; c < CYCLES; c++) { for (int c = 0; c < CYCLES; c++) {
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0; lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
size = strlen(names[n]); size_t size = strlen(names[n]);
uint8_t buffer[1024];
memcpy(buffer, names[n], size); memcpy(buffer, names[n], size);
for (int i = 0; i < SIZE; i += size) { for (int i = 0; i < SIZE; i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
@@ -167,12 +193,15 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
} }
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
size = strlen(names[n]); size_t size = strlen(names[n]);
for (int i = 0; i < SIZE; i += size) { for (int i = 0; i < SIZE; i += size) {
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, size) => size;
assert(memcmp(buffer, names[n], size) == 0); assert(memcmp(buffer, names[n], size) == 0);
} }
@@ -180,8 +209,9 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) { for (int n = 0; n < FILES; n++) {
char path[1024];
sprintf(path, "breakfast/%s", names[n]); sprintf(path, "breakfast/%s", names[n]);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
} }
@@ -190,12 +220,16 @@ code = '''
} }
''' '''
[[case]] # exhaustion test # exhaustion test
[cases.exhaustion]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
size = strlen("exhaustion"); size_t size = strlen("exhaustion");
uint8_t buffer[1024];
memcpy(buffer, "exhaustion", size); memcpy(buffer, "exhaustion", size);
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
lfs_file_sync(&lfs, &file) => 0; lfs_file_sync(&lfs, &file) => 0;
@@ -216,7 +250,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
size = strlen("exhaustion"); size = strlen("exhaustion");
lfs_file_size(&lfs, &file) => size; lfs_file_size(&lfs, &file) => size;
@@ -226,14 +260,18 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # exhaustion wraparound test # exhaustion wraparound test
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / 3)' [cases.exhaustion_wraparound]
defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT);
size = strlen("buffering"); size_t size = strlen("buffering");
uint8_t buffer[1024];
memcpy(buffer, "buffering", size); memcpy(buffer, "buffering", size);
for (int i = 0; i < SIZE; i += size) { for (int i = 0; i < SIZE; i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
@@ -263,7 +301,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
size = strlen("exhaustion"); size = strlen("exhaustion");
lfs_file_size(&lfs, &file) => size; lfs_file_size(&lfs, &file) => size;
@@ -274,17 +312,22 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # dir exhaustion test # dir exhaustion test
[cases.dir_exhaustion]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// find out max file size // find out max file size
lfs_mkdir(&lfs, "exhaustiondir") => 0; lfs_mkdir(&lfs, "exhaustiondir") => 0;
size = strlen("blahblahblahblah"); size_t size = strlen("blahblahblahblah");
uint8_t buffer[1024];
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
lfs_file_t file;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
int count = 0; int count = 0;
int err;
while (true) { while (true) {
err = lfs_file_write(&lfs, &file, buffer, size); err = lfs_file_write(&lfs, &file, buffer, size);
if (err < 0) { if (err < 0) {
@@ -323,17 +366,21 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # what if we have a bad block during an allocation scan? # what if we have a bad block during an allocation scan?
[cases.bad_block_allocation]
in = "lfs.c" in = "lfs.c"
define.LFS_ERASE_CYCLES = 0xffffffff defines.ERASE_CYCLES = 0xffffffff
define.LFS_BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_READERROR' defines.BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_READERROR'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// first fill to exhaustion to find available space // first fill to exhaustion to find available space
lfs_file_t file;
lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "waka"); strcpy((char*)buffer, "waka");
size = strlen("waka"); size_t size = strlen("waka");
lfs_size_t filesize = 0; lfs_size_t filesize = 0;
while (true) { while (true) {
lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size); lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size);
@@ -345,7 +392,7 @@ code = '''
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
// now fill all but a couple of blocks of the filesystem with data // now fill all but a couple of blocks of the filesystem with data
filesize -= 3*LFS_BLOCK_SIZE; filesize -= 3*BLOCK_SIZE;
lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "pacman", LFS_O_WRONLY | LFS_O_CREAT) => 0;
strcpy((char*)buffer, "waka"); strcpy((char*)buffer, "waka");
size = strlen("waka"); size = strlen("waka");
@@ -358,11 +405,11 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// remount to force an alloc scan // remount to force an alloc scan
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
// but mark the head of our file as a "bad block", this is force our // but mark the head of our file as a "bad block", this is force our
// scan to bail early // scan to bail early
lfs_testbd_setwear(&cfg, fileblock, 0xffffffff) => 0; lfs_testbd_setwear(cfg, fileblock, 0xffffffff) => 0;
lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0;
strcpy((char*)buffer, "chomp"); strcpy((char*)buffer, "chomp");
size = strlen("chomp"); size = strlen("chomp");
@@ -377,7 +424,7 @@ code = '''
// now reverse the "bad block" and try to write the file again until we // now reverse the "bad block" and try to write the file again until we
// run out of space // run out of space
lfs_testbd_setwear(&cfg, fileblock, 0) => 0; lfs_testbd_setwear(cfg, fileblock, 0) => 0;
lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "ghost", LFS_O_WRONLY | LFS_O_CREAT) => 0;
strcpy((char*)buffer, "chomp"); strcpy((char*)buffer, "chomp");
size = strlen("chomp"); size = strlen("chomp");
@@ -393,7 +440,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// check that the disk isn't hurt // check that the disk isn't hurt
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "pacman", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "pacman", LFS_O_RDONLY) => 0;
strcpy((char*)buffer, "waka"); strcpy((char*)buffer, "waka");
size = strlen("waka"); size = strlen("waka");
@@ -411,24 +458,29 @@ code = '''
# on the geometry of the block device. But they are valuable. Eventually they # on the geometry of the block device. But they are valuable. Eventually they
# should be removed and replaced with generalized tests. # should be removed and replaced with generalized tests.
[[case]] # chained dir exhaustion test # chained dir exhaustion test
define.LFS_BLOCK_SIZE = 512 [cases.chained_dir_exhaustion]
define.LFS_BLOCK_COUNT = 1024 if = 'BLOCK_SIZE == 512'
if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' defines.BLOCK_COUNT = 1024
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// find out max file size // find out max file size
lfs_mkdir(&lfs, "exhaustiondir") => 0; lfs_mkdir(&lfs, "exhaustiondir") => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
char path[1024];
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, path) => 0;
} }
size = strlen("blahblahblahblah"); size_t size = strlen("blahblahblahblah");
uint8_t buffer[1024];
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
lfs_file_t file;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
int count = 0; int count = 0;
int err;
while (true) { while (true) {
err = lfs_file_write(&lfs, &file, buffer, size); err = lfs_file_write(&lfs, &file, buffer, size);
if (err < 0) { if (err < 0) {
@@ -443,6 +495,7 @@ code = '''
lfs_remove(&lfs, "exhaustion") => 0; lfs_remove(&lfs, "exhaustion") => 0;
lfs_remove(&lfs, "exhaustiondir") => 0; lfs_remove(&lfs, "exhaustiondir") => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
char path[1024];
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
} }
@@ -455,6 +508,7 @@ code = '''
lfs_file_sync(&lfs, &file) => 0; lfs_file_sync(&lfs, &file) => 0;
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
char path[1024];
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, path) => 0;
} }
@@ -482,27 +536,31 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # split dir test # split dir test
define.LFS_BLOCK_SIZE = 512 [cases.split_dir]
define.LFS_BLOCK_COUNT = 1024 if = 'BLOCK_SIZE == 512'
if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' defines.BLOCK_COUNT = 1024
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// create one block hole for half a directory // create one block hole for half a directory
lfs_file_t file;
lfs_file_open(&lfs, &file, "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "bump", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { for (lfs_size_t i = 0; i < cfg->block_size; i += 2) {
uint8_t buffer[1024];
memcpy(&buffer[i], "hi", 2); memcpy(&buffer[i], "hi", 2);
} }
lfs_file_write(&lfs, &file, buffer, cfg.block_size) => cfg.block_size; uint8_t buffer[1024];
lfs_file_write(&lfs, &file, buffer, cfg->block_size) => cfg->block_size;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
size = strlen("blahblahblahblah"); size_t size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < (cfg.block_count-4)*(cfg.block_size-8); i < (cfg->block_count-4)*(cfg->block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -510,7 +568,7 @@ code = '''
// remount to force reset of lookahead // remount to force reset of lookahead
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
// open hole // open hole
lfs_remove(&lfs, "bump") => 0; lfs_remove(&lfs, "bump") => 0;
@@ -518,30 +576,33 @@ code = '''
lfs_mkdir(&lfs, "splitdir") => 0; lfs_mkdir(&lfs, "splitdir") => 0;
lfs_file_open(&lfs, &file, "splitdir/bump", lfs_file_open(&lfs, &file, "splitdir/bump",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (lfs_size_t i = 0; i < cfg.block_size; i += 2) { for (lfs_size_t i = 0; i < cfg->block_size; i += 2) {
memcpy(&buffer[i], "hi", 2); memcpy(&buffer[i], "hi", 2);
} }
lfs_file_write(&lfs, &file, buffer, 2*cfg.block_size) => LFS_ERR_NOSPC; lfs_file_write(&lfs, &file, buffer, 2*cfg->block_size) => LFS_ERR_NOSPC;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # outdated lookahead test # outdated lookahead test
define.LFS_BLOCK_SIZE = 512 [cases.outdated_lookahead]
define.LFS_BLOCK_COUNT = 1024 if = 'BLOCK_SIZE == 512'
if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' defines.BLOCK_COUNT = 1024
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// fill completely with two files // fill completely with two files
lfs_file_t file;
lfs_file_open(&lfs, &file, "exhaustion1", lfs_file_open(&lfs, &file, "exhaustion1",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = strlen("blahblahblahblah"); size_t size = strlen("blahblahblahblah");
uint8_t buffer[1024];
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((cfg->block_count-2)/2)*(cfg->block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -552,7 +613,7 @@ code = '''
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -560,7 +621,7 @@ code = '''
// remount to force reset of lookahead // remount to force reset of lookahead
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
// rewrite one file // rewrite one file
lfs_file_open(&lfs, &file, "exhaustion1", lfs_file_open(&lfs, &file, "exhaustion1",
@@ -569,7 +630,7 @@ code = '''
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((cfg->block_count-2)/2)*(cfg->block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -583,7 +644,7 @@ code = '''
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -592,21 +653,24 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # outdated lookahead and split dir test # outdated lookahead and split dir test
define.LFS_BLOCK_SIZE = 512 [cases.outdated_lookahead_split_dir]
define.LFS_BLOCK_COUNT = 1024 if = 'BLOCK_SIZE == 512'
if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024' defines.BLOCK_COUNT = 1024
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// fill completely with two files // fill completely with two files
lfs_file_t file;
lfs_file_open(&lfs, &file, "exhaustion1", lfs_file_open(&lfs, &file, "exhaustion1",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = strlen("blahblahblahblah"); size_t size = strlen("blahblahblahblah");
uint8_t buffer[1024];
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2)*(cfg.block_size-8); i < ((cfg->block_count-2)/2)*(cfg->block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -617,7 +681,7 @@ code = '''
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2+1)/2)*(cfg.block_size-8); i < ((cfg->block_count-2+1)/2)*(cfg->block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -625,7 +689,7 @@ code = '''
// remount to force reset of lookahead // remount to force reset of lookahead
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
// rewrite one file with a hole of one block // rewrite one file with a hole of one block
lfs_file_open(&lfs, &file, "exhaustion1", lfs_file_open(&lfs, &file, "exhaustion1",
@@ -634,7 +698,7 @@ code = '''
size = strlen("blahblahblahblah"); size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size); memcpy(buffer, "blahblahblahblah", size);
for (lfs_size_t i = 0; for (lfs_size_t i = 0;
i < ((cfg.block_count-2)/2 - 1)*(cfg.block_size-8); i < ((cfg->block_count-2)/2 - 1)*(cfg->block_size-8);
i += size) { i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }

View File

@@ -1,14 +1,17 @@
[[case]] # set/get attribute [cases.get_set_attrs]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs_mkdir(&lfs, "hello") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file); lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
uint8_t buffer[1024];
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
lfs_setattr(&lfs, "hello", 'A', "aaaa", 4) => 0; lfs_setattr(&lfs, "hello", 'A', "aaaa", 4) => 0;
lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0; lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0;
@@ -60,7 +63,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4; lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9; lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9;
@@ -76,17 +79,20 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # set/get root attribute [cases.get_set_root_attrs]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs_mkdir(&lfs, "hello") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file); lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
uint8_t buffer[1024];
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
lfs_setattr(&lfs, "/", 'A', "aaaa", 4) => 0; lfs_setattr(&lfs, "/", 'A', "aaaa", 4) => 0;
lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0; lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0;
@@ -137,7 +143,7 @@ code = '''
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4; lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9; lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9;
@@ -153,17 +159,20 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # set/get file attribute [cases.get_set_file_attrs]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs_mkdir(&lfs, "hello") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file); lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
uint8_t buffer[1024];
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
struct lfs_attr attrs1[] = { struct lfs_attr attrs1[] = {
{'A', buffer, 4}, {'A', buffer, 4},
@@ -238,7 +247,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
struct lfs_attr attrs3[] = { struct lfs_attr attrs3[] = {
{'A', buffer, 4}, {'A', buffer, 4},
@@ -260,20 +269,23 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # deferred file attributes [cases.deferred_file_attrs]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs_mkdir(&lfs, "hello") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "hello/hello", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello"); lfs_file_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file); lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_setattr(&lfs, "hello/hello", 'B', "fffffffff", 9) => 0; lfs_setattr(&lfs, "hello/hello", 'B', "fffffffff", 9) => 0;
lfs_setattr(&lfs, "hello/hello", 'C', "ccccc", 5) => 0; lfs_setattr(&lfs, "hello/hello", 'C', "ccccc", 5) => 0;
uint8_t buffer[1024];
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
struct lfs_attr attrs1[] = { struct lfs_attr attrs1[] = {
{'B', "gggg", 4}, {'B', "gggg", 4},

View File

@@ -1,28 +1,30 @@
# bad blocks with block cycles should be tested in test_relocations # bad blocks with block cycles should be tested in test_relocations
if = 'LFS_BLOCK_CYCLES == -1' if = '(int32_t)BLOCK_CYCLES == -1'
[[case]] # single bad blocks [cases.single_bad_blocks]
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster defines.BLOCK_COUNT = 256 # small bd so test runs faster
define.LFS_ERASE_CYCLES = 0xffffffff defines.ERASE_CYCLES = 0xffffffff
define.LFS_ERASE_VALUE = [0x00, 0xff, -1] defines.ERASE_VALUE = [0x00, 0xff, -1]
define.LFS_BADBLOCK_BEHAVIOR = [ defines.BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR', 'LFS_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR', 'LFS_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR', 'LFS_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP', 'LFS_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP', 'LFS_TESTBD_BADBLOCK_ERASENOOP',
] ]
define.NAMEMULT = 64 defines.NAMEMULT = 64
define.FILEMULT = 1 defines.FILEMULT = 1
code = ''' code = '''
for (lfs_block_t badblock = 2; badblock < LFS_BLOCK_COUNT; badblock++) { for (lfs_block_t badblock = 2; badblock < BLOCK_COUNT; badblock++) {
lfs_testbd_setwear(&cfg, badblock-1, 0) => 0; lfs_testbd_setwear(cfg, badblock-1, 0) => 0;
lfs_testbd_setwear(&cfg, badblock, 0xffffffff) => 0; lfs_testbd_setwear(cfg, badblock, 0xffffffff) => 0;
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i; buffer[j] = '0'+i;
} }
@@ -34,10 +36,11 @@ code = '''
buffer[j+NAMEMULT+1] = '0'+i; buffer[j+NAMEMULT+1] = '0'+i;
} }
buffer[2*NAMEMULT+1] = '\0'; buffer[2*NAMEMULT+1] = '\0';
lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer, lfs_file_open(&lfs, &file, (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = NAMEMULT; lfs_size_t size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) { for (int j = 0; j < i*FILEMULT; j++) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -46,12 +49,14 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i; buffer[j] = '0'+i;
} }
buffer[NAMEMULT] = '\0'; buffer[NAMEMULT] = '\0';
struct lfs_info info;
lfs_stat(&lfs, (char*)buffer, &info) => 0; lfs_stat(&lfs, (char*)buffer, &info) => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
@@ -60,9 +65,10 @@ code = '''
buffer[j+NAMEMULT+1] = '0'+i; buffer[j+NAMEMULT+1] = '0'+i;
} }
buffer[2*NAMEMULT+1] = '\0'; buffer[2*NAMEMULT+1] = '\0';
lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
size = NAMEMULT; int size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) { for (int j = 0; j < i*FILEMULT; j++) {
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs_file_read(&lfs, &file, rbuffer, size) => size;
@@ -75,28 +81,30 @@ code = '''
} }
''' '''
[[case]] # region corruption (causes cascading failures) [cases.region_corruption] # (causes cascading failures)
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster defines.BLOCK_COUNT = 256 # small bd so test runs faster
define.LFS_ERASE_CYCLES = 0xffffffff defines.ERASE_CYCLES = 0xffffffff
define.LFS_ERASE_VALUE = [0x00, 0xff, -1] defines.ERASE_VALUE = [0x00, 0xff, -1]
define.LFS_BADBLOCK_BEHAVIOR = [ defines.BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR', 'LFS_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR', 'LFS_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR', 'LFS_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP', 'LFS_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP', 'LFS_TESTBD_BADBLOCK_ERASENOOP',
] ]
define.NAMEMULT = 64 defines.NAMEMULT = 64
define.FILEMULT = 1 defines.FILEMULT = 1
code = ''' code = '''
for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) { for (lfs_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) {
lfs_testbd_setwear(&cfg, i+2, 0xffffffff) => 0; lfs_testbd_setwear(cfg, i+2, 0xffffffff) => 0;
} }
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i; buffer[j] = '0'+i;
} }
@@ -108,10 +116,11 @@ code = '''
buffer[j+NAMEMULT+1] = '0'+i; buffer[j+NAMEMULT+1] = '0'+i;
} }
buffer[2*NAMEMULT+1] = '\0'; buffer[2*NAMEMULT+1] = '\0';
lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer, lfs_file_open(&lfs, &file, (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = NAMEMULT; lfs_size_t size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) { for (int j = 0; j < i*FILEMULT; j++) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -120,12 +129,14 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i; buffer[j] = '0'+i;
} }
buffer[NAMEMULT] = '\0'; buffer[NAMEMULT] = '\0';
struct lfs_info info;
lfs_stat(&lfs, (char*)buffer, &info) => 0; lfs_stat(&lfs, (char*)buffer, &info) => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
@@ -134,9 +145,10 @@ code = '''
buffer[j+NAMEMULT+1] = '0'+i; buffer[j+NAMEMULT+1] = '0'+i;
} }
buffer[2*NAMEMULT+1] = '\0'; buffer[2*NAMEMULT+1] = '\0';
lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
size = NAMEMULT; lfs_size_t size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) { for (int j = 0; j < i*FILEMULT; j++) {
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs_file_read(&lfs, &file, rbuffer, size) => size;
@@ -148,28 +160,30 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # alternating corruption (causes cascading failures) [cases.alternating_corruption] # (causes cascading failures)
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster defines.BLOCK_COUNT = 256 # small bd so test runs faster
define.LFS_ERASE_CYCLES = 0xffffffff defines.ERASE_CYCLES = 0xffffffff
define.LFS_ERASE_VALUE = [0x00, 0xff, -1] defines.ERASE_VALUE = [0x00, 0xff, -1]
define.LFS_BADBLOCK_BEHAVIOR = [ defines.BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR', 'LFS_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR', 'LFS_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR', 'LFS_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP', 'LFS_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP', 'LFS_TESTBD_BADBLOCK_ERASENOOP',
] ]
define.NAMEMULT = 64 defines.NAMEMULT = 64
define.FILEMULT = 1 defines.FILEMULT = 1
code = ''' code = '''
for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) { for (lfs_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) {
lfs_testbd_setwear(&cfg, (2*i) + 2, 0xffffffff) => 0; lfs_testbd_setwear(cfg, (2*i) + 2, 0xffffffff) => 0;
} }
lfs_format(&lfs, &cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i; buffer[j] = '0'+i;
} }
@@ -181,10 +195,11 @@ code = '''
buffer[j+NAMEMULT+1] = '0'+i; buffer[j+NAMEMULT+1] = '0'+i;
} }
buffer[2*NAMEMULT+1] = '\0'; buffer[2*NAMEMULT+1] = '\0';
lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer, lfs_file_open(&lfs, &file, (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
size = NAMEMULT; lfs_size_t size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) { for (int j = 0; j < i*FILEMULT; j++) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -193,12 +208,14 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) { for (int i = 1; i < 10; i++) {
uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) { for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i; buffer[j] = '0'+i;
} }
buffer[NAMEMULT] = '\0'; buffer[NAMEMULT] = '\0';
struct lfs_info info;
lfs_stat(&lfs, (char*)buffer, &info) => 0; lfs_stat(&lfs, (char*)buffer, &info) => 0;
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
@@ -207,9 +224,10 @@ code = '''
buffer[j+NAMEMULT+1] = '0'+i; buffer[j+NAMEMULT+1] = '0'+i;
} }
buffer[2*NAMEMULT+1] = '\0'; buffer[2*NAMEMULT+1] = '\0';
lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
size = NAMEMULT; lfs_size_t size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) { for (int j = 0; j < i*FILEMULT; j++) {
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs_file_read(&lfs, &file, rbuffer, size) => size;
@@ -222,10 +240,10 @@ code = '''
''' '''
# other corner cases # other corner cases
[[case]] # bad superblocks (corrupt 1 or 0) [cases.bad_superblocks] # (corrupt 1 or 0)
define.LFS_ERASE_CYCLES = 0xffffffff defines.ERASE_CYCLES = 0xffffffff
define.LFS_ERASE_VALUE = [0x00, 0xff, -1] defines.ERASE_VALUE = [0x00, 0xff, -1]
define.LFS_BADBLOCK_BEHAVIOR = [ defines.BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR', 'LFS_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR', 'LFS_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR', 'LFS_TESTBD_BADBLOCK_READERROR',
@@ -233,9 +251,10 @@ define.LFS_BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_ERASENOOP', 'LFS_TESTBD_BADBLOCK_ERASENOOP',
] ]
code = ''' code = '''
lfs_testbd_setwear(&cfg, 0, 0xffffffff) => 0; lfs_testbd_setwear(cfg, 0, 0xffffffff) => 0;
lfs_testbd_setwear(&cfg, 1, 0xffffffff) => 0; lfs_testbd_setwear(cfg, 1, 0xffffffff) => 0;
lfs_format(&lfs, &cfg) => LFS_ERR_NOSPC; lfs_t lfs;
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs_format(&lfs, cfg) => LFS_ERR_NOSPC;
lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
''' '''

View File

@@ -1,8 +1,11 @@
[[case]] # root [cases.root]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -14,20 +17,25 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # many directory creation [cases.many_dir_creation]
define.N = 'range(0, 100, 3)' defines.N = [3,6,9,12,21,33,57,66,72,93,99]
if = 'N < BLOCK_COUNT/2'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "dir%03d", i); sprintf(path, "dir%03d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, path) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -35,6 +43,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "dir%03d", i); sprintf(path, "dir%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -45,20 +54,25 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # many directory removal [cases.many_dir_removal]
define.N = 'range(3, 100, 11)' defines.N = [3,6,9,12,21,33,57,66,72,93,99]
if = 'N < BLOCK_COUNT/2'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "removeme%03d", i); sprintf(path, "removeme%03d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, path) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -66,6 +80,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "removeme%03d", i); sprintf(path, "removeme%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -75,14 +90,15 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "removeme%03d", i); sprintf(path, "removeme%03d", i);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
} }
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -95,20 +111,25 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # many directory rename [cases.many_dir_rename]
define.N = 'range(3, 100, 11)' defines.N = [3,6,9,12,21,33,57,66,72,93,99]
if = 'N < BLOCK_COUNT/2'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "test%03d", i); sprintf(path, "test%03d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, path) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -116,6 +137,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "test%03d", i); sprintf(path, "test%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -125,7 +147,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char oldpath[128]; char oldpath[128];
char newpath[128]; char newpath[128];
@@ -135,7 +157,7 @@ code = '''
} }
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -144,6 +166,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "tedd%03d", i); sprintf(path, "tedd%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -154,29 +177,34 @@ code = '''
lfs_unmount(&lfs); lfs_unmount(&lfs);
''' '''
[[case]] # reentrant many directory creation/rename/removal [cases.reentrant_many_dir]
define.N = [5, 11] defines.N = [5, 11]
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
} }
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "hi%03d", i); sprintf(path, "hi%03d", i);
err = lfs_mkdir(&lfs, path); err = lfs_mkdir(&lfs, path);
assert(err == 0 || err == LFS_ERR_EXIST); assert(err == 0 || err == LFS_ERR_EXIST);
} }
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "hello%03d", i); sprintf(path, "hello%03d", i);
err = lfs_remove(&lfs, path); err = lfs_remove(&lfs, path);
assert(err == 0 || err == LFS_ERR_NOENT); assert(err == 0 || err == LFS_ERR_NOENT);
} }
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -184,6 +212,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "hi%03d", i); sprintf(path, "hi%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -209,6 +238,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "hello%03d", i); sprintf(path, "hello%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -218,6 +248,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "hello%03d", i); sprintf(path, "hello%03d", i);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
} }
@@ -234,22 +265,28 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # file creation [cases.file_creation]
define.N = 'range(3, 100, 11)' defines.N = [3,6,9,12,21,33,57,66,72,93,99]
if = 'N < BLOCK_COUNT/2'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "file%03d", i); sprintf(path, "file%03d", i);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -257,6 +294,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "file%03d", i); sprintf(path, "file%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
@@ -267,22 +305,28 @@ code = '''
lfs_unmount(&lfs); lfs_unmount(&lfs);
''' '''
[[case]] # file removal [cases.file_removal]
define.N = 'range(0, 100, 3)' defines.N = [3,6,9,12,21,33,57,66,72,93,99]
if = 'N < BLOCK_COUNT/2'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "removeme%03d", i); sprintf(path, "removeme%03d", i);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -290,6 +334,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "removeme%03d", i); sprintf(path, "removeme%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
@@ -299,14 +344,15 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "removeme%03d", i); sprintf(path, "removeme%03d", i);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
} }
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -319,22 +365,28 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # file rename [cases.file_rename]
define.N = 'range(0, 100, 3)' defines.N = [3,6,9,12,21,33,57,66,72,93,99]
if = 'N < BLOCK_COUNT/2'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "test%03d", i); sprintf(path, "test%03d", i);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -342,6 +394,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "test%03d", i); sprintf(path, "test%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
@@ -351,7 +404,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char oldpath[128]; char oldpath[128];
char newpath[128]; char newpath[128];
@@ -361,7 +414,7 @@ code = '''
} }
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -370,6 +423,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "tedd%03d", i); sprintf(path, "tedd%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
@@ -380,29 +434,36 @@ code = '''
lfs_unmount(&lfs); lfs_unmount(&lfs);
''' '''
[[case]] # reentrant file creation/rename/removal [cases.reentrant_files]
define.N = [5, 25] defines.N = [5, 25]
if = 'N < BLOCK_COUNT/2'
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
} }
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "hi%03d", i); sprintf(path, "hi%03d", i);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
} }
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "hello%03d", i); sprintf(path, "hello%03d", i);
err = lfs_remove(&lfs, path); err = lfs_remove(&lfs, path);
assert(err == 0 || err == LFS_ERR_NOENT); assert(err == 0 || err == LFS_ERR_NOENT);
} }
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -410,6 +471,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "hi%03d", i); sprintf(path, "hi%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
@@ -435,6 +497,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "hello%03d", i); sprintf(path, "hello%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
@@ -444,6 +507,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "hello%03d", i); sprintf(path, "hello%03d", i);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
} }
@@ -460,24 +524,28 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # nested directories [cases.nested_dirs]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "potato") => 0; lfs_mkdir(&lfs, "potato") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "burito", lfs_file_open(&lfs, &file, "burito",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "potato/baked") => 0; lfs_mkdir(&lfs, "potato/baked") => 0;
lfs_mkdir(&lfs, "potato/sweet") => 0; lfs_mkdir(&lfs, "potato/sweet") => 0;
lfs_mkdir(&lfs, "potato/fried") => 0; lfs_mkdir(&lfs, "potato/fried") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "potato") => 0; lfs_dir_open(&lfs, &dir, "potato") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
info.type => LFS_TYPE_DIR; info.type => LFS_TYPE_DIR;
@@ -498,21 +566,21 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// try removing? // try removing?
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// try renaming? // try renaming?
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "potato", "coldpotato") => 0; lfs_rename(&lfs, "potato", "coldpotato") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "coldpotato", "warmpotato") => 0; lfs_rename(&lfs, "coldpotato", "warmpotato") => 0;
lfs_rename(&lfs, "warmpotato", "hotpotato") => 0; lfs_rename(&lfs, "warmpotato", "hotpotato") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_remove(&lfs, "potato") => LFS_ERR_NOENT; lfs_remove(&lfs, "potato") => LFS_ERR_NOENT;
lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT; lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT;
lfs_remove(&lfs, "warmpotato") => LFS_ERR_NOENT; lfs_remove(&lfs, "warmpotato") => LFS_ERR_NOENT;
@@ -520,7 +588,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// try cross-directory renaming // try cross-directory renaming
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "coldpotato") => 0; lfs_mkdir(&lfs, "coldpotato") => 0;
lfs_rename(&lfs, "hotpotato/baked", "coldpotato/baked") => 0; lfs_rename(&lfs, "hotpotato/baked", "coldpotato/baked") => 0;
lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY; lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY;
@@ -536,7 +604,7 @@ code = '''
lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "hotpotato") => 0; lfs_dir_open(&lfs, &dir, "hotpotato") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -558,7 +626,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// final remove // final remove
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
lfs_remove(&lfs, "hotpotato/baked") => 0; lfs_remove(&lfs, "hotpotato/baked") => 0;
lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
@@ -568,7 +636,7 @@ code = '''
lfs_remove(&lfs, "hotpotato") => 0; lfs_remove(&lfs, "hotpotato") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -584,17 +652,22 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # recursive remove [cases.recursive_remove]
define.N = [10, 100] defines.N = [10, 100]
if = 'N < BLOCK_COUNT/2'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "prickly-pear") => 0; lfs_mkdir(&lfs, "prickly-pear") => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "prickly-pear/cactus%03d", i); sprintf(path, "prickly-pear/cactus%03d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, path) => 0;
} }
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; lfs_dir_open(&lfs, &dir, "prickly-pear") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -602,6 +675,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "cactus%03d", i); sprintf(path, "cactus%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -611,7 +685,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs); lfs_unmount(&lfs);
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY; lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY;
lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; lfs_dir_open(&lfs, &dir, "prickly-pear") => 0;
@@ -622,6 +696,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
char path[1024];
sprintf(path, "cactus%03d", i); sprintf(path, "cactus%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -636,22 +711,24 @@ code = '''
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT; lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT; lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # other error cases [cases.other_errors]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "potato") => 0; lfs_mkdir(&lfs, "potato") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "burito", lfs_file_open(&lfs, &file, "burito",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST; lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST;
lfs_mkdir(&lfs, "burito") => LFS_ERR_EXIST; lfs_mkdir(&lfs, "burito") => LFS_ERR_EXIST;
@@ -659,6 +736,7 @@ code = '''
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST;
lfs_file_open(&lfs, &file, "potato", lfs_file_open(&lfs, &file, "potato",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; 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, "tomato") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir, "burito") => LFS_ERR_NOTDIR; 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, "tomato", LFS_O_RDONLY) => LFS_ERR_NOENT;
@@ -678,6 +756,7 @@ code = '''
// check that errors did not corrupt directory // check that errors did not corrupt directory
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -696,7 +775,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// or on disk // or on disk
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -715,21 +794,26 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # directory seek [cases.directory_seek]
define.COUNT = [4, 128, 132] defines.COUNT = [4, 128, 132]
if = 'COUNT < BLOCK_COUNT/2'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0; lfs_mkdir(&lfs, "hello") => 0;
for (int i = 0; i < COUNT; i++) { for (int i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "hello/kitty%03d", i); sprintf(path, "hello/kitty%03d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, path) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
for (int j = 2; j < COUNT; j++) { for (int j = 2; j < COUNT; j++) {
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "hello") => 0; lfs_dir_open(&lfs, &dir, "hello") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -739,6 +823,7 @@ code = '''
lfs_soff_t pos; lfs_soff_t pos;
for (int i = 0; i < j; i++) { for (int i = 0; i < j; i++) {
char path[1024];
sprintf(path, "kitty%03d", i); sprintf(path, "kitty%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0); assert(strcmp(info.name, path) == 0);
@@ -748,13 +833,14 @@ code = '''
} }
lfs_dir_seek(&lfs, &dir, pos) => 0; lfs_dir_seek(&lfs, &dir, pos) => 0;
char path[1024];
sprintf(path, "kitty%03d", j); sprintf(path, "kitty%03d", j);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0); assert(strcmp(info.name, path) == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
lfs_dir_rewind(&lfs, &dir) => 0; lfs_dir_rewind(&lfs, &dir) => 0;
sprintf(path, "kitty%03d", 0); sprintf(path, "kitty%03u", 0);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -776,20 +862,25 @@ code = '''
} }
''' '''
[[case]] # root seek [cases.root_seek]
define.COUNT = [4, 128, 132] defines.COUNT = [4, 128, 132]
if = 'COUNT < BLOCK_COUNT/2'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < COUNT; i++) { for (int i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "hi%03d", i); sprintf(path, "hi%03d", i);
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, path) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
for (int j = 2; j < COUNT; j++) { for (int j = 2; j < COUNT; j++) {
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -799,6 +890,7 @@ code = '''
lfs_soff_t pos; lfs_soff_t pos;
for (int i = 0; i < j; i++) { for (int i = 0; i < j; i++) {
char path[1024];
sprintf(path, "hi%03d", i); sprintf(path, "hi%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0); assert(strcmp(info.name, path) == 0);
@@ -808,13 +900,14 @@ code = '''
} }
lfs_dir_seek(&lfs, &dir, pos) => 0; lfs_dir_seek(&lfs, &dir, pos) => 0;
char path[1024];
sprintf(path, "hi%03d", j); sprintf(path, "hi%03d", j);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0); assert(strcmp(info.name, path) == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
lfs_dir_rewind(&lfs, &dir) => 0; lfs_dir_rewind(&lfs, &dir) => 0;
sprintf(path, "hi%03d", 0); sprintf(path, "hi%03u", 0);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);

View File

@@ -2,19 +2,23 @@
# Note that these tests are intended for 512 byte inline sizes. They should # Note that these tests are intended for 512 byte inline sizes. They should
# still pass with other inline sizes but wouldn't be testing anything. # still pass with other inline sizes but wouldn't be testing anything.
define.LFS_CACHE_SIZE = 512 defines.CACHE_SIZE = 512
if = 'LFS_CACHE_SIZE % LFS_PROG_SIZE == 0 && LFS_CACHE_SIZE == 512' if = 'CACHE_SIZE % PROG_SIZE == 0 && CACHE_SIZE == 512'
[[case]] # entry grow test [cases.entry_grow]
code = ''' code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// write hi0 20 // write hi0 20
char path[1024];
lfs_size_t size;
sprintf(path, "hi0"); size = 20; sprintf(path, "hi0"); size = 20;
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
@@ -94,16 +98,20 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # entry shrink test [cases.entry_shrink]
code = ''' code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// write hi0 20 // write hi0 20
char path[1024];
lfs_size_t size;
sprintf(path, "hi0"); size = 20; sprintf(path, "hi0"); size = 20;
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
@@ -183,16 +191,20 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # entry spill test [cases.entry_spill]
code = ''' code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// write hi0 200 // write hi0 200
char path[1024];
lfs_size_t size;
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
@@ -256,16 +268,20 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # entry push spill test [cases.entry_push_spill]
code = ''' code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// write hi0 200 // write hi0 200
char path[1024];
lfs_size_t size;
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
@@ -345,16 +361,20 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # entry push spill two test [cases.entry_push_spill_two]
code = ''' code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// write hi0 200 // write hi0 200
char path[1024];
lfs_size_t size;
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
@@ -449,16 +469,20 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # entry drop test [cases.entry_drop]
code = ''' code = '''
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
uint8_t rbuffer[1024]; uint8_t rbuffer[1024];
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// write hi0 200 // write hi0 200
char path[1024];
lfs_size_t size;
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size); memset(wbuffer, 'c', size);
@@ -491,6 +515,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_remove(&lfs, "hi1") => 0; lfs_remove(&lfs, "hi1") => 0;
struct lfs_info info;
lfs_stat(&lfs, "hi1", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "hi1", &info) => LFS_ERR_NOENT;
// read hi0 200 // read hi0 200
sprintf(path, "hi0"); size = 200; sprintf(path, "hi0"); size = 200;
@@ -547,15 +572,18 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # create too big [cases.create_too_big]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
char path[1024];
memset(path, 'm', 200); memset(path, 'm', 200);
path[200] = '\0'; path[200] = '\0';
size = 400; lfs_size_t size = 400;
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];
@@ -572,15 +600,18 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # resize too big [cases.resize_too_big]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
char path[1024];
memset(path, 'm', 200); memset(path, 'm', 200);
path[200] = '\0'; path[200] = '\0';
size = 40; lfs_size_t size = 40;
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
uint8_t wbuffer[1024]; uint8_t wbuffer[1024];

View File

@@ -3,16 +3,17 @@
# invalid pointer tests (outside of block_count) # invalid pointer tests (outside of block_count)
[[case]] # invalid tail-pointer test [cases.invalid_tail_pointer]
define.TAIL_TYPE = ['LFS_TYPE_HARDTAIL', 'LFS_TYPE_SOFTTAIL'] defines.TAIL_TYPE = ['LFS_TYPE_HARDTAIL', 'LFS_TYPE_SOFTTAIL']
define.INVALSET = [0x3, 0x1, 0x2] defines.INVALSET = [0x3, 0x1, 0x2]
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// change tail-pointer to invalid pointers // change tail-pointer to invalid pointers
lfs_init(&lfs, &cfg) => 0; lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
@@ -23,25 +24,27 @@ code = '''
lfs_deinit(&lfs) => 0; lfs_deinit(&lfs) => 0;
// test that mount fails gracefully // test that mount fails gracefully
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
''' '''
[[case]] # invalid dir pointer test [cases.invalid_dir_pointer]
define.INVALSET = [0x3, 0x1, 0x2] defines.INVALSET = [0x3, 0x1, 0x2]
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// make a dir // make a dir
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "dir_here") => 0; lfs_mkdir(&lfs, "dir_here") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// change the dir pointer to be invalid // change the dir pointer to be invalid
lfs_init(&lfs, &cfg) => 0; lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
// make sure id 1 == our directory // make sure id 1 == our directory
uint8_t buffer[1024];
lfs_dir_get(&lfs, &mdir, lfs_dir_get(&lfs, &mdir,
LFS_MKTAG(0x700, 0x3ff, 0), LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("dir_here")), buffer) LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("dir_here")), buffer)
@@ -57,14 +60,17 @@ code = '''
// test that accessing our bad dir fails, note there's a number // test that accessing our bad dir fails, note there's a number
// of ways to access the dir, some can fail, but some don't // of ways to access the dir, some can fail, but some don't
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "dir_here", &info) => 0; lfs_stat(&lfs, "dir_here", &info) => 0;
assert(strcmp(info.name, "dir_here") == 0); assert(strcmp(info.name, "dir_here") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "dir_here") => LFS_ERR_CORRUPT; lfs_dir_open(&lfs, &dir, "dir_here") => LFS_ERR_CORRUPT;
lfs_stat(&lfs, "dir_here/file_here", &info) => LFS_ERR_CORRUPT; lfs_stat(&lfs, "dir_here/file_here", &info) => LFS_ERR_CORRUPT;
lfs_dir_open(&lfs, &dir, "dir_here/dir_here") => LFS_ERR_CORRUPT; lfs_dir_open(&lfs, &dir, "dir_here/dir_here") => LFS_ERR_CORRUPT;
lfs_file_t file;
lfs_file_open(&lfs, &file, "dir_here/file_here", lfs_file_open(&lfs, &file, "dir_here/file_here",
LFS_O_RDONLY) => LFS_ERR_CORRUPT; LFS_O_RDONLY) => LFS_ERR_CORRUPT;
lfs_file_open(&lfs, &file, "dir_here/file_here", lfs_file_open(&lfs, &file, "dir_here/file_here",
@@ -72,24 +78,27 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # invalid file pointer test [cases.invalid_file_pointer]
in = "lfs.c" in = "lfs.c"
define.SIZE = [10, 1000, 100000] # faked file size defines.SIZE = [10, 1000, 100000] # faked file size
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// make a file // make a file
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "file_here", lfs_file_open(&lfs, &file, "file_here",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// change the file pointer to be invalid // change the file pointer to be invalid
lfs_init(&lfs, &cfg) => 0; lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
// make sure id 1 == our file // make sure id 1 == our file
uint8_t buffer[1024];
lfs_dir_get(&lfs, &mdir, lfs_dir_get(&lfs, &mdir,
LFS_MKTAG(0x700, 0x3ff, 0), LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer) LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer)
@@ -103,7 +112,8 @@ code = '''
// test that accessing our bad file fails, note there's a number // test that accessing our bad file fails, note there's a number
// of ways to access the dir, some can fail, but some don't // of ways to access the dir, some can fail, but some don't
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "file_here", &info) => 0; lfs_stat(&lfs, "file_here", &info) => 0;
assert(strcmp(info.name, "file_here") == 0); assert(strcmp(info.name, "file_here") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
@@ -114,20 +124,22 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
// any allocs that traverse CTZ must unfortunately must fail // any allocs that traverse CTZ must unfortunately must fail
if (SIZE > 2*LFS_BLOCK_SIZE) { if (SIZE > 2*BLOCK_SIZE) {
lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT; lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # invalid pointer in CTZ skip-list test [cases.invalid_ctz_pointer] # invalid pointer in CTZ skip-list test
define.SIZE = ['2*LFS_BLOCK_SIZE', '3*LFS_BLOCK_SIZE', '4*LFS_BLOCK_SIZE'] defines.SIZE = ['2*BLOCK_SIZE', '3*BLOCK_SIZE', '4*BLOCK_SIZE']
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// make a file // make a file
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "file_here", lfs_file_open(&lfs, &file, "file_here",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (int i = 0; i < SIZE; i++) { for (int i = 0; i < SIZE; i++) {
@@ -137,10 +149,11 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// change pointer in CTZ skip-list to be invalid // change pointer in CTZ skip-list to be invalid
lfs_init(&lfs, &cfg) => 0; lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
// make sure id 1 == our file and get our CTZ structure // make sure id 1 == our file and get our CTZ structure
uint8_t buffer[4*BLOCK_SIZE];
lfs_dir_get(&lfs, &mdir, lfs_dir_get(&lfs, &mdir,
LFS_MKTAG(0x700, 0x3ff, 0), LFS_MKTAG(0x700, 0x3ff, 0),
LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer) LFS_MKTAG(LFS_TYPE_NAME, 1, strlen("file_here")), buffer)
@@ -153,18 +166,19 @@ code = '''
=> LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz)); => LFS_MKTAG(LFS_TYPE_CTZSTRUCT, 1, sizeof(struct lfs_ctz));
lfs_ctz_fromle32(&ctz); lfs_ctz_fromle32(&ctz);
// rewrite block to contain bad pointer // rewrite block to contain bad pointer
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t bbuffer[BLOCK_SIZE];
cfg.read(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->read(cfg, ctz.head, 0, bbuffer, BLOCK_SIZE) => 0;
uint32_t bad = lfs_tole32(0xcccccccc); uint32_t bad = lfs_tole32(0xcccccccc);
memcpy(&bbuffer[0], &bad, sizeof(bad)); memcpy(&bbuffer[0], &bad, sizeof(bad));
memcpy(&bbuffer[4], &bad, sizeof(bad)); memcpy(&bbuffer[4], &bad, sizeof(bad));
cfg.erase(&cfg, ctz.head) => 0; cfg->erase(cfg, ctz.head) => 0;
cfg.prog(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->prog(cfg, ctz.head, 0, bbuffer, BLOCK_SIZE) => 0;
lfs_deinit(&lfs) => 0; lfs_deinit(&lfs) => 0;
// test that accessing our bad file fails, note there's a number // test that accessing our bad file fails, note there's a number
// of ways to access the dir, some can fail, but some don't // of ways to access the dir, some can fail, but some don't
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "file_here", &info) => 0; lfs_stat(&lfs, "file_here", &info) => 0;
assert(strcmp(info.name, "file_here") == 0); assert(strcmp(info.name, "file_here") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
@@ -175,22 +189,23 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
// any allocs that traverse CTZ must unfortunately must fail // any allocs that traverse CTZ must unfortunately must fail
if (SIZE > 2*LFS_BLOCK_SIZE) { if (SIZE > 2*BLOCK_SIZE) {
lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT; lfs_mkdir(&lfs, "dir_here") => LFS_ERR_CORRUPT;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # invalid gstate pointer [cases.invalid_gstate_pointer]
define.INVALSET = [0x3, 0x1, 0x2] defines.INVALSET = [0x3, 0x1, 0x2]
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// create an invalid gstate // create an invalid gstate
lfs_init(&lfs, &cfg) => 0; lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_fs_prepmove(&lfs, 1, (lfs_block_t [2]){ lfs_fs_prepmove(&lfs, 1, (lfs_block_t [2]){
@@ -202,21 +217,22 @@ code = '''
// test that mount fails gracefully // test that mount fails gracefully
// mount may not fail, but our first alloc should fail when // mount may not fail, but our first alloc should fail when
// we try to fix the gstate // we try to fix the gstate
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "should_fail") => LFS_ERR_CORRUPT; lfs_mkdir(&lfs, "should_fail") => LFS_ERR_CORRUPT;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
# cycle detection/recovery tests # cycle detection/recovery tests
[[case]] # metadata-pair threaded-list loop test [cases.mdir_loop] # metadata-pair threaded-list loop test
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
// create littlefs // create littlefs
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// change tail-pointer to point to ourself // change tail-pointer to point to ourself
lfs_init(&lfs, &cfg) => 0; lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
@@ -225,20 +241,21 @@ code = '''
lfs_deinit(&lfs) => 0; lfs_deinit(&lfs) => 0;
// test that mount fails gracefully // test that mount fails gracefully
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
''' '''
[[case]] # metadata-pair threaded-list 2-length loop test [cases.mdir_loop_2] # metadata-pair threaded-list 2-length loop test
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
// create littlefs with child dir // create littlefs with child dir
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "child") => 0; lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// find child // find child
lfs_init(&lfs, &cfg) => 0; lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_block_t pair[2]; lfs_block_t pair[2];
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
@@ -255,20 +272,21 @@ code = '''
lfs_deinit(&lfs) => 0; lfs_deinit(&lfs) => 0;
// test that mount fails gracefully // test that mount fails gracefully
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
''' '''
[[case]] # metadata-pair threaded-list 1-length child loop test [cases.mdir_loop_child] # metadata-pair threaded-list 1-length child loop test
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
// create littlefs with child dir // create littlefs with child dir
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "child") => 0; lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// find child // find child
lfs_init(&lfs, &cfg) => 0; lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir; lfs_mdir_t mdir;
lfs_block_t pair[2]; lfs_block_t pair[2];
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
@@ -284,5 +302,5 @@ code = '''
lfs_deinit(&lfs) => 0; lfs_deinit(&lfs) => 0;
// test that mount fails gracefully // test that mount fails gracefully
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
''' '''

View File

@@ -1,30 +1,34 @@
[[case]] # test running a filesystem to exhaustion # test running a filesystem to exhaustion
define.LFS_ERASE_CYCLES = 10 [cases.exhaustion]
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster defines.ERASE_CYCLES = 10
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' defines.BLOCK_COUNT = 256 # small bd so test runs faster
define.LFS_BADBLOCK_BEHAVIOR = [ defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
defines.BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR', 'LFS_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR', 'LFS_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR', 'LFS_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP', 'LFS_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP', 'LFS_TESTBD_BADBLOCK_ERASENOOP',
] ]
define.FILES = 10 defines.FILES = 10
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0; lfs_mkdir(&lfs, "roadrunner") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size // chose name, roughly random seed, and random 2^n size
char path[1024];
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); lfs_size_t size = 1 << ((rand() % 10)+2);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
@@ -33,14 +37,14 @@ code = '''
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC); assert(res == 1 || res == LFS_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) { if (res == LFS_ERR_NOSPC) {
err = lfs_file_close(&lfs, &file); int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS_ERR_NOSPC);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
goto exhausted; goto exhausted;
} }
} }
err = lfs_file_close(&lfs, &file); int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
@@ -50,10 +54,12 @@ code = '''
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
char path[1024];
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); lfs_size_t size = 1 << ((rand() % 10)+2);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
@@ -71,10 +77,12 @@ code = '''
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
char path[1024];
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
struct lfs_info info;
lfs_stat(&lfs, path, &info) => 0; lfs_stat(&lfs, path, &info) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
@@ -82,31 +90,35 @@ exhausted:
LFS_WARN("completed %d cycles", cycle); LFS_WARN("completed %d cycles", cycle);
''' '''
[[case]] # test running a filesystem to exhaustion # test running a filesystem to exhaustion
# which also requires expanding superblocks # which also requires expanding superblocks
define.LFS_ERASE_CYCLES = 10 [cases.exhaustion_superblocks]
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster defines.ERASE_CYCLES = 10
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' defines.BLOCK_COUNT = 256 # small bd so test runs faster
define.LFS_BADBLOCK_BEHAVIOR = [ defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
defines.BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR', 'LFS_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR', 'LFS_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR', 'LFS_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP', 'LFS_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP', 'LFS_TESTBD_BADBLOCK_ERASENOOP',
] ]
define.FILES = 10 defines.FILES = 10
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size // chose name, roughly random seed, and random 2^n size
char path[1024];
sprintf(path, "test%d", i); sprintf(path, "test%d", i);
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); lfs_size_t size = 1 << ((rand() % 10)+2);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
@@ -115,14 +127,14 @@ code = '''
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC); assert(res == 1 || res == LFS_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) { if (res == LFS_ERR_NOSPC) {
err = lfs_file_close(&lfs, &file); int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS_ERR_NOSPC);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
goto exhausted; goto exhausted;
} }
} }
err = lfs_file_close(&lfs, &file); int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
@@ -132,10 +144,12 @@ code = '''
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
char path[1024];
sprintf(path, "test%d", i); sprintf(path, "test%d", i);
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); lfs_size_t size = 1 << ((rand() % 10)+2);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
@@ -153,9 +167,11 @@ code = '''
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
char path[1024];
struct lfs_info info;
sprintf(path, "test%d", i); sprintf(path, "test%d", i);
lfs_stat(&lfs, path, &info) => 0; lfs_stat(&lfs, path, &info) => 0;
} }
@@ -169,35 +185,39 @@ exhausted:
# into increasing the block devices lifetime. This is something we can actually # into increasing the block devices lifetime. This is something we can actually
# check for. # check for.
[[case]] # wear-level test running a filesystem to exhaustion # wear-level test running a filesystem to exhaustion
define.LFS_ERASE_CYCLES = 20 [cases.wear_leveling_exhaustion]
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster defines.ERASE_CYCLES = 20
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' defines.BLOCK_COUNT = 256 # small bd so test runs faster
define.FILES = 10 defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
defines.FILES = 10
code = ''' code = '''
uint32_t run_cycles[2]; uint32_t run_cycles[2];
const uint32_t run_block_count[2] = {LFS_BLOCK_COUNT/2, LFS_BLOCK_COUNT}; const uint32_t run_block_count[2] = {BLOCK_COUNT/2, BLOCK_COUNT};
for (int run = 0; run < 2; run++) { for (int run = 0; run < 2; run++) {
for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) { for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) {
lfs_testbd_setwear(&cfg, b, lfs_testbd_setwear(cfg, b,
(b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0; (b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0;
} }
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0; lfs_mkdir(&lfs, "roadrunner") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size // chose name, roughly random seed, and random 2^n size
char path[1024];
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); lfs_size_t size = 1 << ((rand() % 10)+2);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
@@ -206,14 +226,14 @@ code = '''
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC); assert(res == 1 || res == LFS_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) { if (res == LFS_ERR_NOSPC) {
err = lfs_file_close(&lfs, &file); int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS_ERR_NOSPC);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
goto exhausted; goto exhausted;
} }
} }
err = lfs_file_close(&lfs, &file); int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
@@ -223,10 +243,12 @@ code = '''
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
char path[1024];
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); lfs_size_t size = 1 << ((rand() % 10)+2);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
@@ -244,9 +266,11 @@ code = '''
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
char path[1024];
struct lfs_info info;
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
lfs_stat(&lfs, path, &info) => 0; lfs_stat(&lfs, path, &info) => 0;
} }
@@ -261,32 +285,36 @@ exhausted:
LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
''' '''
[[case]] # wear-level test + expanding superblock # wear-level test + expanding superblock
define.LFS_ERASE_CYCLES = 20 [cases.wear_leveling_exhaustion_superblocks]
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster defines.ERASE_CYCLES = 20
define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2' defines.BLOCK_COUNT = 256 # small bd so test runs faster
define.FILES = 10 defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
defines.FILES = 10
code = ''' code = '''
uint32_t run_cycles[2]; uint32_t run_cycles[2];
const uint32_t run_block_count[2] = {LFS_BLOCK_COUNT/2, LFS_BLOCK_COUNT}; const uint32_t run_block_count[2] = {BLOCK_COUNT/2, BLOCK_COUNT};
for (int run = 0; run < 2; run++) { for (int run = 0; run < 2; run++) {
for (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) { for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) {
lfs_testbd_setwear(&cfg, b, lfs_testbd_setwear(cfg, b,
(b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0; (b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0;
} }
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size // chose name, roughly random seed, and random 2^n size
char path[1024];
sprintf(path, "test%d", i); sprintf(path, "test%d", i);
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); lfs_size_t size = 1 << ((rand() % 10)+2);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
@@ -295,14 +323,14 @@ code = '''
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC); assert(res == 1 || res == LFS_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) { if (res == LFS_ERR_NOSPC) {
err = lfs_file_close(&lfs, &file); int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS_ERR_NOSPC);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
goto exhausted; goto exhausted;
} }
} }
err = lfs_file_close(&lfs, &file); int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
@@ -312,10 +340,12 @@ code = '''
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
char path[1024];
sprintf(path, "test%d", i); sprintf(path, "test%d", i);
srand(cycle * i); srand(cycle * i);
size = 1 << ((rand() % 10)+2); lfs_size_t size = 1 << ((rand() % 10)+2);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
@@ -333,9 +363,11 @@ code = '''
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
char path[1024];
struct lfs_info info;
sprintf(path, "test%d", i); sprintf(path, "test%d", i);
lfs_stat(&lfs, path, &info) => 0; lfs_stat(&lfs, path, &info) => 0;
} }
@@ -350,28 +382,32 @@ exhausted:
LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]); LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
''' '''
[[case]] # test that we wear blocks roughly evenly # test that we wear blocks roughly evenly
define.LFS_ERASE_CYCLES = 0xffffffff [cases.wear_leveling_distribution]
define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster defines.ERASE_CYCLES = 0xffffffff
define.LFS_BLOCK_CYCLES = [5, 4, 3, 2, 1] defines.BLOCK_COUNT = 256 # small bd so test runs faster
define.CYCLES = 100 defines.BLOCK_CYCLES = [5, 4, 3, 2, 1]
define.FILES = 10 defines.CYCLES = 100
if = 'LFS_BLOCK_CYCLES < CYCLES/10' defines.FILES = 10
if = 'BLOCK_CYCLES < CYCLES/10'
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0; lfs_mkdir(&lfs, "roadrunner") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint32_t cycle = 0; uint32_t cycle = 0;
while (cycle < CYCLES) { while (cycle < CYCLES) {
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size // chose name, roughly random seed, and random 2^n size
char path[1024];
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
srand(cycle * i); srand(cycle * i);
size = 1 << 4; //((rand() % 10)+2); lfs_size_t size = 1 << 4; //((rand() % 10)+2);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
@@ -380,14 +416,14 @@ code = '''
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1); lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || res == LFS_ERR_NOSPC); assert(res == 1 || res == LFS_ERR_NOSPC);
if (res == LFS_ERR_NOSPC) { if (res == LFS_ERR_NOSPC) {
err = lfs_file_close(&lfs, &file); int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS_ERR_NOSPC);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
goto exhausted; goto exhausted;
} }
} }
err = lfs_file_close(&lfs, &file); int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC); assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) { if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
@@ -397,10 +433,12 @@ code = '''
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
char path[1024];
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
srand(cycle * i); srand(cycle * i);
size = 1 << 4; //((rand() % 10)+2); lfs_size_t size = 1 << 4; //((rand() % 10)+2);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
for (lfs_size_t j = 0; j < size; j++) { for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26); char c = 'a' + (rand() % 26);
@@ -418,9 +456,11 @@ code = '''
exhausted: exhausted:
// should still be readable // should still be readable
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) { for (uint32_t i = 0; i < FILES; i++) {
// check for errors // check for errors
char path[1024];
struct lfs_info info;
sprintf(path, "roadrunner/test%d", i); sprintf(path, "roadrunner/test%d", i);
lfs_stat(&lfs, path, &info) => 0; lfs_stat(&lfs, path, &info) => 0;
} }
@@ -433,8 +473,8 @@ exhausted:
lfs_testbd_wear_t totalwear = 0; lfs_testbd_wear_t totalwear = 0;
lfs_testbd_wear_t maxwear = 0; lfs_testbd_wear_t maxwear = 0;
// skip 0 and 1 as superblock movement is intentionally avoided // skip 0 and 1 as superblock movement is intentionally avoided
for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) {
lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); lfs_testbd_wear_t wear = lfs_testbd_getwear(cfg, b);
printf("%08x: wear %d\n", b, wear); printf("%08x: wear %d\n", b, wear);
assert(wear >= 0); assert(wear >= 0);
if (wear < minwear) { if (wear < minwear) {
@@ -445,15 +485,15 @@ exhausted:
} }
totalwear += wear; totalwear += wear;
} }
lfs_testbd_wear_t avgwear = totalwear / LFS_BLOCK_COUNT; lfs_testbd_wear_t avgwear = totalwear / BLOCK_COUNT;
LFS_WARN("max wear: %d cycles", maxwear); LFS_WARN("max wear: %d cycles", maxwear);
LFS_WARN("avg wear: %d cycles", totalwear / LFS_BLOCK_COUNT); LFS_WARN("avg wear: %d cycles", totalwear / (int)BLOCK_COUNT);
LFS_WARN("min wear: %d cycles", minwear); LFS_WARN("min wear: %d cycles", minwear);
// find standard deviation^2 // find standard deviation^2
lfs_testbd_wear_t dev2 = 0; lfs_testbd_wear_t dev2 = 0;
for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) { for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) {
lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b); lfs_testbd_wear_t wear = lfs_testbd_getwear(cfg, b);
assert(wear >= 0); assert(wear >= 0);
lfs_testbd_swear_t diff = wear - avgwear; lfs_testbd_swear_t diff = wear - avgwear;
dev2 += diff*diff; dev2 += diff*diff;

View File

@@ -1,17 +1,20 @@
[[case]] # simple file test [cases.simple_file]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "hello", lfs_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
size = strlen("Hello World!")+1; lfs_size_t size = strlen("Hello World!")+1;
uint8_t buffer[1024];
strcpy((char*)buffer, "Hello World!"); strcpy((char*)buffer, "Hello World!");
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, size) => size;
assert(strcmp((char*)buffer, "Hello World!") == 0); assert(strcmp((char*)buffer, "Hello World!") == 0);
@@ -19,17 +22,20 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # larger files [cases.large_files]
define.SIZE = [32, 8192, 262144, 0, 7, 8193] defines.SIZE = [32, 8192, 262144, 0, 7, 8193]
define.CHUNKSIZE = [31, 16, 33, 1, 1023] defines.CHUNKSIZE = [31, 16, 33, 1, 1023]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// write // write
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "avacado", lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
srand(1); srand(1);
uint8_t buffer[1024];
for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
for (lfs_size_t b = 0; b < chunk; b++) { for (lfs_size_t b = 0; b < chunk; b++) {
@@ -41,7 +47,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE; lfs_file_size(&lfs, &file) => SIZE;
srand(1); srand(1);
@@ -57,15 +63,18 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # rewriting files [cases.rewriting_files]
define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
define.CHUNKSIZE = [31, 16, 1] defines.CHUNKSIZE = [31, 16, 1]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// write // write
lfs_mount(&lfs, &cfg) => 1; lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
uint8_t buffer[1024];
lfs_file_open(&lfs, &file, "avacado", lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
srand(1); srand(1);
@@ -80,7 +89,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1; lfs_file_size(&lfs, &file) => SIZE1;
srand(1); srand(1);
@@ -96,7 +105,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// rewrite // rewrite
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY) => 0;
srand(2); srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
@@ -110,7 +119,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => lfs_max(SIZE1, SIZE2); lfs_file_size(&lfs, &file) => lfs_max(SIZE1, SIZE2);
srand(2); srand(2);
@@ -139,15 +148,18 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # appending files [cases.appending_files]
define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
define.CHUNKSIZE = [31, 16, 1] defines.CHUNKSIZE = [31, 16, 1]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// write // write
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
uint8_t buffer[1024];
lfs_file_open(&lfs, &file, "avacado", lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
srand(1); srand(1);
@@ -162,7 +174,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1; lfs_file_size(&lfs, &file) => SIZE1;
srand(1); srand(1);
@@ -178,7 +190,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// append // append
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_APPEND) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_APPEND) => 0;
srand(2); srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
@@ -192,7 +204,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1 + SIZE2; lfs_file_size(&lfs, &file) => SIZE1 + SIZE2;
srand(1); srand(1);
@@ -216,15 +228,18 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # truncating files [cases.truncating_files]
define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
define.CHUNKSIZE = [31, 16, 1] defines.CHUNKSIZE = [31, 16, 1]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// write // write
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
uint8_t buffer[1024];
lfs_file_open(&lfs, &file, "avacado", lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
srand(1); srand(1);
@@ -239,7 +254,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1; lfs_file_size(&lfs, &file) => SIZE1;
srand(1); srand(1);
@@ -255,7 +270,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// truncate // truncate
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_TRUNC) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_TRUNC) => 0;
srand(2); srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
@@ -269,7 +284,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// read // read
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE2; lfs_file_size(&lfs, &file) => SIZE2;
srand(2); srand(2);
@@ -285,22 +300,25 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # reentrant file writing [cases.reentrant_file_writing]
define.SIZE = [32, 0, 7, 2049] defines.SIZE = [32, 0, 7, 2049]
define.CHUNKSIZE = [31, 16, 65] defines.CHUNKSIZE = [31, 16, 65]
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&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); err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY);
assert(err == LFS_ERR_NOENT || err == 0); assert(err == LFS_ERR_NOENT || err == 0);
if (err == 0) { if (err == 0) {
// can only be 0 (new file) or full size // can only be 0 (new file) or full size
size = lfs_file_size(&lfs, &file); lfs_size_t size = lfs_file_size(&lfs, &file);
assert(size == 0 || size == SIZE); assert(size == 0 || size == SIZE);
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
} }
@@ -333,8 +351,8 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # reentrant file writing with syncs [cases.reentrant_file_writing_sync]
define = [ defines = [
# append (O(n)) # append (O(n))
{MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]}, {MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]},
# truncate (O(n^2)) # truncate (O(n^2))
@@ -344,17 +362,20 @@ define = [
] ]
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&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); err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY);
assert(err == LFS_ERR_NOENT || err == 0); assert(err == LFS_ERR_NOENT || err == 0);
if (err == 0) { if (err == 0) {
// with syncs we could be any size, but it at least must be valid data // with syncs we could be any size, but it at least must be valid data
size = lfs_file_size(&lfs, &file); lfs_size_t size = lfs_file_size(&lfs, &file);
assert(size <= SIZE); assert(size <= SIZE);
srand(1); srand(1);
for (lfs_size_t i = 0; i < size; i += CHUNKSIZE) { for (lfs_size_t i = 0; i < size; i += CHUNKSIZE) {
@@ -370,7 +391,7 @@ code = '''
// write // write
lfs_file_open(&lfs, &file, "avacado", lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | MODE) => 0; LFS_O_WRONLY | LFS_O_CREAT | MODE) => 0;
size = lfs_file_size(&lfs, &file); lfs_size_t size = lfs_file_size(&lfs, &file);
assert(size <= SIZE); assert(size <= SIZE);
srand(1); srand(1);
lfs_size_t skip = (MODE == LFS_O_APPEND) ? size : 0; lfs_size_t skip = (MODE == LFS_O_APPEND) ? size : 0;
@@ -403,19 +424,22 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # many files [cases.many_files]
define.N = 300 defines.N = 300
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// create N files of 7 bytes // create N files of 7 bytes
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
lfs_file_t file;
char path[1024];
sprintf(path, "file_%03d", i); sprintf(path, "file_%03d", i);
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
char wbuffer[1024]; char wbuffer[1024];
size = 7; lfs_size_t size = 7;
snprintf(wbuffer, size, "Hi %03d", i); sprintf(wbuffer, "Hi %03d", i);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -428,25 +452,28 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # many files with power cycle [cases.many_files_power_cycle]
define.N = 300 defines.N = 300
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// create N files of 7 bytes // create N files of 7 bytes
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
lfs_file_t file;
char path[1024];
sprintf(path, "file_%03d", i); sprintf(path, "file_%03d", i);
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
char wbuffer[1024]; char wbuffer[1024];
size = 7; lfs_size_t size = 7;
snprintf(wbuffer, size, "Hi %03d", i); sprintf(wbuffer, "Hi %03d", i);
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
char rbuffer[1024]; char rbuffer[1024];
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size; lfs_file_read(&lfs, &file, rbuffer, size) => size;
assert(strcmp(rbuffer, wbuffer) == 0); assert(strcmp(rbuffer, wbuffer) == 0);
@@ -455,22 +482,25 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # many files with power loss [cases.many_files_power_loss]
define.N = 300 defines.N = 300
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
} }
// create N files of 7 bytes // create N files of 7 bytes
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
lfs_file_t file;
char path[1024];
sprintf(path, "file_%03d", i); sprintf(path, "file_%03d", i);
err = lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT); err = lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT);
char wbuffer[1024]; char wbuffer[1024];
size = 7; lfs_size_t size = 7;
snprintf(wbuffer, size, "Hi %03d", i); sprintf(wbuffer, "Hi %03d", i);
if ((lfs_size_t)lfs_file_size(&lfs, &file) != size) { if ((lfs_size_t)lfs_file_size(&lfs, &file) != size) {
lfs_file_write(&lfs, &file, wbuffer, size) => size; lfs_file_write(&lfs, &file, wbuffer, size) => size;
} }

View File

@@ -1,13 +1,15 @@
[[case]] # interspersed file test [cases.interspersed_files]
define.SIZE = [10, 100] defines.SIZE = [10, 100]
define.FILES = [4, 10, 26] defines.FILES = [4, 10, 26]
code = ''' code = '''
lfs_t lfs;
lfs_file_t files[FILES]; lfs_file_t files[FILES];
const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
char path[1024];
sprintf(path, "%c", alphas[j]); sprintf(path, "%c", alphas[j]);
lfs_file_open(&lfs, &files[j], path, lfs_file_open(&lfs, &files[j], path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
@@ -23,7 +25,9 @@ code = '''
lfs_file_close(&lfs, &files[j]); lfs_file_close(&lfs, &files[j]);
} }
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -31,6 +35,7 @@ code = '''
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
char path[1024];
sprintf(path, "%c", alphas[j]); sprintf(path, "%c", alphas[j]);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0); assert(strcmp(info.name, path) == 0);
@@ -41,12 +46,14 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
char path[1024];
sprintf(path, "%c", alphas[j]); sprintf(path, "%c", alphas[j]);
lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0;
} }
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
uint8_t buffer[1024];
lfs_file_read(&lfs, &files[j], buffer, 1) => 1; lfs_file_read(&lfs, &files[j], buffer, 1) => 1;
assert(buffer[0] == alphas[j]); assert(buffer[0] == alphas[j]);
} }
@@ -59,15 +66,18 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # interspersed remove file test [cases.interspersed_remove_files]
define.SIZE = [10, 100] defines.SIZE = [10, 100]
define.FILES = [4, 10, 26] defines.FILES = [4, 10, 26]
code = ''' code = '''
lfs_t lfs;
const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
char path[1024];
sprintf(path, "%c", alphas[j]); sprintf(path, "%c", alphas[j]);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
for (int i = 0; i < SIZE; i++) { for (int i = 0; i < SIZE; i++) {
@@ -77,18 +87,22 @@ code = '''
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "zzz", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &file, "zzz", LFS_O_WRONLY | LFS_O_CREAT) => 0;
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
lfs_file_write(&lfs, &file, (const void*)"~", 1) => 1; lfs_file_write(&lfs, &file, (const void*)"~", 1) => 1;
lfs_file_sync(&lfs, &file) => 0; lfs_file_sync(&lfs, &file) => 0;
char path[1024];
sprintf(path, "%c", alphas[j]); sprintf(path, "%c", alphas[j]);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
} }
lfs_file_close(&lfs, &file); lfs_file_close(&lfs, &file);
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -104,6 +118,7 @@ code = '''
lfs_file_open(&lfs, &file, "zzz", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "zzz", LFS_O_RDONLY) => 0;
for (int i = 0; i < FILES; i++) { for (int i = 0; i < FILES; i++) {
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 1) => 1; lfs_file_read(&lfs, &file, buffer, 1) => 1;
assert(buffer[0] == '~'); assert(buffer[0] == '~');
} }
@@ -112,11 +127,12 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # remove inconveniently test [cases.remove_inconveniently]
define.SIZE = [10, 100] defines.SIZE = [10, 100]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t files[3]; lfs_file_t files[3];
lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_open(&lfs, &files[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0; lfs_file_open(&lfs, &files[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0;
@@ -140,7 +156,9 @@ code = '''
lfs_file_close(&lfs, &files[1]); lfs_file_close(&lfs, &files[1]);
lfs_file_close(&lfs, &files[2]); lfs_file_close(&lfs, &files[2]);
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -161,6 +179,7 @@ code = '''
lfs_file_open(&lfs, &files[0], "e", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &files[0], "e", LFS_O_RDONLY) => 0;
lfs_file_open(&lfs, &files[1], "g", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &files[1], "g", LFS_O_RDONLY) => 0;
for (int i = 0; i < SIZE; i++) { for (int i = 0; i < SIZE; i++) {
uint8_t buffer[1024];
lfs_file_read(&lfs, &files[0], buffer, 1) => 1; lfs_file_read(&lfs, &files[0], buffer, 1) => 1;
assert(buffer[0] == 'e'); assert(buffer[0] == 'e');
lfs_file_read(&lfs, &files[1], buffer, 1) => 1; lfs_file_read(&lfs, &files[1], buffer, 1) => 1;
@@ -172,21 +191,23 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # reentrant interspersed file test [cases.reentrant_interspersed_files]
define.SIZE = [10, 100] defines.SIZE = [10, 100]
define.FILES = [4, 10, 26] defines.FILES = [4, 10, 26]
reentrant = true reentrant = true
code = ''' code = '''
lfs_t lfs;
lfs_file_t files[FILES]; lfs_file_t files[FILES];
const char alphas[] = "abcdefghijklmnopqrstuvwxyz"; const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
err = lfs_mount(&lfs, &cfg); int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
} }
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
char path[1024];
sprintf(path, "%c", alphas[j]); sprintf(path, "%c", alphas[j]);
lfs_file_open(&lfs, &files[j], path, lfs_file_open(&lfs, &files[j], path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
@@ -194,8 +215,8 @@ code = '''
for (int i = 0; i < SIZE; i++) { for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
size = lfs_file_size(&lfs, &files[j]); lfs_ssize_t size = lfs_file_size(&lfs, &files[j]);
assert((int)size >= 0); assert(size >= 0);
if ((int)size <= i) { if ((int)size <= i) {
lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1; lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1;
lfs_file_sync(&lfs, &files[j]) => 0; lfs_file_sync(&lfs, &files[j]) => 0;
@@ -207,7 +228,9 @@ code = '''
lfs_file_close(&lfs, &files[j]); lfs_file_close(&lfs, &files[j]);
} }
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -215,6 +238,7 @@ code = '''
assert(strcmp(info.name, "..") == 0); assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
char path[1024];
sprintf(path, "%c", alphas[j]); sprintf(path, "%c", alphas[j]);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0); assert(strcmp(info.name, path) == 0);
@@ -225,12 +249,14 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
char path[1024];
sprintf(path, "%c", alphas[j]); sprintf(path, "%c", alphas[j]);
lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0;
} }
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
for (int j = 0; j < FILES; j++) { for (int j = 0; j < FILES; j++) {
uint8_t buffer[1024];
lfs_file_read(&lfs, &files[j], buffer, 1) => 1; lfs_file_read(&lfs, &files[j], buffer, 1) => 1;
assert(buffer[0] == alphas[j]); assert(buffer[0] == alphas[j]);
} }

View File

@@ -1,11 +1,13 @@
[[case]] # move file [cases.move_file]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
lfs_mkdir(&lfs, "d") => 0; lfs_mkdir(&lfs, "d") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_write(&lfs, &file, "hola\n", 5) => 5; lfs_file_write(&lfs, &file, "hola\n", 5) => 5;
lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
@@ -13,11 +15,13 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -44,6 +48,7 @@ code = '''
lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 0;
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 5) => 5; lfs_file_read(&lfs, &file, buffer, 5) => 5;
memcmp(buffer, "hola\n", 5) => 0; memcmp(buffer, "hola\n", 5) => 0;
lfs_file_read(&lfs, &file, buffer, 8) => 8; lfs_file_read(&lfs, &file, buffer, 8) => 8;
@@ -55,31 +60,35 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # noop move, yes this is legal [cases.nop_move] # yes this is legal
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "hi") => 0; lfs_mkdir(&lfs, "hi") => 0;
lfs_rename(&lfs, "hi", "hi") => 0; lfs_rename(&lfs, "hi", "hi") => 0;
lfs_mkdir(&lfs, "hi/hi") => 0; lfs_mkdir(&lfs, "hi/hi") => 0;
lfs_rename(&lfs, "hi/hi", "hi/hi") => 0; lfs_rename(&lfs, "hi/hi", "hi/hi") => 0;
lfs_mkdir(&lfs, "hi/hi/hi") => 0; lfs_mkdir(&lfs, "hi/hi/hi") => 0;
lfs_rename(&lfs, "hi/hi/hi", "hi/hi/hi") => 0; lfs_rename(&lfs, "hi/hi/hi", "hi/hi/hi") => 0;
struct lfs_info info;
lfs_stat(&lfs, "hi/hi/hi", &info) => 0; lfs_stat(&lfs, "hi/hi/hi", &info) => 0;
assert(strcmp(info.name, "hi") == 0); assert(strcmp(info.name, "hi") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # move file corrupt source [cases.move_file_corrupt_source]
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
lfs_mkdir(&lfs, "d") => 0; lfs_mkdir(&lfs, "d") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_write(&lfs, &file, "hola\n", 5) => 5; lfs_file_write(&lfs, &file, "hola\n", 5) => 5;
lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
@@ -87,28 +96,30 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// corrupt the source // corrupt the source
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_block_t block = dir.m.pair[0]; lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t buffer[BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&buffer[off-3], BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; cfg->erase(cfg, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; cfg->sync(cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -146,16 +157,19 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # move file corrupt source and dest # move file corrupt source and dest
[cases.move_file_corrupt_source_dest]
in = "lfs.c" in = "lfs.c"
if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
lfs_mkdir(&lfs, "d") => 0; lfs_mkdir(&lfs, "d") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_write(&lfs, &file, "hola\n", 5) => 5; lfs_file_write(&lfs, &file, "hola\n", 5) => 5;
lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
@@ -163,44 +177,46 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// corrupt the source // corrupt the source
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_block_t block = dir.m.pair[0]; lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t buffer[BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&buffer[off-3], BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; cfg->erase(cfg, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; cfg->sync(cfg) => 0;
// corrupt the destination // corrupt the destination
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0; lfs_dir_open(&lfs, &dir, "c") => 0;
block = dir.m.pair[0]; block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
off = LFS_BLOCK_SIZE-1; off = BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&buffer[off-3], BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; cfg->erase(cfg, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; cfg->sync(cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -238,16 +254,18 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # move file after corrupt [cases.move_file_after_corrupt]
in = "lfs.c" in = "lfs.c"
if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
lfs_mkdir(&lfs, "d") => 0; lfs_mkdir(&lfs, "d") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_write(&lfs, &file, "hola\n", 5) => 5; lfs_file_write(&lfs, &file, "hola\n", 5) => 5;
lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
@@ -255,49 +273,51 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// corrupt the source // corrupt the source
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_block_t block = dir.m.pair[0]; lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t buffer[BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&buffer[off-3], BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; cfg->erase(cfg, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; cfg->sync(cfg) => 0;
// corrupt the destination // corrupt the destination
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0; lfs_dir_open(&lfs, &dir, "c") => 0;
block = dir.m.pair[0]; block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
off = LFS_BLOCK_SIZE-1; off = BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&buffer[off-3], BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; cfg->erase(cfg, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; cfg->sync(cfg) => 0;
// continue move // continue move
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 0; lfs_rename(&lfs, "a/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -335,13 +355,14 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # simple reentrant move file [cases.reentrant_move_file]
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
} }
err = lfs_mkdir(&lfs, "a"); err = lfs_mkdir(&lfs, "a");
assert(!err || err == LFS_ERR_EXIST); assert(!err || err == LFS_ERR_EXIST);
@@ -354,9 +375,10 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
// there should never exist _2_ hello files // there should never exist _2_ hello files
int count = 0; int count = 0;
struct lfs_info info;
if (lfs_stat(&lfs, "a/hello", &info) == 0) { if (lfs_stat(&lfs, "a/hello", &info) == 0) {
assert(strcmp(info.name, "hello") == 0); assert(strcmp(info.name, "hello") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
@@ -384,7 +406,7 @@ code = '''
assert(count <= 1); assert(count <= 1);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
if (lfs_stat(&lfs, "a/hello", &info) == 0 && info.size > 0) { if (lfs_stat(&lfs, "a/hello", &info) == 0 && info.size > 0) {
lfs_rename(&lfs, "a/hello", "b/hello") => 0; lfs_rename(&lfs, "a/hello", "b/hello") => 0;
} else if (lfs_stat(&lfs, "b/hello", &info) == 0) { } else if (lfs_stat(&lfs, "b/hello", &info) == 0) {
@@ -397,6 +419,7 @@ code = '''
break; break;
} else { } else {
// create file // create file
lfs_file_t file;
lfs_file_open(&lfs, &file, "a/hello", lfs_file_open(&lfs, &file, "a/hello",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hola\n", 5) => 5; lfs_file_write(&lfs, &file, "hola\n", 5) => 5;
@@ -407,7 +430,9 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
} }
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -431,10 +456,12 @@ code = '''
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0;
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 5) => 5; lfs_file_read(&lfs, &file, buffer, 5) => 5;
memcmp(buffer, "hola\n", 5) => 0; memcmp(buffer, "hola\n", 5) => 0;
lfs_file_read(&lfs, &file, buffer, 8) => 8; lfs_file_read(&lfs, &file, buffer, 8) => 8;
@@ -445,10 +472,11 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # move dir [cases.move_dir]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
@@ -459,11 +487,13 @@ code = '''
lfs_mkdir(&lfs, "a/hi/ohayo") => 0; lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -510,11 +540,12 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # move dir corrupt source [cases.move_dir_corrupt_source]
in = "lfs.c" in = "lfs.c"
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
@@ -525,28 +556,30 @@ code = '''
lfs_mkdir(&lfs, "a/hi/ohayo") => 0; lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// corrupt the source // corrupt the source
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_block_t block = dir.m.pair[0]; lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t buffer[BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&buffer[off-3], BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; cfg->erase(cfg, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; cfg->sync(cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -593,12 +626,13 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # move dir corrupt source and dest [cases.move_dir_corrupt_source_dest]
in = "lfs.c" in = "lfs.c"
if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
@@ -609,44 +643,46 @@ code = '''
lfs_mkdir(&lfs, "a/hi/ohayo") => 0; lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// corrupt the source // corrupt the source
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_block_t block = dir.m.pair[0]; lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t buffer[BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&buffer[off-3], BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; cfg->erase(cfg, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; cfg->sync(cfg) => 0;
// corrupt the destination // corrupt the destination
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0; lfs_dir_open(&lfs, &dir, "c") => 0;
block = dir.m.pair[0]; block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
off = LFS_BLOCK_SIZE-1; off = BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&buffer[off-3], BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; cfg->erase(cfg, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; cfg->sync(cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -693,12 +729,13 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # move dir after corrupt [cases.move_dir_after_corrupt]
in = "lfs.c" in = "lfs.c"
if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
@@ -709,49 +746,51 @@ code = '''
lfs_mkdir(&lfs, "a/hi/ohayo") => 0; lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// corrupt the source // corrupt the source
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_block_t block = dir.m.pair[0]; lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t buffer[BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&buffer[off-3], BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; cfg->erase(cfg, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; cfg->sync(cfg) => 0;
// corrupt the destination // corrupt the destination
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0; lfs_dir_open(&lfs, &dir, "c") => 0;
block = dir.m.pair[0]; block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
off = LFS_BLOCK_SIZE-1; off = BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&buffer[off-3], BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; cfg->erase(cfg, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; cfg->sync(cfg) => 0;
// continue move // continue move
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 0; lfs_rename(&lfs, "a/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -798,13 +837,14 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # simple reentrant move dir [cases.reentrant_move_dir]
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
} }
err = lfs_mkdir(&lfs, "a"); err = lfs_mkdir(&lfs, "a");
assert(!err || err == LFS_ERR_EXIST); assert(!err || err == LFS_ERR_EXIST);
@@ -817,9 +857,10 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
while (true) { while (true) {
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
// there should never exist _2_ hi directories // there should never exist _2_ hi directories
int count = 0; int count = 0;
struct lfs_info info;
if (lfs_stat(&lfs, "a/hi", &info) == 0) { if (lfs_stat(&lfs, "a/hi", &info) == 0) {
assert(strcmp(info.name, "hi") == 0); assert(strcmp(info.name, "hi") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -843,7 +884,7 @@ code = '''
assert(count <= 1); assert(count <= 1);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
if (lfs_stat(&lfs, "a/hi", &info) == 0) { if (lfs_stat(&lfs, "a/hi", &info) == 0) {
lfs_rename(&lfs, "a/hi", "b/hi") => 0; lfs_rename(&lfs, "a/hi", "b/hi") => 0;
} else if (lfs_stat(&lfs, "b/hi", &info) == 0) { } else if (lfs_stat(&lfs, "b/hi", &info) == 0) {
@@ -868,7 +909,9 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
} }
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "a") => 0; lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -915,14 +958,16 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # move state stealing [cases.move_state_stealing]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0; lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0; lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0; lfs_mkdir(&lfs, "c") => 0;
lfs_mkdir(&lfs, "d") => 0; lfs_mkdir(&lfs, "d") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_write(&lfs, &file, "hola\n", 5) => 5; lfs_file_write(&lfs, &file, "hola\n", 5) => 5;
lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
@@ -930,21 +975,22 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hello", "b/hello") => 0; lfs_rename(&lfs, "a/hello", "b/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "b/hello", "c/hello") => 0; lfs_rename(&lfs, "b/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "c/hello", "d/hello") => 0; lfs_rename(&lfs, "c/hello", "d/hello") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT; lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0;
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 5) => 5; lfs_file_read(&lfs, &file, buffer, 5) => 5;
memcmp(buffer, "hola\n", 5) => 0; memcmp(buffer, "hola\n", 5) => 0;
lfs_file_read(&lfs, &file, buffer, 8) => 8; lfs_file_read(&lfs, &file, buffer, 8) => 8;
@@ -954,12 +1000,13 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_remove(&lfs, "b") => 0; lfs_remove(&lfs, "b") => 0;
lfs_remove(&lfs, "c") => 0; lfs_remove(&lfs, "c") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "a", &info) => 0; lfs_stat(&lfs, "a", &info) => 0;
lfs_stat(&lfs, "b", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "b", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "c", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "c", &info) => LFS_ERR_NOENT;
@@ -979,12 +1026,16 @@ code = '''
''' '''
# Other specific corner cases # Other specific corner cases
[[case]] # create + delete in same commit with neighbors
# create + delete in same commit with neighbors
[cases.create_delete_same]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// littlefs keeps files sorted, so we know the order these will be in // littlefs keeps files sorted, so we know the order these will be in
lfs_file_t file;
lfs_file_open(&lfs, &file, "/1.move_me", lfs_file_open(&lfs, &file, "/1.move_me",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -1024,6 +1075,8 @@ code = '''
lfs_file_close(&lfs, &files[2]) => 0; lfs_file_close(&lfs, &files[2]) => 0;
// check that nothing was corrupted // check that nothing was corrupted
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -1051,6 +1104,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0;
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 7) => 7; lfs_file_read(&lfs, &file, buffer, 7) => 7;
assert(strcmp((char*)buffer, "test.4") == 0); assert(strcmp((char*)buffer, "test.4") == 0);
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -1124,13 +1178,15 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
# Other specific corner cases # create + delete + delete in same commit with neighbors
[[case]] # create + delete + delete in same commit with neighbors [cases.create_delete_delete_same]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// littlefs keeps files sorted, so we know the order these will be in // littlefs keeps files sorted, so we know the order these will be in
lfs_file_t file;
lfs_file_open(&lfs, &file, "/1.move_me", lfs_file_open(&lfs, &file, "/1.move_me",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -1175,6 +1231,8 @@ code = '''
lfs_file_close(&lfs, &files[2]) => 0; lfs_file_close(&lfs, &files[2]) => 0;
// check that nothing was corrupted // check that nothing was corrupted
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -1202,6 +1260,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0;
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 7) => 7; lfs_file_read(&lfs, &file, buffer, 7) => 7;
assert(strcmp((char*)buffer, "test.4") == 0); assert(strcmp((char*)buffer, "test.4") == 0);
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -1281,14 +1340,17 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # create + delete in different dirs with neighbors # create + delete in different dirs with neighbors
[cases.create_delete_different]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
// littlefs keeps files sorted, so we know the order these will be in // littlefs keeps files sorted, so we know the order these will be in
lfs_mkdir(&lfs, "/dir.1") => 0; lfs_mkdir(&lfs, "/dir.1") => 0;
lfs_mkdir(&lfs, "/dir.2") => 0; lfs_mkdir(&lfs, "/dir.2") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "/dir.1/1.move_me", lfs_file_open(&lfs, &file, "/dir.1/1.move_me",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -1340,6 +1402,8 @@ code = '''
lfs_file_close(&lfs, &files[3]) => 0; lfs_file_close(&lfs, &files[3]) => 0;
// check that nothing was corrupted // check that nothing was corrupted
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -1397,6 +1461,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_file_open(&lfs, &file, "/dir.1/0.before", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "/dir.1/0.before", LFS_O_RDONLY) => 0;
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 7) => 7; lfs_file_read(&lfs, &file, buffer, 7) => 7;
assert(strcmp((char*)buffer, "test.5") == 0); assert(strcmp((char*)buffer, "test.5") == 0);
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -1518,17 +1583,20 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # move fix in relocation # move fix in relocation
[cases.move_fix_relocation]
in = "lfs.c" in = "lfs.c"
define.RELOCATIONS = 'range(0x3+1)' defines.RELOCATIONS = [0x0, 0x1, 0x2, 0x3]
define.LFS_ERASE_CYCLES = 0xffffffff defines.ERASE_CYCLES = 0xffffffff
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "/parent") => 0; lfs_mkdir(&lfs, "/parent") => 0;
lfs_mkdir(&lfs, "/parent/child") => 0; lfs_mkdir(&lfs, "/parent/child") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "/parent/1.move_me", lfs_file_open(&lfs, &file, "/parent/1.move_me",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "move me", lfs_file_write(&lfs, &file, "move me",
@@ -1568,15 +1636,17 @@ code = '''
// force specific directories to relocate // force specific directories to relocate
if (RELOCATIONS & 0x1) { if (RELOCATIONS & 0x1) {
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/parent"); lfs_dir_open(&lfs, &dir, "/parent");
lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; lfs_testbd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0;
lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_testbd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
} }
if (RELOCATIONS & 0x2) { if (RELOCATIONS & 0x2) {
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/parent/child"); lfs_dir_open(&lfs, &dir, "/parent/child");
lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; lfs_testbd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0;
lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_testbd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
} }
@@ -1593,6 +1663,8 @@ code = '''
lfs_file_close(&lfs, &files[3]) => 0; lfs_file_close(&lfs, &files[3]) => 0;
// check that nothing was corrupted // check that nothing was corrupted
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "/parent") => 0; lfs_dir_open(&lfs, &dir, "/parent") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -1637,6 +1709,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_file_open(&lfs, &file, "/parent/0.before", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "/parent/0.before", LFS_O_RDONLY) => 0;
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 7) => 7; lfs_file_read(&lfs, &file, buffer, 7) => 7;
assert(strcmp((char*)buffer, "test.5") == 0); assert(strcmp((char*)buffer, "test.5") == 0);
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -1655,18 +1728,21 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # move fix in relocation with predecessor # move fix in relocation with predecessor
[cases.move_fix_relocation_predecessor]
in = "lfs.c" in = "lfs.c"
define.RELOCATIONS = 'range(0x7+1)' defines.RELOCATIONS = [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7]
define.LFS_ERASE_CYCLES = 0xffffffff defines.ERASE_CYCLES = 0xffffffff
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "/parent") => 0; lfs_mkdir(&lfs, "/parent") => 0;
lfs_mkdir(&lfs, "/parent/child") => 0; lfs_mkdir(&lfs, "/parent/child") => 0;
lfs_mkdir(&lfs, "/parent/sibling") => 0; lfs_mkdir(&lfs, "/parent/sibling") => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "/parent/sibling/1.move_me", lfs_file_open(&lfs, &file, "/parent/sibling/1.move_me",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "move me", lfs_file_write(&lfs, &file, "move me",
@@ -1706,21 +1782,24 @@ code = '''
// force specific directories to relocate // force specific directories to relocate
if (RELOCATIONS & 0x1) { if (RELOCATIONS & 0x1) {
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/parent"); lfs_dir_open(&lfs, &dir, "/parent");
lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; lfs_testbd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0;
lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_testbd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
} }
if (RELOCATIONS & 0x2) { if (RELOCATIONS & 0x2) {
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/parent/sibling"); lfs_dir_open(&lfs, &dir, "/parent/sibling");
lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; lfs_testbd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0;
lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_testbd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
} }
if (RELOCATIONS & 0x4) { if (RELOCATIONS & 0x4) {
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/parent/child"); lfs_dir_open(&lfs, &dir, "/parent/child");
lfs_testbd_setwear(&cfg, dir.m.pair[0], 0xffffffff) => 0; lfs_testbd_setwear(cfg, dir.m.pair[0], 0xffffffff) => 0;
lfs_testbd_setwear(&cfg, dir.m.pair[1], 0xffffffff) => 0; lfs_testbd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
} }
@@ -1739,6 +1818,8 @@ code = '''
lfs_file_close(&lfs, &files[3]) => 0; lfs_file_close(&lfs, &files[3]) => 0;
// check that nothing was corrupted // check that nothing was corrupted
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "/parent") => 0; lfs_dir_open(&lfs, &dir, "/parent") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0); assert(strcmp(info.name, ".") == 0);
@@ -1796,6 +1877,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_file_open(&lfs, &file, "/parent/sibling/0.before", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "/parent/sibling/0.before", LFS_O_RDONLY) => 0;
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 7) => 7; lfs_file_read(&lfs, &file, buffer, 7) => 7;
assert(strcmp((char*)buffer, "test.5") == 0); assert(strcmp((char*)buffer, "test.5") == 0);
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;

View File

@@ -1,9 +1,10 @@
[[case]] # orphan test [cases.orphan]
in = "lfs.c" in = "lfs.c"
if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "parent") => 0; lfs_mkdir(&lfs, "parent") => 0;
lfs_mkdir(&lfs, "parent/orphan") => 0; lfs_mkdir(&lfs, "parent/orphan") => 0;
lfs_mkdir(&lfs, "parent/child") => 0; lfs_mkdir(&lfs, "parent/child") => 0;
@@ -13,29 +14,31 @@ code = '''
// corrupt the child's most recent commit, this should be the update // corrupt the child's most recent commit, this should be the update
// to the linked-list entry, which should orphan the orphan. Note this // to the linked-list entry, which should orphan the orphan. Note this
// makes a lot of assumptions about the remove operation. // makes a lot of assumptions about the remove operation.
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "parent/child") => 0; lfs_dir_open(&lfs, &dir, "parent/child") => 0;
lfs_block_t block = dir.m.pair[0]; lfs_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
uint8_t bbuffer[LFS_BLOCK_SIZE]; uint8_t buffer[BLOCK_SIZE];
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
int off = LFS_BLOCK_SIZE-1; int off = BLOCK_SIZE-1;
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) { while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1; off -= 1;
} }
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3); memset(&buffer[off-3], BLOCK_SIZE, 3);
cfg.erase(&cfg, block) => 0; cfg->erase(cfg, block) => 0;
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0; cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
cfg.sync(&cfg) => 0; cfg->sync(cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "parent/child", &info) => 0; lfs_stat(&lfs, "parent/child", &info) => 0;
lfs_fs_size(&lfs) => 8; lfs_fs_size(&lfs) => 8;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "parent/child", &info) => 0; lfs_stat(&lfs, "parent/child", &info) => 0;
lfs_fs_size(&lfs) => 8; lfs_fs_size(&lfs) => 8;
@@ -48,7 +51,7 @@ code = '''
lfs_fs_size(&lfs) => 8; lfs_fs_size(&lfs) => 8;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "parent/child", &info) => 0; lfs_stat(&lfs, "parent/child", &info) => 0;
lfs_stat(&lfs, "parent/otherchild", &info) => 0; lfs_stat(&lfs, "parent/otherchild", &info) => 0;
@@ -56,43 +59,48 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # reentrant testing for orphans, basically just spam mkdir/remove # reentrant testing for orphans, basically just spam mkdir/remove
[cases.reentrant_orphan]
reentrant = true reentrant = true
# TODO fix this case, caused by non-DAG trees # TODO fix this case, caused by non-DAG trees
if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' if = '!(DEPTH == 3 && CACHE_SIZE != 64)'
define = [ defines = [
{FILES=6, DEPTH=1, CYCLES=20}, {FILES=6, DEPTH=1, CYCLES=20},
{FILES=26, DEPTH=1, CYCLES=20}, {FILES=26, DEPTH=1, CYCLES=20},
{FILES=3, DEPTH=3, CYCLES=20}, {FILES=3, DEPTH=3, CYCLES=20},
] ]
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
} }
srand(1); srand(1);
const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; const char alpha[] = "abcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < CYCLES; i++) { for (unsigned i = 0; i < CYCLES; i++) {
// create random path // create random path
char full_path[256]; char full_path[256];
for (int d = 0; d < DEPTH; d++) { for (unsigned d = 0; d < DEPTH; d++) {
sprintf(&full_path[2*d], "/%c", alpha[rand() % FILES]); sprintf(&full_path[2*d], "/%c", alpha[rand() % FILES]);
} }
// if it does not exist, we create it, else we destroy // if it does not exist, we create it, else we destroy
struct lfs_info info;
int res = lfs_stat(&lfs, full_path, &info); int res = lfs_stat(&lfs, full_path, &info);
if (res == LFS_ERR_NOENT) { if (res == LFS_ERR_NOENT) {
// create each directory in turn, ignore if dir already exists // create each directory in turn, ignore if dir already exists
for (int d = 0; d < DEPTH; d++) { for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
err = lfs_mkdir(&lfs, path); err = lfs_mkdir(&lfs, path);
assert(!err || err == LFS_ERR_EXIST); assert(!err || err == LFS_ERR_EXIST);
} }
for (int d = 0; d < DEPTH; d++) { for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
lfs_stat(&lfs, path, &info) => 0; lfs_stat(&lfs, path, &info) => 0;
@@ -106,6 +114,7 @@ code = '''
// try to delete path in reverse order, ignore if dir is not empty // try to delete path in reverse order, ignore if dir is not empty
for (int d = DEPTH-1; d >= 0; d--) { for (int d = DEPTH-1; d >= 0; d--) {
char path[1024];
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
err = lfs_remove(&lfs, path); err = lfs_remove(&lfs, path);

View File

@@ -1,13 +1,16 @@
[[case]] # simple path test # simple path test
[cases.path]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0; lfs_mkdir(&lfs, "tea/coldtea") => 0;
struct lfs_info info;
lfs_stat(&lfs, "tea/hottea", &info) => 0; lfs_stat(&lfs, "tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "/tea/hottea", &info) => 0; lfs_stat(&lfs, "/tea/hottea", &info) => 0;
@@ -21,15 +24,18 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # redundant slashes # redundant slashes
[cases.redundant_slashes]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0; lfs_mkdir(&lfs, "tea/coldtea") => 0;
struct lfs_info info;
lfs_stat(&lfs, "/tea/hottea", &info) => 0; lfs_stat(&lfs, "/tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "//tea//hottea", &info) => 0; lfs_stat(&lfs, "//tea//hottea", &info) => 0;
@@ -45,15 +51,18 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # dot path test # dot path test
[cases.dot_path]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0; lfs_mkdir(&lfs, "tea/coldtea") => 0;
struct lfs_info info;
lfs_stat(&lfs, "./tea/hottea", &info) => 0; lfs_stat(&lfs, "./tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "/./tea/hottea", &info) => 0; lfs_stat(&lfs, "/./tea/hottea", &info) => 0;
@@ -71,10 +80,12 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # dot dot path test # dot dot path test
[cases.dot_dot_path]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0;
@@ -84,6 +95,7 @@ code = '''
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs_mkdir(&lfs, "coffee/warmcoffee") => 0;
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; lfs_mkdir(&lfs, "coffee/coldcoffee") => 0;
struct lfs_info info;
lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0; lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0; lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0;
@@ -101,15 +113,18 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # trailing dot path test # trailing dot path test
[cases.trailing_dot_path]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0; lfs_mkdir(&lfs, "tea/coldtea") => 0;
struct lfs_info info;
lfs_stat(&lfs, "tea/hottea/", &info) => 0; lfs_stat(&lfs, "tea/hottea/", &info) => 0;
assert(strcmp(info.name, "hottea") == 0); assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "tea/hottea/.", &info) => 0; lfs_stat(&lfs, "tea/hottea/.", &info) => 0;
@@ -123,11 +138,14 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # leading dot path test # leading dot path test
[cases.leading_dot_path]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, ".milk") => 0; lfs_mkdir(&lfs, ".milk") => 0;
struct lfs_info info;
lfs_stat(&lfs, ".milk", &info) => 0; lfs_stat(&lfs, ".milk", &info) => 0;
strcmp(info.name, ".milk") => 0; strcmp(info.name, ".milk") => 0;
lfs_stat(&lfs, "tea/.././.milk", &info) => 0; lfs_stat(&lfs, "tea/.././.milk", &info) => 0;
@@ -135,10 +153,12 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # root dot dot path test # root dot dot path test
[cases.root_dot_dot_path]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0; lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0; lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0; lfs_mkdir(&lfs, "tea/warmtea") => 0;
@@ -148,6 +168,7 @@ code = '''
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs_mkdir(&lfs, "coffee/warmcoffee") => 0;
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; lfs_mkdir(&lfs, "coffee/coldcoffee") => 0;
struct lfs_info info;
lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0; strcmp(info.name, "hottea") => 0;
@@ -159,10 +180,13 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # invalid path tests # invalid path tests
[cases.invalid_path]
code = ''' code = '''
lfs_format(&lfs, &cfg); lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg);
lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "dirt", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "dirt", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "dirt/ground", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "dirt/ground", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "dirt/ground/earth", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "dirt/ground/earth", &info) => LFS_ERR_NOENT;
@@ -172,6 +196,7 @@ code = '''
lfs_remove(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; lfs_remove(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT;
lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT; lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT;
lfs_file_t file;
lfs_file_open(&lfs, &file, "dirt/ground", LFS_O_WRONLY | LFS_O_CREAT) lfs_file_open(&lfs, &file, "dirt/ground", LFS_O_WRONLY | LFS_O_CREAT)
=> LFS_ERR_NOENT; => LFS_ERR_NOENT;
lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT;
@@ -180,15 +205,19 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # root operations # root operations
[cases.root]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "/", &info) => 0; lfs_stat(&lfs, "/", &info) => 0;
assert(strcmp(info.name, "/") == 0); assert(strcmp(info.name, "/") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST;
lfs_file_t file;
lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY | LFS_O_CREAT) lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY | LFS_O_CREAT)
=> LFS_ERR_ISDIR; => LFS_ERR_ISDIR;
@@ -196,10 +225,13 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # root representations # root representations
[cases.root_reprs]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "/", &info) => 0; lfs_stat(&lfs, "/", &info) => 0;
assert(strcmp(info.name, "/") == 0); assert(strcmp(info.name, "/") == 0);
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
@@ -221,10 +253,13 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # superblock conflict test # superblock conflict test
[cases.superblock_conflict]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT; lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT;
lfs_remove(&lfs, "littlefs") => LFS_ERR_NOENT; lfs_remove(&lfs, "littlefs") => LFS_ERR_NOENT;
@@ -237,18 +272,22 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # max path test # max path test
[cases.max_path]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "coffee") => 0; lfs_mkdir(&lfs, "coffee") => 0;
lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; lfs_mkdir(&lfs, "coffee/hotcoffee") => 0;
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs_mkdir(&lfs, "coffee/warmcoffee") => 0;
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; lfs_mkdir(&lfs, "coffee/coldcoffee") => 0;
char path[1024];
memset(path, 'w', LFS_NAME_MAX+1); memset(path, 'w', LFS_NAME_MAX+1);
path[LFS_NAME_MAX+1] = '\0'; path[LFS_NAME_MAX+1] = '\0';
lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG;
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT)
=> LFS_ERR_NAMETOOLONG; => LFS_ERR_NAMETOOLONG;
@@ -261,19 +300,23 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # really big path test # really big path test
[cases.really_big_path]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "coffee") => 0; lfs_mkdir(&lfs, "coffee") => 0;
lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; lfs_mkdir(&lfs, "coffee/hotcoffee") => 0;
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; lfs_mkdir(&lfs, "coffee/warmcoffee") => 0;
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; lfs_mkdir(&lfs, "coffee/coldcoffee") => 0;
char path[1024];
memset(path, 'w', LFS_NAME_MAX); memset(path, 'w', LFS_NAME_MAX);
path[LFS_NAME_MAX] = '\0'; path[LFS_NAME_MAX] = '\0';
lfs_mkdir(&lfs, path) => 0; lfs_mkdir(&lfs, path) => 0;
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;

View File

@@ -1,15 +1,18 @@
# specific corner cases worth explicitly testing for # specific corner cases worth explicitly testing for
[[case]] # dangling split dir test [cases.dangling_split_dir]
define.ITERATIONS = 20 defines.ITERATIONS = 20
define.COUNT = 10 defines.COUNT = 10
define.LFS_BLOCK_CYCLES = [8, 1] defines.BLOCK_CYCLES = [8, 1]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// fill up filesystem so only ~16 blocks are left // fill up filesystem so only ~16 blocks are left
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0;
uint8_t buffer[512];
memset(buffer, 0, 512); memset(buffer, 0, 512);
while (LFS_BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { while (BLOCK_COUNT - lfs_fs_size(&lfs) > 16) {
lfs_file_write(&lfs, &file, buffer, 512) => 512; lfs_file_write(&lfs, &file, buffer, 512) => 512;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -17,18 +20,22 @@ code = '''
lfs_mkdir(&lfs, "child") => 0; lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int j = 0; j < ITERATIONS; j++) { for (unsigned j = 0; j < ITERATIONS; j++) {
for (int i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
} }
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "child") => 0; lfs_dir_open(&lfs, &dir, "child") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
for (int i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "test%03d_loooooooooooooooooong_name", i); sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, path) => 0;
@@ -36,46 +43,54 @@ code = '''
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
if (j == ITERATIONS-1) { if (j == (unsigned)ITERATIONS-1) {
break; break;
} }
for (int i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
} }
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "child") => 0; lfs_dir_open(&lfs, &dir, "child") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
for (int i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "test%03d_loooooooooooooooooong_name", i); sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, path) => 0;
} }
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
for (int i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # outdated head test [cases.outdated_head]
define.ITERATIONS = 20 defines.ITERATIONS = 20
define.COUNT = 10 defines.COUNT = 10
define.LFS_BLOCK_CYCLES = [8, 1] defines.BLOCK_CYCLES = [8, 1]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
// fill up filesystem so only ~16 blocks are left // fill up filesystem so only ~16 blocks are left
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0;
uint8_t buffer[512];
memset(buffer, 0, 512); memset(buffer, 0, 512);
while (LFS_BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { while (BLOCK_COUNT - lfs_fs_size(&lfs) > 16) {
lfs_file_write(&lfs, &file, buffer, 512) => 512; lfs_file_write(&lfs, &file, buffer, 512) => 512;
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -83,18 +98,22 @@ code = '''
lfs_mkdir(&lfs, "child") => 0; lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (int j = 0; j < ITERATIONS; j++) { for (unsigned j = 0; j < ITERATIONS; j++) {
for (int i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
} }
lfs_dir_t dir;
struct lfs_info info;
lfs_dir_open(&lfs, &dir, "child") => 0; lfs_dir_open(&lfs, &dir, "child") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
for (int i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "test%03d_loooooooooooooooooong_name", i); sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, path) => 0;
@@ -110,7 +129,8 @@ code = '''
lfs_dir_rewind(&lfs, &dir) => 0; lfs_dir_rewind(&lfs, &dir) => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
for (int i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "test%03d_loooooooooooooooooong_name", i); sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, path) => 0;
@@ -126,7 +146,8 @@ code = '''
lfs_dir_rewind(&lfs, &dir) => 0; lfs_dir_rewind(&lfs, &dir) => 0;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
for (int i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "test%03d_loooooooooooooooooong_name", i); sprintf(path, "test%03d_loooooooooooooooooong_name", i);
lfs_dir_read(&lfs, &dir, &info) => 1; lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0; strcmp(info.name, path) => 0;
@@ -135,7 +156,8 @@ code = '''
lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0; lfs_dir_close(&lfs, &dir) => 0;
for (int i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs_remove(&lfs, path) => 0; lfs_remove(&lfs, path) => 0;
} }
@@ -143,45 +165,50 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # reentrant testing for relocations, this is the same as the # reentrant testing for relocations, this is the same as the
# orphan testing, except here we also set block_cycles so that # orphan testing, except here we also set block_cycles so that
# almost every tree operation needs a relocation # almost every tree operation needs a relocation
[cases.reentrant_relocations]
reentrant = true reentrant = true
# TODO fix this case, caused by non-DAG trees # TODO fix this case, caused by non-DAG trees
if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' if = '!(DEPTH == 3 && CACHE_SIZE != 64)'
define = [ defines = [
{FILES=6, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=6, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1},
{FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=26, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1},
{FILES=3, DEPTH=3, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=3, DEPTH=3, CYCLES=20, BLOCK_CYCLES=1},
] ]
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
} }
srand(1); srand(1);
const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; const char alpha[] = "abcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < CYCLES; i++) { for (unsigned i = 0; i < CYCLES; i++) {
// create random path // create random path
char full_path[256]; char full_path[256];
for (int d = 0; d < DEPTH; d++) { for (unsigned d = 0; d < DEPTH; d++) {
sprintf(&full_path[2*d], "/%c", alpha[rand() % FILES]); sprintf(&full_path[2*d], "/%c", alpha[rand() % FILES]);
} }
// if it does not exist, we create it, else we destroy // if it does not exist, we create it, else we destroy
struct lfs_info info;
int res = lfs_stat(&lfs, full_path, &info); int res = lfs_stat(&lfs, full_path, &info);
if (res == LFS_ERR_NOENT) { if (res == LFS_ERR_NOENT) {
// create each directory in turn, ignore if dir already exists // create each directory in turn, ignore if dir already exists
for (int d = 0; d < DEPTH; d++) { for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
err = lfs_mkdir(&lfs, path); err = lfs_mkdir(&lfs, path);
assert(!err || err == LFS_ERR_EXIST); assert(!err || err == LFS_ERR_EXIST);
} }
for (int d = 0; d < DEPTH; d++) { for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
lfs_stat(&lfs, path, &info) => 0; lfs_stat(&lfs, path, &info) => 0;
@@ -194,7 +221,8 @@ code = '''
assert(info.type == LFS_TYPE_DIR); assert(info.type == LFS_TYPE_DIR);
// try to delete path in reverse order, ignore if dir is not empty // try to delete path in reverse order, ignore if dir is not empty
for (int d = DEPTH-1; d >= 0; d--) { for (unsigned d = DEPTH-1; d+1 > 0; d--) {
char path[1024];
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
err = lfs_remove(&lfs, path); err = lfs_remove(&lfs, path);
@@ -207,44 +235,49 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # reentrant testing for relocations, but now with random renames! # reentrant testing for relocations, but now with random renames!
[cases.reentrant_relocations_renames]
reentrant = true reentrant = true
# TODO fix this case, caused by non-DAG trees # TODO fix this case, caused by non-DAG trees
if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)' if = '!(DEPTH == 3 && CACHE_SIZE != 64)'
define = [ defines = [
{FILES=6, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=6, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1},
{FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=26, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1},
{FILES=3, DEPTH=3, CYCLES=20, LFS_BLOCK_CYCLES=1}, {FILES=3, DEPTH=3, CYCLES=20, BLOCK_CYCLES=1},
] ]
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
} }
srand(1); srand(1);
const char alpha[] = "abcdefghijklmnopqrstuvwxyz"; const char alpha[] = "abcdefghijklmnopqrstuvwxyz";
for (int i = 0; i < CYCLES; i++) { for (unsigned i = 0; i < CYCLES; i++) {
// create random path // create random path
char full_path[256]; char full_path[256];
for (int d = 0; d < DEPTH; d++) { for (unsigned d = 0; d < DEPTH; d++) {
sprintf(&full_path[2*d], "/%c", alpha[rand() % FILES]); sprintf(&full_path[2*d], "/%c", alpha[rand() % FILES]);
} }
// if it does not exist, we create it, else we destroy // if it does not exist, we create it, else we destroy
struct lfs_info info;
int res = lfs_stat(&lfs, full_path, &info); int res = lfs_stat(&lfs, full_path, &info);
assert(!res || res == LFS_ERR_NOENT); assert(!res || res == LFS_ERR_NOENT);
if (res == LFS_ERR_NOENT) { if (res == LFS_ERR_NOENT) {
// create each directory in turn, ignore if dir already exists // create each directory in turn, ignore if dir already exists
for (int d = 0; d < DEPTH; d++) { for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
err = lfs_mkdir(&lfs, path); err = lfs_mkdir(&lfs, path);
assert(!err || err == LFS_ERR_EXIST); assert(!err || err == LFS_ERR_EXIST);
} }
for (int d = 0; d < DEPTH; d++) { for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
lfs_stat(&lfs, path, &info) => 0; lfs_stat(&lfs, path, &info) => 0;
@@ -257,7 +290,7 @@ code = '''
// create new random path // create new random path
char new_path[256]; char new_path[256];
for (int d = 0; d < DEPTH; d++) { for (unsigned d = 0; d < DEPTH; d++) {
sprintf(&new_path[2*d], "/%c", alpha[rand() % FILES]); sprintf(&new_path[2*d], "/%c", alpha[rand() % FILES]);
} }
@@ -266,7 +299,8 @@ code = '''
assert(!res || res == LFS_ERR_NOENT); assert(!res || res == LFS_ERR_NOENT);
if (res == LFS_ERR_NOENT) { if (res == LFS_ERR_NOENT) {
// stop once some dir is renamed // stop once some dir is renamed
for (int d = 0; d < DEPTH; d++) { for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(&path[2*d], &full_path[2*d]); strcpy(&path[2*d], &full_path[2*d]);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
strcpy(&path[128+2*d], &new_path[2*d]); strcpy(&path[128+2*d], &new_path[2*d]);
@@ -278,7 +312,8 @@ code = '''
} }
} }
for (int d = 0; d < DEPTH; d++) { for (unsigned d = 0; d < DEPTH; d++) {
char path[1024];
strcpy(path, new_path); strcpy(path, new_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
lfs_stat(&lfs, path, &info) => 0; lfs_stat(&lfs, path, &info) => 0;
@@ -290,7 +325,8 @@ code = '''
} else { } else {
// try to delete path in reverse order, // try to delete path in reverse order,
// ignore if dir is not empty // ignore if dir is not empty
for (int d = DEPTH-1; d >= 0; d--) { for (unsigned d = DEPTH-1; d+1 > 0; d--) {
char path[1024];
strcpy(path, full_path); strcpy(path, full_path);
path[2*d+2] = '\0'; path[2*d+2] = '\0';
err = lfs_remove(&lfs, path); err = lfs_remove(&lfs, path);

View File

@@ -1,6 +1,7 @@
[[case]] # simple file seek # simple file seek
define = [ [cases.seek]
defines = [
{COUNT=132, SKIP=4}, {COUNT=132, SKIP=4},
{COUNT=132, SKIP=128}, {COUNT=132, SKIP=128},
{COUNT=200, SKIP=10}, {COUNT=200, SKIP=10},
@@ -9,11 +10,14 @@ define = [
{COUNT=4, SKIP=2}, {COUNT=4, SKIP=2},
] ]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "kitty", lfs_file_open(&lfs, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
size = strlen("kittycatcat"); size_t size = strlen("kittycatcat");
uint8_t buffer[1024];
memcpy(buffer, "kittycatcat", size); memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < COUNT; j++) { for (int j = 0; j < COUNT; j++) {
lfs_file_write(&lfs, &file, buffer, size); lfs_file_write(&lfs, &file, buffer, size);
@@ -21,7 +25,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY) => 0;
lfs_soff_t pos = -1; lfs_soff_t pos = -1;
@@ -68,8 +72,9 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # simple file seek and write # simple file seek and write
define = [ [cases.seek_write]
defines = [
{COUNT=132, SKIP=4}, {COUNT=132, SKIP=4},
{COUNT=132, SKIP=128}, {COUNT=132, SKIP=128},
{COUNT=200, SKIP=10}, {COUNT=200, SKIP=10},
@@ -78,11 +83,14 @@ define = [
{COUNT=4, SKIP=2}, {COUNT=4, SKIP=2},
] ]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "kitty", lfs_file_open(&lfs, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
size = strlen("kittycatcat"); size_t size = strlen("kittycatcat");
uint8_t buffer[1024];
memcpy(buffer, "kittycatcat", size); memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < COUNT; j++) { for (int j = 0; j < COUNT; j++) {
lfs_file_write(&lfs, &file, buffer, size); lfs_file_write(&lfs, &file, buffer, size);
@@ -90,7 +98,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
lfs_soff_t pos = -1; lfs_soff_t pos = -1;
@@ -129,15 +137,18 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # boundary seek and writes # boundary seek and writes
define.COUNT = 132 [cases.boundary_seek_write]
define.OFFSETS = '"{512, 1020, 513, 1021, 511, 1019, 1441}"' defines.COUNT = 132
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "kitty", lfs_file_open(&lfs, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
size = strlen("kittycatcat"); size_t size = strlen("kittycatcat");
uint8_t buffer[1024];
memcpy(buffer, "kittycatcat", size); memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < COUNT; j++) { for (int j = 0; j < COUNT; j++) {
lfs_file_write(&lfs, &file, buffer, size); lfs_file_write(&lfs, &file, buffer, size);
@@ -145,11 +156,11 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
size = strlen("hedgehoghog"); size = strlen("hedgehoghog");
const lfs_soff_t offsets[] = OFFSETS; const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019, 1441};
for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) {
lfs_soff_t off = offsets[i]; lfs_soff_t off = offsets[i];
@@ -183,8 +194,9 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # out of bounds seek # out of bounds seek
define = [ [cases.out_of_bounds_seek]
defines = [
{COUNT=132, SKIP=4}, {COUNT=132, SKIP=4},
{COUNT=132, SKIP=128}, {COUNT=132, SKIP=128},
{COUNT=200, SKIP=10}, {COUNT=200, SKIP=10},
@@ -193,18 +205,21 @@ define = [
{COUNT=4, SKIP=3}, {COUNT=4, SKIP=3},
] ]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "kitty", lfs_file_open(&lfs, &file, "kitty",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
size = strlen("kittycatcat"); size_t size = strlen("kittycatcat");
uint8_t buffer[1024];
memcpy(buffer, "kittycatcat", size); memcpy(buffer, "kittycatcat", size);
for (int j = 0; j < COUNT; j++) { for (int j = 0; j < COUNT; j++) {
lfs_file_write(&lfs, &file, buffer, size); lfs_file_write(&lfs, &file, buffer, size);
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
size = strlen("kittycatcat"); size = strlen("kittycatcat");
@@ -238,16 +253,20 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # inline write and seek # inline write and seek
define.SIZE = [2, 4, 128, 132] [cases.inline_write_seek]
defines.SIZE = [2, 4, 128, 132]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "tinykitty", lfs_file_open(&lfs, &file, "tinykitty",
LFS_O_RDWR | LFS_O_CREAT) => 0; LFS_O_RDWR | LFS_O_CREAT) => 0;
int j = 0; int j = 0;
int k = 0; int k = 0;
uint8_t buffer[1024];
memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26); memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26);
for (unsigned i = 0; i < SIZE; i++) { for (unsigned i = 0; i < SIZE; i++) {
lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1; lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1;
@@ -305,16 +324,20 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # file seek and write with power-loss # file seek and write with power-loss
[cases.reentrant_seek_write]
# must be power-of-2 for quadratic probing to be exhaustive # must be power-of-2 for quadratic probing to be exhaustive
define.COUNT = [4, 64, 128] defines.COUNT = [4, 64, 128]
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
} }
lfs_file_t file;
uint8_t buffer[1024];
err = lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY); err = lfs_file_open(&lfs, &file, "kitty", LFS_O_RDONLY);
assert(!err || err == LFS_ERR_NOENT); assert(!err || err == LFS_ERR_NOENT);
if (!err) { if (!err) {
@@ -334,14 +357,14 @@ code = '''
if (lfs_file_size(&lfs, &file) == 0) { if (lfs_file_size(&lfs, &file) == 0) {
for (int j = 0; j < COUNT; j++) { for (int j = 0; j < COUNT; j++) {
strcpy((char*)buffer, "kittycatcat"); strcpy((char*)buffer, "kittycatcat");
size = strlen((char*)buffer); size_t size = strlen((char*)buffer);
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
} }
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
strcpy((char*)buffer, "doggodogdog"); strcpy((char*)buffer, "doggodogdog");
size = strlen((char*)buffer); size_t size = strlen((char*)buffer);
lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "kitty", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => COUNT*size; lfs_file_size(&lfs, &file) => COUNT*size;

View File

@@ -1,41 +1,53 @@
[[case]] # simple formatting test # simple formatting test
[cases.format]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
''' '''
[[case]] # mount/unmount # mount/unmount
[cases.mount]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # reentrant format # reentrant format
[cases.reentrant_format]
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
} }
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # invalid mount # invalid mount
[cases.invalid_mount]
code = ''' code = '''
lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; lfs_t lfs;
lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
''' '''
[[case]] # expanding superblock # expanding superblock
define.LFS_BLOCK_CYCLES = [32, 33, 1] [cases.expanding_superblock]
define.N = [10, 100, 1000] defines.LFS_BLOCK_CYCLES = [32, 33, 1]
defines.N = [10, 100, 1000]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
lfs_file_t file;
lfs_file_open(&lfs, &file, "dummy", lfs_file_open(&lfs, &file, "dummy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
struct lfs_info info;
lfs_stat(&lfs, "dummy", &info) => 0; lfs_stat(&lfs, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
@@ -44,25 +56,30 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// one last check after power-cycle // one last check after power-cycle
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "dummy", lfs_file_open(&lfs, &file, "dummy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
struct lfs_info info;
lfs_stat(&lfs, "dummy", &info) => 0; lfs_stat(&lfs, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # expanding superblock with power cycle # expanding superblock with power cycle
define.LFS_BLOCK_CYCLES = [32, 33, 1] [cases.expanding_superblock_power_cycle]
define.N = [10, 100, 1000] defines.LFS_BLOCK_CYCLES = [32, 33, 1]
defines.N = [10, 100, 1000]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_format(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
// remove lingering dummy? // remove lingering dummy?
err = lfs_stat(&lfs, "dummy", &info); struct lfs_info info;
int err = lfs_stat(&lfs, "dummy", &info);
assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); assert(err == 0 || (err == LFS_ERR_NOENT && i == 0));
if (!err) { if (!err) {
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
@@ -70,6 +87,7 @@ code = '''
lfs_remove(&lfs, "dummy") => 0; lfs_remove(&lfs, "dummy") => 0;
} }
lfs_file_t file;
lfs_file_open(&lfs, &file, "dummy", lfs_file_open(&lfs, &file, "dummy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -80,26 +98,30 @@ code = '''
} }
// one last check after power-cycle // one last check after power-cycle
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "dummy", &info) => 0; lfs_stat(&lfs, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # reentrant expanding superblock # reentrant expanding superblock
define.LFS_BLOCK_CYCLES = [2, 1] [cases.reentrant_expanding_superblock]
define.N = 24 defines.LFS_BLOCK_CYCLES = [2, 1]
defines.N = 24
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
} }
for (int i = 0; i < N; i++) { for (int i = 0; i < N; i++) {
// remove lingering dummy? // remove lingering dummy?
struct lfs_info info;
err = lfs_stat(&lfs, "dummy", &info); err = lfs_stat(&lfs, "dummy", &info);
assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); assert(err == 0 || (err == LFS_ERR_NOENT && i == 0));
if (!err) { if (!err) {
@@ -108,6 +130,7 @@ code = '''
lfs_remove(&lfs, "dummy") => 0; lfs_remove(&lfs, "dummy") => 0;
} }
lfs_file_t file;
lfs_file_open(&lfs, &file, "dummy", lfs_file_open(&lfs, &file, "dummy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
@@ -119,7 +142,8 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// one last check after power-cycle // one last check after power-cycle
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
struct lfs_info info;
lfs_stat(&lfs, "dummy", &info) => 0; lfs_stat(&lfs, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0); assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG); assert(info.type == LFS_TYPE_REG);

View File

@@ -1,14 +1,18 @@
[[case]] # simple truncate # simple truncate
define.MEDIUMSIZE = [32, 2048] [cases.truncate]
define.LARGESIZE = 8192 defines.MEDIUMSIZE = [32, 2048]
defines.LARGESIZE = 8192
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "baldynoop", lfs_file_open(&lfs, &file, "baldynoop",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size = strlen((char*)buffer); size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) { for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -17,7 +21,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE; lfs_file_size(&lfs, &file) => LARGESIZE;
@@ -27,7 +31,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs_file_size(&lfs, &file) => MEDIUMSIZE;
@@ -42,17 +46,21 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # truncate and read # truncate and read
define.MEDIUMSIZE = [32, 2048] [cases.truncate_read]
define.LARGESIZE = 8192 defines.MEDIUMSIZE = [32, 2048]
defines.LARGESIZE = 8192
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "baldyread", lfs_file_open(&lfs, &file, "baldyread",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size = strlen((char*)buffer); size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) { for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -61,7 +69,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE; lfs_file_size(&lfs, &file) => LARGESIZE;
@@ -78,7 +86,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs_file_size(&lfs, &file) => MEDIUMSIZE;
@@ -93,14 +101,18 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # write, truncate, and read # write, truncate, and read
[cases.write_truncate_read]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "sequence", lfs_file_open(&lfs, &file, "sequence",
LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0;
size = lfs_min(lfs.cfg->cache_size, sizeof(buffer)/2); uint8_t buffer[1024];
size_t size = lfs_min(lfs.cfg->cache_size, sizeof(buffer)/2);
lfs_size_t qsize = size / 4; lfs_size_t qsize = size / 4;
uint8_t *wb = buffer; uint8_t *wb = buffer;
uint8_t *rb = buffer + size; uint8_t *rb = buffer + size;
@@ -145,17 +157,21 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # truncate and write # truncate and write
define.MEDIUMSIZE = [32, 2048] [cases.truncate_write]
define.LARGESIZE = 8192 defines.MEDIUMSIZE = [32, 2048]
defines.LARGESIZE = 8192
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "baldywrite", lfs_file_open(&lfs, &file, "baldywrite",
LFS_O_WRONLY | LFS_O_CREAT) => 0; LFS_O_WRONLY | LFS_O_CREAT) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size = strlen((char*)buffer); size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) { for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -164,7 +180,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => LARGESIZE; lfs_file_size(&lfs, &file) => LARGESIZE;
@@ -181,7 +197,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0; lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs_file_size(&lfs, &file) => MEDIUMSIZE;
@@ -196,26 +212,30 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # truncate write under powerloss # truncate write under powerloss
define.SMALLSIZE = [4, 512] [cases.reentrant_truncate_write]
define.MEDIUMSIZE = [32, 1024] defines.SMALLSIZE = [4, 512]
define.LARGESIZE = 2048 defines.MEDIUMSIZE = [32, 1024]
defines.LARGESIZE = 2048
reentrant = true reentrant = true
code = ''' code = '''
err = lfs_mount(&lfs, &cfg); lfs_t lfs;
int err = lfs_mount(&lfs, cfg);
if (err) { if (err) {
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
} }
lfs_file_t file;
err = lfs_file_open(&lfs, &file, "baldy", LFS_O_RDONLY); err = lfs_file_open(&lfs, &file, "baldy", LFS_O_RDONLY);
assert(!err || err == LFS_ERR_NOENT); assert(!err || err == LFS_ERR_NOENT);
if (!err) { if (!err) {
size = lfs_file_size(&lfs, &file); size_t size = lfs_file_size(&lfs, &file);
assert(size == 0 || assert(size == 0 ||
size == LARGESIZE || size == (size_t)LARGESIZE ||
size == MEDIUMSIZE || size == (size_t)MEDIUMSIZE ||
size == SMALLSIZE); size == (size_t)SMALLSIZE);
for (lfs_off_t j = 0; j < size; j += 4) { for (lfs_off_t j = 0; j < size; j += 4) {
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 4) => 4; lfs_file_read(&lfs, &file, buffer, 4) => 4;
assert(memcmp(buffer, "hair", 4) == 0 || assert(memcmp(buffer, "hair", 4) == 0 ||
memcmp(buffer, "bald", 4) == 0 || memcmp(buffer, "bald", 4) == 0 ||
@@ -227,8 +247,9 @@ code = '''
lfs_file_open(&lfs, &file, "baldy", lfs_file_open(&lfs, &file, "baldy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
lfs_file_size(&lfs, &file) => 0; lfs_file_size(&lfs, &file) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size = strlen((char*)buffer); size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) { for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -262,12 +283,14 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # more aggressive general truncation tests # more aggressive general truncation tests
define.CONFIG = 'range(6)' [cases.aggressive_truncate]
define.SMALLSIZE = 32 defines.CONFIG = [0,1,2,3,4,5]
define.MEDIUMSIZE = 2048 defines.SMALLSIZE = 32
define.LARGESIZE = 8192 defines.MEDIUMSIZE = 2048
defines.LARGESIZE = 8192
code = ''' code = '''
lfs_t lfs;
#define COUNT 5 #define COUNT 5
const struct { const struct {
lfs_off_t startsizes[COUNT]; lfs_off_t startsizes[COUNT];
@@ -312,16 +335,19 @@ code = '''
const lfs_off_t *hotsizes = configs[CONFIG].hotsizes; const lfs_off_t *hotsizes = configs[CONFIG].hotsizes;
const lfs_off_t *coldsizes = configs[CONFIG].coldsizes; const lfs_off_t *coldsizes = configs[CONFIG].coldsizes;
lfs_format(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (unsigned i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "hairyhead%d", i); sprintf(path, "hairyhead%d", i);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size = strlen((char*)buffer); size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < startsizes[i]; j += size) { for (lfs_off_t j = 0; j < startsizes[i]; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
} }
@@ -340,21 +366,25 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (unsigned i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "hairyhead%d", i); sprintf(path, "hairyhead%d", i);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => hotsizes[i]; lfs_file_size(&lfs, &file) => hotsizes[i];
size = strlen("hair"); size_t size = strlen("hair");
lfs_off_t j = 0; lfs_off_t j = 0;
for (; j < startsizes[i] && j < hotsizes[i]; j += size) { for (; j < startsizes[i] && j < hotsizes[i]; j += size) {
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0; memcmp(buffer, "hair", size) => 0;
} }
for (; j < hotsizes[i]; j += size) { for (; j < hotsizes[i]; j += size) {
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "\0\0\0\0", size) => 0; memcmp(buffer, "\0\0\0\0", size) => 0;
} }
@@ -367,22 +397,26 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
for (unsigned i = 0; i < COUNT; i++) { for (unsigned i = 0; i < COUNT; i++) {
char path[1024];
sprintf(path, "hairyhead%d", i); sprintf(path, "hairyhead%d", i);
lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => coldsizes[i]; lfs_file_size(&lfs, &file) => coldsizes[i];
size = strlen("hair"); size_t size = strlen("hair");
lfs_off_t j = 0; lfs_off_t j = 0;
for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i]; for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i];
j += size) { j += size) {
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0; memcmp(buffer, "hair", size) => 0;
} }
for (; j < coldsizes[i]; j += size) { for (; j < coldsizes[i]; j += size) {
uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size; lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "\0\0\0\0", size) => 0; memcmp(buffer, "\0\0\0\0", size) => 0;
} }
@@ -393,16 +427,20 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
''' '''
[[case]] # noop truncate # noop truncate
define.MEDIUMSIZE = [32, 2048] [cases.nop_truncate]
defines.MEDIUMSIZE = [32, 2048]
code = ''' code = '''
lfs_format(&lfs, &cfg) => 0; lfs_t lfs;
lfs_mount(&lfs, &cfg) => 0; lfs_format(&lfs, cfg) => 0;
lfs_mount(&lfs, cfg) => 0;
lfs_file_t file;
lfs_file_open(&lfs, &file, "baldynoop", lfs_file_open(&lfs, &file, "baldynoop",
LFS_O_RDWR | LFS_O_CREAT) => 0; LFS_O_RDWR | LFS_O_CREAT) => 0;
uint8_t buffer[1024];
strcpy((char*)buffer, "hair"); strcpy((char*)buffer, "hair");
size = strlen((char*)buffer); size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size; lfs_file_write(&lfs, &file, buffer, size) => size;
@@ -426,7 +464,7 @@ code = '''
lfs_unmount(&lfs) => 0; lfs_unmount(&lfs) => 0;
// still there after reboot? // still there after reboot?
lfs_mount(&lfs, &cfg) => 0; lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => MEDIUMSIZE; lfs_file_size(&lfs, &file) => MEDIUMSIZE;
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) { for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {