Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/littlefs-project/littlefs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile36
-rw-r--r--runners/test_runner.c22
-rw-r--r--runners/test_runner.h6
-rwxr-xr-xscripts/test.py1759
-rwxr-xr-xscripts/test_.py1027
-rw-r--r--tests/test_alloc.toml292
-rw-r--r--tests/test_attrs.toml50
-rw-r--r--tests/test_badblocks.toml129
-rw-r--r--tests/test_dirs.toml267
-rw-r--r--tests/test_entries.toml87
-rw-r--r--tests/test_evil.toml116
-rw-r--r--tests/test_exhaustion.toml204
-rw-r--r--tests/test_files.toml174
-rw-r--r--tests/test_interspersed.toml72
-rw-r--r--tests/test_move.toml458
-rw-r--r--tests/test_orphans.toml61
-rw-r--r--tests/test_paths.toml121
-rw-r--r--tests/test_relocations.toml162
-rw-r--r--tests/test_seek.toml97
-rw-r--r--tests/test_superblocks.toml86
-rw-r--r--tests/test_truncate.toml154
21 files changed, 2550 insertions, 2830 deletions
diff --git a/Makefile b/Makefile
index fc16451..9cc3770 100644
--- a/Makefile
+++ b/Makefile
@@ -32,7 +32,7 @@ DEP := $(SRC:%.c=$(BUILDDIR)%.d)
ASM := $(SRC:%.c=$(BUILDDIR)%.s)
CGI := $(SRC:%.c=$(BUILDDIR)%.ci)
-TESTS ?= $(wildcard tests_/*.toml)
+TESTS ?= $(wildcard tests/*.toml)
TEST_SRC ?= $(SRC) \
$(filter-out $(wildcard bd/*.*.c),$(wildcard bd/*.c)) \
runners/test_runner.c
@@ -53,10 +53,11 @@ override CFLAGS += -g3
override CFLAGS += -I.
override CFLAGS += -std=c99 -Wall -pedantic
override CFLAGS += -Wextra -Wshadow -Wjump-misses-init -Wundef
+override CFLAGS += -ftrack-macro-expansion=0
-override TESTFLAGS_ += -b
+override TESTFLAGS += -b
# forward -j flag
-override TESTFLAGS_ += $(filter -j%,$(MAKEFLAGS))
+override TESTFLAGS += $(filter -j%,$(MAKEFLAGS))
ifdef VERBOSE
override TESTFLAGS += -v
override CALLSFLAGS += -v
@@ -65,15 +66,14 @@ override DATAFLAGS += -v
override STACKFLAGS += -v
override STRUCTSFLAGS += -v
override COVERAGEFLAGS += -v
-override TESTFLAGS_ += -v
-override TESTCFLAGS_ += -v
+override TESTFLAGS += -v
+override TESTCFLAGS += -v
endif
ifdef EXEC
-override TESTFLAGS_ += --exec="$(EXEC)"
+override TESTFLAGS += --exec="$(EXEC)"
endif
ifdef COVERAGE
-override TESTFLAGS += --coverage
-override TESTFLAGS_ += --coverage
+override TESTFLAGS += --coverage
endif
ifdef BUILDDIR
override TESTFLAGS += --build-dir="$(BUILDDIR:/=)"
@@ -112,23 +112,16 @@ tags:
calls: $(CGI)
./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
test_runner: $(BUILDDIR)runners/test_runner
-.PHONY: test_
-test_: test_runner
- ./scripts/test_.py --runner=$(BUILDDIR)runners/test_runner $(TESTFLAGS_)
+.PHONY: test
+test: test_runner
+ ./scripts/test.py --runner=$(BUILDDIR)runners/test_runner $(TESTFLAGS)
.PHONY: test_list
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
code: $(OBJ)
@@ -199,10 +192,10 @@ $(BUILDDIR)%.a.c: $(BUILDDIR)%.c
./scripts/explode_asserts.py $< -o $@
$(BUILDDIR)%.t.c: %.toml
- ./scripts/test_.py -c $< $(TESTCFLAGS_) -o $@
+ ./scripts/test.py -c $< $(TESTCFLAGS) -o $@
$(BUILDDIR)%.t.c: %.c $(TESTS)
- ./scripts/test_.py -c $(TESTS) -s $< $(TESTCFLAGS_) -o $@
+ ./scripts/test.py -c $(TESTS) -s $< $(TESTCFLAGS) -o $@
# clean everything
.PHONY: clean
@@ -215,7 +208,6 @@ clean:
rm -f $(CGI)
rm -f $(DEP)
rm -f $(ASM)
- rm -f $(BUILDDIR)tests/*.toml.*
rm -f $(TEST_TSRC)
rm -f $(TEST_TASRC)
rm -f $(TEST_TAOBJ)
diff --git a/runners/test_runner.c b/runners/test_runner.c
index 1b3ea5c..21ff1c0 100644
--- a/runners/test_runner.c
+++ b/runners/test_runner.c
@@ -10,17 +10,17 @@
// test geometries
struct test_geometry {
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]
= TEST_GEOMETRIES;
// test define lookup and management
-const uintmax_t *test_override_defines;
-uintmax_t (*const *test_case_defines)(void);
-const uintmax_t *test_geometry_defines;
-const uintmax_t test_default_defines[TEST_PREDEFINE_COUNT]
+const intmax_t *test_override_defines;
+intmax_t (*const *test_case_defines)(void);
+const intmax_t *test_geometry_defines;
+const intmax_t test_default_defines[TEST_PREDEFINE_COUNT]
= TEST_DEFAULTS;
uint8_t test_override_predefine_map[TEST_PREDEFINE_COUNT];
@@ -37,7 +37,7 @@ const char *const *test_define_names;
size_t test_define_count;
-uintmax_t test_predefine(size_t define) {
+intmax_t test_predefine(size_t define) {
if (test_override_defines
&& test_override_predefine_map[define] != 0xff) {
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
&& test_override_define_map[define] != 0xff) {
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(
const char *const *override_names,
- const uintmax_t *override_defines,
+ const intmax_t *override_defines,
size_t override_count) {
test_override_defines = override_defines;
test_override_names = override_names;
@@ -583,7 +583,7 @@ int main(int argc, char **argv) {
void (*op)(void) = run;
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_cap = 0;
@@ -685,10 +685,10 @@ int main(int argc, char **argv) {
override_names = realloc(override_names, override_cap
* sizeof(const char *));
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
char *sep = strchr(optarg, '=');
char *parsed = NULL;
diff --git a/runners/test_runner.h b/runners/test_runner.h
index 22cbcaa..e033637 100644
--- a/runners/test_runner.h
+++ b/runners/test_runner.h
@@ -19,7 +19,7 @@ struct test_case {
test_types_t types;
size_t permutations;
- uintmax_t (*const *const *defines)(void);
+ intmax_t (*const *const *defines)(void);
bool (*filter)(void);
void (*run)(struct lfs_config *cfg);
@@ -43,8 +43,8 @@ extern const size_t test_suite_count;
// access generated test defines
-uintmax_t test_predefine(size_t define);
-uintmax_t test_define(size_t define);
+intmax_t test_predefine(size_t define);
+intmax_t test_define(size_t define);
// a few preconfigured defines that control how tests run
#define READ_SIZE test_predefine(0)
diff --git a/scripts/test.py b/scripts/test.py
index 92a13b1..4110bba 100755
--- a/scripts/test.py
+++ b/scripts/test.py
@@ -1,860 +1,1027 @@
#!/usr/bin/env python3
-
-# This script manages littlefs tests, which are configured with
-# .toml files stored in the tests directory.
+#
+# Script to compile and runs tests.
#
-import toml
+import collections as co
+import errno
import glob
-import re
-import os
-import io
import itertools as it
-import collections.abc as abc
-import subprocess as sp
-import base64
-import sys
-import copy
-import shlex
+import math as m
+import os
import pty
-import errno
+import re
+import shlex
+import shutil
import signal
+import subprocess as sp
+import threading as th
+import time
+import toml
-TEST_PATHS = 'tests'
-RULES = """
-# add block devices to sources
-TESTSRC ?= $(SRC) $(wildcard bd/*.c)
-
-define FLATTEN
-%(path)s%%$(subst /,.,$(target)): $(target)
- ./scripts/explode_asserts.py $$< -o $$@
-endef
-$(foreach target,$(TESTSRC),$(eval $(FLATTEN)))
-
--include %(path)s*.d
-.SECONDARY:
-%(path)s.test: %(path)s.test.o \\
- $(foreach t,$(subst /,.,$(TESTSRC:.c=.o)),%(path)s.$t)
- $(CC) $(CFLAGS) $^ $(LFLAGS) -o $@
+TEST_PATHS = ['tests']
+RUNNER_PATH = './runners/test_runner'
-# needed in case builddir is different
-%(path)s%%.o: %(path)s%%.c
- $(CC) -c -MMD $(CFLAGS) $< -o $@
-"""
-COVERAGE_RULES = """
-%(path)s.test: override CFLAGS += -fprofile-arcs -ftest-coverage
-
-# delete lingering coverage
-%(path)s.test: | %(path)s.info.clean
-.PHONY: %(path)s.info.clean
-%(path)s.info.clean:
- rm -f %(path)s*.gcda
-
-# accumulate coverage info
-.PHONY: %(path)s.info
-%(path)s.info:
- $(strip $(LCOV) -c \\
- $(addprefix -d ,$(wildcard %(path)s*.gcda)) \\
- --rc 'geninfo_adjust_src_path=$(shell pwd)' \\
- -o $@)
- $(LCOV) -e $@ $(addprefix /,$(SRC)) -o $@
-ifdef COVERAGETARGET
- $(strip $(LCOV) -a $@ \\
- $(addprefix -a ,$(wildcard $(COVERAGETARGET))) \\
- -o $(COVERAGETARGET))
-endif
-"""
-GLOBALS = """
-//////////////// AUTOGENERATED TEST ////////////////
-#include "lfs.h"
+SUITE_PROLOGUE = """
+#include "runners/test_runner.h"
#include "bd/lfs_testbd.h"
#include <stdio.h>
-extern const char *lfs_testbd_path;
-extern uint32_t lfs_testbd_cycles;
"""
-DEFINES = {
- 'LFS_READ_SIZE': 16,
- 'LFS_PROG_SIZE': 'LFS_READ_SIZE',
- 'LFS_BLOCK_SIZE': 512,
- 'LFS_BLOCK_COUNT': 1024,
- 'LFS_BLOCK_CYCLES': -1,
- 'LFS_CACHE_SIZE': '(64 % LFS_PROG_SIZE == 0 ? 64 : LFS_PROG_SIZE)',
- 'LFS_LOOKAHEAD_SIZE': 16,
- 'LFS_ERASE_VALUE': 0xff,
- 'LFS_ERASE_CYCLES': 0,
- 'LFS_BADBLOCK_BEHAVIOR': 'LFS_TESTBD_BADBLOCK_PROGERROR',
-}
-PROLOGUE = """
- // prologue
- __attribute__((unused)) lfs_t lfs;
- __attribute__((unused)) lfs_testbd_t bd;
- __attribute__((unused)) lfs_file_t file;
- __attribute__((unused)) lfs_dir_t dir;
- __attribute__((unused)) struct lfs_info info;
- __attribute__((unused)) char path[1024];
- __attribute__((unused)) uint8_t buffer[1024];
- __attribute__((unused)) lfs_size_t size;
- __attribute__((unused)) int err;
-
- __attribute__((unused)) const struct lfs_config cfg = {
- .context = &bd,
- .read = lfs_testbd_read,
- .prog = lfs_testbd_prog,
- .erase = lfs_testbd_erase,
- .sync = lfs_testbd_sync,
- .read_size = LFS_READ_SIZE,
- .prog_size = LFS_PROG_SIZE,
- .block_size = LFS_BLOCK_SIZE,
- .block_count = LFS_BLOCK_COUNT,
- .block_cycles = LFS_BLOCK_CYCLES,
- .cache_size = LFS_CACHE_SIZE,
- .lookahead_size = LFS_LOOKAHEAD_SIZE,
- };
-
- __attribute__((unused)) const struct lfs_testbd_config bdcfg = {
- .erase_value = LFS_ERASE_VALUE,
- .erase_cycles = LFS_ERASE_CYCLES,
- .badblock_behavior = LFS_BADBLOCK_BEHAVIOR,
- .power_cycles = lfs_testbd_cycles,
- };
-
- lfs_testbd_createcfg(&cfg, lfs_testbd_path, &bdcfg) => 0;
+CASE_PROLOGUE = """
"""
-EPILOGUE = """
- // epilogue
- lfs_testbd_destroy(&cfg) => 0;
+CASE_EPILOGUE = """
"""
-PASS = '\033[32m✓\033[0m'
-FAIL = '\033[31m✗\033[0m'
-class TestFailure(Exception):
- def __init__(self, case, returncode=None, stdout=None, assert_=None):
- self.case = case
- self.returncode = returncode
- self.stdout = stdout
- self.assert_ = assert_
-class TestCase:
- def __init__(self, config, filter=filter,
- suite=None, caseno=None, lineno=None, **_):
- self.config = config
- self.filter = filter
- self.suite = suite
- self.caseno = caseno
- self.lineno = lineno
-
- self.code = config['code']
- self.code_lineno = config['code_lineno']
- self.defines = config.get('define', {})
- self.if_ = config.get('if', None)
- self.in_ = config.get('in', None)
-
- self.result = None
-
- def __str__(self):
- if hasattr(self, 'permno'):
- if any(k not in self.case.defines for k in self.defines):
- return '%s#%d#%d (%s)' % (
- self.suite.name, self.caseno, self.permno, ', '.join(
- '%s=%s' % (k, v) for k, v in self.defines.items()
- if k not in self.case.defines))
- else:
- return '%s#%d#%d' % (
- self.suite.name, self.caseno, self.permno)
- else:
- return '%s#%d' % (
- self.suite.name, self.caseno)
-
- def permute(self, class_=None, defines={}, permno=None, **_):
- ncase = (class_ or type(self))(self.config)
- for k, v in self.__dict__.items():
- setattr(ncase, k, v)
- ncase.case = self
- ncase.perms = [ncase]
- ncase.permno = permno
- ncase.defines = defines
- return ncase
-
- def build(self, f, **_):
- # prologue
- for k, v in sorted(self.defines.items()):
- if k not in self.suite.defines:
- f.write('#define %s %s\n' % (k, v))
-
- f.write('void test_case%d(%s) {' % (self.caseno, ','.join(
- '\n'+8*' '+'__attribute__((unused)) intmax_t %s' % k
- for k in sorted(self.perms[0].defines)
- if k not in self.defines)))
-
- f.write(PROLOGUE)
- f.write('\n')
- f.write(4*' '+'// test case %d\n' % self.caseno)
- f.write(4*' '+'#line %d "%s"\n' % (self.code_lineno, self.suite.path))
-
- # test case goes here
- f.write(self.code)
-
- # epilogue
- f.write(EPILOGUE)
- f.write('}\n')
-
- for k, v in sorted(self.defines.items()):
- if k not in self.suite.defines:
- f.write('#undef %s\n' % k)
-
- def shouldtest(self, **args):
- if (self.filter is not None and
- len(self.filter) >= 1 and
- self.filter[0] != self.caseno):
- return False
- elif (self.filter is not None and
- len(self.filter) >= 2 and
- self.filter[1] != self.permno):
- return False
- elif args.get('no_internal') and self.in_ is not None:
- return False
- elif self.if_ is not None:
- if_ = self.if_
- while True:
- for k, v in sorted(self.defines.items(),
- key=lambda x: len(x[0]), reverse=True):
- if k in if_:
- if_ = if_.replace(k, '(%s)' % v)
- break
- else:
- break
- if_ = (
- re.sub('(\&\&|\?)', ' and ',
- re.sub('(\|\||:)', ' or ',
- re.sub('!(?!=)', ' not ', if_))))
- return eval(if_)
- else:
- return True
-
- def test(self, exec=[], persist=False, cycles=None,
- gdb=False, failure=None, disk=None, **args):
- # build command
- cmd = exec + ['./%s.test' % self.suite.path,
- repr(self.caseno), repr(self.permno)]
-
- # persist disk or keep in RAM for speed?
- if persist:
- if not disk:
- disk = self.suite.path + '.disk'
- if persist != 'noerase':
- try:
- with open(disk, 'w') as f:
- f.truncate(0)
- if args.get('verbose'):
- print('truncate --size=0', disk)
- except FileNotFoundError:
- pass
-
- cmd.append(disk)
-
- # simulate power-loss after n cycles?
- if cycles:
- cmd.append(str(cycles))
-
- # failed? drop into debugger?
- if gdb and failure:
- ncmd = ['gdb']
- if gdb == 'assert':
- ncmd.extend(['-ex', 'r'])
- if failure.assert_:
- ncmd.extend(['-ex', 'up 2'])
- elif gdb == 'main':
- ncmd.extend([
- '-ex', 'b %s:%d' % (self.suite.path, self.code_lineno),
- '-ex', 'r'])
- ncmd.extend(['--args'] + cmd)
-
- if args.get('verbose'):
- print(' '.join(shlex.quote(c) for c in ncmd))
- signal.signal(signal.SIGINT, signal.SIG_IGN)
- sys.exit(sp.call(ncmd))
-
- # run test case!
- mpty, spty = pty.openpty()
- if args.get('verbose'):
- print(' '.join(shlex.quote(c) for c in cmd))
- proc = sp.Popen(cmd, stdout=spty, stderr=spty)
- os.close(spty)
- mpty = os.fdopen(mpty, 'r', 1)
- stdout = []
- assert_ = None
- try:
- while True:
- try:
- line = mpty.readline()
- except OSError as e:
- if e.errno == errno.EIO:
- break
- raise
- if not line:
- break;
- stdout.append(line)
- if args.get('verbose'):
- sys.stdout.write(line)
- # intercept asserts
- m = re.match(
- '^{0}([^:]+):(\d+):(?:\d+:)?{0}{1}:{0}(.*)$'
- .format('(?:\033\[[\d;]*.| )*', 'assert'),
- line)
- if m and assert_ is None:
- try:
- with open(m.group(1)) as f:
- lineno = int(m.group(2))
- line = (next(it.islice(f, lineno-1, None))
- .strip('\n'))
- assert_ = {
- 'path': m.group(1),
- 'line': line,
- 'lineno': lineno,
- 'message': m.group(3)}
- except:
- pass
- except KeyboardInterrupt:
- raise TestFailure(self, 1, stdout, None)
- proc.wait()
-
- # did we pass?
- if proc.returncode != 0:
- raise TestFailure(self, proc.returncode, stdout, assert_)
- else:
- return PASS
+def testpath(path):
+ path, *_ = path.split('#', 1)
+ return path
-class ValgrindTestCase(TestCase):
- def __init__(self, config, **args):
- self.leaky = config.get('leaky', False)
- super().__init__(config, **args)
+def testsuite(path):
+ suite = testpath(path)
+ suite = os.path.basename(suite)
+ if suite.endswith('.toml'):
+ suite = suite[:-len('.toml')]
+ return suite
- def shouldtest(self, **args):
- return not self.leaky and super().shouldtest(**args)
+def testcase(path):
+ _, case, *_ = path.split('#', 2)
+ return '%s#%s' % (testsuite(path), case)
- def test(self, exec=[], **args):
- verbose = args.get('verbose')
- uninit = (self.defines.get('LFS_ERASE_VALUE', None) == -1)
- exec = [
- 'valgrind',
- '--leak-check=full',
- ] + (['--undef-value-errors=no'] if uninit else []) + [
- ] + (['--track-origins=yes'] if not uninit else []) + [
- '--error-exitcode=4',
- '--error-limit=no',
- ] + (['--num-callers=1'] if not verbose else []) + [
- '-q'] + exec
- return super().test(exec=exec, **args)
-
-class ReentrantTestCase(TestCase):
- def __init__(self, config, **args):
- self.reentrant = config.get('reentrant', False)
- super().__init__(config, **args)
-
- def shouldtest(self, **args):
- return self.reentrant and super().shouldtest(**args)
-
- def test(self, persist=False, gdb=False, failure=None, **args):
- for cycles in it.count(1):
- # clear disk first?
- if cycles == 1 and persist != 'noerase':
- persist = 'erase'
- else:
- persist = 'noerase'
+# TODO move this out in other files
+def openio(path, mode='r'):
+ if path == '-':
+ if 'r' in mode:
+ return os.fdopen(os.dup(sys.stdin.fileno()), 'r')
+ else:
+ return os.fdopen(os.dup(sys.stdout.fileno()), 'w')
+ else:
+ return open(path, mode)
- # exact cycle we should drop into debugger?
- if gdb and failure and failure.cycleno == cycles:
- return super().test(gdb=gdb, persist=persist, cycles=cycles,
- failure=failure, **args)
+class TestCase:
+ # create a TestCase object from a config
+ def __init__(self, config, args={}):
+ self.name = config.pop('name')
+ self.path = config.pop('path')
+ self.suite = config.pop('suite')
+ self.lineno = config.pop('lineno', None)
+ self.if_ = config.pop('if', None)
+ if isinstance(self.if_, bool):
+ self.if_ = 'true' if self.if_ else 'false'
+ self.code = config.pop('code')
+ self.code_lineno = config.pop('code_lineno', None)
+ self.in_ = config.pop('in',
+ config.pop('suite_in', None))
+
+ self.normal = config.pop('normal',
+ config.pop('suite_normal', True))
+ self.reentrant = config.pop('reentrant',
+ config.pop('suite_reentrant', False))
+
+ # figure out defines and build possible permutations
+ self.defines = set()
+ self.permutations = []
+
+ suite_defines = config.pop('suite_defines', {})
+ if not isinstance(suite_defines, list):
+ suite_defines = [suite_defines]
+ defines = config.pop('defines', {})
+ if not isinstance(defines, list):
+ defines = [defines]
+
+ # build possible permutations
+ for suite_defines_ in suite_defines:
+ self.defines |= suite_defines_.keys()
+ for defines_ in defines:
+ self.defines |= defines_.keys()
+ self.permutations.extend(map(dict, it.product(*(
+ [(k, v) for v in (vs if isinstance(vs, list) else [vs])]
+ for k, vs in sorted(
+ (suite_defines_ | defines_).items())))))
+
+ for k in config.keys():
+ print('\x1b[01;33mwarning:\x1b[m in %s, found unused key %r'
+ % (self.id(), k),
+ file=sys.stderr)
+
+ def id(self):
+ return '%s#%s' % (self.suite, self.name)
- # run tests, but kill the program after prog/erase has
- # been hit n cycles. We exit with a special return code if the
- # program has not finished, since this isn't a test failure.
- try:
- return super().test(persist=persist, cycles=cycles, **args)
- except TestFailure as nfailure:
- if nfailure.returncode == 33:
- continue
- else:
- nfailure.cycleno = cycles
- raise
class TestSuite:
- def __init__(self, path, classes=[TestCase], defines={},
- filter=None, **args):
- self.name = os.path.basename(path)
- if self.name.endswith('.toml'):
- self.name = self.name[:-len('.toml')]
- if args.get('build_dir'):
- self.toml = path
- self.path = args['build_dir'] + '/' + path
- else:
- self.toml = path
- self.path = path
- self.classes = classes
- self.defines = defines.copy()
- self.filter = filter
+ # create a TestSuite object from a toml file
+ def __init__(self, path, args={}):
+ self.name = testsuite(path)
+ self.path = testpath(path)
- with open(self.toml) as f:
+ # load toml file and parse test cases
+ with open(self.path) as f:
# load tests
config = toml.load(f)
# find line numbers
f.seek(0)
- linenos = []
+ case_linenos = []
code_linenos = []
for i, line in enumerate(f):
- if re.match(r'\[\[\s*case\s*\]\]', line):
- linenos.append(i+1)
- if re.match(r'code\s*=\s*(\'\'\'|""")', line):
+ match = re.match(
+ '(?P<case>\[\s*cases\s*\.\s*(?P<name>\w+)\s*\])'
+ '|' '(?P<code>code\s*=)',
+ line)
+ if match and match.group('case'):
+ case_linenos.append((i+1, match.group('name')))
+ elif match and match.group('code'):
code_linenos.append(i+2)
- code_linenos.reverse()
-
- # grab global config
- for k, v in config.get('define', {}).items():
- if k not in self.defines:
- self.defines[k] = v
- self.code = config.get('code', None)
- if self.code is not None:
- self.code_lineno = code_linenos.pop()
-
- # create initial test cases
- self.cases = []
- for i, (case, lineno) in enumerate(zip(config['case'], linenos)):
- # code lineno?
- if 'code' in case:
- case['code_lineno'] = code_linenos.pop()
- # merge conditions if necessary
- if 'if' in config and 'if' in case:
- case['if'] = '(%s) && (%s)' % (config['if'], case['if'])
- elif 'if' in config:
- case['if'] = config['if']
- # initialize test case
- self.cases.append(TestCase(case, filter=filter,
- suite=self, caseno=i+1, lineno=lineno, **args))
-
- def __str__(self):
+ # sort in case toml parsing did not retain order
+ case_linenos.sort()
+
+ cases = config.pop('cases')
+ for (lineno, name), (nlineno, _) in it.zip_longest(
+ case_linenos, case_linenos[1:],
+ fillvalue=(float('inf'), None)):
+ code_lineno = min(
+ (l for l in code_linenos if l >= lineno and l < nlineno),
+ default=None)
+ cases[name]['lineno'] = lineno
+ cases[name]['code_lineno'] = code_lineno
+
+ self.if_ = config.pop('if', None)
+ if isinstance(self.if_, bool):
+ self.if_ = 'true' if self.if_ else 'false'
+
+ self.code = config.pop('code', None)
+ self.code_lineno = min(
+ (l for l in code_linenos
+ if not case_linenos or l < case_linenos[0][0]),
+ default=None)
+
+ # a couple of these we just forward to all cases
+ defines = config.pop('defines', {})
+ in_ = config.pop('in', None)
+ normal = config.pop('normal', True)
+ reentrant = config.pop('reentrant', False)
+
+ self.cases = []
+ for name, case in sorted(cases.items(),
+ key=lambda c: c[1].get('lineno')):
+ self.cases.append(TestCase(config={
+ 'name': name,
+ 'path': path + (':%d' % case['lineno']
+ if 'lineno' in case else ''),
+ 'suite': self.name,
+ 'suite_defines': defines,
+ 'suite_in': in_,
+ 'suite_normal': normal,
+ 'suite_reentrant': reentrant,
+ **case}))
+
+ # combine per-case defines
+ self.defines = set.union(*(
+ set(case.defines) for case in self.cases))
+
+ # combine other per-case things
+ self.normal = any(case.normal for case in self.cases)
+ self.reentrant = any(case.reentrant for case in self.cases)
+
+ for k in config.keys():
+ print('\x1b[01;33mwarning:\x1b[m in %s, found unused key %r'
+ % (self.id(), k),
+ file=sys.stderr)
+
+ def id(self):
return self.name
- def __lt__(self, other):
- return self.name < other.name
-
- def permute(self, **args):
- for case in self.cases:
- # lets find all parameterized definitions, in one of [args.D,
- # suite.defines, case.defines, DEFINES]. Note that each of these
- # can be either a dict of defines, or a list of dicts, expressing
- # an initial set of permutations.
- pending = [{}]
- for inits in [self.defines, case.defines, DEFINES]:
- if not isinstance(inits, list):
- inits = [inits]
-
- npending = []
- for init, pinit in it.product(inits, pending):
- ninit = pinit.copy()
- for k, v in init.items():
- if k not in ninit:
- try:
- ninit[k] = eval(v)
- except:
- ninit[k] = v
- npending.append(ninit)
-
- pending = npending
-
- # expand permutations
- pending = list(reversed(pending))
- expanded = []
- while pending:
- perm = pending.pop()
- for k, v in sorted(perm.items()):
- if not isinstance(v, str) and isinstance(v, abc.Iterable):
- for nv in reversed(v):
- nperm = perm.copy()
- nperm[k] = nv
- pending.append(nperm)
- break
- else:
- expanded.append(perm)
-
- # generate permutations
- case.perms = []
- for i, (class_, defines) in enumerate(
- it.product(self.classes, expanded)):
- case.perms.append(case.permute(
- class_, defines, permno=i+1, **args))
-
- # also track non-unique defines
- case.defines = {}
- for k, v in case.perms[0].defines.items():
- if all(perm.defines[k] == v for perm in case.perms):
- case.defines[k] = v
-
- # track all perms and non-unique defines
- self.perms = []
- for case in self.cases:
- self.perms.extend(case.perms)
-
- self.defines = {}
- for k, v in self.perms[0].defines.items():
- if all(perm.defines.get(k, None) == v for perm in self.perms):
- self.defines[k] = v
-
- return self.perms
-
- def build(self, **args):
- # build test files
- tf = open(self.path + '.test.tc', 'w')
- tf.write(GLOBALS)
- if self.code is not None:
- tf.write('#line %d "%s"\n' % (self.code_lineno, self.path))
- tf.write(self.code)
-
- tfs = {None: tf}
- for case in self.cases:
- if case.in_ not in tfs:
- tfs[case.in_] = open(self.path+'.'+
- re.sub('(\.c)?$', '.tc', case.in_.replace('/', '.')), 'w')
- tfs[case.in_].write('#line 1 "%s"\n' % case.in_)
- with open(case.in_) as f:
- for line in f:
- tfs[case.in_].write(line)
- tfs[case.in_].write('\n')
- tfs[case.in_].write(GLOBALS)
-
- tfs[case.in_].write('\n')
- case.build(tfs[case.in_], **args)
-
- tf.write('\n')
- tf.write('const char *lfs_testbd_path;\n')
- tf.write('uint32_t lfs_testbd_cycles;\n')
- tf.write('int main(int argc, char **argv) {\n')
- tf.write(4*' '+'int case_ = (argc > 1) ? atoi(argv[1]) : 0;\n')
- tf.write(4*' '+'int perm = (argc > 2) ? atoi(argv[2]) : 0;\n')
- tf.write(4*' '+'lfs_testbd_path = (argc > 3) ? argv[3] : NULL;\n')
- tf.write(4*' '+'lfs_testbd_cycles = (argc > 4) ? atoi(argv[4]) : 0;\n')
- for perm in self.perms:
- # test declaration
- tf.write(4*' '+'extern void test_case%d(%s);\n' % (
- perm.caseno, ', '.join(
- 'intmax_t %s' % k for k in sorted(perm.defines)
- if k not in perm.case.defines)))
- # test call
- tf.write(4*' '+
- 'if (argc < 3 || (case_ == %d && perm == %d)) {'
- ' test_case%d(%s); '
- '}\n' % (perm.caseno, perm.permno, perm.caseno, ', '.join(
- str(v) for k, v in sorted(perm.defines.items())
- if k not in perm.case.defines)))
- tf.write('}\n')
-
- for tf in tfs.values():
- tf.close()
-
- # write makefiles
- with open(self.path + '.mk', 'w') as mk:
- mk.write(RULES.replace(4*' ', '\t') % dict(path=self.path))
- mk.write('\n')
-
- # add coverage hooks?
- if args.get('coverage'):
- mk.write(COVERAGE_RULES.replace(4*' ', '\t') % dict(
- path=self.path))
- mk.write('\n')
-
- # add truly global defines globally
- for k, v in sorted(self.defines.items()):
- mk.write('%s.test: override CFLAGS += -D%s=%r\n'
- % (self.path, k, v))
-
- for path in tfs:
- if path is None:
- mk.write('%s: %s | %s\n' % (
- self.path+'.test.c',
- self.toml,
- self.path+'.test.tc'))
- else:
- mk.write('%s: %s %s | %s\n' % (
- self.path+'.'+path.replace('/', '.'),
- self.toml,
- path,
- self.path+'.'+re.sub('(\.c)?$', '.tc',
- path.replace('/', '.'))))
- mk.write('\t./scripts/explode_asserts.py $| -o $@\n')
-
- self.makefile = self.path + '.mk'
- self.target = self.path + '.test'
- return self.makefile, self.target
-
- def test(self, **args):
- # run test suite!
- if not args.get('verbose', True):
- sys.stdout.write(self.name + ' ')
- sys.stdout.flush()
- for perm in self.perms:
- if not perm.shouldtest(**args):
- continue
- try:
- result = perm.test(**args)
- except TestFailure as failure:
- perm.result = failure
- if not args.get('verbose', True):
- sys.stdout.write(FAIL)
- sys.stdout.flush()
- if not args.get('keep_going'):
- if not args.get('verbose', True):
- sys.stdout.write('\n')
- raise
- else:
- perm.result = PASS
- if not args.get('verbose', True):
- sys.stdout.write(PASS)
- sys.stdout.flush()
- if not args.get('verbose', True):
- sys.stdout.write('\n')
+def compile(**args):
+ # find .toml files
+ paths = []
+ for path in args.get('test_ids', TEST_PATHS):
+ if os.path.isdir(path):
+ path = path + '/*.toml'
-def main(**args):
- # figure out explicit defines
- defines = {}
- for define in args['D']:
- k, v, *_ = define.split('=', 2) + ['']
- defines[k] = v
-
- # and what class of TestCase to run
- classes = []
- if args.get('normal'):
- classes.append(TestCase)
- if args.get('reentrant'):
- classes.append(ReentrantTestCase)
+ for path in glob.glob(path):
+ paths.append(path)
+
+ if not paths:
+ print('no test suites found in %r?' % args['test_ids'])
+ sys.exit(-1)
+
+ if not args.get('source'):
+ if len(paths) > 1:
+ print('more than one test suite for compilation? (%r)'
+ % args['test_ids'])
+ sys.exit(-1)
+
+ # load our suite
+ suite = TestSuite(paths[0])
+ else:
+ # load all suites
+ suites = [TestSuite(path) for path in paths]
+ suites.sort(key=lambda s: s.name)
+
+ # write generated test source
+ if 'output' in args:
+ with openio(args['output'], 'w') as f:
+ _write = f.write
+ def write(s):
+ f.lineno += s.count('\n')
+ _write(s)
+ def writeln(s=''):
+ f.lineno += s.count('\n') + 1
+ _write(s)
+ _write('\n')
+ f.lineno = 1
+ f.write = write
+ f.writeln = writeln
+
+ # redirect littlefs tracing
+ f.writeln('#define LFS_TRACE_(fmt, ...) do { \\')
+ f.writeln(8*' '+'extern FILE *test_trace; \\')
+ f.writeln(8*' '+'if (test_trace) { \\')
+ f.writeln(12*' '+'fprintf(test_trace, '
+ '"%s:%d:trace: " fmt "%s\\n", \\')
+ f.writeln(20*' '+'__FILE__, __LINE__, __VA_ARGS__); \\')
+ f.writeln(8*' '+'} \\')
+ f.writeln(4*' '+'} while (0)')
+ f.writeln('#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")')
+ f.writeln('#define LFS_TESTBD_TRACE(...) '
+ 'LFS_TRACE_(__VA_ARGS__, "")')
+ f.writeln()
+
+ # write out generated functions, this can end up in different
+ # files depending on the "in" attribute
+ #
+ # note it's up to the specific generated file to declare
+ # the test defines
+ def write_case_functions(f, suite, case):
+ # create case define functions
+ if case.defines:
+ # deduplicate defines by value to try to reduce the
+ # number of functions we generate
+ define_cbs = {}
+ for i, defines in enumerate(case.permutations):
+ for k, v in sorted(defines.items()):
+ if v not in define_cbs:
+ name = ('__test__%s__%s__%s__%d'
+ % (suite.name, case.name, k, i))
+ define_cbs[v] = name
+ f.writeln('intmax_t %s(void) {' % name)
+ f.writeln(4*' '+'return %s;' % v)
+ f.writeln('}')
+ f.writeln()
+ f.writeln('intmax_t (*const *const '
+ '__test__%s__%s__defines[])(void) = {'
+ % (suite.name, case.name))
+ for defines in case.permutations:
+ f.writeln(4*' '+'(intmax_t (*const[])(void)){')
+ for define in sorted(suite.defines):
+ f.writeln(8*' '+'%s,' % (
+ define_cbs[defines[define]]
+ if define in defines
+ else 'NULL'))
+ f.writeln(4*' '+'},')
+ f.writeln('};')
+ f.writeln()
+
+ # create case filter function
+ if suite.if_ is not None or case.if_ is not None:
+ f.writeln('bool __test__%s__%s__filter(void) {'
+ % (suite.name, case.name))
+ f.writeln(4*' '+'return %s;'
+ % ' && '.join('(%s)' % if_
+ for if_ in [suite.if_, case.if_]
+ if if_ is not None))
+ f.writeln('}')
+ f.writeln()
+
+ # create case run function
+ f.writeln('void __test__%s__%s__run('
+ '__attribute__((unused)) struct lfs_config *cfg) {'
+ % (suite.name, case.name))
+ if CASE_PROLOGUE.strip():
+ f.writeln(4*' '+'%s'
+ % CASE_PROLOGUE.strip().replace('\n', '\n'+4*' '))
+ f.writeln()
+ f.writeln(4*' '+'// test case %s' % case.id())
+ if case.code_lineno is not None:
+ f.writeln(4*' '+'#line %d "%s"'
+ % (case.code_lineno, suite.path))
+ f.write(case.code)
+ if case.code_lineno is not None:
+ f.writeln(4*' '+'#line %d "%s"'
+ % (f.lineno+1, args['output']))
+ if CASE_EPILOGUE.strip():
+ f.writeln()
+ f.writeln(4*' '+'%s'
+ % CASE_EPILOGUE.strip().replace('\n', '\n'+4*' '))
+ f.writeln('}')
+ f.writeln()
+
+ if not args.get('source'):
+ # write test suite prologue
+ f.writeln('%s' % SUITE_PROLOGUE.strip())
+ f.writeln()
+ if suite.code is not None:
+ if suite.code_lineno is not None:
+ f.writeln('#line %d "%s"'
+ % (suite.code_lineno, suite.path))
+ f.write(suite.code)
+ if suite.code_lineno is not None:
+ f.writeln('#line %d "%s"'
+ % (f.lineno+1, args['output']))
+ f.writeln()
+
+ if suite.defines:
+ for i, define in enumerate(sorted(suite.defines)):
+ f.writeln('#ifndef %s' % define)
+ f.writeln('#define %-24s test_define(%d)'
+ % (define, i))
+ f.writeln('#endif')
+ f.writeln()
+
+ for case in suite.cases:
+ # create case functions
+ if case.in_ is None:
+ write_case_functions(f, suite, case)
+ else:
+ if case.defines:
+ f.writeln('extern intmax_t (*const *const '
+ '__test__%s__%s__defines[])(void);'
+ % (suite.name, case.name))
+ if suite.if_ is not None or case.if_ is not None:
+ f.writeln('extern bool __test__%s__%s__filter('
+ 'void);'
+ % (suite.name, case.name))
+ f.writeln('extern void __test__%s__%s__run('
+ 'struct lfs_config *cfg);'
+ % (suite.name, case.name))
+ f.writeln()
+
+ # create case struct
+ f.writeln('const struct test_case __test__%s__%s__case = {'
+ % (suite.name, case.name))
+ f.writeln(4*' '+'.id = "%s",' % case.id())
+ f.writeln(4*' '+'.name = "%s",' % case.name)
+ f.writeln(4*' '+'.path = "%s",' % case.path)
+ f.writeln(4*' '+'.types = %s,'
+ % ' | '.join(filter(None, [
+ 'TEST_NORMAL' if case.normal else None,
+ 'TEST_REENTRANT' if case.reentrant else None])))
+ f.writeln(4*' '+'.permutations = %d,'
+ % len(case.permutations))
+ if case.defines:
+ f.writeln(4*' '+'.defines = __test__%s__%s__defines,'
+ % (suite.name, case.name))
+ if suite.if_ is not None or case.if_ is not None:
+ f.writeln(4*' '+'.filter = __test__%s__%s__filter,'
+ % (suite.name, case.name))
+ f.writeln(4*' '+'.run = __test__%s__%s__run,'
+ % (suite.name, case.name))
+ f.writeln('};')
+ f.writeln()
+
+ # create suite define names
+ if suite.defines:
+ f.writeln('const char *const __test__%s__define_names[] = {'
+ % suite.name)
+ for k in sorted(suite.defines):
+ f.writeln(4*' '+'"%s",' % k)
+ f.writeln('};')
+ f.writeln()
+
+ # create suite struct
+ f.writeln('const struct test_suite __test__%s__suite = {'
+ % suite.name)
+ f.writeln(4*' '+'.id = "%s",' % suite.id())
+ f.writeln(4*' '+'.name = "%s",' % suite.name)
+ f.writeln(4*' '+'.path = "%s",' % suite.path)
+ f.writeln(4*' '+'.types = %s,'
+ % ' | '.join(filter(None, [
+ 'TEST_NORMAL' if suite.normal else None,
+ 'TEST_REENTRANT' if suite.reentrant else None])))
+ if suite.defines:
+ f.writeln(4*' '+'.define_names = __test__%s__define_names,'
+ % suite.name)
+ f.writeln(4*' '+'.define_count = %d,' % len(suite.defines))
+ f.writeln(4*' '+'.cases = (const struct test_case *const []){')
+ for case in suite.cases:
+ f.writeln(8*' '+'&__test__%s__%s__case,'
+ % (suite.name, case.name))
+ f.writeln(4*' '+'},')
+ f.writeln(4*' '+'.case_count = %d,' % len(suite.cases))
+ f.writeln('};')
+ f.writeln()
+
+ else:
+ # copy source
+ f.writeln('#line 1 "%s"' % args['source'])
+ with open(args['source']) as sf:
+ shutil.copyfileobj(sf, f)
+ f.writeln()
+
+ f.write(SUITE_PROLOGUE)
+ f.writeln()
+
+ # write any internal tests
+ for suite in suites:
+ for case in suite.cases:
+ if (case.in_ is not None
+ and os.path.normpath(case.in_)
+ == os.path.normpath(args['source'])):
+ # write defines, but note we need to undef any
+ # new defines since we're in someone else's file
+ if suite.defines:
+ for i, define in enumerate(
+ sorted(suite.defines)):
+ f.writeln('#ifndef %s' % define)
+ f.writeln('#define %-24s test_define(%d)'
+ % (define, i))
+ f.writeln('#define __TEST__%s__NEEDS_UNDEF'
+ % define)
+ f.writeln('#endif')
+ f.writeln()
+
+ write_case_functions(f, suite, case)
+
+ if suite.defines:
+ for define in sorted(suite.defines):
+ f.writeln('#ifdef __TEST__%s__NEEDS_UNDEF'
+ % define)
+ f.writeln('#undef __TEST__%s__NEEDS_UNDEF'
+ % define)
+ f.writeln('#undef %s' % define)
+ f.writeln('#endif')
+ f.writeln()
+
+ # add suite info to test_runner.c
+ if args['source'] == 'runners/test_runner.c':
+ f.writeln()
+ for suite in suites:
+ f.writeln('extern const struct test_suite '
+ '__test__%s__suite;' % suite.name)
+ f.writeln('const struct test_suite *test_suites[] = {')
+ for suite in suites:
+ f.writeln(4*' '+'&__test__%s__suite,' % suite.name)
+ f.writeln('};')
+ f.writeln('const size_t test_suite_count = %d;'
+ % len(suites))
+
+def runner(**args):
+ cmd = args['runner'].copy()
+ cmd.extend(args.get('test_ids'))
+
+ # run under some external command?
+ cmd[:0] = args.get('exec', [])
+
+ # run under valgrind?
if args.get('valgrind'):
- classes.append(ValgrindTestCase)
- if not classes:
- classes = [TestCase]
-
- suites = []
- for testpath in args['test_paths']:
- # optionally specified test case/perm
- testpath, *filter = testpath.split('#')
- filter = [int(f) for f in filter]
-
- # figure out the suite's toml file
- if os.path.isdir(testpath):
- testpath = testpath + '/*.toml'
- elif os.path.isfile(testpath):
- testpath = testpath
- elif testpath.endswith('.toml'):
- testpath = TEST_PATHS + '/' + testpath
- else:
- testpath = TEST_PATHS + '/' + testpath + '.toml'
-
- # find tests
- for path in glob.glob(testpath):
- suites.append(TestSuite(path, classes, defines, filter, **args))
-
- # sort for reproducibility
- suites = sorted(suites)
-
- # generate permutations
- for suite in suites:
- suite.permute(**args)
-
- # build tests in parallel
- print('====== building ======')
- makefiles = []
- targets = []
- for suite in suites:
- makefile, target = suite.build(**args)
- makefiles.append(makefile)
- targets.append(target)
-
- cmd = (['make', '-f', 'Makefile'] +
- list(it.chain.from_iterable(['-f', m] for m in makefiles)) +
- [target for target in targets])
- mpty, spty = pty.openpty()
+ cmd[:0] = filter(None, [
+ 'valgrind',
+ '--leak-check=full',
+ '--track-origins=yes',
+ '--error-exitcode=4',
+ '-q'])
+
+ # filter tests?
+ if args.get('normal'): cmd.append('-n')
+ if args.get('reentrant'): cmd.append('-r')
+ if args.get('geometry'):
+ cmd.append('-G%s' % args.get('geometry'))
+
+ # defines?
+ if args.get('define'):
+ for define in args.get('define'):
+ cmd.append('-D%s' % define)
+
+ return cmd
+
+def list_(**args):
+ cmd = runner(**args)
+ if args.get('summary'): cmd.append('--summary')
+ if args.get('list_suites'): cmd.append('--list-suites')
+ if args.get('list_cases'): cmd.append('--list-cases')
+ if args.get('list_paths'): cmd.append('--list-paths')
+ if args.get('list_defines'): cmd.append('--list-defines')
+ if args.get('list_geometries'): cmd.append('--list-geometries')
+
if args.get('verbose'):
print(' '.join(shlex.quote(c) for c in cmd))
- proc = sp.Popen(cmd, stdout=spty, stderr=spty)
- os.close(spty)
- mpty = os.fdopen(mpty, 'r', 1)
- stdout = []
- while True:
- try:
- line = mpty.readline()
- except OSError as e:
- if e.errno == errno.EIO:
- break
- raise
- if not line:
- break;
- stdout.append(line)
- if args.get('verbose'):
- sys.stdout.write(line)
- # intercept warnings
- m = re.match(
- '^{0}([^:]+):(\d+):(?:\d+:)?{0}{1}:{0}(.*)$'
- .format('(?:\033\[[\d;]*.| )*', 'warning'),
- line)
- if m and not args.get('verbose'):
- try:
- with open(m.group(1)) as f:
- lineno = int(m.group(2))
- line = next(it.islice(f, lineno-1, None)).strip('\n')
- sys.stdout.write(
- "\033[01m{path}:{lineno}:\033[01;35mwarning:\033[m "
- "{message}\n{line}\n\n".format(
- path=m.group(1), line=line, lineno=lineno,
- message=m.group(3)))
- except:
- pass
+ sys.exit(sp.call(cmd))
+
+
+def find_cases(runner_, **args):
+ # query from runner
+ cmd = runner_ + ['--list-cases']
+ if args.get('verbose'):
+ print(' '.join(shlex.quote(c) for c in cmd))
+ proc = sp.Popen(cmd,
+ stdout=sp.PIPE,
+ stderr=sp.PIPE if not args.get('verbose') else None,
+ universal_newlines=True,
+ errors='replace')
+ expected_suite_perms = co.defaultdict(lambda: 0)
+ expected_case_perms = co.defaultdict(lambda: 0)
+ expected_perms = 0
+ total_perms = 0
+ pattern = re.compile(
+ '^(?P<id>(?P<case>(?P<suite>[^#]+)#[^\s#]+)[^\s]*)\s+'
+ '[^\s]+\s+(?P<filtered>\d+)/(?P<perms>\d+)')
+ # skip the first line
+ for line in it.islice(proc.stdout, 1, None):
+ m = pattern.match(line)
+ if m:
+ filtered = int(m.group('filtered'))
+ expected_suite_perms[m.group('suite')] += filtered
+ expected_case_perms[m.group('id')] += filtered
+ expected_perms += filtered
+ total_perms += int(m.group('perms'))
proc.wait()
if proc.returncode != 0:
if not args.get('verbose'):
- for line in stdout:
+ for line in proc.stderr:
sys.stdout.write(line)
sys.exit(-1)
- print('built %d test suites, %d test cases, %d permutations' % (
- len(suites),
- sum(len(suite.cases) for suite in suites),
- sum(len(suite.perms) for suite in suites)))
+ return (
+ expected_suite_perms,
+ expected_case_perms,
+ expected_perms,
+ total_perms)
- total = 0
- for suite in suites:
- for perm in suite.perms:
- total += perm.shouldtest(**args)
- if total != sum(len(suite.perms) for suite in suites):
- print('filtered down to %d permutations' % total)
+def find_paths(runner_, **args):
+ # query from runner
+ cmd = runner_ + ['--list-paths']
+ if args.get('verbose'):
+ print(' '.join(shlex.quote(c) for c in cmd))
+ proc = sp.Popen(cmd,
+ stdout=sp.PIPE,
+ stderr=sp.PIPE if not args.get('verbose') else None,
+ universal_newlines=True,
+ errors='replace')
+ paths = co.OrderedDict()
+ pattern = re.compile(
+ '^(?P<id>(?P<case>(?P<suite>[^#]+)#[^\s#]+)[^\s]*)\s+'
+ '(?P<path>[^:]+):(?P<lineno>\d+)')
+ for line in proc.stdout:
+ m = pattern.match(line)
+ if m:
+ paths[m.group('id')] = (m.group('path'), int(m.group('lineno')))
+ proc.wait()
+ if proc.returncode != 0:
+ if not args.get('verbose'):
+ for line in proc.stderr:
+ sys.stdout.write(line)
+ sys.exit(-1)
- # only requested to build?
- if args.get('build'):
- return 0
+ return paths
- print('====== testing ======')
- try:
- for suite in suites:
- suite.test(**args)
- except TestFailure:
- pass
+def find_defines(runner_, **args):
+ # query from runner
+ cmd = runner_ + ['--list-defines']
+ if args.get('verbose'):
+ print(' '.join(shlex.quote(c) for c in cmd))
+ proc = sp.Popen(cmd,
+ stdout=sp.PIPE,
+ stderr=sp.PIPE if not args.get('verbose') else None,
+ universal_newlines=True,
+ errors='replace')
+ defines = co.OrderedDict()
+ pattern = re.compile(
+ '^(?P<id>(?P<case>(?P<suite>[^#]+)#[^\s#]+)[^\s]*)\s+'
+ '(?P<defines>(?:\w+=\w+\s*)+)')
+ for line in proc.stdout:
+ m = pattern.match(line)
+ if m:
+ defines[m.group('id')] = {k: v
+ for k, v in re.findall('(\w+)=(\w+)', m.group('defines'))}
+ proc.wait()
+ if proc.returncode != 0:
+ if not args.get('verbose'):
+ for line in proc.stderr:
+ sys.stdout.write(line)
+ sys.exit(-1)
- print('====== results ======')
- passed = 0
- failed = 0
- for suite in suites:
- for perm in suite.perms:
- if perm.result == PASS:
- passed += 1
- elif isinstance(perm.result, TestFailure):
- sys.stdout.write(
- "\033[01m{path}:{lineno}:\033[01;31mfailure:\033[m "
- "{perm} failed\n".format(
- perm=perm, path=perm.suite.path, lineno=perm.lineno,
- returncode=perm.result.returncode or 0))
- if perm.result.stdout:
- if perm.result.assert_:
- stdout = perm.result.stdout[:-1]
- else:
- stdout = perm.result.stdout
- for line in stdout[-5:]:
- sys.stdout.write(line)
- if perm.result.assert_:
- sys.stdout.write(
- "\033[01m{path}:{lineno}:\033[01;31massert:\033[m "
- "{message}\n{line}\n".format(
- **perm.result.assert_))
- sys.stdout.write('\n')
- failed += 1
-
- if args.get('coverage'):
- # collect coverage info
- # why -j1? lcov doesn't work in parallel because of gcov limitations
- cmd = (['make', '-j1', '-f', 'Makefile'] +
- list(it.chain.from_iterable(['-f', m] for m in makefiles)) +
- (['COVERAGETARGET=%s' % args['coverage']]
- if isinstance(args['coverage'], str) else []) +
- [suite.path + '.info' for suite in suites
- if any(perm.result == PASS for perm in suite.perms)])
+ return defines
+
+
+class TestFailure(Exception):
+ def __init__(self, id, returncode, output, assert_=None):
+ self.id = id
+ self.returncode = returncode
+ self.output = output
+ self.assert_ = assert_
+
+def run_stage(name, runner_, **args):
+ # get expected suite/case/perm counts
+ expected_suite_perms, expected_case_perms, expected_perms, total_perms = (
+ find_cases(runner_, **args))
+
+ passed_suite_perms = co.defaultdict(lambda: 0)
+ passed_case_perms = co.defaultdict(lambda: 0)
+ passed_perms = 0
+ failures = []
+ killed = False
+
+ pattern = re.compile('^(?:'
+ '(?P<op>running|finished|skipped) '
+ '(?P<id>(?P<case>(?P<suite>[^#]+)#[^\s#]+)[^\s]*)'
+ '|' '(?P<path>[^:]+):(?P<lineno>\d+):(?P<op_>assert):'
+ ' *(?P<message>.*)' ')$')
+ locals = th.local()
+ children = set()
+
+ def run_runner(runner_):
+ nonlocal passed_suite_perms
+ nonlocal passed_case_perms
+ nonlocal passed_perms
+ nonlocal locals
+
+ # run the tests!
+ cmd = runner_.copy()
+ if args.get('disk'):
+ cmd.append('--disk=%s' % args['disk'])
+ if args.get('trace'):
+ cmd.append('--trace=%s' % args['trace'])
if args.get('verbose'):
print(' '.join(shlex.quote(c) for c in cmd))
- proc = sp.Popen(cmd,
- stdout=sp.PIPE if not args.get('verbose') else None,
- stderr=sp.STDOUT if not args.get('verbose') else None,
- universal_newlines=True)
- stdout = []
- for line in proc.stdout:
- stdout.append(line)
+ mpty, spty = pty.openpty()
+ proc = sp.Popen(cmd, stdout=spty, stderr=spty)
+ os.close(spty)
+ children.add(proc)
+ mpty = os.fdopen(mpty, 'r', 1)
+ if args.get('output'):
+ output = openio(args['output'], 'w')
+
+ last_id = None
+ last_output = []
+ last_assert = None
+ try:
+ while True:
+ # parse a line for state changes
+ try:
+ line = mpty.readline()
+ except OSError as e:
+ if e.errno == errno.EIO:
+ break
+ raise
+ if not line:
+ break
+ last_output.append(line)
+ if args.get('output'):
+ output.write(line)
+ elif args.get('verbose'):
+ sys.stdout.write(line)
+
+ m = pattern.match(line)
+ if m:
+ op = m.group('op') or m.group('op_')
+ if op == 'running':
+ locals.seen_perms += 1
+ last_id = m.group('id')
+ last_output = []
+ last_assert = None
+ elif op == 'finished':
+ passed_suite_perms[m.group('suite')] += 1
+ passed_case_perms[m.group('case')] += 1
+ passed_perms += 1
+ elif op == 'skipped':
+ locals.seen_perms += 1
+ elif op == 'assert':
+ last_assert = (
+ m.group('path'),
+ int(m.group('lineno')),
+ m.group('message'))
+ # go ahead and kill the process, aborting takes a while
+ if args.get('keep_going'):
+ proc.kill()
+ except KeyboardInterrupt:
+ raise TestFailure(last_id, 1, last_output)
+ finally:
+ children.remove(proc)
+ mpty.close()
+ if args.get('output'):
+ output.close()
+
proc.wait()
if proc.returncode != 0:
+ raise TestFailure(
+ last_id,
+ proc.returncode,
+ last_output,
+ last_assert)
+
+ def run_job(runner, start=None, step=None):
+ nonlocal failures
+ nonlocal locals
+
+ start = start or 0
+ step = step or 1
+ while start < total_perms:
+ runner_ = runner.copy()
+ if start is not None:
+ runner_.append('--start=%d' % start)
+ if step is not None:
+ runner_.append('--step=%d' % step)
+ if args.get('isolate') or args.get('valgrind'):
+ runner_.append('--stop=%d' % (start+step))
+
+ try:
+ # run the tests
+ locals.seen_perms = 0
+ run_runner(runner_)
+ assert locals.seen_perms > 0
+ start += locals.seen_perms*step
+
+ except TestFailure as failure:
+ # race condition for multiple failures?
+ if failures and not args.get('keep_going'):
+ break
+
+ failures.append(failure)
+
+ if args.get('keep_going') and not killed:
+ # resume after failed test
+ assert locals.seen_perms > 0
+ start += locals.seen_perms*step
+ continue
+ else:
+ # stop other tests
+ for child in children.copy():
+ child.kill()
+
+
+ # parallel jobs?
+ runners = []
+ if 'jobs' in args:
+ for job in range(args['jobs']):
+ runners.append(th.Thread(
+ target=run_job, args=(runner_, job, args['jobs'])))
+ else:
+ runners.append(th.Thread(
+ target=run_job, args=(runner_, None, None)))
+
+ for r in runners:
+ r.start()
+
+ needs_newline = False
+ try:
+ while any(r.is_alive() for r in runners):
+ time.sleep(0.01)
+
if not args.get('verbose'):
- for line in stdout:
- sys.stdout.write(line)
- sys.exit(-1)
+ sys.stdout.write('\r\x1b[K'
+ 'running \x1b[%dm%s:\x1b[m %s '
+ % (32 if not failures else 31,
+ name,
+ ', '.join(filter(None, [
+ '%d/%d suites' % (
+ sum(passed_suite_perms[k] == v
+ for k, v in expected_suite_perms.items()),
+ len(expected_suite_perms))
+ if (not args.get('by_suites')
+ and not args.get('by_cases')) else None,
+ '%d/%d cases' % (
+ sum(passed_case_perms[k] == v
+ for k, v in expected_case_perms.items()),
+ len(expected_case_perms))
+ if not args.get('by_cases') else None,
+ '%d/%d perms' % (passed_perms, expected_perms),
+ '\x1b[31m%d/%d failures\x1b[m'
+ % (len(failures), expected_perms)
+ if failures else None]))))
+ sys.stdout.flush()
+ needs_newline = True
+ except KeyboardInterrupt:
+ # this is handled by the runner threads, we just
+ # need to not abort here
+ killed = True
+ finally:
+ if needs_newline:
+ print()
+
+ for r in runners:
+ r.join()
+
+ return (
+ expected_perms,
+ passed_perms,
+ failures,
+ killed)
+
+
+def run(**args):
+ start = time.time()
+
+ runner_ = runner(**args)
+ print('using runner: %s'
+ % ' '.join(shlex.quote(c) for c in runner_))
+ expected_suite_perms, expected_case_perms, expected_perms, total_perms = (
+ find_cases(runner_, **args))
+ print('found %d suites, %d cases, %d/%d permutations'
+ % (len(expected_suite_perms),
+ len(expected_case_perms),
+ expected_perms,
+ total_perms))
+ print()
+
+ expected = 0
+ passed = 0
+ failures = []
+ for type, by in it.product(
+ ['normal', 'reentrant'],
+ expected_case_perms.keys() if args.get('by_cases')
+ else expected_suite_perms.keys() if args.get('by_suites')
+ else [None]):
+ # rebuild runner for each stage to override test identifier if needed
+ stage_runner = runner(**args | {
+ 'test_ids': [by] if by is not None else args.get('test_ids', []),
+ 'normal': type == 'normal',
+ 'reentrant': type == 'reentrant'})
+
+ # spawn jobs for stage
+ expected_, passed_, failures_, killed = run_stage(
+ '%s %s' % (type, by or 'tests'), stage_runner, **args)
+ expected += expected_
+ passed += passed_
+ failures.extend(failures_)
+ if (failures and not args.get('keep_going')) or killed:
+ break
+
+ # show summary
+ print()
+ print('\x1b[%dmdone:\x1b[m %d/%d passed, %d/%d failed, in %.2fs'
+ % (32 if not failures else 31,
+ passed, expected, len(failures), expected,
+ time.time()-start))
+ print()
+
+ # print each failure
+ if failures:
+ # get some extra info from runner
+ runner_paths = find_paths(runner_, **args)
+ runner_defines = find_defines(runner_, **args)
+
+ for failure in failures:
+ # show summary of failure
+ path, lineno = runner_paths[testcase(failure.id)]
+ defines = runner_defines[failure.id]
+
+ print('\x1b[01m%s:%d:\x1b[01;31mfailure:\x1b[m %s%s failed'
+ % (path, lineno, failure.id,
+ ' (%s)' % ', '.join(
+ '%s=%s' % (k, v) for k, v in defines.items())
+ if defines else ''))
+
+ if failure.output:
+ output = failure.output
+ if failure.assert_ is not None:
+ output = output[:-1]
+ for line in output[-5:]:
+ sys.stdout.write(line)
+
+ if failure.assert_ is not None:
+ path, lineno, message = failure.assert_
+ print('\x1b[01m%s:%d:\x1b[01;31massert:\x1b[m %s'
+ % (path, lineno, message))
+ with open(path) as f:
+ line = next(it.islice(f, lineno-1, None)).strip('\n')
+ print(line)
+ print()
+
+ # drop into gdb?
+ if failures and (args.get('gdb')
+ or args.get('gdb_case')
+ or args.get('gdb_main')):
+ failure = failures[0]
+ runner_ = runner(**args | {'test_ids': [failure.id]})
+
+ if args.get('gdb_main'):
+ cmd = ['gdb',
+ '-ex', 'break main',
+ '-ex', 'run',
+ '--args'] + runner_
+ elif args.get('gdb_case'):
+ path, lineno = runner_paths[testcase(failure.id)]
+ cmd = ['gdb',
+ '-ex', 'break %s:%d' % (path, lineno),
+ '-ex', 'run',
+ '--args'] + runner_
+ elif failure.assert_ is not None:
+ cmd = ['gdb',
+ '-ex', 'run',
+ '-ex', 'frame function raise',
+ '-ex', 'up 2',
+ '--args'] + runner_
+ else:
+ cmd = ['gdb',
+ '-ex', 'run',
+ '--args'] + runner_
+
+ # exec gdb interactively
+ if args.get('verbose'):
+ print(' '.join(shlex.quote(c) for c in cmd))
+ os.execvp(cmd[0], cmd)
+
+ return 1 if failures else 0
+
+
+def main(**args):
+ if args.get('compile'):
+ compile(**args)
+ elif (args.get('summary')
+ or args.get('list_suites')
+ or args.get('list_cases')
+ or args.get('list_paths')
+ or args.get('list_defines')
+ or args.get('list_geometries')
+ or args.get('list_defaults')):
+ list_(**args)
+ else:
+ run(**args)
- if args.get('gdb'):
- failure = None
- for suite in suites:
- for perm in suite.perms:
- if isinstance(perm.result, TestFailure):
- failure = perm.result
- if failure is not None:
- print('======= gdb ======')
- # drop into gdb
- failure.case.test(failure=failure, **args)
- sys.exit(0)
-
- print('tests passed %d/%d (%.1f%%)' % (passed, total,
- 100*(passed/total if total else 1.0)))
- print('tests failed %d/%d (%.1f%%)' % (failed, total,
- 100*(failed/total if total else 1.0)))
- return 1 if failed > 0 else 0
if __name__ == "__main__":
import argparse
+ import sys
parser = argparse.ArgumentParser(
- description="Run parameterized tests in various configurations.")
- parser.add_argument('test_paths', nargs='*', default=[TEST_PATHS],
- help="Description of test(s) to run. By default, this is all tests \
- found in the \"{0}\" directory. Here, you can specify a different \
- directory of tests, a specific file, a suite by name, and even \
- specific test cases and permutations. For example \
- \"test_dirs#1\" or \"{0}/test_dirs.toml#1#1\".".format(TEST_PATHS))
- parser.add_argument('-D', action='append', default=[],
- help="Overriding parameter definitions.")
+ description="Build and run tests.",
+ conflict_handler='resolve')
+ parser.add_argument('test_ids', nargs='*',
+ help="Description of testis to run. May be a directory, path, or \
+ test identifier. Test identifiers are of the form \
+ <suite_name>#<case_name>#<permutation>, but suffixes can be \
+ dropped to run any matching tests. Defaults to %r." % TEST_PATHS)
parser.add_argument('-v', '--verbose', action='store_true',
- help="Output everything that is happening.")
- parser.add_argument('-k', '--keep-going', action='store_true',
- help="Run all tests instead of stopping on first error. Useful for CI.")
- parser.add_argument('-p', '--persist', choices=['erase', 'noerase'],
- nargs='?', const='erase',
- help="Store disk image in a file.")
- parser.add_argument('-b', '--build', action='store_true',
- help="Only build the tests, do not execute.")
- parser.add_argument('-g', '--gdb', choices=['init', 'main', 'assert'],
- nargs='?', const='assert',
+ help="Output commands that run behind the scenes.")
+ # test flags
+ test_parser = parser.add_argument_group('test options')
+ test_parser.add_argument('-Y', '--summary', action='store_true',
+ help="Show quick summary.")
+ test_parser.add_argument('-l', '--list-suites', action='store_true',
+ help="List test suites.")
+ test_parser.add_argument('-L', '--list-cases', action='store_true',
+ help="List test cases.")
+ test_parser.add_argument('--list-paths', action='store_true',
+ help="List the path for each test case.")
+ test_parser.add_argument('--list-defines', action='store_true',
+ help="List the defines for each test permutation.")
+ test_parser.add_argument('--list-geometries', action='store_true',
+ help="List the disk geometries used for testing.")
+ test_parser.add_argument('--list-defaults', action='store_true',
+ help="List the default defines in this test-runner.")
+ test_parser.add_argument('-D', '--define', action='append',
+ help="Override a test define.")
+ test_parser.add_argument('-G', '--geometry',
+ help="Filter by geometry.")
+ test_parser.add_argument('-n', '--normal', action='store_true',
+ help="Filter for normal tests. Can be combined.")
+ test_parser.add_argument('-r', '--reentrant', action='store_true',
+ help="Filter for reentrant tests. Can be combined.")
+ test_parser.add_argument('-d', '--disk',
+ help="Use this file as the disk.")
+ test_parser.add_argument('-t', '--trace',
+ help="Redirect trace output to this file.")
+ test_parser.add_argument('-o', '--output',
+ help="Redirect stdout and stderr to this file.")
+ test_parser.add_argument('--runner', default=[RUNNER_PATH],
+ type=lambda x: x.split(),
+ help="Path to runner, defaults to %r" % RUNNER_PATH)
+ test_parser.add_argument('-j', '--jobs', nargs='?', type=int,
+ const=len(os.sched_getaffinity(0)),
+ help="Number of parallel runners to run.")
+ test_parser.add_argument('-k', '--keep-going', action='store_true',
+ help="Don't stop on first error.")
+ test_parser.add_argument('-i', '--isolate', action='store_true',
+ help="Run each test permutation in a separate process.")
+ test_parser.add_argument('-b', '--by-suites', action='store_true',
+ help="Step through tests by suite.")
+ test_parser.add_argument('-B', '--by-cases', action='store_true',
+ help="Step through tests by case.")
+ test_parser.add_argument('--gdb', action='store_true',
help="Drop into gdb on test failure.")
- parser.add_argument('--no-internal', action='store_true',
- help="Don't run tests that require internal knowledge.")
- parser.add_argument('-n', '--normal', action='store_true',
- help="Run tests normally.")
- parser.add_argument('-r', '--reentrant', action='store_true',
- help="Run reentrant tests with simulated power-loss.")
- parser.add_argument('--valgrind', action='store_true',
- help="Run non-leaky tests under valgrind to check for memory leaks.")
- parser.add_argument('--exec', default=[], type=lambda e: e.split(),
- help="Run tests with another executable prefixed on the command line.")
- parser.add_argument('--disk',
- help="Specify a file to use for persistent/reentrant tests.")
- parser.add_argument('--coverage', type=lambda x: x if x else True,
- nargs='?', const='',
- help="Collect coverage information during testing. This uses lcov/gcov \
- to accumulate coverage information into *.info files. May also \
- a path to a *.info file to accumulate coverage info into.")
- parser.add_argument('--build-dir',
- help="Build relative to the specified directory instead of the \
- current directory.")
-
- sys.exit(main(**vars(parser.parse_args())))
+ test_parser.add_argument('--gdb-case', action='store_true',
+ help="Drop into gdb on test failure but stop at the beginning \
+ of the failing test case.")
+ test_parser.add_argument('--gdb-main', action='store_true',
+ help="Drop into gdb on test failure but stop at the beginning \
+ of main.")
+ test_parser.add_argument('--valgrind', action='store_true',
+ help="Run under Valgrind to find memory errors. Implicitly sets \
+ --isolate.")
+ test_parser.add_argument('--exec', default=[], type=lambda e: e.split(),
+ help="Run under another executable.")
+ # compilation flags
+ comp_parser = parser.add_argument_group('compilation options')
+ comp_parser.add_argument('-c', '--compile', action='store_true',
+ help="Compile a test suite or source file.")
+ comp_parser.add_argument('-s', '--source',
+ help="Source file to compile, possibly injecting internal tests.")
+ comp_parser.add_argument('-o', '--output',
+ help="Output file.")
+ # TODO apply this to other scripts?
+ sys.exit(main(**{k: v
+ for k, v in vars(parser.parse_args()).items()
+ if v is not None}))
diff --git a/scripts/test_.py b/scripts/test_.py
deleted file mode 100755
index 02147ef..0000000
--- a/scripts/test_.py
+++ /dev/null
@@ -1,1027 +0,0 @@
-#!/usr/bin/env python3
-#
-# Script to compile and runs tests.
-#
-
-import collections as co
-import errno
-import glob
-import itertools as it
-import math as m
-import os
-import pty
-import re
-import shlex
-import shutil
-import signal
-import subprocess as sp
-import threading as th
-import time
-import toml
-
-
-TEST_PATHS = ['tests_']
-RUNNER_PATH = './runners/test_runner'
-
-SUITE_PROLOGUE = """
-#include "runners/test_runner.h"
-#include "bd/lfs_testbd.h"
-#include <stdio.h>
-"""
-CASE_PROLOGUE = """
-"""
-CASE_EPILOGUE = """
-"""
-
-
-def testpath(path):
- path, *_ = path.split('#', 1)
- return path
-
-def testsuite(path):
- suite = testpath(path)
- suite = os.path.basename(suite)
- if suite.endswith('.toml'):
- suite = suite[:-len('.toml')]
- return suite
-
-def testcase(path):
- _, case, *_ = path.split('#', 2)
- return '%s#%s' % (testsuite(path), case)
-
-# TODO move this out in other files
-def openio(path, mode='r'):
- if path == '-':
- if 'r' in mode:
- return os.fdopen(os.dup(sys.stdin.fileno()), 'r')
- else:
- return os.fdopen(os.dup(sys.stdout.fileno()), 'w')
- else:
- return open(path, mode)
-
-class TestCase:
- # create a TestCase object from a config
- def __init__(self, config, args={}):
- self.name = config.pop('name')
- self.path = config.pop('path')
- self.suite = config.pop('suite')
- self.lineno = config.pop('lineno', None)
- self.if_ = config.pop('if', None)
- if isinstance(self.if_, bool):
- self.if_ = 'true' if self.if_ else 'false'
- self.code = config.pop('code')
- self.code_lineno = config.pop('code_lineno', None)
- self.in_ = config.pop('in',
- config.pop('suite_in', None))
-
- self.normal = config.pop('normal',
- config.pop('suite_normal', True))
- self.reentrant = config.pop('reentrant',
- config.pop('suite_reentrant', False))
-
- # figure out defines and build possible permutations
- self.defines = set()
- self.permutations = []
-
- suite_defines = config.pop('suite_defines', {})
- if not isinstance(suite_defines, list):
- suite_defines = [suite_defines]
- defines = config.pop('defines', {})
- if not isinstance(defines, list):
- defines = [defines]
-
- # build possible permutations
- for suite_defines_ in suite_defines:
- self.defines |= suite_defines_.keys()
- for defines_ in defines:
- self.defines |= defines_.keys()
- self.permutations.extend(map(dict, it.product(*(
- [(k, v) for v in (vs if isinstance(vs, list) else [vs])]
- for k, vs in sorted(
- (suite_defines_ | defines_).items())))))
-
- for k in config.keys():
- print('\x1b[01;33mwarning:\x1b[m in %s, found unused key %r'
- % (self.id(), k),
- file=sys.stderr)
-
- def id(self):
- return '%s#%s' % (self.suite, self.name)
-
-
-class TestSuite:
- # create a TestSuite object from a toml file
- def __init__(self, path, args={}):
- self.name = testsuite(path)
- self.path = testpath(path)
-
- # load toml file and parse test cases
- with open(self.path) as f:
- # load tests
- config = toml.load(f)
-
- # find line numbers
- f.seek(0)
- case_linenos = []
- code_linenos = []
- for i, line in enumerate(f):
- match = re.match(
- '(?P<case>\[\s*cases\s*\.\s*(?P<name>\w+)\s*\])'
- '|' '(?P<code>code\s*=)',
- line)
- if match and match.group('case'):
- case_linenos.append((i+1, match.group('name')))
- elif match and match.group('code'):
- code_linenos.append(i+2)
-
- # sort in case toml parsing did not retain order
- case_linenos.sort()
-
- cases = config.pop('cases')
- for (lineno, name), (nlineno, _) in it.zip_longest(
- case_linenos, case_linenos[1:],
- fillvalue=(float('inf'), None)):
- code_lineno = min(
- (l for l in code_linenos if l >= lineno and l < nlineno),
- default=None)
- cases[name]['lineno'] = lineno
- cases[name]['code_lineno'] = code_lineno
-
- self.if_ = config.pop('if', None)
- if isinstance(self.if_, bool):
- self.if_ = 'true' if self.if_ else 'false'
-
- self.code = config.pop('code', None)
- self.code_lineno = min(
- (l for l in code_linenos
- if not case_linenos or l < case_linenos[0][0]),
- default=None)
-
- # a couple of these we just forward to all cases
- defines = config.pop('defines', {})
- in_ = config.pop('in', None)
- normal = config.pop('normal', True)
- reentrant = config.pop('reentrant', False)
-
- self.cases = []
- for name, case in sorted(cases.items(),
- key=lambda c: c[1].get('lineno')):
- self.cases.append(TestCase(config={
- 'name': name,
- 'path': path + (':%d' % case['lineno']
- if 'lineno' in case else ''),
- 'suite': self.name,
- 'suite_defines': defines,
- 'suite_in': in_,
- 'suite_normal': normal,
- 'suite_reentrant': reentrant,
- **case}))
-
- # combine per-case defines
- self.defines = set.union(*(
- set(case.defines) for case in self.cases))
-
- # combine other per-case things
- self.normal = any(case.normal for case in self.cases)
- self.reentrant = any(case.reentrant for case in self.cases)
-
- for k in config.keys():
- print('\x1b[01;33mwarning:\x1b[m in %s, found unused key %r'
- % (self.id(), k),
- file=sys.stderr)
-
- def id(self):
- return self.name
-
-
-
-def compile(**args):
- # find .toml files
- paths = []
- for path in args.get('test_ids', TEST_PATHS):
- if os.path.isdir(path):
- path = path + '/*.toml'
-
- for path in glob.glob(path):
- paths.append(path)
-
- if not paths:
- print('no test suites found in %r?' % args['test_ids'])
- sys.exit(-1)
-
- if not args.get('source'):
- if len(paths) > 1:
- print('more than one test suite for compilation? (%r)'
- % args['test_ids'])
- sys.exit(-1)
-
- # load our suite
- suite = TestSuite(paths[0])
- else:
- # load all suites
- suites = [TestSuite(path) for path in paths]
- suites.sort(key=lambda s: s.name)
-
- # write generated test source
- if 'output' in args:
- with openio(args['output'], 'w') as f:
- _write = f.write
- def write(s):
- f.lineno += s.count('\n')
- _write(s)
- def writeln(s=''):
- f.lineno += s.count('\n') + 1
- _write(s)
- _write('\n')
- f.lineno = 1
- f.write = write
- f.writeln = writeln
-
- # redirect littlefs tracing
- f.writeln('#define LFS_TRACE_(fmt, ...) do { \\')
- f.writeln(8*' '+'extern FILE *test_trace; \\')
- f.writeln(8*' '+'if (test_trace) { \\')
- f.writeln(12*' '+'fprintf(test_trace, '
- '"%s:%d:trace: " fmt "%s\\n", \\')
- f.writeln(20*' '+'__FILE__, __LINE__, __VA_ARGS__); \\')
- f.writeln(8*' '+'} \\')
- f.writeln(4*' '+'} while (0)')
- f.writeln('#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")')
- f.writeln('#define LFS_TESTBD_TRACE(...) '
- 'LFS_TRACE_(__VA_ARGS__, "")')
- f.writeln()
-
- # write out generated functions, this can end up in different
- # files depending on the "in" attribute
- #
- # note it's up to the specific generated file to declare
- # the test defines
- def write_case_functions(f, suite, case):
- # create case define functions
- if case.defines:
- # deduplicate defines by value to try to reduce the
- # number of functions we generate
- define_cbs = {}
- for i, defines in enumerate(case.permutations):
- for k, v in sorted(defines.items()):
- if v not in define_cbs:
- name = ('__test__%s__%s__%s__%d'
- % (suite.name, case.name, k, i))
- define_cbs[v] = name
- f.writeln('uintmax_t %s(void) {' % name)
- f.writeln(4*' '+'return %s;' % v)
- f.writeln('}')
- f.writeln()
- f.writeln('uintmax_t (*const *const '
- '__test__%s__%s__defines[])(void) = {'
- % (suite.name, case.name))
- for defines in case.permutations:
- f.writeln(4*' '+'(uintmax_t (*const[])(void)){')
- for define in sorted(suite.defines):
- f.writeln(8*' '+'%s,' % (
- define_cbs[defines[define]]
- if define in defines
- else 'NULL'))
- f.writeln(4*' '+'},')
- f.writeln('};')
- f.writeln()
-
- # create case filter function
- if suite.if_ is not None or case.if_ is not None:
- f.writeln('bool __test__%s__%s__filter(void) {'
- % (suite.name, case.name))
- f.writeln(4*' '+'return %s;'
- % ' && '.join('(%s)' % if_
- for if_ in [suite.if_, case.if_]
- if if_ is not None))
- f.writeln('}')
- f.writeln()
-
- # create case run function
- f.writeln('void __test__%s__%s__run('
- '__attribute__((unused)) struct lfs_config *cfg) {'
- % (suite.name, case.name))
- if CASE_PROLOGUE.strip():
- f.writeln(4*' '+'%s'
- % CASE_PROLOGUE.strip().replace('\n', '\n'+4*' '))
- f.writeln()
- f.writeln(4*' '+'// test case %s' % case.id())
- if case.code_lineno is not None:
- f.writeln(4*' '+'#line %d "%s"'
- % (case.code_lineno, suite.path))
- f.write(case.code)
- if case.code_lineno is not None:
- f.writeln(4*' '+'#line %d "%s"'
- % (f.lineno+1, args['output']))
- if CASE_EPILOGUE.strip():
- f.writeln()
- f.writeln(4*' '+'%s'
- % CASE_EPILOGUE.strip().replace('\n', '\n'+4*' '))
- f.writeln('}')
- f.writeln()
-
- if not args.get('source'):
- # write test suite prologue
- f.writeln('%s' % SUITE_PROLOGUE.strip())
- f.writeln()
- if suite.code is not None:
- if suite.code_lineno is not None:
- f.writeln('#line %d "%s"'
- % (suite.code_lineno, suite.path))
- f.write(suite.code)
- if suite.code_lineno is not None:
- f.writeln('#line %d "%s"'
- % (f.lineno+1, args['output']))
- f.writeln()
-
- if suite.defines:
- for i, define in enumerate(sorted(suite.defines)):
- f.writeln('#ifndef %s' % define)
- f.writeln('#define %-24s test_define(%d)'
- % (define, i))
- f.writeln('#endif')
- f.writeln()
-
- for case in suite.cases:
- # create case functions
- if case.in_ is None:
- write_case_functions(f, suite, case)
- else:
- if case.defines:
- f.writeln('extern uintmax_t (*const *const '
- '__test__%s__%s__defines[])(void);'
- % (suite.name, case.name))
- if suite.if_ is not None or case.if_ is not None:
- f.writeln('extern bool __test__%s__%s__filter('
- 'void);'
- % (suite.name, case.name))
- f.writeln('extern void __test__%s__%s__run('
- 'struct lfs_config *cfg);'
- % (suite.name, case.name))
- f.writeln()
-
- # create case struct
- f.writeln('const struct test_case __test__%s__%s__case = {'
- % (suite.name, case.name))
- f.writeln(4*' '+'.id = "%s",' % case.id())
- f.writeln(4*' '+'.name = "%s",' % case.name)
- f.writeln(4*' '+'.path = "%s",' % case.path)
- f.writeln(4*' '+'.types = %s,'
- % ' | '.join(filter(None, [
- 'TEST_NORMAL' if case.normal else None,
- 'TEST_REENTRANT' if case.reentrant else None])))
- f.writeln(4*' '+'.permutations = %d,'
- % len(case.permutations))
- if case.defines:
- f.writeln(4*' '+'.defines = __test__%s__%s__defines,'
- % (suite.name, case.name))
- if suite.if_ is not None or case.if_ is not None:
- f.writeln(4*' '+'.filter = __test__%s__%s__filter,'
- % (suite.name, case.name))
- f.writeln(4*' '+'.run = __test__%s__%s__run,'
- % (suite.name, case.name))
- f.writeln('};')
- f.writeln()
-
- # create suite define names
- if suite.defines:
- f.writeln('const char *const __test__%s__define_names[] = {'
- % suite.name)
- for k in sorted(suite.defines):
- f.writeln(4*' '+'"%s",' % k)
- f.writeln('};')
- f.writeln()
-
- # create suite struct
- f.writeln('const struct test_suite __test__%s__suite = {'
- % suite.name)
- f.writeln(4*' '+'.id = "%s",' % suite.id())
- f.writeln(4*' '+'.name = "%s",' % suite.name)
- f.writeln(4*' '+'.path = "%s",' % suite.path)
- f.writeln(4*' '+'.types = %s,'
- % ' | '.join(filter(None, [
- 'TEST_NORMAL' if suite.normal else None,
- 'TEST_REENTRANT' if suite.reentrant else None])))
- if suite.defines:
- f.writeln(4*' '+'.define_names = __test__%s__define_names,'
- % suite.name)
- f.writeln(4*' '+'.define_count = %d,' % len(suite.defines))
- f.writeln(4*' '+'.cases = (const struct test_case *const []){')
- for case in suite.cases:
- f.writeln(8*' '+'&__test__%s__%s__case,'
- % (suite.name, case.name))
- f.writeln(4*' '+'},')
- f.writeln(4*' '+'.case_count = %d,' % len(suite.cases))
- f.writeln('};')
- f.writeln()
-
- else:
- # copy source
- f.writeln('#line 1 "%s"' % args['source'])
- with open(args['source']) as sf:
- shutil.copyfileobj(sf, f)
- f.writeln()
-
- f.write(SUITE_PROLOGUE)
- f.writeln()
-
- # write any internal tests
- for suite in suites:
- for case in suite.cases:
- if (case.in_ is not None
- and os.path.normpath(case.in_)
- == os.path.normpath(args['source'])):
- # write defines, but note we need to undef any
- # new defines since we're in someone else's file
- if suite.defines:
- for i, define in enumerate(
- sorted(suite.defines)):
- f.writeln('#ifndef %s' % define)
- f.writeln('#define %-24s test_define(%d)'
- % (define, i))
- f.writeln('#define __TEST__%s__NEEDS_UNDEF'
- % define)
- f.writeln('#endif')
- f.writeln()
-
- write_case_functions(f, suite, case)
-
- if suite.defines:
- for define in sorted(suite.defines):
- f.writeln('#ifdef __TEST__%s__NEEDS_UNDEF'
- % define)
- f.writeln('#undef __TEST__%s__NEEDS_UNDEF'
- % define)
- f.writeln('#undef %s' % define)
- f.writeln('#endif')
- f.writeln()
-
- # add suite info to test_runner.c
- if args['source'] == 'runners/test_runner.c':
- f.writeln()
- for suite in suites:
- f.writeln('extern const struct test_suite '
- '__test__%s__suite;' % suite.name)
- f.writeln('const struct test_suite *test_suites[] = {')
- for suite in suites:
- f.writeln(4*' '+'&__test__%s__suite,' % suite.name)
- f.writeln('};')
- f.writeln('const size_t test_suite_count = %d;'
- % len(suites))
-
-def runner(**args):
- cmd = args['runner'].copy()
- cmd.extend(args.get('test_ids'))
-
- # run under some external command?
- cmd[:0] = args.get('exec', [])
-
- # run under valgrind?
- if args.get('valgrind'):
- cmd[:0] = filter(None, [
- 'valgrind',
- '--leak-check=full',
- '--track-origins=yes',
- '--error-exitcode=4',
- '-q'])
-
- # filter tests?
- if args.get('normal'): cmd.append('-n')
- if args.get('reentrant'): cmd.append('-r')
- if args.get('geometry'):
- cmd.append('-G%s' % args.get('geometry'))
-
- # defines?
- if args.get('define'):
- for define in args.get('define'):
- cmd.append('-D%s' % define)
-
- return cmd
-
-def list_(**args):
- cmd = runner(**args)
- if args.get('summary'): cmd.append('--summary')
- if args.get('list_suites'): cmd.append('--list-suites')
- if args.get('list_cases'): cmd.append('--list-cases')
- if args.get('list_paths'): cmd.append('--list-paths')
- if args.get('list_defines'): cmd.append('--list-defines')
- if args.get('list_geometries'): cmd.append('--list-geometries')
-
- if args.get('verbose'):
- print(' '.join(shlex.quote(c) for c in cmd))
- sys.exit(sp.call(cmd))
-
-
-def find_cases(runner_, **args):
- # query from runner
- cmd = runner_ + ['--list-cases']
- if args.get('verbose'):
- print(' '.join(shlex.quote(c) for c in cmd))
- proc = sp.Popen(cmd,
- stdout=sp.PIPE,
- stderr=sp.PIPE if not args.get('verbose') else None,
- universal_newlines=True,
- errors='replace')
- expected_suite_perms = co.defaultdict(lambda: 0)
- expected_case_perms = co.defaultdict(lambda: 0)
- expected_perms = 0
- total_perms = 0
- pattern = re.compile(
- '^(?P<id>(?P<case>(?P<suite>[^#]+)#[^\s#]+)[^\s]*)\s+'
- '[^\s]+\s+(?P<filtered>\d+)/(?P<perms>\d+)')
- # skip the first line
- for line in it.islice(proc.stdout, 1, None):
- m = pattern.match(line)
- if m:
- filtered = int(m.group('filtered'))
- expected_suite_perms[m.group('suite')] += filtered
- expected_case_perms[m.group('id')] += filtered
- expected_perms += filtered
- total_perms += int(m.group('perms'))
- proc.wait()
- if proc.returncode != 0:
- if not args.get('verbose'):
- for line in proc.stderr:
- sys.stdout.write(line)
- sys.exit(-1)
-
- return (
- expected_suite_perms,
- expected_case_perms,
- expected_perms,
- total_perms)
-
-def find_paths(runner_, **args):
- # query from runner
- cmd = runner_ + ['--list-paths']
- if args.get('verbose'):
- print(' '.join(shlex.quote(c) for c in cmd))
- proc = sp.Popen(cmd,
- stdout=sp.PIPE,
- stderr=sp.PIPE if not args.get('verbose') else None,
- universal_newlines=True,
- errors='replace')
- paths = co.OrderedDict()
- pattern = re.compile(
- '^(?P<id>(?P<case>(?P<suite>[^#]+)#[^\s#]+)[^\s]*)\s+'
- '(?P<path>[^:]+):(?P<lineno>\d+)')
- for line in proc.stdout:
- m = pattern.match(line)
- if m:
- paths[m.group('id')] = (m.group('path'), int(m.group('lineno')))
- proc.wait()
- if proc.returncode != 0:
- if not args.get('verbose'):
- for line in proc.stderr:
- sys.stdout.write(line)
- sys.exit(-1)
-
- return paths
-
-def find_defines(runner_, **args):
- # query from runner
- cmd = runner_ + ['--list-defines']
- if args.get('verbose'):
- print(' '.join(shlex.quote(c) for c in cmd))
- proc = sp.Popen(cmd,
- stdout=sp.PIPE,
- stderr=sp.PIPE if not args.get('verbose') else None,
- universal_newlines=True,
- errors='replace')
- defines = co.OrderedDict()
- pattern = re.compile(
- '^(?P<id>(?P<case>(?P<suite>[^#]+)#[^\s#]+)[^\s]*)\s+'
- '(?P<defines>(?:\w+=\w+\s*)+)')
- for line in proc.stdout:
- m = pattern.match(line)
- if m:
- defines[m.group('id')] = {k: v
- for k, v in re.findall('(\w+)=(\w+)', m.group('defines'))}
- proc.wait()
- if proc.returncode != 0:
- if not args.get('verbose'):
- for line in proc.stderr:
- sys.stdout.write(line)
- sys.exit(-1)
-
- return defines
-
-
-class TestFailure(Exception):
- def __init__(self, id, returncode, output, assert_=None):
- self.id = id
- self.returncode = returncode
- self.output = output
- self.assert_ = assert_
-
-def run_stage(name, runner_, **args):
- # get expected suite/case/perm counts
- expected_suite_perms, expected_case_perms, expected_perms, total_perms = (
- find_cases(runner_, **args))
-
- passed_suite_perms = co.defaultdict(lambda: 0)
- passed_case_perms = co.defaultdict(lambda: 0)
- passed_perms = 0
- failures = []
- killed = False
-
- pattern = re.compile('^(?:'
- '(?P<op>running|finished|skipped) '
- '(?P<id>(?P<case>(?P<suite>[^#]+)#[^\s#]+)[^\s]*)'
- '|' '(?P<path>[^:]+):(?P<lineno>\d+):(?P<op_>assert):'
- ' *(?P<message>.*)' ')$')
- locals = th.local()
- children = set()
-
- def run_runner(runner_):
- nonlocal passed_suite_perms
- nonlocal passed_case_perms
- nonlocal passed_perms
- nonlocal locals
-
- # run the tests!
- cmd = runner_.copy()
- if args.get('disk'):
- cmd.append('--disk=%s' % args['disk'])
- if args.get('trace'):
- cmd.append('--trace=%s' % args['trace'])
- if args.get('verbose'):
- print(' '.join(shlex.quote(c) for c in cmd))
- mpty, spty = pty.openpty()
- proc = sp.Popen(cmd, stdout=spty, stderr=spty)
- os.close(spty)
- children.add(proc)
- mpty = os.fdopen(mpty, 'r', 1)
- if args.get('output'):
- output = openio(args['output'], 'w')
-
- last_id = None
- last_output = []
- last_assert = None
- try:
- while True:
- # parse a line for state changes
- try:
- line = mpty.readline()
- except OSError as e:
- if e.errno == errno.EIO:
- break
- raise
- if not line:
- break
- last_output.append(line)
- if args.get('output'):
- output.write(line)
- elif args.get('verbose'):
- sys.stdout.write(line)
-
- m = pattern.match(line)
- if m:
- op = m.group('op') or m.group('op_')
- if op == 'running':
- locals.seen_perms += 1
- last_id = m.group('id')
- last_output = []
- last_assert = None
- elif op == 'finished':
- passed_suite_perms[m.group('suite')] += 1
- passed_case_perms[m.group('case')] += 1
- passed_perms += 1
- elif op == 'skipped':
- locals.seen_perms += 1
- elif op == 'assert':
- last_assert = (
- m.group('path'),
- int(m.group('lineno')),
- m.group('message'))
- # go ahead and kill the process, aborting takes a while
- if args.get('keep_going'):
- proc.kill()
- except KeyboardInterrupt:
- raise TestFailure(last_id, 1, last_output)
- finally:
- children.remove(proc)
- mpty.close()
- if args.get('output'):
- output.close()
-
- proc.wait()
- if proc.returncode != 0:
- raise TestFailure(
- last_id,
- proc.returncode,
- last_output,
- last_assert)
-
- def run_job(runner, start=None, step=None):
- nonlocal failures
- nonlocal locals
-
- start = start or 0
- step = step or 1
- while start < total_perms:
- runner_ = runner.copy()
- if start is not None:
- runner_.append('--start=%d' % start)
- if step is not None:
- runner_.append('--step=%d' % step)
- if args.get('isolate') or args.get('valgrind'):
- runner_.append('--stop=%d' % (start+step))
-
- try:
- # run the tests
- locals.seen_perms = 0
- run_runner(runner_)
- assert locals.seen_perms > 0
- start += locals.seen_perms*step
-
- except TestFailure as failure:
- # race condition for multiple failures?
- if failures and not args.get('keep_going'):
- break
-
- failures.append(failure)
-
- if args.get('keep_going') and not killed:
- # resume after failed test
- assert locals.seen_perms > 0
- start += locals.seen_perms*step
- continue
- else:
- # stop other tests
- for child in children.copy():
- child.kill()
-
-
- # parallel jobs?
- runners = []
- if 'jobs' in args:
- for job in range(args['jobs']):
- runners.append(th.Thread(
- target=run_job, args=(runner_, job, args['jobs'])))
- else:
- runners.append(th.Thread(
- target=run_job, args=(runner_, None, None)))
-
- for r in runners:
- r.start()
-
- needs_newline = False
- try:
- while any(r.is_alive() for r in runners):
- time.sleep(0.01)
-
- if not args.get('verbose'):
- sys.stdout.write('\r\x1b[K'
- 'running \x1b[%dm%s:\x1b[m %s '
- % (32 if not failures else 31,
- name,
- ', '.join(filter(None, [
- '%d/%d suites' % (
- sum(passed_suite_perms[k] == v
- for k, v in expected_suite_perms.items()),
- len(expected_suite_perms))
- if (not args.get('by_suites')
- and not args.get('by_cases')) else None,
- '%d/%d cases' % (
- sum(passed_case_perms[k] == v
- for k, v in expected_case_perms.items()),
- len(expected_case_perms))
- if not args.get('by_cases') else None,
- '%d/%d perms' % (passed_perms, expected_perms),
- '\x1b[31m%d/%d failures\x1b[m'
- % (len(failures), expected_perms)
- if failures else None]))))
- sys.stdout.flush()
- needs_newline = True
- except KeyboardInterrupt:
- # this is handled by the runner threads, we just
- # need to not abort here
- killed = True
- finally:
- if needs_newline:
- print()
-
- for r in runners:
- r.join()
-
- return (
- expected_perms,
- passed_perms,
- failures,
- killed)
-
-
-def run(**args):
- start = time.time()
-
- runner_ = runner(**args)
- print('using runner: %s'
- % ' '.join(shlex.quote(c) for c in runner_))
- expected_suite_perms, expected_case_perms, expected_perms, total_perms = (
- find_cases(runner_, **args))
- print('found %d suites, %d cases, %d/%d permutations'
- % (len(expected_suite_perms),
- len(expected_case_perms),
- expected_perms,
- total_perms))
- print()
-
- expected = 0
- passed = 0
- failures = []
- for type, by in it.product(
- ['normal', 'reentrant'],
- expected_case_perms.keys() if args.get('by_cases')
- else expected_suite_perms.keys() if args.get('by_suites')
- else [None]):
- # rebuild runner for each stage to override test identifier if needed
- stage_runner = runner(**args | {
- 'test_ids': [by] if by is not None else args.get('test_ids', []),
- 'normal': type == 'normal',
- 'reentrant': type == 'reentrant'})
-
- # spawn jobs for stage
- expected_, passed_, failures_, killed = run_stage(
- '%s %s' % (type, by or 'tests'), stage_runner, **args)
- expected += expected_
- passed += passed_
- failures.extend(failures_)
- if (failures and not args.get('keep_going')) or killed:
- break
-
- # show summary
- print()
- print('\x1b[%dmdone:\x1b[m %d/%d passed, %d/%d failed, in %.2fs'
- % (32 if not failures else 31,
- passed, expected, len(failures), expected,
- time.time()-start))
- print()
-
- # print each failure
- if failures:
- # get some extra info from runner
- runner_paths = find_paths(runner_, **args)
- runner_defines = find_defines(runner_, **args)
-
- for failure in failures:
- # show summary of failure
- path, lineno = runner_paths[testcase(failure.id)]
- defines = runner_defines[failure.id]
-
- print('\x1b[01m%s:%d:\x1b[01;31mfailure:\x1b[m %s%s failed'
- % (path, lineno, failure.id,
- ' (%s)' % ', '.join(
- '%s=%s' % (k, v) for k, v in defines.items())
- if defines else ''))
-
- if failure.output:
- output = failure.output
- if failure.assert_ is not None:
- output = output[:-1]
- for line in output[-5:]:
- sys.stdout.write(line)
-
- if failure.assert_ is not None:
- path, lineno, message = failure.assert_
- print('\x1b[01m%s:%d:\x1b[01;31massert:\x1b[m %s'
- % (path, lineno, message))
- with open(path) as f:
- line = next(it.islice(f, lineno-1, None)).strip('\n')
- print(line)
- print()
-
- # drop into gdb?
- if failures and (args.get('gdb')
- or args.get('gdb_case')
- or args.get('gdb_main')):
- failure = failures[0]
- runner_ = runner(**args | {'test_ids': [failure.id]})
-
- if args.get('gdb_main'):
- cmd = ['gdb',
- '-ex', 'break main',
- '-ex', 'run',
- '--args'] + runner_
- elif args.get('gdb_case'):
- path, lineno = runner_paths[testcase(failure.id)]
- cmd = ['gdb',
- '-ex', 'break %s:%d' % (path, lineno),
- '-ex', 'run',
- '--args'] + runner_
- elif failure.assert_ is not None:
- cmd = ['gdb',
- '-ex', 'run',
- '-ex', 'frame function raise',
- '-ex', 'up 2',
- '--args'] + runner_
- else:
- cmd = ['gdb',
- '-ex', 'run',
- '--args'] + runner_
-
- # exec gdb interactively
- if args.get('verbose'):
- print(' '.join(shlex.quote(c) for c in cmd))
- os.execvp(cmd[0], cmd)
-
- return 1 if failures else 0
-
-
-def main(**args):
- if args.get('compile'):
- compile(**args)
- elif (args.get('summary')
- or args.get('list_suites')
- or args.get('list_cases')
- or args.get('list_paths')
- or args.get('list_defines')
- or args.get('list_geometries')
- or args.get('list_defaults')):
- list_(**args)
- else:
- run(**args)
-
-
-if __name__ == "__main__":
- import argparse
- import sys
- parser = argparse.ArgumentParser(
- description="Build and run tests.",
- conflict_handler='resolve')
- parser.add_argument('test_ids', nargs='*',
- help="Description of testis to run. May be a directory, path, or \
- test identifier. Test identifiers are of the form \
- <suite_name>#<case_name>#<permutation>, but suffixes can be \
- dropped to run any matching tests. Defaults to %r." % TEST_PATHS)
- parser.add_argument('-v', '--verbose', action='store_true',
- help="Output commands that run behind the scenes.")
- # test flags
- test_parser = parser.add_argument_group('test options')
- test_parser.add_argument('-Y', '--summary', action='store_true',
- help="Show quick summary.")
- test_parser.add_argument('-l', '--list-suites', action='store_true',
- help="List test suites.")
- test_parser.add_argument('-L', '--list-cases', action='store_true',
- help="List test cases.")
- test_parser.add_argument('--list-paths', action='store_true',
- help="List the path for each test case.")
- test_parser.add_argument('--list-defines', action='store_true',
- help="List the defines for each test permutation.")
- test_parser.add_argument('--list-geometries', action='store_true',
- help="List the disk geometries used for testing.")
- test_parser.add_argument('--list-defaults', action='store_true',
- help="List the default defines in this test-runner.")
- test_parser.add_argument('-D', '--define', action='append',
- help="Override a test define.")
- test_parser.add_argument('-G', '--geometry',
- help="Filter by geometry.")
- test_parser.add_argument('-n', '--normal', action='store_true',
- help="Filter for normal tests. Can be combined.")
- test_parser.add_argument('-r', '--reentrant', action='store_true',
- help="Filter for reentrant tests. Can be combined.")
- test_parser.add_argument('-d', '--disk',
- help="Use this file as the disk.")
- test_parser.add_argument('-t', '--trace',
- help="Redirect trace output to this file.")
- test_parser.add_argument('-o', '--output',
- help="Redirect stdout and stderr to this file.")
- test_parser.add_argument('--runner', default=[RUNNER_PATH],
- type=lambda x: x.split(),
- help="Path to runner, defaults to %r" % RUNNER_PATH)
- test_parser.add_argument('-j', '--jobs', nargs='?', type=int,
- const=len(os.sched_getaffinity(0)),
- help="Number of parallel runners to run.")
- test_parser.add_argument('-k', '--keep-going', action='store_true',
- help="Don't stop on first error.")
- test_parser.add_argument('-i', '--isolate', action='store_true',
- help="Run each test permutation in a separate process.")
- test_parser.add_argument('-b', '--by-suites', action='store_true',
- help="Step through tests by suite.")
- test_parser.add_argument('-B', '--by-cases', action='store_true',
- help="Step through tests by case.")
- test_parser.add_argument('--gdb', action='store_true',
- help="Drop into gdb on test failure.")
- test_parser.add_argument('--gdb-case', action='store_true',
- help="Drop into gdb on test failure but stop at the beginning \
- of the failing test case.")
- test_parser.add_argument('--gdb-main', action='store_true',
- help="Drop into gdb on test failure but stop at the beginning \
- of main.")
- test_parser.add_argument('--valgrind', action='store_true',
- help="Run under Valgrind to find memory errors. Implicitly sets \
- --isolate.")
- test_parser.add_argument('--exec', default=[], type=lambda e: e.split(),
- help="Run under another executable.")
- # compilation flags
- comp_parser = parser.add_argument_group('compilation options')
- comp_parser.add_argument('-c', '--compile', action='store_true',
- help="Compile a test suite or source file.")
- comp_parser.add_argument('-s', '--source',
- help="Source file to compile, possibly injecting internal tests.")
- comp_parser.add_argument('-o', '--output',
- help="Output file.")
- # TODO apply this to other scripts?
- sys.exit(main(**{k: v
- for k, v in vars(parser.parse_args()).items()
- if v is not None}))
diff --git a/tests/test_alloc.toml b/tests/test_alloc.toml
index fa92da5..4e43db3 100644
--- a/tests/test_alloc.toml
+++ b/tests/test_alloc.toml
@@ -1,27 +1,30 @@
# allocator tests
# 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
-define.FILES = 3
-define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)'
+# parallel allocation test
+[cases.parallel_allocation]
+defines.FILES = 3
+defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
code = '''
- const char *names[FILES] = {"bacon", "eggs", "pancakes"};
+ const char *names[] = {"bacon", "eggs", "pancakes"};
lfs_file_t files[FILES];
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) {
+ char path[1024];
sprintf(path, "breakfast/%s", names[n]);
lfs_file_open(&lfs, &files[n], path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
}
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) {
lfs_file_write(&lfs, &files[n], names[n], size) => size;
}
@@ -31,12 +34,15 @@ code = '''
}
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) {
+ char path[1024];
sprintf(path, "breakfast/%s", names[n]);
+ lfs_file_t file;
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) {
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size;
assert(memcmp(buffer, names[n], size) == 0);
}
@@ -45,23 +51,28 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # serial allocation test
-define.FILES = 3
-define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)'
+# serial allocation test
+[cases.serial_allocation]
+defines.FILES = 3
+defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
code = '''
- const char *names[FILES] = {"bacon", "eggs", "pancakes"};
+ const char *names[] = {"bacon", "eggs", "pancakes"};
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0;
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]);
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
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);
for (int i = 0; i < SIZE; i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
@@ -70,12 +81,15 @@ code = '''
lfs_unmount(&lfs) => 0;
}
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) {
+ char path[1024];
sprintf(path, "breakfast/%s", names[n]);
+ lfs_file_t file;
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) {
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size;
assert(memcmp(buffer, names[n], size) == 0);
}
@@ -84,29 +98,32 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # parallel allocation reuse test
-define.FILES = 3
-define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)'
-define.CYCLES = [1, 10]
+# parallel allocation reuse test
+[cases.parallel_allocation_reuse]
+defines.FILES = 3
+defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
+defines.CYCLES = [1, 10]
code = '''
- const char *names[FILES] = {"bacon", "eggs", "pancakes"};
+ const char *names[] = {"bacon", "eggs", "pancakes"};
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++) {
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) {
+ char path[1024];
sprintf(path, "breakfast/%s", names[n]);
lfs_file_open(&lfs, &files[n], path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
}
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) {
lfs_file_write(&lfs, &files[n], names[n], size) => size;
}
@@ -116,12 +133,15 @@ code = '''
}
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) {
+ char path[1024];
sprintf(path, "breakfast/%s", names[n]);
+ lfs_file_t file;
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) {
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size;
assert(memcmp(buffer, names[n], size) == 0);
}
@@ -129,8 +149,9 @@ code = '''
}
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) {
+ char path[1024];
sprintf(path, "breakfast/%s", names[n]);
lfs_remove(&lfs, path) => 0;
}
@@ -139,26 +160,31 @@ code = '''
}
'''
-[[case]] # serial allocation reuse test
-define.FILES = 3
-define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-6)) / FILES)'
-define.CYCLES = [1, 10]
+# serial allocation reuse test
+[cases.serial_allocation_reuse]
+defines.FILES = 3
+defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-6)) / FILES)'
+defines.CYCLES = [1, 10]
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++) {
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "breakfast") => 0;
lfs_unmount(&lfs) => 0;
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]);
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
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);
for (int i = 0; i < SIZE; i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
@@ -167,12 +193,15 @@ code = '''
lfs_unmount(&lfs) => 0;
}
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) {
+ char path[1024];
sprintf(path, "breakfast/%s", names[n]);
+ lfs_file_t file;
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) {
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size;
assert(memcmp(buffer, names[n], size) == 0);
}
@@ -180,8 +209,9 @@ code = '''
}
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int n = 0; n < FILES; n++) {
+ char path[1024];
sprintf(path, "breakfast/%s", names[n]);
lfs_remove(&lfs, path) => 0;
}
@@ -190,12 +220,16 @@ code = '''
}
'''
-[[case]] # exhaustion test
+# exhaustion test
+[cases.exhaustion]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ 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);
- size = strlen("exhaustion");
+ size_t size = strlen("exhaustion");
+ uint8_t buffer[1024];
memcpy(buffer, "exhaustion", size);
lfs_file_write(&lfs, &file, buffer, size) => size;
lfs_file_sync(&lfs, &file) => 0;
@@ -216,7 +250,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
size = strlen("exhaustion");
lfs_file_size(&lfs, &file) => size;
@@ -226,14 +260,18 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # exhaustion wraparound test
-define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / 3)'
+# exhaustion wraparound test
+[cases.exhaustion_wraparound]
+defines.SIZE = '(((BLOCK_SIZE-8)*(BLOCK_COUNT-4)) / 3)'
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ 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);
- size = strlen("buffering");
+ size_t size = strlen("buffering");
+ uint8_t buffer[1024];
memcpy(buffer, "buffering", size);
for (int i = 0; i < SIZE; i += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
@@ -263,7 +301,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY);
size = strlen("exhaustion");
lfs_file_size(&lfs, &file) => size;
@@ -274,17 +312,22 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # dir exhaustion test
+# dir exhaustion test
+[cases.dir_exhaustion]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// find out max file size
lfs_mkdir(&lfs, "exhaustiondir") => 0;
- size = strlen("blahblahblahblah");
+ size_t size = strlen("blahblahblahblah");
+ uint8_t buffer[1024];
memcpy(buffer, "blahblahblahblah", size);
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
int count = 0;
+ int err;
while (true) {
err = lfs_file_write(&lfs, &file, buffer, size);
if (err < 0) {
@@ -323,17 +366,21 @@ code = '''
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"
-define.LFS_ERASE_CYCLES = 0xffffffff
-define.LFS_BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_READERROR'
+defines.ERASE_CYCLES = 0xffffffff
+defines.BADBLOCK_BEHAVIOR = 'LFS_TESTBD_BADBLOCK_READERROR'
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// 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;
+ uint8_t buffer[1024];
strcpy((char*)buffer, "waka");
- size = strlen("waka");
+ size_t size = strlen("waka");
lfs_size_t filesize = 0;
while (true) {
lfs_ssize_t res = lfs_file_write(&lfs, &file, buffer, size);
@@ -345,7 +392,7 @@ code = '''
}
lfs_file_close(&lfs, &file) => 0;
// 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;
strcpy((char*)buffer, "waka");
size = strlen("waka");
@@ -358,11 +405,11 @@ code = '''
lfs_unmount(&lfs) => 0;
// 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
// 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;
strcpy((char*)buffer, "chomp");
size = strlen("chomp");
@@ -377,7 +424,7 @@ code = '''
// now reverse the "bad block" and try to write the file again until we
// 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;
strcpy((char*)buffer, "chomp");
size = strlen("chomp");
@@ -393,7 +440,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// 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;
strcpy((char*)buffer, "waka");
size = strlen("waka");
@@ -411,24 +458,29 @@ code = '''
# on the geometry of the block device. But they are valuable. Eventually they
# should be removed and replaced with generalized tests.
-[[case]] # chained dir exhaustion test
-define.LFS_BLOCK_SIZE = 512
-define.LFS_BLOCK_COUNT = 1024
-if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024'
+# chained dir exhaustion test
+[cases.chained_dir_exhaustion]
+if = 'BLOCK_SIZE == 512'
+defines.BLOCK_COUNT = 1024
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// find out max file size
lfs_mkdir(&lfs, "exhaustiondir") => 0;
for (int i = 0; i < 10; i++) {
+ char path[1024];
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_mkdir(&lfs, path) => 0;
}
- size = strlen("blahblahblahblah");
+ size_t size = strlen("blahblahblahblah");
+ uint8_t buffer[1024];
memcpy(buffer, "blahblahblahblah", size);
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
int count = 0;
+ int err;
while (true) {
err = lfs_file_write(&lfs, &file, buffer, size);
if (err < 0) {
@@ -443,6 +495,7 @@ code = '''
lfs_remove(&lfs, "exhaustion") => 0;
lfs_remove(&lfs, "exhaustiondir") => 0;
for (int i = 0; i < 10; i++) {
+ char path[1024];
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_remove(&lfs, path) => 0;
}
@@ -455,6 +508,7 @@ code = '''
lfs_file_sync(&lfs, &file) => 0;
for (int i = 0; i < 10; i++) {
+ char path[1024];
sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i);
lfs_mkdir(&lfs, path) => 0;
}
@@ -482,27 +536,31 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # split dir test
-define.LFS_BLOCK_SIZE = 512
-define.LFS_BLOCK_COUNT = 1024
-if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024'
+# split dir test
+[cases.split_dir]
+if = 'BLOCK_SIZE == 512'
+defines.BLOCK_COUNT = 1024
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// 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;
- 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);
}
- 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_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT);
- size = strlen("blahblahblahblah");
+ size_t size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
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) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -510,7 +568,7 @@ code = '''
// remount to force reset of lookahead
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// open hole
lfs_remove(&lfs, "bump") => 0;
@@ -518,30 +576,33 @@ code = '''
lfs_mkdir(&lfs, "splitdir") => 0;
lfs_file_open(&lfs, &file, "splitdir/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) {
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_unmount(&lfs) => 0;
'''
-[[case]] # outdated lookahead test
-define.LFS_BLOCK_SIZE = 512
-define.LFS_BLOCK_COUNT = 1024
-if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024'
+# outdated lookahead test
+[cases.outdated_lookahead]
+if = 'BLOCK_SIZE == 512'
+defines.BLOCK_COUNT = 1024
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// fill completely with two files
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "exhaustion1",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
- size = strlen("blahblahblahblah");
+ size_t size = strlen("blahblahblahblah");
+ uint8_t buffer[1024];
memcpy(buffer, "blahblahblahblah", size);
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) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -552,7 +613,7 @@ code = '''
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
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) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -560,7 +621,7 @@ code = '''
// remount to force reset of lookahead
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// rewrite one file
lfs_file_open(&lfs, &file, "exhaustion1",
@@ -569,7 +630,7 @@ code = '''
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
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) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -583,7 +644,7 @@ code = '''
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
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) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -592,21 +653,24 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # outdated lookahead and split dir test
-define.LFS_BLOCK_SIZE = 512
-define.LFS_BLOCK_COUNT = 1024
-if = 'LFS_BLOCK_SIZE == 512 && LFS_BLOCK_COUNT == 1024'
+# outdated lookahead and split dir test
+[cases.outdated_lookahead_split_dir]
+if = 'BLOCK_SIZE == 512'
+defines.BLOCK_COUNT = 1024
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// fill completely with two files
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "exhaustion1",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
- size = strlen("blahblahblahblah");
+ size_t size = strlen("blahblahblahblah");
+ uint8_t buffer[1024];
memcpy(buffer, "blahblahblahblah", size);
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) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -617,7 +681,7 @@ code = '''
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
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) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -625,7 +689,7 @@ code = '''
// remount to force reset of lookahead
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// rewrite one file with a hole of one block
lfs_file_open(&lfs, &file, "exhaustion1",
@@ -634,7 +698,7 @@ code = '''
size = strlen("blahblahblahblah");
memcpy(buffer, "blahblahblahblah", size);
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) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
diff --git a/tests/test_attrs.toml b/tests/test_attrs.toml
index db8d0c7..719ea68 100644
--- a/tests/test_attrs.toml
+++ b/tests/test_attrs.toml
@@ -1,14 +1,17 @@
-[[case]] # set/get attribute
+[cases.get_set_attrs]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 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_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ uint8_t buffer[1024];
memset(buffer, 0, sizeof(buffer));
lfs_setattr(&lfs, "hello", 'A', "aaaa", 4) => 0;
lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0;
@@ -60,7 +63,7 @@ code = '''
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
memset(buffer, 0, sizeof(buffer));
lfs_getattr(&lfs, "hello", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "hello", 'B', buffer+4, 9) => 9;
@@ -76,17 +79,20 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # set/get root attribute
+[cases.get_set_root_attrs]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 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_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ uint8_t buffer[1024];
memset(buffer, 0, sizeof(buffer));
lfs_setattr(&lfs, "/", 'A', "aaaa", 4) => 0;
lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0;
@@ -137,7 +143,7 @@ code = '''
lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
memset(buffer, 0, sizeof(buffer));
lfs_getattr(&lfs, "/", 'A', buffer, 4) => 4;
lfs_getattr(&lfs, "/", 'B', buffer+4, 9) => 9;
@@ -153,17 +159,20 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # set/get file attribute
+[cases.get_set_file_attrs]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 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_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file);
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ uint8_t buffer[1024];
memset(buffer, 0, sizeof(buffer));
struct lfs_attr attrs1[] = {
{'A', buffer, 4},
@@ -238,7 +247,7 @@ code = '''
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
memset(buffer, 0, sizeof(buffer));
struct lfs_attr attrs3[] = {
{'A', buffer, 4},
@@ -260,20 +269,23 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # deferred file attributes
+[cases.deferred_file_attrs]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 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_write(&lfs, &file, "hello", strlen("hello")) => strlen("hello");
lfs_file_close(&lfs, &file);
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", 'C', "ccccc", 5) => 0;
+ uint8_t buffer[1024];
memset(buffer, 0, sizeof(buffer));
struct lfs_attr attrs1[] = {
{'B', "gggg", 4},
diff --git a/tests/test_badblocks.toml b/tests/test_badblocks.toml
index 06967a6..c5cab47 100644
--- a/tests/test_badblocks.toml
+++ b/tests/test_badblocks.toml
@@ -1,28 +1,30 @@
# 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
-define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
-define.LFS_ERASE_CYCLES = 0xffffffff
-define.LFS_ERASE_VALUE = [0x00, 0xff, -1]
-define.LFS_BADBLOCK_BEHAVIOR = [
+[cases.single_bad_blocks]
+defines.BLOCK_COUNT = 256 # small bd so test runs faster
+defines.ERASE_CYCLES = 0xffffffff
+defines.ERASE_VALUE = [0x00, 0xff, -1]
+defines.BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP',
]
-define.NAMEMULT = 64
-define.FILEMULT = 1
+defines.NAMEMULT = 64
+defines.FILEMULT = 1
code = '''
- for (lfs_block_t badblock = 2; badblock < LFS_BLOCK_COUNT; badblock++) {
- lfs_testbd_setwear(&cfg, badblock-1, 0) => 0;
- lfs_testbd_setwear(&cfg, badblock, 0xffffffff) => 0;
-
- lfs_format(&lfs, &cfg) => 0;
+ for (lfs_block_t badblock = 2; badblock < BLOCK_COUNT; badblock++) {
+ lfs_testbd_setwear(cfg, badblock-1, 0) => 0;
+ lfs_testbd_setwear(cfg, badblock, 0xffffffff) => 0;
+
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) {
+ uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i;
}
@@ -34,10 +36,11 @@ code = '''
buffer[j+NAMEMULT+1] = '0'+i;
}
buffer[2*NAMEMULT+1] = '\0';
+ lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0;
- size = NAMEMULT;
+ lfs_size_t size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -46,12 +49,14 @@ code = '''
}
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) {
+ uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i;
}
buffer[NAMEMULT] = '\0';
+ struct lfs_info info;
lfs_stat(&lfs, (char*)buffer, &info) => 0;
info.type => LFS_TYPE_DIR;
@@ -60,9 +65,10 @@ code = '''
buffer[j+NAMEMULT+1] = '0'+i;
}
buffer[2*NAMEMULT+1] = '\0';
+ lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0;
- size = NAMEMULT;
+ int size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) {
uint8_t rbuffer[1024];
lfs_file_read(&lfs, &file, rbuffer, size) => size;
@@ -75,28 +81,30 @@ code = '''
}
'''
-[[case]] # region corruption (causes cascading failures)
-define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
-define.LFS_ERASE_CYCLES = 0xffffffff
-define.LFS_ERASE_VALUE = [0x00, 0xff, -1]
-define.LFS_BADBLOCK_BEHAVIOR = [
+[cases.region_corruption] # (causes cascading failures)
+defines.BLOCK_COUNT = 256 # small bd so test runs faster
+defines.ERASE_CYCLES = 0xffffffff
+defines.ERASE_VALUE = [0x00, 0xff, -1]
+defines.BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP',
]
-define.NAMEMULT = 64
-define.FILEMULT = 1
+defines.NAMEMULT = 64
+defines.FILEMULT = 1
code = '''
- for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) {
- lfs_testbd_setwear(&cfg, i+2, 0xffffffff) => 0;
+ for (lfs_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) {
+ 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++) {
+ uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i;
}
@@ -108,10 +116,11 @@ code = '''
buffer[j+NAMEMULT+1] = '0'+i;
}
buffer[2*NAMEMULT+1] = '\0';
+ lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0;
- size = NAMEMULT;
+ lfs_size_t size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -120,12 +129,14 @@ code = '''
}
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) {
+ uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i;
}
buffer[NAMEMULT] = '\0';
+ struct lfs_info info;
lfs_stat(&lfs, (char*)buffer, &info) => 0;
info.type => LFS_TYPE_DIR;
@@ -134,9 +145,10 @@ code = '''
buffer[j+NAMEMULT+1] = '0'+i;
}
buffer[2*NAMEMULT+1] = '\0';
+ lfs_file_t file;
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++) {
uint8_t rbuffer[1024];
lfs_file_read(&lfs, &file, rbuffer, size) => size;
@@ -148,28 +160,30 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # alternating corruption (causes cascading failures)
-define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
-define.LFS_ERASE_CYCLES = 0xffffffff
-define.LFS_ERASE_VALUE = [0x00, 0xff, -1]
-define.LFS_BADBLOCK_BEHAVIOR = [
+[cases.alternating_corruption] # (causes cascading failures)
+defines.BLOCK_COUNT = 256 # small bd so test runs faster
+defines.ERASE_CYCLES = 0xffffffff
+defines.ERASE_VALUE = [0x00, 0xff, -1]
+defines.BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP',
]
-define.NAMEMULT = 64
-define.FILEMULT = 1
+defines.NAMEMULT = 64
+defines.FILEMULT = 1
code = '''
- for (lfs_block_t i = 0; i < (LFS_BLOCK_COUNT-2)/2; i++) {
- lfs_testbd_setwear(&cfg, (2*i) + 2, 0xffffffff) => 0;
+ for (lfs_block_t i = 0; i < (BLOCK_COUNT-2)/2; i++) {
+ 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++) {
+ uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i;
}
@@ -181,10 +195,11 @@ code = '''
buffer[j+NAMEMULT+1] = '0'+i;
}
buffer[2*NAMEMULT+1] = '\0';
+ lfs_file_t file;
lfs_file_open(&lfs, &file, (char*)buffer,
LFS_O_WRONLY | LFS_O_CREAT) => 0;
- size = NAMEMULT;
+ lfs_size_t size = NAMEMULT;
for (int j = 0; j < i*FILEMULT; j++) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -193,12 +208,14 @@ code = '''
}
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int i = 1; i < 10; i++) {
+ uint8_t buffer[1024];
for (int j = 0; j < NAMEMULT; j++) {
buffer[j] = '0'+i;
}
buffer[NAMEMULT] = '\0';
+ struct lfs_info info;
lfs_stat(&lfs, (char*)buffer, &info) => 0;
info.type => LFS_TYPE_DIR;
@@ -207,9 +224,10 @@ code = '''
buffer[j+NAMEMULT+1] = '0'+i;
}
buffer[2*NAMEMULT+1] = '\0';
+ lfs_file_t file;
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++) {
uint8_t rbuffer[1024];
lfs_file_read(&lfs, &file, rbuffer, size) => size;
@@ -222,10 +240,10 @@ code = '''
'''
# other corner cases
-[[case]] # bad superblocks (corrupt 1 or 0)
-define.LFS_ERASE_CYCLES = 0xffffffff
-define.LFS_ERASE_VALUE = [0x00, 0xff, -1]
-define.LFS_BADBLOCK_BEHAVIOR = [
+[cases.bad_superblocks] # (corrupt 1 or 0)
+defines.ERASE_CYCLES = 0xffffffff
+defines.ERASE_VALUE = [0x00, 0xff, -1]
+defines.BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR',
@@ -233,9 +251,10 @@ define.LFS_BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_ERASENOOP',
]
code = '''
- lfs_testbd_setwear(&cfg, 0, 0xffffffff) => 0;
- lfs_testbd_setwear(&cfg, 1, 0xffffffff) => 0;
+ lfs_testbd_setwear(cfg, 0, 0xffffffff) => 0;
+ lfs_testbd_setwear(cfg, 1, 0xffffffff) => 0;
- lfs_format(&lfs, &cfg) => LFS_ERR_NOSPC;
- lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => LFS_ERR_NOSPC;
+ lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
'''
diff --git a/tests/test_dirs.toml b/tests/test_dirs.toml
index 270f4f8..60346c0 100644
--- a/tests/test_dirs.toml
+++ b/tests/test_dirs.toml
@@ -1,8 +1,11 @@
-[[case]] # root
+[cases.root]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0);
@@ -14,20 +17,25 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # many directory creation
-define.N = 'range(0, 100, 3)'
+[cases.many_dir_creation]
+defines.N = [3,6,9,12,21,33,57,66,72,93,99]
+if = 'N < BLOCK_COUNT/2'
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++) {
+ char path[1024];
sprintf(path, "dir%03d", i);
lfs_mkdir(&lfs, path) => 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;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0);
@@ -35,6 +43,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "dir%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
@@ -45,20 +54,25 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # many directory removal
-define.N = 'range(3, 100, 11)'
+[cases.many_dir_removal]
+defines.N = [3,6,9,12,21,33,57,66,72,93,99]
+if = 'N < BLOCK_COUNT/2'
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++) {
+ char path[1024];
sprintf(path, "removeme%03d", i);
lfs_mkdir(&lfs, path) => 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;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0);
@@ -66,6 +80,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "removeme%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
@@ -75,14 +90,15 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs);
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "removeme%03d", i);
lfs_remove(&lfs, path) => 0;
}
lfs_unmount(&lfs);
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
@@ -95,20 +111,25 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # many directory rename
-define.N = 'range(3, 100, 11)'
+[cases.many_dir_rename]
+defines.N = [3,6,9,12,21,33,57,66,72,93,99]
+if = 'N < BLOCK_COUNT/2'
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++) {
+ char path[1024];
sprintf(path, "test%03d", i);
lfs_mkdir(&lfs, path) => 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;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0);
@@ -116,6 +137,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "test%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
@@ -125,7 +147,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs);
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) {
char oldpath[128];
char newpath[128];
@@ -135,7 +157,7 @@ code = '''
}
lfs_unmount(&lfs);
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
@@ -144,6 +166,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "tedd%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
@@ -154,29 +177,34 @@ code = '''
lfs_unmount(&lfs);
'''
-[[case]] # reentrant many directory creation/rename/removal
-define.N = [5, 11]
+[cases.reentrant_many_dir]
+defines.N = [5, 11]
reentrant = true
code = '''
- err = lfs_mount(&lfs, &cfg);
+ lfs_t lfs;
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
}
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "hi%03d", i);
err = lfs_mkdir(&lfs, path);
assert(err == 0 || err == LFS_ERR_EXIST);
}
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "hello%03d", i);
err = lfs_remove(&lfs, path);
assert(err == 0 || err == LFS_ERR_NOENT);
}
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0);
@@ -184,6 +212,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "hi%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
@@ -209,6 +238,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "hello%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
@@ -218,6 +248,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0;
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "hello%03d", i);
lfs_remove(&lfs, path) => 0;
}
@@ -234,22 +265,28 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # file creation
-define.N = 'range(3, 100, 11)'
+[cases.file_creation]
+defines.N = [3,6,9,12,21,33,57,66,72,93,99]
+if = 'N < BLOCK_COUNT/2'
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++) {
+ char path[1024];
sprintf(path, "file%03d", i);
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0);
@@ -257,6 +294,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "file%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG);
@@ -267,22 +305,28 @@ code = '''
lfs_unmount(&lfs);
'''
-[[case]] # file removal
-define.N = 'range(0, 100, 3)'
+[cases.file_removal]
+defines.N = [3,6,9,12,21,33,57,66,72,93,99]
+if = 'N < BLOCK_COUNT/2'
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++) {
+ char path[1024];
sprintf(path, "removeme%03d", i);
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0);
@@ -290,6 +334,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "removeme%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG);
@@ -299,14 +344,15 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs);
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "removeme%03d", i);
lfs_remove(&lfs, path) => 0;
}
lfs_unmount(&lfs);
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
@@ -319,22 +365,28 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # file rename
-define.N = 'range(0, 100, 3)'
+[cases.file_rename]
+defines.N = [3,6,9,12,21,33,57,66,72,93,99]
+if = 'N < BLOCK_COUNT/2'
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++) {
+ char path[1024];
sprintf(path, "test%03d", i);
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
}
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0);
@@ -342,6 +394,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "test%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG);
@@ -351,7 +404,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs);
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) {
char oldpath[128];
char newpath[128];
@@ -361,7 +414,7 @@ code = '''
}
lfs_unmount(&lfs);
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
@@ -370,6 +423,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "tedd%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG);
@@ -380,29 +434,36 @@ code = '''
lfs_unmount(&lfs);
'''
-[[case]] # reentrant file creation/rename/removal
-define.N = [5, 25]
+[cases.reentrant_files]
+defines.N = [5, 25]
+if = 'N < BLOCK_COUNT/2'
reentrant = true
code = '''
- err = lfs_mount(&lfs, &cfg);
+ lfs_t lfs;
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
}
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "hi%03d", i);
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_close(&lfs, &file) => 0;
}
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "hello%03d", i);
err = lfs_remove(&lfs, path);
assert(err == 0 || err == LFS_ERR_NOENT);
}
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0);
@@ -410,6 +471,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "hi%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG);
@@ -435,6 +497,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "hello%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_REG);
@@ -444,6 +507,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0;
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "hello%03d", i);
lfs_remove(&lfs, path) => 0;
}
@@ -460,24 +524,28 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # nested directories
+[cases.nested_dirs]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "potato") => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "burito",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "potato/baked") => 0;
lfs_mkdir(&lfs, "potato/sweet") => 0;
lfs_mkdir(&lfs, "potato/fried") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "potato") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
info.type => LFS_TYPE_DIR;
@@ -498,21 +566,21 @@ code = '''
lfs_unmount(&lfs) => 0;
// try removing?
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY;
lfs_unmount(&lfs) => 0;
// try renaming?
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "potato", "coldpotato") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "coldpotato", "warmpotato") => 0;
lfs_rename(&lfs, "warmpotato", "hotpotato") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_remove(&lfs, "potato") => LFS_ERR_NOENT;
lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT;
lfs_remove(&lfs, "warmpotato") => LFS_ERR_NOENT;
@@ -520,7 +588,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// try cross-directory renaming
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "coldpotato") => 0;
lfs_rename(&lfs, "hotpotato/baked", "coldpotato/baked") => 0;
lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY;
@@ -536,7 +604,7 @@ code = '''
lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "hotpotato") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -558,7 +626,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// final remove
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
lfs_remove(&lfs, "hotpotato/baked") => 0;
lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY;
@@ -568,7 +636,7 @@ code = '''
lfs_remove(&lfs, "hotpotato") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -584,17 +652,22 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # recursive remove
-define.N = [10, 100]
+[cases.recursive_remove]
+defines.N = [10, 100]
+if = 'N < BLOCK_COUNT/2'
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "prickly-pear") => 0;
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "prickly-pear/cactus%03d", i);
lfs_mkdir(&lfs, path) => 0;
}
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "prickly-pear") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0);
@@ -602,6 +675,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "cactus%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
@@ -611,7 +685,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs);
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY;
lfs_dir_open(&lfs, &dir, "prickly-pear") => 0;
@@ -622,6 +696,7 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, "..") == 0);
for (int i = 0; i < N; i++) {
+ char path[1024];
sprintf(path, "cactus%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
@@ -636,22 +711,24 @@ code = '''
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT;
lfs_unmount(&lfs) => 0;
'''
-[[case]] # other error cases
+[cases.other_errors]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "potato") => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "burito",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "potato") => 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_file_open(&lfs, &file, "potato",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST;
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "tomato") => LFS_ERR_NOENT;
lfs_dir_open(&lfs, &dir, "burito") => LFS_ERR_NOTDIR;
lfs_file_open(&lfs, &file, "tomato", LFS_O_RDONLY) => LFS_ERR_NOENT;
@@ -678,6 +756,7 @@ code = '''
// check that errors did not corrupt directory
lfs_dir_open(&lfs, &dir, "/") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
assert(strcmp(info.name, ".") == 0);
@@ -696,7 +775,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// or on disk
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(info.type == LFS_TYPE_DIR);
@@ -715,21 +794,26 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # directory seek
-define.COUNT = [4, 128, 132]
+[cases.directory_seek]
+defines.COUNT = [4, 128, 132]
+if = 'COUNT < BLOCK_COUNT/2'
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "hello") => 0;
for (int i = 0; i < COUNT; i++) {
+ char path[1024];
sprintf(path, "hello/kitty%03d", i);
lfs_mkdir(&lfs, path) => 0;
}
lfs_unmount(&lfs) => 0;
for (int j = 2; j < COUNT; j++) {
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "hello") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -739,6 +823,7 @@ code = '''
lfs_soff_t pos;
for (int i = 0; i < j; i++) {
+ char path[1024];
sprintf(path, "kitty%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0);
@@ -748,13 +833,14 @@ code = '''
}
lfs_dir_seek(&lfs, &dir, pos) => 0;
+ char path[1024];
sprintf(path, "kitty%03d", j);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0);
assert(info.type == LFS_TYPE_DIR);
lfs_dir_rewind(&lfs, &dir) => 0;
- sprintf(path, "kitty%03d", 0);
+ sprintf(path, "kitty%03u", 0);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -776,20 +862,25 @@ code = '''
}
'''
-[[case]] # root seek
-define.COUNT = [4, 128, 132]
+[cases.root_seek]
+defines.COUNT = [4, 128, 132]
+if = 'COUNT < BLOCK_COUNT/2'
code = '''
- 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 = 0; i < COUNT; i++) {
+ char path[1024];
sprintf(path, "hi%03d", i);
lfs_mkdir(&lfs, path) => 0;
}
lfs_unmount(&lfs) => 0;
for (int j = 2; j < COUNT; j++) {
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -799,6 +890,7 @@ code = '''
lfs_soff_t pos;
for (int i = 0; i < j; i++) {
+ char path[1024];
sprintf(path, "hi%03d", i);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0);
@@ -808,13 +900,14 @@ code = '''
}
lfs_dir_seek(&lfs, &dir, pos) => 0;
+ char path[1024];
sprintf(path, "hi%03d", j);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0);
assert(info.type == LFS_TYPE_DIR);
lfs_dir_rewind(&lfs, &dir) => 0;
- sprintf(path, "hi%03d", 0);
+ sprintf(path, "hi%03u", 0);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
diff --git a/tests/test_entries.toml b/tests/test_entries.toml
index 81e175f..6c1f1d7 100644
--- a/tests/test_entries.toml
+++ b/tests/test_entries.toml
@@ -2,19 +2,23 @@
# 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.
-define.LFS_CACHE_SIZE = 512
-if = 'LFS_CACHE_SIZE % LFS_PROG_SIZE == 0 && LFS_CACHE_SIZE == 512'
+defines.CACHE_SIZE = 512
+if = 'CACHE_SIZE % PROG_SIZE == 0 && CACHE_SIZE == 512'
-[[case]] # entry grow test
+[cases.entry_grow]
code = '''
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// write hi0 20
+ char path[1024];
+ lfs_size_t size;
sprintf(path, "hi0"); size = 20;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
@@ -94,16 +98,20 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # entry shrink test
+[cases.entry_shrink]
code = '''
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// write hi0 20
+ char path[1024];
+ lfs_size_t size;
sprintf(path, "hi0"); size = 20;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
@@ -183,16 +191,20 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # entry spill test
+[cases.entry_spill]
code = '''
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// write hi0 200
+ char path[1024];
+ lfs_size_t size;
sprintf(path, "hi0"); size = 200;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
@@ -256,16 +268,20 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # entry push spill test
+[cases.entry_push_spill]
code = '''
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// write hi0 200
+ char path[1024];
+ lfs_size_t size;
sprintf(path, "hi0"); size = 200;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
@@ -345,16 +361,20 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # entry push spill two test
+[cases.entry_push_spill_two]
code = '''
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// write hi0 200
+ char path[1024];
+ lfs_size_t size;
sprintf(path, "hi0"); size = 200;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
@@ -449,16 +469,20 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # entry drop test
+[cases.entry_drop]
code = '''
uint8_t wbuffer[1024];
uint8_t rbuffer[1024];
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// write hi0 200
+ char path[1024];
+ lfs_size_t size;
sprintf(path, "hi0"); size = 200;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
memset(wbuffer, 'c', size);
@@ -491,6 +515,7 @@ code = '''
lfs_file_close(&lfs, &file) => 0;
lfs_remove(&lfs, "hi1") => 0;
+ struct lfs_info info;
lfs_stat(&lfs, "hi1", &info) => LFS_ERR_NOENT;
// read hi0 200
sprintf(path, "hi0"); size = 200;
@@ -547,15 +572,18 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # create too big
+[cases.create_too_big]
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);
path[200] = '\0';
- size = 400;
+ lfs_size_t size = 400;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
uint8_t wbuffer[1024];
@@ -572,15 +600,18 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # resize too big
+[cases.resize_too_big]
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);
path[200] = '\0';
- size = 40;
+ lfs_size_t size = 40;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
uint8_t wbuffer[1024];
diff --git a/tests/test_evil.toml b/tests/test_evil.toml
index 920d3a0..78a5034 100644
--- a/tests/test_evil.toml
+++ b/tests/test_evil.toml
@@ -3,16 +3,17 @@
# invalid pointer tests (outside of block_count)
-[[case]] # invalid tail-pointer test
-define.TAIL_TYPE = ['LFS_TYPE_HARDTAIL', 'LFS_TYPE_SOFTTAIL']
-define.INVALSET = [0x3, 0x1, 0x2]
+[cases.invalid_tail_pointer]
+defines.TAIL_TYPE = ['LFS_TYPE_HARDTAIL', 'LFS_TYPE_SOFTTAIL']
+defines.INVALSET = [0x3, 0x1, 0x2]
in = "lfs.c"
code = '''
// create littlefs
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
// change tail-pointer to invalid pointers
- lfs_init(&lfs, &cfg) => 0;
+ lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
@@ -23,25 +24,27 @@ code = '''
lfs_deinit(&lfs) => 0;
// test that mount fails gracefully
- lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT;
+ lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
'''
-[[case]] # invalid dir pointer test
-define.INVALSET = [0x3, 0x1, 0x2]
+[cases.invalid_dir_pointer]
+defines.INVALSET = [0x3, 0x1, 0x2]
in = "lfs.c"
code = '''
// create littlefs
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
// make a dir
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "dir_here") => 0;
lfs_unmount(&lfs) => 0;
// change the dir pointer to be invalid
- lfs_init(&lfs, &cfg) => 0;
+ lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
// make sure id 1 == our directory
+ uint8_t buffer[1024];
lfs_dir_get(&lfs, &mdir,
LFS_MKTAG(0x700, 0x3ff, 0),
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
// 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;
assert(strcmp(info.name, "dir_here") == 0);
assert(info.type == LFS_TYPE_DIR);
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "dir_here") => 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_file_t file;
lfs_file_open(&lfs, &file, "dir_here/file_here",
LFS_O_RDONLY) => LFS_ERR_CORRUPT;
lfs_file_open(&lfs, &file, "dir_here/file_here",
@@ -72,24 +78,27 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # invalid file pointer test
+[cases.invalid_file_pointer]
in = "lfs.c"
-define.SIZE = [10, 1000, 100000] # faked file size
+defines.SIZE = [10, 1000, 100000] # faked file size
code = '''
// create littlefs
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
// 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_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// change the file pointer to be invalid
- lfs_init(&lfs, &cfg) => 0;
+ lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
// make sure id 1 == our file
+ uint8_t buffer[1024];
lfs_dir_get(&lfs, &mdir,
LFS_MKTAG(0x700, 0x3ff, 0),
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
// 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;
assert(strcmp(info.name, "file_here") == 0);
assert(info.type == LFS_TYPE_REG);
@@ -114,20 +124,22 @@ code = '''
lfs_file_close(&lfs, &file) => 0;
// 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_unmount(&lfs) => 0;
'''
-[[case]] # invalid pointer in CTZ skip-list test
-define.SIZE = ['2*LFS_BLOCK_SIZE', '3*LFS_BLOCK_SIZE', '4*LFS_BLOCK_SIZE']
+[cases.invalid_ctz_pointer] # invalid pointer in CTZ skip-list test
+defines.SIZE = ['2*BLOCK_SIZE', '3*BLOCK_SIZE', '4*BLOCK_SIZE']
in = "lfs.c"
code = '''
// create littlefs
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
// 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_O_WRONLY | LFS_O_CREAT) => 0;
for (int i = 0; i < SIZE; i++) {
@@ -137,10 +149,11 @@ code = '''
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
// change pointer in CTZ skip-list to be invalid
- lfs_init(&lfs, &cfg) => 0;
+ lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
// make sure id 1 == our file and get our CTZ structure
+ uint8_t buffer[4*BLOCK_SIZE];
lfs_dir_get(&lfs, &mdir,
LFS_MKTAG(0x700, 0x3ff, 0),
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_ctz_fromle32(&ctz);
// rewrite block to contain bad pointer
- uint8_t bbuffer[LFS_BLOCK_SIZE];
- cfg.read(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
+ uint8_t bbuffer[BLOCK_SIZE];
+ cfg->read(cfg, ctz.head, 0, bbuffer, BLOCK_SIZE) => 0;
uint32_t bad = lfs_tole32(0xcccccccc);
memcpy(&bbuffer[0], &bad, sizeof(bad));
memcpy(&bbuffer[4], &bad, sizeof(bad));
- cfg.erase(&cfg, ctz.head) => 0;
- cfg.prog(&cfg, ctz.head, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
+ cfg->erase(cfg, ctz.head) => 0;
+ cfg->prog(cfg, ctz.head, 0, bbuffer, BLOCK_SIZE) => 0;
lfs_deinit(&lfs) => 0;
// 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
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ struct lfs_info info;
lfs_stat(&lfs, "file_here", &info) => 0;
assert(strcmp(info.name, "file_here") == 0);
assert(info.type == LFS_TYPE_REG);
@@ -175,22 +189,23 @@ code = '''
lfs_file_close(&lfs, &file) => 0;
// 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_unmount(&lfs) => 0;
'''
-[[case]] # invalid gstate pointer
-define.INVALSET = [0x3, 0x1, 0x2]
+[cases.invalid_gstate_pointer]
+defines.INVALSET = [0x3, 0x1, 0x2]
in = "lfs.c"
code = '''
// create littlefs
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
// create an invalid gstate
- lfs_init(&lfs, &cfg) => 0;
+ lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_fs_prepmove(&lfs, 1, (lfs_block_t [2]){
@@ -202,21 +217,22 @@ code = '''
// test that mount fails gracefully
// mount may not fail, but our first alloc should fail when
// 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_unmount(&lfs) => 0;
'''
# cycle detection/recovery tests
-[[case]] # metadata-pair threaded-list loop test
+[cases.mdir_loop] # metadata-pair threaded-list loop test
in = "lfs.c"
code = '''
// create littlefs
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
// change tail-pointer to point to ourself
- lfs_init(&lfs, &cfg) => 0;
+ lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS(
@@ -225,20 +241,21 @@ code = '''
lfs_deinit(&lfs) => 0;
// 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"
code = '''
// create littlefs with child dir
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0;
// find child
- lfs_init(&lfs, &cfg) => 0;
+ lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_block_t pair[2];
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
@@ -255,20 +272,21 @@ code = '''
lfs_deinit(&lfs) => 0;
// 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"
code = '''
// create littlefs with child dir
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0;
// find child
- lfs_init(&lfs, &cfg) => 0;
+ lfs_init(&lfs, cfg) => 0;
lfs_mdir_t mdir;
lfs_block_t pair[2];
lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0;
@@ -284,5 +302,5 @@ code = '''
lfs_deinit(&lfs) => 0;
// test that mount fails gracefully
- lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT;
+ lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
'''
diff --git a/tests/test_exhaustion.toml b/tests/test_exhaustion.toml
index 569611c..1914d62 100644
--- a/tests/test_exhaustion.toml
+++ b/tests/test_exhaustion.toml
@@ -1,30 +1,34 @@
-[[case]] # test running a filesystem to exhaustion
-define.LFS_ERASE_CYCLES = 10
-define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
-define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
-define.LFS_BADBLOCK_BEHAVIOR = [
+# test running a filesystem to exhaustion
+[cases.exhaustion]
+defines.ERASE_CYCLES = 10
+defines.BLOCK_COUNT = 256 # small bd so test runs faster
+defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
+defines.BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP',
]
-define.FILES = 10
+defines.FILES = 10
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0;
lfs_unmount(&lfs) => 0;
uint32_t cycle = 0;
while (true) {
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size
+ char path[1024];
sprintf(path, "roadrunner/test%d", 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_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
@@ -33,14 +37,14 @@ code = '''
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || 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);
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
- err = lfs_file_close(&lfs, &file);
+ int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0;
@@ -50,10 +54,12 @@ code = '''
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
+ char path[1024];
sprintf(path, "roadrunner/test%d", 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;
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26);
@@ -71,10 +77,12 @@ code = '''
exhausted:
// should still be readable
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
+ char path[1024];
sprintf(path, "roadrunner/test%d", i);
+ struct lfs_info info;
lfs_stat(&lfs, path, &info) => 0;
}
lfs_unmount(&lfs) => 0;
@@ -82,31 +90,35 @@ exhausted:
LFS_WARN("completed %d cycles", cycle);
'''
-[[case]] # test running a filesystem to exhaustion
- # which also requires expanding superblocks
-define.LFS_ERASE_CYCLES = 10
-define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
-define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
-define.LFS_BADBLOCK_BEHAVIOR = [
+# test running a filesystem to exhaustion
+# which also requires expanding superblocks
+[cases.exhaustion_superblocks]
+defines.ERASE_CYCLES = 10
+defines.BLOCK_COUNT = 256 # small bd so test runs faster
+defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
+defines.BADBLOCK_BEHAVIOR = [
'LFS_TESTBD_BADBLOCK_PROGERROR',
'LFS_TESTBD_BADBLOCK_ERASEERROR',
'LFS_TESTBD_BADBLOCK_READERROR',
'LFS_TESTBD_BADBLOCK_PROGNOOP',
'LFS_TESTBD_BADBLOCK_ERASENOOP',
]
-define.FILES = 10
+defines.FILES = 10
code = '''
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
uint32_t cycle = 0;
while (true) {
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size
+ char path[1024];
sprintf(path, "test%d", 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_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
@@ -115,14 +127,14 @@ code = '''
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || 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);
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
- err = lfs_file_close(&lfs, &file);
+ int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0;
@@ -132,10 +144,12 @@ code = '''
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
+ char path[1024];
sprintf(path, "test%d", 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;
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26);
@@ -153,9 +167,11 @@ code = '''
exhausted:
// should still be readable
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
+ char path[1024];
+ struct lfs_info info;
sprintf(path, "test%d", i);
lfs_stat(&lfs, path, &info) => 0;
}
@@ -169,35 +185,39 @@ exhausted:
# into increasing the block devices lifetime. This is something we can actually
# check for.
-[[case]] # wear-level test running a filesystem to exhaustion
-define.LFS_ERASE_CYCLES = 20
-define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
-define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
-define.FILES = 10
+# wear-level test running a filesystem to exhaustion
+[cases.wear_leveling_exhaustion]
+defines.ERASE_CYCLES = 20
+defines.BLOCK_COUNT = 256 # small bd so test runs faster
+defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
+defines.FILES = 10
code = '''
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 (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) {
- lfs_testbd_setwear(&cfg, b,
- (b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0;
+ for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) {
+ lfs_testbd_setwear(cfg, b,
+ (b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0;
}
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0;
lfs_unmount(&lfs) => 0;
uint32_t cycle = 0;
while (true) {
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size
+ char path[1024];
sprintf(path, "roadrunner/test%d", 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_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
@@ -206,14 +226,14 @@ code = '''
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || 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);
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
- err = lfs_file_close(&lfs, &file);
+ int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0;
@@ -223,10 +243,12 @@ code = '''
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
+ char path[1024];
sprintf(path, "roadrunner/test%d", 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;
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26);
@@ -244,9 +266,11 @@ code = '''
exhausted:
// should still be readable
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
+ char path[1024];
+ struct lfs_info info;
sprintf(path, "roadrunner/test%d", i);
lfs_stat(&lfs, path, &info) => 0;
}
@@ -261,32 +285,36 @@ exhausted:
LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
'''
-[[case]] # wear-level test + expanding superblock
-define.LFS_ERASE_CYCLES = 20
-define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
-define.LFS_BLOCK_CYCLES = 'LFS_ERASE_CYCLES / 2'
-define.FILES = 10
+# wear-level test + expanding superblock
+[cases.wear_leveling_exhaustion_superblocks]
+defines.ERASE_CYCLES = 20
+defines.BLOCK_COUNT = 256 # small bd so test runs faster
+defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
+defines.FILES = 10
code = '''
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 (lfs_block_t b = 0; b < LFS_BLOCK_COUNT; b++) {
- lfs_testbd_setwear(&cfg, b,
- (b < run_block_count[run]) ? 0 : LFS_ERASE_CYCLES) => 0;
+ for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) {
+ lfs_testbd_setwear(cfg, b,
+ (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;
while (true) {
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size
+ char path[1024];
sprintf(path, "test%d", 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_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
@@ -295,14 +323,14 @@ code = '''
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || 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);
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
- err = lfs_file_close(&lfs, &file);
+ int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0;
@@ -312,10 +340,12 @@ code = '''
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
+ char path[1024];
sprintf(path, "test%d", 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;
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26);
@@ -333,9 +363,11 @@ code = '''
exhausted:
// should still be readable
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
+ char path[1024];
+ struct lfs_info info;
sprintf(path, "test%d", i);
lfs_stat(&lfs, path, &info) => 0;
}
@@ -350,28 +382,32 @@ exhausted:
LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
'''
-[[case]] # test that we wear blocks roughly evenly
-define.LFS_ERASE_CYCLES = 0xffffffff
-define.LFS_BLOCK_COUNT = 256 # small bd so test runs faster
-define.LFS_BLOCK_CYCLES = [5, 4, 3, 2, 1]
-define.CYCLES = 100
-define.FILES = 10
-if = 'LFS_BLOCK_CYCLES < CYCLES/10'
+# test that we wear blocks roughly evenly
+[cases.wear_leveling_distribution]
+defines.ERASE_CYCLES = 0xffffffff
+defines.BLOCK_COUNT = 256 # small bd so test runs faster
+defines.BLOCK_CYCLES = [5, 4, 3, 2, 1]
+defines.CYCLES = 100
+defines.FILES = 10
+if = 'BLOCK_CYCLES < CYCLES/10'
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "roadrunner") => 0;
lfs_unmount(&lfs) => 0;
uint32_t cycle = 0;
while (cycle < CYCLES) {
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// chose name, roughly random seed, and random 2^n size
+ char path[1024];
sprintf(path, "roadrunner/test%d", 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_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
@@ -380,14 +416,14 @@ code = '''
lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
assert(res == 1 || 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);
lfs_unmount(&lfs) => 0;
goto exhausted;
}
}
- err = lfs_file_close(&lfs, &file);
+ int err = lfs_file_close(&lfs, &file);
assert(err == 0 || err == LFS_ERR_NOSPC);
if (err == LFS_ERR_NOSPC) {
lfs_unmount(&lfs) => 0;
@@ -397,10 +433,12 @@ code = '''
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
+ char path[1024];
sprintf(path, "roadrunner/test%d", 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;
for (lfs_size_t j = 0; j < size; j++) {
char c = 'a' + (rand() % 26);
@@ -418,9 +456,11 @@ code = '''
exhausted:
// should still be readable
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (uint32_t i = 0; i < FILES; i++) {
// check for errors
+ char path[1024];
+ struct lfs_info info;
sprintf(path, "roadrunner/test%d", i);
lfs_stat(&lfs, path, &info) => 0;
}
@@ -433,8 +473,8 @@ exhausted:
lfs_testbd_wear_t totalwear = 0;
lfs_testbd_wear_t maxwear = 0;
// skip 0 and 1 as superblock movement is intentionally avoided
- for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) {
- lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b);
+ for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) {
+ lfs_testbd_wear_t wear = lfs_testbd_getwear(cfg, b);
printf("%08x: wear %d\n", b, wear);
assert(wear >= 0);
if (wear < minwear) {
@@ -445,15 +485,15 @@ exhausted:
}
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("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);
// find standard deviation^2
lfs_testbd_wear_t dev2 = 0;
- for (lfs_block_t b = 2; b < LFS_BLOCK_COUNT; b++) {
- lfs_testbd_wear_t wear = lfs_testbd_getwear(&cfg, b);
+ for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) {
+ lfs_testbd_wear_t wear = lfs_testbd_getwear(cfg, b);
assert(wear >= 0);
lfs_testbd_swear_t diff = wear - avgwear;
dev2 += diff*diff;
diff --git a/tests/test_files.toml b/tests/test_files.toml
index 5463054..026e47f 100644
--- a/tests/test_files.toml
+++ b/tests/test_files.toml
@@ -1,17 +1,20 @@
-[[case]] # simple file test
+[cases.simple_file]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "hello",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
- size = strlen("Hello World!")+1;
+ lfs_size_t size = strlen("Hello World!")+1;
+ uint8_t buffer[1024];
strcpy((char*)buffer, "Hello World!");
lfs_file_write(&lfs, &file, buffer, size) => size;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, buffer, size) => size;
assert(strcmp((char*)buffer, "Hello World!") == 0);
@@ -19,17 +22,20 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # larger files
-define.SIZE = [32, 8192, 262144, 0, 7, 8193]
-define.CHUNKSIZE = [31, 16, 33, 1, 1023]
+[cases.large_files]
+defines.SIZE = [32, 8192, 262144, 0, 7, 8193]
+defines.CHUNKSIZE = [31, 16, 33, 1, 1023]
code = '''
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
// write
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "avacado",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
srand(1);
+ uint8_t buffer[1024];
for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) {
lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i);
for (lfs_size_t b = 0; b < chunk; b++) {
@@ -41,7 +47,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// read
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE;
srand(1);
@@ -57,15 +63,18 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # rewriting files
-define.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
-define.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
-define.CHUNKSIZE = [31, 16, 1]
+[cases.rewriting_files]
+defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
+defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
+defines.CHUNKSIZE = [31, 16, 1]
code = '''
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
// 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_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
srand(1);
@@ -80,7 +89,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// read
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1;
srand(1);
@@ -96,7 +105,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// rewrite
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY) => 0;
srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
@@ -110,7 +119,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// read
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => lfs_max(SIZE1, SIZE2);
srand(2);
@@ -139,15 +148,18 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # appending files
-define.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
-define.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
-define.CHUNKSIZE = [31, 16, 1]
+[cases.appending_files]
+defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
+defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
+defines.CHUNKSIZE = [31, 16, 1]
code = '''
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
// 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_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
srand(1);
@@ -162,7 +174,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// read
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1;
srand(1);
@@ -178,7 +190,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// append
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_APPEND) => 0;
srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
@@ -192,7 +204,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// read
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1 + SIZE2;
srand(1);
@@ -216,15 +228,18 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # truncating files
-define.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
-define.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
-define.CHUNKSIZE = [31, 16, 1]
+[cases.truncating_files]
+defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
+defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
+defines.CHUNKSIZE = [31, 16, 1]
code = '''
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
// 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_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
srand(1);
@@ -239,7 +254,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// read
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE1;
srand(1);
@@ -255,7 +270,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// truncate
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_TRUNC) => 0;
srand(2);
for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) {
@@ -269,7 +284,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// read
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => SIZE2;
srand(2);
@@ -285,22 +300,25 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # reentrant file writing
-define.SIZE = [32, 0, 7, 2049]
-define.CHUNKSIZE = [31, 16, 65]
+[cases.reentrant_file_writing]
+defines.SIZE = [32, 0, 7, 2049]
+defines.CHUNKSIZE = [31, 16, 65]
reentrant = true
code = '''
- err = lfs_mount(&lfs, &cfg);
+ lfs_t lfs;
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
}
+ lfs_file_t file;
+ uint8_t buffer[1024];
err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY);
assert(err == LFS_ERR_NOENT || err == 0);
if (err == 0) {
// can only be 0 (new file) or full size
- size = lfs_file_size(&lfs, &file);
+ lfs_size_t size = lfs_file_size(&lfs, &file);
assert(size == 0 || size == SIZE);
lfs_file_close(&lfs, &file) => 0;
}
@@ -333,8 +351,8 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # reentrant file writing with syncs
-define = [
+[cases.reentrant_file_writing_sync]
+defines = [
# append (O(n))
{MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]},
# truncate (O(n^2))
@@ -344,17 +362,20 @@ define = [
]
reentrant = true
code = '''
- err = lfs_mount(&lfs, &cfg);
+ lfs_t lfs;
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
}
+ lfs_file_t file;
+ uint8_t buffer[1024];
err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY);
assert(err == LFS_ERR_NOENT || err == 0);
if (err == 0) {
// with syncs we could be any size, but it at least must be valid data
- size = lfs_file_size(&lfs, &file);
+ lfs_size_t size = lfs_file_size(&lfs, &file);
assert(size <= SIZE);
srand(1);
for (lfs_size_t i = 0; i < size; i += CHUNKSIZE) {
@@ -370,7 +391,7 @@ code = '''
// write
lfs_file_open(&lfs, &file, "avacado",
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);
srand(1);
lfs_size_t skip = (MODE == LFS_O_APPEND) ? size : 0;
@@ -403,19 +424,22 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # many files
-define.N = 300
+[cases.many_files]
+defines.N = 300
code = '''
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
// create N files of 7 bytes
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) {
+ lfs_file_t file;
+ char path[1024];
sprintf(path, "file_%03d", i);
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
char wbuffer[1024];
- size = 7;
- snprintf(wbuffer, size, "Hi %03d", i);
+ lfs_size_t size = 7;
+ sprintf(wbuffer, "Hi %03d", i);
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0;
@@ -428,25 +452,28 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # many files with power cycle
-define.N = 300
+[cases.many_files_power_cycle]
+defines.N = 300
code = '''
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
// create N files of 7 bytes
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) {
+ lfs_file_t file;
+ char path[1024];
sprintf(path, "file_%03d", i);
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
char wbuffer[1024];
- size = 7;
- snprintf(wbuffer, size, "Hi %03d", i);
+ lfs_size_t size = 7;
+ sprintf(wbuffer, "Hi %03d", i);
lfs_file_write(&lfs, &file, wbuffer, size) => size;
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
char rbuffer[1024];
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_read(&lfs, &file, rbuffer, size) => size;
assert(strcmp(rbuffer, wbuffer) == 0);
@@ -455,22 +482,25 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # many files with power loss
-define.N = 300
+[cases.many_files_power_loss]
+defines.N = 300
reentrant = true
code = '''
- err = lfs_mount(&lfs, &cfg);
+ lfs_t lfs;
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
}
// create N files of 7 bytes
for (int i = 0; i < N; i++) {
+ lfs_file_t file;
+ char path[1024];
sprintf(path, "file_%03d", i);
err = lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT);
char wbuffer[1024];
- size = 7;
- snprintf(wbuffer, size, "Hi %03d", i);
+ lfs_size_t size = 7;
+ sprintf(wbuffer, "Hi %03d", i);
if ((lfs_size_t)lfs_file_size(&lfs, &file) != size) {
lfs_file_write(&lfs, &file, wbuffer, size) => size;
}
diff --git a/tests/test_interspersed.toml b/tests/test_interspersed.toml
index 87a0578..92d96d8 100644
--- a/tests/test_interspersed.toml
+++ b/tests/test_interspersed.toml
@@ -1,13 +1,15 @@
-[[case]] # interspersed file test
-define.SIZE = [10, 100]
-define.FILES = [4, 10, 26]
+[cases.interspersed_files]
+defines.SIZE = [10, 100]
+defines.FILES = [4, 10, 26]
code = '''
+ lfs_t lfs;
lfs_file_t files[FILES];
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int j = 0; j < FILES; j++) {
+ char path[1024];
sprintf(path, "%c", alphas[j]);
lfs_file_open(&lfs, &files[j], path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
@@ -23,7 +25,9 @@ code = '''
lfs_file_close(&lfs, &files[j]);
}
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -31,6 +35,7 @@ code = '''
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
for (int j = 0; j < FILES; j++) {
+ char path[1024];
sprintf(path, "%c", alphas[j]);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0);
@@ -41,12 +46,14 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0;
for (int j = 0; j < FILES; j++) {
+ char path[1024];
sprintf(path, "%c", alphas[j]);
lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0;
}
for (int i = 0; i < 10; i++) {
for (int j = 0; j < FILES; j++) {
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &files[j], buffer, 1) => 1;
assert(buffer[0] == alphas[j]);
}
@@ -59,15 +66,18 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # interspersed remove file test
-define.SIZE = [10, 100]
-define.FILES = [4, 10, 26]
+[cases.interspersed_remove_files]
+defines.SIZE = [10, 100]
+defines.FILES = [4, 10, 26]
code = '''
+ lfs_t lfs;
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (int j = 0; j < FILES; j++) {
+ char path[1024];
sprintf(path, "%c", alphas[j]);
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
for (int i = 0; i < SIZE; i++) {
@@ -77,18 +87,22 @@ code = '''
}
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;
for (int j = 0; j < FILES; j++) {
lfs_file_write(&lfs, &file, (const void*)"~", 1) => 1;
lfs_file_sync(&lfs, &file) => 0;
+ char path[1024];
sprintf(path, "%c", alphas[j]);
lfs_remove(&lfs, path) => 0;
}
lfs_file_close(&lfs, &file);
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -104,6 +118,7 @@ code = '''
lfs_file_open(&lfs, &file, "zzz", LFS_O_RDONLY) => 0;
for (int i = 0; i < FILES; i++) {
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 1) => 1;
assert(buffer[0] == '~');
}
@@ -112,11 +127,12 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # remove inconveniently test
-define.SIZE = [10, 100]
+[cases.remove_inconveniently]
+defines.SIZE = [10, 100]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_file_t files[3];
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;
@@ -140,7 +156,9 @@ code = '''
lfs_file_close(&lfs, &files[1]);
lfs_file_close(&lfs, &files[2]);
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -161,6 +179,7 @@ code = '''
lfs_file_open(&lfs, &files[0], "e", LFS_O_RDONLY) => 0;
lfs_file_open(&lfs, &files[1], "g", LFS_O_RDONLY) => 0;
for (int i = 0; i < SIZE; i++) {
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &files[0], buffer, 1) => 1;
assert(buffer[0] == 'e');
lfs_file_read(&lfs, &files[1], buffer, 1) => 1;
@@ -172,21 +191,23 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # reentrant interspersed file test
-define.SIZE = [10, 100]
-define.FILES = [4, 10, 26]
+[cases.reentrant_interspersed_files]
+defines.SIZE = [10, 100]
+defines.FILES = [4, 10, 26]
reentrant = true
code = '''
+ lfs_t lfs;
lfs_file_t files[FILES];
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
- err = lfs_mount(&lfs, &cfg);
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
}
for (int j = 0; j < FILES; j++) {
+ char path[1024];
sprintf(path, "%c", alphas[j]);
lfs_file_open(&lfs, &files[j], path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0;
@@ -194,8 +215,8 @@ code = '''
for (int i = 0; i < SIZE; i++) {
for (int j = 0; j < FILES; j++) {
- size = lfs_file_size(&lfs, &files[j]);
- assert((int)size >= 0);
+ lfs_ssize_t size = lfs_file_size(&lfs, &files[j]);
+ assert(size >= 0);
if ((int)size <= i) {
lfs_file_write(&lfs, &files[j], &alphas[j], 1) => 1;
lfs_file_sync(&lfs, &files[j]) => 0;
@@ -207,7 +228,9 @@ code = '''
lfs_file_close(&lfs, &files[j]);
}
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/") => 0;
+ struct lfs_info info;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -215,6 +238,7 @@ code = '''
assert(strcmp(info.name, "..") == 0);
assert(info.type == LFS_TYPE_DIR);
for (int j = 0; j < FILES; j++) {
+ char path[1024];
sprintf(path, "%c", alphas[j]);
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, path) == 0);
@@ -225,12 +249,14 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0;
for (int j = 0; j < FILES; j++) {
+ char path[1024];
sprintf(path, "%c", alphas[j]);
lfs_file_open(&lfs, &files[j], path, LFS_O_RDONLY) => 0;
}
for (int i = 0; i < 10; i++) {
for (int j = 0; j < FILES; j++) {
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &files[j], buffer, 1) => 1;
assert(buffer[0] == alphas[j]);
}
diff --git a/tests/test_move.toml b/tests/test_move.toml
index bb3b713..f1825e4 100644
--- a/tests/test_move.toml
+++ b/tests/test_move.toml
@@ -1,11 +1,13 @@
-[[case]] # move file
+[cases.move_file]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 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_write(&lfs, &file, "hola\n", 5) => 5;
lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
@@ -13,11 +15,13 @@ code = '''
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 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_read(&lfs, &dir, &info) => 1;
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, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 0;
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 5) => 5;
memcmp(buffer, "hola\n", 5) => 0;
lfs_file_read(&lfs, &file, buffer, 8) => 8;
@@ -55,31 +60,35 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # noop move, yes this is legal
+[cases.nop_move] # yes this is legal
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "hi") => 0;
lfs_rename(&lfs, "hi", "hi") => 0;
lfs_mkdir(&lfs, "hi/hi") => 0;
lfs_rename(&lfs, "hi/hi", "hi/hi") => 0;
lfs_mkdir(&lfs, "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;
assert(strcmp(info.name, "hi") == 0);
assert(info.type == LFS_TYPE_DIR);
lfs_unmount(&lfs) => 0;
'''
-[[case]] # move file corrupt source
+[cases.move_file_corrupt_source]
in = "lfs.c"
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 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_write(&lfs, &file, "hola\n", 5) => 5;
lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
@@ -87,28 +96,30 @@ code = '''
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0;
// 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_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
- uint8_t bbuffer[LFS_BLOCK_SIZE];
- cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- int off = LFS_BLOCK_SIZE-1;
- while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
+ uint8_t buffer[BLOCK_SIZE];
+ cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ int off = BLOCK_SIZE-1;
+ while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1;
}
- memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
- cfg.erase(&cfg, block) => 0;
- cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- cfg.sync(&cfg) => 0;
+ memset(&buffer[off-3], BLOCK_SIZE, 3);
+ cfg->erase(cfg, block) => 0;
+ cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ cfg->sync(cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -146,16 +157,19 @@ code = '''
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"
-if = 'LFS_PROG_SIZE <= 0x3fe' # only works with one crc per commit
+if = 'PROG_SIZE <= 0x3fe' # only works with one crc per commit
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 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_write(&lfs, &file, "hola\n", 5) => 5;
lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
@@ -163,44 +177,46 @@ code = '''
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0;
// 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_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
- uint8_t bbuffer[LFS_BLOCK_SIZE];
- cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- int off = LFS_BLOCK_SIZE-1;
- while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
+ uint8_t buffer[BLOCK_SIZE];
+ cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ int off = BLOCK_SIZE-1;
+ while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1;
}
- memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
- cfg.erase(&cfg, block) => 0;
- cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- cfg.sync(&cfg) => 0;
+ memset(&buffer[off-3], BLOCK_SIZE, 3);
+ cfg->erase(cfg, block) => 0;
+ cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ cfg->sync(cfg) => 0;
// corrupt the destination
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0;
block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
- cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- off = LFS_BLOCK_SIZE-1;
- while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
+ cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ off = BLOCK_SIZE-1;
+ while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1;
}
- memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
- cfg.erase(&cfg, block) => 0;
- cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- cfg.sync(&cfg) => 0;
+ memset(&buffer[off-3], BLOCK_SIZE, 3);
+ cfg->erase(cfg, block) => 0;
+ cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ cfg->sync(cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -238,16 +254,18 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # move file after corrupt
+[cases.move_file_after_corrupt]
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 = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 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_write(&lfs, &file, "hola\n", 5) => 5;
lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
@@ -255,49 +273,51 @@ code = '''
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0;
// 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_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
- uint8_t bbuffer[LFS_BLOCK_SIZE];
- cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- int off = LFS_BLOCK_SIZE-1;
- while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
+ uint8_t buffer[BLOCK_SIZE];
+ cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ int off = BLOCK_SIZE-1;
+ while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1;
}
- memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
- cfg.erase(&cfg, block) => 0;
- cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- cfg.sync(&cfg) => 0;
+ memset(&buffer[off-3], BLOCK_SIZE, 3);
+ cfg->erase(cfg, block) => 0;
+ cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ cfg->sync(cfg) => 0;
// corrupt the destination
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0;
block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
- cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- off = LFS_BLOCK_SIZE-1;
- while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
+ cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ off = BLOCK_SIZE-1;
+ while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1;
}
- memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
- cfg.erase(&cfg, block) => 0;
- cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- cfg.sync(&cfg) => 0;
+ memset(&buffer[off-3], BLOCK_SIZE, 3);
+ cfg->erase(cfg, block) => 0;
+ cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ cfg->sync(cfg) => 0;
// continue move
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -335,13 +355,14 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # simple reentrant move file
+[cases.reentrant_move_file]
reentrant = true
code = '''
- err = lfs_mount(&lfs, &cfg);
+ lfs_t lfs;
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
}
err = lfs_mkdir(&lfs, "a");
assert(!err || err == LFS_ERR_EXIST);
@@ -354,9 +375,10 @@ code = '''
lfs_unmount(&lfs) => 0;
while (true) {
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// there should never exist _2_ hello files
int count = 0;
+ struct lfs_info info;
if (lfs_stat(&lfs, "a/hello", &info) == 0) {
assert(strcmp(info.name, "hello") == 0);
assert(info.type == LFS_TYPE_REG);
@@ -384,7 +406,7 @@ code = '''
assert(count <= 1);
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) {
lfs_rename(&lfs, "a/hello", "b/hello") => 0;
} else if (lfs_stat(&lfs, "b/hello", &info) == 0) {
@@ -397,6 +419,7 @@ code = '''
break;
} else {
// create file
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "a/hello",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "hola\n", 5) => 5;
@@ -407,7 +430,9 @@ code = '''
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_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -431,10 +456,12 @@ code = '''
lfs_dir_read(&lfs, &dir, &info) => 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, "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, "d/hello", LFS_O_RDONLY) => 0;
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 5) => 5;
memcmp(buffer, "hola\n", 5) => 0;
lfs_file_read(&lfs, &file, buffer, 8) => 8;
@@ -445,10 +472,11 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # move dir
+[cases.move_dir]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0;
@@ -459,11 +487,13 @@ code = '''
lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 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_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -510,11 +540,12 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # move dir corrupt source
+[cases.move_dir_corrupt_source]
in = "lfs.c"
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0;
@@ -525,28 +556,30 @@ code = '''
lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0;
// 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_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
- uint8_t bbuffer[LFS_BLOCK_SIZE];
- cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- int off = LFS_BLOCK_SIZE-1;
- while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
+ uint8_t buffer[BLOCK_SIZE];
+ cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ int off = BLOCK_SIZE-1;
+ while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1;
}
- memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
- cfg.erase(&cfg, block) => 0;
- cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- cfg.sync(&cfg) => 0;
+ memset(&buffer[off-3], BLOCK_SIZE, 3);
+ cfg->erase(cfg, block) => 0;
+ cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ cfg->sync(cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -593,12 +626,13 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # move dir corrupt source and dest
+[cases.move_dir_corrupt_source_dest]
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 = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0;
@@ -609,44 +643,46 @@ code = '''
lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0;
// 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_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
- uint8_t bbuffer[LFS_BLOCK_SIZE];
- cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- int off = LFS_BLOCK_SIZE-1;
- while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
+ uint8_t buffer[BLOCK_SIZE];
+ cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ int off = BLOCK_SIZE-1;
+ while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1;
}
- memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
- cfg.erase(&cfg, block) => 0;
- cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- cfg.sync(&cfg) => 0;
+ memset(&buffer[off-3], BLOCK_SIZE, 3);
+ cfg->erase(cfg, block) => 0;
+ cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ cfg->sync(cfg) => 0;
// corrupt the destination
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0;
block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
- cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- off = LFS_BLOCK_SIZE-1;
- while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
+ cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ off = BLOCK_SIZE-1;
+ while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1;
}
- memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
- cfg.erase(&cfg, block) => 0;
- cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- cfg.sync(&cfg) => 0;
+ memset(&buffer[off-3], BLOCK_SIZE, 3);
+ cfg->erase(cfg, block) => 0;
+ cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ cfg->sync(cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -693,12 +729,13 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # move dir after corrupt
+[cases.move_dir_after_corrupt]
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 = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 0;
@@ -709,49 +746,51 @@ code = '''
lfs_mkdir(&lfs, "a/hi/ohayo") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0;
// 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_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
- uint8_t bbuffer[LFS_BLOCK_SIZE];
- cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- int off = LFS_BLOCK_SIZE-1;
- while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
+ uint8_t buffer[BLOCK_SIZE];
+ cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ int off = BLOCK_SIZE-1;
+ while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1;
}
- memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
- cfg.erase(&cfg, block) => 0;
- cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- cfg.sync(&cfg) => 0;
+ memset(&buffer[off-3], BLOCK_SIZE, 3);
+ cfg->erase(cfg, block) => 0;
+ cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ cfg->sync(cfg) => 0;
// corrupt the destination
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "c") => 0;
block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
- cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- off = LFS_BLOCK_SIZE-1;
- while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
+ cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ off = BLOCK_SIZE-1;
+ while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1;
}
- memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
- cfg.erase(&cfg, block) => 0;
- cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- cfg.sync(&cfg) => 0;
+ memset(&buffer[off-3], BLOCK_SIZE, 3);
+ cfg->erase(cfg, block) => 0;
+ cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ cfg->sync(cfg) => 0;
// continue move
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hi", "c/hi") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_dir_open(&lfs, &dir, "a") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -798,13 +837,14 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # simple reentrant move dir
+[cases.reentrant_move_dir]
reentrant = true
code = '''
- err = lfs_mount(&lfs, &cfg);
+ lfs_t lfs;
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
}
err = lfs_mkdir(&lfs, "a");
assert(!err || err == LFS_ERR_EXIST);
@@ -817,9 +857,10 @@ code = '''
lfs_unmount(&lfs) => 0;
while (true) {
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// there should never exist _2_ hi directories
int count = 0;
+ struct lfs_info info;
if (lfs_stat(&lfs, "a/hi", &info) == 0) {
assert(strcmp(info.name, "hi") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -843,7 +884,7 @@ code = '''
assert(count <= 1);
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
if (lfs_stat(&lfs, "a/hi", &info) == 0) {
lfs_rename(&lfs, "a/hi", "b/hi") => 0;
} else if (lfs_stat(&lfs, "b/hi", &info) == 0) {
@@ -868,7 +909,9 @@ code = '''
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_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -915,14 +958,16 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # move state stealing
+[cases.move_state_stealing]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "a") => 0;
lfs_mkdir(&lfs, "b") => 0;
lfs_mkdir(&lfs, "c") => 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_write(&lfs, &file, "hola\n", 5) => 5;
lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8;
@@ -930,21 +975,22 @@ code = '''
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "a/hello", "b/hello") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "b/hello", "c/hello") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_rename(&lfs, "c/hello", "d/hello") => 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, "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, "d/hello", LFS_O_RDONLY) => 0;
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 5) => 5;
memcmp(buffer, "hola\n", 5) => 0;
lfs_file_read(&lfs, &file, buffer, 8) => 8;
@@ -954,12 +1000,13 @@ code = '''
lfs_file_close(&lfs, &file) => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_remove(&lfs, "b") => 0;
lfs_remove(&lfs, "c") => 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, "b", &info) => LFS_ERR_NOENT;
lfs_stat(&lfs, "c", &info) => LFS_ERR_NOENT;
@@ -979,12 +1026,16 @@ code = '''
'''
# Other specific corner cases
-[[case]] # create + delete in same commit with neighbors
+
+# create + delete in same commit with neighbors
+[cases.create_delete_same]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// 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_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0;
@@ -1024,6 +1075,8 @@ code = '''
lfs_file_close(&lfs, &files[2]) => 0;
// check that nothing was corrupted
+ lfs_dir_t dir;
+ struct lfs_info info;
lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -1051,6 +1104,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0;
lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0;
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 7) => 7;
assert(strcmp((char*)buffer, "test.4") == 0);
lfs_file_close(&lfs, &file) => 0;
@@ -1124,13 +1178,15 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-# Other specific corner cases
-[[case]] # create + delete + delete in same commit with neighbors
+# create + delete + delete in same commit with neighbors
+[cases.create_delete_delete_same]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// 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_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0;
@@ -1175,6 +1231,8 @@ code = '''
lfs_file_close(&lfs, &files[2]) => 0;
// check that nothing was corrupted
+ lfs_dir_t dir;
+ struct lfs_info info;
lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -1202,6 +1260,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 0;
lfs_file_open(&lfs, &file, "/0.before", LFS_O_RDONLY) => 0;
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 7) => 7;
assert(strcmp((char*)buffer, "test.4") == 0);
lfs_file_close(&lfs, &file) => 0;
@@ -1281,14 +1340,17 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # create + delete in different dirs with neighbors
+# create + delete in different dirs with neighbors
+[cases.create_delete_different]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// littlefs keeps files sorted, so we know the order these will be in
lfs_mkdir(&lfs, "/dir.1") => 0;
lfs_mkdir(&lfs, "/dir.2") => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "/dir.1/1.move_me",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0;
@@ -1340,6 +1402,8 @@ code = '''
lfs_file_close(&lfs, &files[3]) => 0;
// check that nothing was corrupted
+ lfs_dir_t dir;
+ struct lfs_info info;
lfs_dir_open(&lfs, &dir, "/") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -1397,6 +1461,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 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;
assert(strcmp((char*)buffer, "test.5") == 0);
lfs_file_close(&lfs, &file) => 0;
@@ -1518,17 +1583,20 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # move fix in relocation
+# move fix in relocation
+[cases.move_fix_relocation]
in = "lfs.c"
-define.RELOCATIONS = 'range(0x3+1)'
-define.LFS_ERASE_CYCLES = 0xffffffff
+defines.RELOCATIONS = [0x0, 0x1, 0x2, 0x3]
+defines.ERASE_CYCLES = 0xffffffff
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "/parent") => 0;
lfs_mkdir(&lfs, "/parent/child") => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "/parent/1.move_me",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "move me",
@@ -1568,15 +1636,17 @@ code = '''
// force specific directories to relocate
if (RELOCATIONS & 0x1) {
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/parent");
- 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[0], 0xffffffff) => 0;
+ lfs_testbd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0;
}
if (RELOCATIONS & 0x2) {
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/parent/child");
- 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[0], 0xffffffff) => 0;
+ lfs_testbd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0;
}
@@ -1593,6 +1663,8 @@ code = '''
lfs_file_close(&lfs, &files[3]) => 0;
// check that nothing was corrupted
+ lfs_dir_t dir;
+ struct lfs_info info;
lfs_dir_open(&lfs, &dir, "/parent") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -1637,6 +1709,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 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;
assert(strcmp((char*)buffer, "test.5") == 0);
lfs_file_close(&lfs, &file) => 0;
@@ -1655,18 +1728,21 @@ code = '''
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"
-define.RELOCATIONS = 'range(0x7+1)'
-define.LFS_ERASE_CYCLES = 0xffffffff
+defines.RELOCATIONS = [0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7]
+defines.ERASE_CYCLES = 0xffffffff
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "/parent") => 0;
lfs_mkdir(&lfs, "/parent/child") => 0;
lfs_mkdir(&lfs, "/parent/sibling") => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "/parent/sibling/1.move_me",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_write(&lfs, &file, "move me",
@@ -1706,21 +1782,24 @@ code = '''
// force specific directories to relocate
if (RELOCATIONS & 0x1) {
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/parent");
- 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[0], 0xffffffff) => 0;
+ lfs_testbd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0;
}
if (RELOCATIONS & 0x2) {
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/parent/sibling");
- 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[0], 0xffffffff) => 0;
+ lfs_testbd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0;
}
if (RELOCATIONS & 0x4) {
+ lfs_dir_t dir;
lfs_dir_open(&lfs, &dir, "/parent/child");
- 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[0], 0xffffffff) => 0;
+ lfs_testbd_setwear(cfg, dir.m.pair[1], 0xffffffff) => 0;
lfs_dir_close(&lfs, &dir) => 0;
}
@@ -1739,6 +1818,8 @@ code = '''
lfs_file_close(&lfs, &files[3]) => 0;
// check that nothing was corrupted
+ lfs_dir_t dir;
+ struct lfs_info info;
lfs_dir_open(&lfs, &dir, "/parent") => 0;
lfs_dir_read(&lfs, &dir, &info) => 1;
assert(strcmp(info.name, ".") == 0);
@@ -1796,6 +1877,7 @@ code = '''
lfs_dir_close(&lfs, &dir) => 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;
assert(strcmp((char*)buffer, "test.5") == 0);
lfs_file_close(&lfs, &file) => 0;
diff --git a/tests/test_orphans.toml b/tests/test_orphans.toml
index 241e273..fd9b521 100644
--- a/tests/test_orphans.toml
+++ b/tests/test_orphans.toml
@@ -1,9 +1,10 @@
-[[case]] # orphan test
+[cases.orphan]
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 = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "parent") => 0;
lfs_mkdir(&lfs, "parent/orphan") => 0;
lfs_mkdir(&lfs, "parent/child") => 0;
@@ -13,29 +14,31 @@ code = '''
// corrupt the child's most recent commit, this should be the update
// to the linked-list entry, which should orphan the orphan. Note this
// 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_block_t block = dir.m.pair[0];
lfs_dir_close(&lfs, &dir) => 0;
lfs_unmount(&lfs) => 0;
- uint8_t bbuffer[LFS_BLOCK_SIZE];
- cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- int off = LFS_BLOCK_SIZE-1;
- while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
+ uint8_t buffer[BLOCK_SIZE];
+ cfg->read(cfg, block, 0, buffer, BLOCK_SIZE) => 0;
+ int off = BLOCK_SIZE-1;
+ while (off >= 0 && buffer[off] == ERASE_VALUE) {
off -= 1;
}
- memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
- cfg.erase(&cfg, block) => 0;
- cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
- cfg.sync(&cfg) => 0;
+ memset(&buffer[off-3], BLOCK_SIZE, 3);
+ cfg->erase(cfg, block) => 0;
+ cfg->prog(cfg, block, 0, buffer, BLOCK_SIZE) => 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/child", &info) => 0;
lfs_fs_size(&lfs) => 8;
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/child", &info) => 0;
lfs_fs_size(&lfs) => 8;
@@ -48,7 +51,7 @@ code = '''
lfs_fs_size(&lfs) => 8;
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/child", &info) => 0;
lfs_stat(&lfs, "parent/otherchild", &info) => 0;
@@ -56,43 +59,48 @@ code = '''
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
# TODO fix this case, caused by non-DAG trees
-if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)'
-define = [
+if = '!(DEPTH == 3 && CACHE_SIZE != 64)'
+defines = [
{FILES=6, DEPTH=1, CYCLES=20},
{FILES=26, DEPTH=1, CYCLES=20},
{FILES=3, DEPTH=3, CYCLES=20},
]
code = '''
- err = lfs_mount(&lfs, &cfg);
+ lfs_t lfs;
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
}
srand(1);
const char alpha[] = "abcdefghijklmnopqrstuvwxyz";
- for (int i = 0; i < CYCLES; i++) {
+ for (unsigned i = 0; i < CYCLES; i++) {
// create random path
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]);
}
// if it does not exist, we create it, else we destroy
+ struct lfs_info info;
int res = lfs_stat(&lfs, full_path, &info);
if (res == LFS_ERR_NOENT) {
// 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);
path[2*d+2] = '\0';
err = lfs_mkdir(&lfs, path);
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);
path[2*d+2] = '\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
for (int d = DEPTH-1; d >= 0; d--) {
+ char path[1024];
strcpy(path, full_path);
path[2*d+2] = '\0';
err = lfs_remove(&lfs, path);
diff --git a/tests/test_paths.toml b/tests/test_paths.toml
index a7474c0..310364d 100644
--- a/tests/test_paths.toml
+++ b/tests/test_paths.toml
@@ -1,13 +1,16 @@
-[[case]] # simple path test
+# simple path test
+[cases.path]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0;
+ struct lfs_info info;
lfs_stat(&lfs, "tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "/tea/hottea", &info) => 0;
@@ -21,15 +24,18 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # redundant slashes
+# redundant slashes
+[cases.redundant_slashes]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0;
+ struct lfs_info info;
lfs_stat(&lfs, "/tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "//tea//hottea", &info) => 0;
@@ -45,15 +51,18 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # dot path test
+# dot path test
+[cases.dot_path]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0;
+ struct lfs_info info;
lfs_stat(&lfs, "./tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "/./tea/hottea", &info) => 0;
@@ -71,10 +80,12 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # dot dot path test
+# dot dot path test
+[cases.dot_dot_path]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0;
@@ -84,6 +95,7 @@ code = '''
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0;
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0;
+ struct lfs_info info;
lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0;
assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0;
@@ -101,15 +113,18 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # trailing dot path test
+# trailing dot path test
+[cases.trailing_dot_path]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0;
lfs_mkdir(&lfs, "tea/coldtea") => 0;
+ struct lfs_info info;
lfs_stat(&lfs, "tea/hottea/", &info) => 0;
assert(strcmp(info.name, "hottea") == 0);
lfs_stat(&lfs, "tea/hottea/.", &info) => 0;
@@ -123,11 +138,14 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # leading dot path test
+# leading dot path test
+[cases.leading_dot_path]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, ".milk") => 0;
+ struct lfs_info info;
lfs_stat(&lfs, ".milk", &info) => 0;
strcmp(info.name, ".milk") => 0;
lfs_stat(&lfs, "tea/.././.milk", &info) => 0;
@@ -135,10 +153,12 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # root dot dot path test
+# root dot dot path test
+[cases.root_dot_dot_path]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "tea") => 0;
lfs_mkdir(&lfs, "tea/hottea") => 0;
lfs_mkdir(&lfs, "tea/warmtea") => 0;
@@ -148,6 +168,7 @@ code = '''
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0;
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0;
+ struct lfs_info info;
lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0;
strcmp(info.name, "hottea") => 0;
@@ -159,10 +180,13 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # invalid path tests
+# invalid path tests
+[cases.invalid_path]
code = '''
- lfs_format(&lfs, &cfg);
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ 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/ground", &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_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_ERR_NOENT;
lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT;
@@ -180,15 +205,19 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # root operations
+# root operations
+[cases.root]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ struct lfs_info info;
lfs_stat(&lfs, "/", &info) => 0;
assert(strcmp(info.name, "/") == 0);
assert(info.type == LFS_TYPE_DIR);
lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY | LFS_O_CREAT)
=> LFS_ERR_ISDIR;
@@ -196,10 +225,13 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # root representations
+# root representations
+[cases.root_reprs]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ struct lfs_info info;
lfs_stat(&lfs, "/", &info) => 0;
assert(strcmp(info.name, "/") == 0);
assert(info.type == LFS_TYPE_DIR);
@@ -221,10 +253,13 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # superblock conflict test
+# superblock conflict test
+[cases.superblock_conflict]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ struct lfs_info info;
lfs_stat(&lfs, "littlefs", &info) => LFS_ERR_NOENT;
lfs_remove(&lfs, "littlefs") => LFS_ERR_NOENT;
@@ -237,18 +272,22 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # max path test
+# max path test
+[cases.max_path]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "coffee") => 0;
lfs_mkdir(&lfs, "coffee/hotcoffee") => 0;
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0;
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0;
+ char path[1024];
memset(path, 'w', LFS_NAME_MAX+1);
path[LFS_NAME_MAX+1] = '\0';
lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT)
=> LFS_ERR_NAMETOOLONG;
@@ -261,19 +300,23 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # really big path test
+# really big path test
+[cases.really_big_path]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_mkdir(&lfs, "coffee") => 0;
lfs_mkdir(&lfs, "coffee/hotcoffee") => 0;
lfs_mkdir(&lfs, "coffee/warmcoffee") => 0;
lfs_mkdir(&lfs, "coffee/coldcoffee") => 0;
+ char path[1024];
memset(path, 'w', LFS_NAME_MAX);
path[LFS_NAME_MAX] = '\0';
lfs_mkdir(&lfs, path) => 0;
lfs_remove(&lfs, path) => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT) => 0;
lfs_file_close(&lfs, &file) => 0;
diff --git a/tests/test_relocations.toml b/tests/test_relocations.toml
index 71b1047..f177c73 100644
--- a/tests/test_relocations.toml
+++ b/tests/test_relocations.toml
@@ -1,15 +1,18 @@
# specific corner cases worth explicitly testing for
-[[case]] # dangling split dir test
-define.ITERATIONS = 20
-define.COUNT = 10
-define.LFS_BLOCK_CYCLES = [8, 1]
+[cases.dangling_split_dir]
+defines.ITERATIONS = 20
+defines.COUNT = 10
+defines.BLOCK_CYCLES = [8, 1]
code = '''
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
// 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;
+ uint8_t buffer[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_close(&lfs, &file) => 0;
@@ -17,18 +20,22 @@ code = '''
lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
- for (int j = 0; j < ITERATIONS; j++) {
- for (int i = 0; i < COUNT; i++) {
+ lfs_mount(&lfs, cfg) => 0;
+ for (unsigned j = 0; j < ITERATIONS; j++) {
+ for (unsigned i = 0; i < COUNT; i++) {
+ char path[1024];
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_close(&lfs, &file) => 0;
}
+ lfs_dir_t dir;
+ struct lfs_info info;
lfs_dir_open(&lfs, &dir, "child") => 0;
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);
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0;
@@ -36,46 +43,54 @@ code = '''
lfs_dir_read(&lfs, &dir, &info) => 0;
lfs_dir_close(&lfs, &dir) => 0;
- if (j == ITERATIONS-1) {
+ if (j == (unsigned)ITERATIONS-1) {
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);
lfs_remove(&lfs, path) => 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_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);
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0;
}
lfs_dir_read(&lfs, &dir, &info) => 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);
lfs_remove(&lfs, path) => 0;
}
lfs_unmount(&lfs) => 0;
'''
-[[case]] # outdated head test
-define.ITERATIONS = 20
-define.COUNT = 10
-define.LFS_BLOCK_CYCLES = [8, 1]
+[cases.outdated_head]
+defines.ITERATIONS = 20
+defines.COUNT = 10
+defines.BLOCK_CYCLES = [8, 1]
code = '''
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
// 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;
+ uint8_t buffer[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_close(&lfs, &file) => 0;
@@ -83,18 +98,22 @@ code = '''
lfs_mkdir(&lfs, "child") => 0;
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
- for (int j = 0; j < ITERATIONS; j++) {
- for (int i = 0; i < COUNT; i++) {
+ lfs_mount(&lfs, cfg) => 0;
+ for (unsigned j = 0; j < ITERATIONS; j++) {
+ for (unsigned i = 0; i < COUNT; i++) {
+ char path[1024];
sprintf(path, "child/test%03d_loooooooooooooooooong_name", i);
lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0;
lfs_file_close(&lfs, &file) => 0;
}
+ lfs_dir_t dir;
+ struct lfs_info info;
lfs_dir_open(&lfs, &dir, "child") => 0;
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);
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0;
@@ -110,7 +129,8 @@ code = '''
lfs_dir_rewind(&lfs, &dir) => 0;
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);
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0;
@@ -126,7 +146,8 @@ code = '''
lfs_dir_rewind(&lfs, &dir) => 0;
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);
lfs_dir_read(&lfs, &dir, &info) => 1;
strcmp(info.name, path) => 0;
@@ -135,7 +156,8 @@ code = '''
lfs_dir_read(&lfs, &dir, &info) => 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);
lfs_remove(&lfs, path) => 0;
}
@@ -143,45 +165,50 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # reentrant testing for relocations, this is the same as the
- # orphan testing, except here we also set block_cycles so that
- # almost every tree operation needs a relocation
+# reentrant testing for relocations, this is the same as the
+# orphan testing, except here we also set block_cycles so that
+# almost every tree operation needs a relocation
+[cases.reentrant_relocations]
reentrant = true
# TODO fix this case, caused by non-DAG trees
-if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)'
-define = [
- {FILES=6, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1},
- {FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1},
- {FILES=3, DEPTH=3, CYCLES=20, LFS_BLOCK_CYCLES=1},
+if = '!(DEPTH == 3 && CACHE_SIZE != 64)'
+defines = [
+ {FILES=6, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1},
+ {FILES=26, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1},
+ {FILES=3, DEPTH=3, CYCLES=20, BLOCK_CYCLES=1},
]
code = '''
- err = lfs_mount(&lfs, &cfg);
+ lfs_t lfs;
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
}
srand(1);
const char alpha[] = "abcdefghijklmnopqrstuvwxyz";
- for (int i = 0; i < CYCLES; i++) {
+ for (unsigned i = 0; i < CYCLES; i++) {
// create random path
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]);
}
// if it does not exist, we create it, else we destroy
+ struct lfs_info info;
int res = lfs_stat(&lfs, full_path, &info);
if (res == LFS_ERR_NOENT) {
// 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);
path[2*d+2] = '\0';
err = lfs_mkdir(&lfs, path);
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);
path[2*d+2] = '\0';
lfs_stat(&lfs, path, &info) => 0;
@@ -194,7 +221,8 @@ code = '''
assert(info.type == LFS_TYPE_DIR);
// 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);
path[2*d+2] = '\0';
err = lfs_remove(&lfs, path);
@@ -207,44 +235,49 @@ code = '''
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
# TODO fix this case, caused by non-DAG trees
-if = '!(DEPTH == 3 && LFS_CACHE_SIZE != 64)'
-define = [
- {FILES=6, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1},
- {FILES=26, DEPTH=1, CYCLES=20, LFS_BLOCK_CYCLES=1},
- {FILES=3, DEPTH=3, CYCLES=20, LFS_BLOCK_CYCLES=1},
+if = '!(DEPTH == 3 && CACHE_SIZE != 64)'
+defines = [
+ {FILES=6, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1},
+ {FILES=26, DEPTH=1, CYCLES=20, BLOCK_CYCLES=1},
+ {FILES=3, DEPTH=3, CYCLES=20, BLOCK_CYCLES=1},
]
code = '''
- err = lfs_mount(&lfs, &cfg);
+ lfs_t lfs;
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
}
srand(1);
const char alpha[] = "abcdefghijklmnopqrstuvwxyz";
- for (int i = 0; i < CYCLES; i++) {
+ for (unsigned i = 0; i < CYCLES; i++) {
// create random path
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]);
}
// if it does not exist, we create it, else we destroy
+ struct lfs_info info;
int res = lfs_stat(&lfs, full_path, &info);
assert(!res || res == LFS_ERR_NOENT);
if (res == LFS_ERR_NOENT) {
// 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);
path[2*d+2] = '\0';
err = lfs_mkdir(&lfs, path);
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);
path[2*d+2] = '\0';
lfs_stat(&lfs, path, &info) => 0;
@@ -257,7 +290,7 @@ code = '''
// create new random path
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]);
}
@@ -266,7 +299,8 @@ code = '''
assert(!res || res == LFS_ERR_NOENT);
if (res == LFS_ERR_NOENT) {
// 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]);
path[2*d+2] = '\0';
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);
path[2*d+2] = '\0';
lfs_stat(&lfs, path, &info) => 0;
@@ -290,7 +325,8 @@ code = '''
} else {
// 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);
path[2*d+2] = '\0';
err = lfs_remove(&lfs, path);
diff --git a/tests/test_seek.toml b/tests/test_seek.toml
index 79d7728..383c1ba 100644
--- a/tests/test_seek.toml
+++ b/tests/test_seek.toml
@@ -1,6 +1,7 @@
-[[case]] # simple file seek
-define = [
+# simple file seek
+[cases.seek]
+defines = [
{COUNT=132, SKIP=4},
{COUNT=132, SKIP=128},
{COUNT=200, SKIP=10},
@@ -9,11 +10,14 @@ define = [
{COUNT=4, SKIP=2},
]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "kitty",
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);
for (int j = 0; j < COUNT; j++) {
lfs_file_write(&lfs, &file, buffer, size);
@@ -21,7 +25,7 @@ code = '''
lfs_file_close(&lfs, &file) => 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_soff_t pos = -1;
@@ -68,8 +72,9 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # simple file seek and write
-define = [
+# simple file seek and write
+[cases.seek_write]
+defines = [
{COUNT=132, SKIP=4},
{COUNT=132, SKIP=128},
{COUNT=200, SKIP=10},
@@ -78,11 +83,14 @@ define = [
{COUNT=4, SKIP=2},
]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "kitty",
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);
for (int j = 0; j < COUNT; j++) {
lfs_file_write(&lfs, &file, buffer, size);
@@ -90,7 +98,7 @@ code = '''
lfs_file_close(&lfs, &file) => 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_soff_t pos = -1;
@@ -129,15 +137,18 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # boundary seek and writes
-define.COUNT = 132
-define.OFFSETS = '"{512, 1020, 513, 1021, 511, 1019, 1441}"'
+# boundary seek and writes
+[cases.boundary_seek_write]
+defines.COUNT = 132
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "kitty",
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);
for (int j = 0; j < COUNT; j++) {
lfs_file_write(&lfs, &file, buffer, size);
@@ -145,11 +156,11 @@ code = '''
lfs_file_close(&lfs, &file) => 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;
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++) {
lfs_soff_t off = offsets[i];
@@ -183,8 +194,9 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # out of bounds seek
-define = [
+# out of bounds seek
+[cases.out_of_bounds_seek]
+defines = [
{COUNT=132, SKIP=4},
{COUNT=132, SKIP=128},
{COUNT=200, SKIP=10},
@@ -193,18 +205,21 @@ define = [
{COUNT=4, SKIP=3},
]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "kitty",
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);
for (int j = 0; j < COUNT; j++) {
lfs_file_write(&lfs, &file, buffer, size);
}
lfs_file_close(&lfs, &file) => 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;
size = strlen("kittycatcat");
@@ -238,16 +253,20 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # inline write and seek
-define.SIZE = [2, 4, 128, 132]
+# inline write and seek
+[cases.inline_write_seek]
+defines.SIZE = [2, 4, 128, 132]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "tinykitty",
LFS_O_RDWR | LFS_O_CREAT) => 0;
int j = 0;
int k = 0;
+ uint8_t buffer[1024];
memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26);
for (unsigned i = 0; i < SIZE; i++) {
lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1;
@@ -305,16 +324,20 @@ code = '''
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
-define.COUNT = [4, 64, 128]
+defines.COUNT = [4, 64, 128]
reentrant = true
code = '''
- err = lfs_mount(&lfs, &cfg);
+ lfs_t lfs;
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&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);
assert(!err || err == LFS_ERR_NOENT);
if (!err) {
@@ -334,14 +357,14 @@ code = '''
if (lfs_file_size(&lfs, &file) == 0) {
for (int j = 0; j < COUNT; j++) {
strcpy((char*)buffer, "kittycatcat");
- size = strlen((char*)buffer);
+ size_t size = strlen((char*)buffer);
lfs_file_write(&lfs, &file, buffer, size) => size;
}
}
lfs_file_close(&lfs, &file) => 0;
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_size(&lfs, &file) => COUNT*size;
diff --git a/tests/test_superblocks.toml b/tests/test_superblocks.toml
index 407c845..d511675 100644
--- a/tests/test_superblocks.toml
+++ b/tests/test_superblocks.toml
@@ -1,41 +1,53 @@
-[[case]] # simple formatting test
+# simple formatting test
+[cases.format]
code = '''
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
'''
-[[case]] # mount/unmount
+# mount/unmount
+[cases.mount]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
lfs_unmount(&lfs) => 0;
'''
-[[case]] # reentrant format
+# reentrant format
+[cases.reentrant_format]
reentrant = true
code = '''
- err = lfs_mount(&lfs, &cfg);
+ lfs_t lfs;
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
}
lfs_unmount(&lfs) => 0;
'''
-[[case]] # invalid mount
+# invalid mount
+[cases.invalid_mount]
code = '''
- lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT;
+ lfs_t lfs;
+ lfs_mount(&lfs, cfg) => LFS_ERR_CORRUPT;
'''
-[[case]] # expanding superblock
-define.LFS_BLOCK_CYCLES = [32, 33, 1]
-define.N = [10, 100, 1000]
+# expanding superblock
+[cases.expanding_superblock]
+defines.LFS_BLOCK_CYCLES = [32, 33, 1]
+defines.N = [10, 100, 1000]
code = '''
- 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 = 0; i < N; i++) {
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "dummy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
+ struct lfs_info info;
lfs_stat(&lfs, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG);
@@ -44,25 +56,30 @@ code = '''
lfs_unmount(&lfs) => 0;
// 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_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
+ struct lfs_info info;
lfs_stat(&lfs, "dummy", &info) => 0;
assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG);
lfs_unmount(&lfs) => 0;
'''
-[[case]] # expanding superblock with power cycle
-define.LFS_BLOCK_CYCLES = [32, 33, 1]
-define.N = [10, 100, 1000]
+# expanding superblock with power cycle
+[cases.expanding_superblock_power_cycle]
+defines.LFS_BLOCK_CYCLES = [32, 33, 1]
+defines.N = [10, 100, 1000]
code = '''
- lfs_format(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
for (int i = 0; i < N; i++) {
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
// 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));
if (!err) {
assert(strcmp(info.name, "dummy") == 0);
@@ -70,6 +87,7 @@ code = '''
lfs_remove(&lfs, "dummy") => 0;
}
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "dummy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
@@ -80,26 +98,30 @@ code = '''
}
// 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;
assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG);
lfs_unmount(&lfs) => 0;
'''
-[[case]] # reentrant expanding superblock
-define.LFS_BLOCK_CYCLES = [2, 1]
-define.N = 24
+# reentrant expanding superblock
+[cases.reentrant_expanding_superblock]
+defines.LFS_BLOCK_CYCLES = [2, 1]
+defines.N = 24
reentrant = true
code = '''
- err = lfs_mount(&lfs, &cfg);
+ lfs_t lfs;
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
}
for (int i = 0; i < N; i++) {
// remove lingering dummy?
+ struct lfs_info info;
err = lfs_stat(&lfs, "dummy", &info);
assert(err == 0 || (err == LFS_ERR_NOENT && i == 0));
if (!err) {
@@ -108,6 +130,7 @@ code = '''
lfs_remove(&lfs, "dummy") => 0;
}
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "dummy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0;
lfs_file_close(&lfs, &file) => 0;
@@ -119,7 +142,8 @@ code = '''
lfs_unmount(&lfs) => 0;
// 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;
assert(strcmp(info.name, "dummy") == 0);
assert(info.type == LFS_TYPE_REG);
diff --git a/tests/test_truncate.toml b/tests/test_truncate.toml
index 850d7aa..fc83ce3 100644
--- a/tests/test_truncate.toml
+++ b/tests/test_truncate.toml
@@ -1,14 +1,18 @@
-[[case]] # simple truncate
-define.MEDIUMSIZE = [32, 2048]
-define.LARGESIZE = 8192
+# simple truncate
+[cases.truncate]
+defines.MEDIUMSIZE = [32, 2048]
+defines.LARGESIZE = 8192
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "baldynoop",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
+ uint8_t buffer[1024];
strcpy((char*)buffer, "hair");
- size = strlen((char*)buffer);
+ size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -17,7 +21,7 @@ code = '''
lfs_file_close(&lfs, &file) => 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_size(&lfs, &file) => LARGESIZE;
@@ -27,7 +31,7 @@ code = '''
lfs_file_close(&lfs, &file) => 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_size(&lfs, &file) => MEDIUMSIZE;
@@ -42,17 +46,21 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # truncate and read
-define.MEDIUMSIZE = [32, 2048]
-define.LARGESIZE = 8192
+# truncate and read
+[cases.truncate_read]
+defines.MEDIUMSIZE = [32, 2048]
+defines.LARGESIZE = 8192
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "baldyread",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
+ uint8_t buffer[1024];
strcpy((char*)buffer, "hair");
- size = strlen((char*)buffer);
+ size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -61,7 +69,7 @@ code = '''
lfs_file_close(&lfs, &file) => 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_size(&lfs, &file) => LARGESIZE;
@@ -78,7 +86,7 @@ code = '''
lfs_file_close(&lfs, &file) => 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_size(&lfs, &file) => MEDIUMSIZE;
@@ -93,14 +101,18 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # write, truncate, and read
+# write, truncate, and read
+[cases.write_truncate_read]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "sequence",
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;
uint8_t *wb = buffer;
uint8_t *rb = buffer + size;
@@ -145,17 +157,21 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # truncate and write
-define.MEDIUMSIZE = [32, 2048]
-define.LARGESIZE = 8192
+# truncate and write
+[cases.truncate_write]
+defines.MEDIUMSIZE = [32, 2048]
+defines.LARGESIZE = 8192
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "baldywrite",
LFS_O_WRONLY | LFS_O_CREAT) => 0;
+ uint8_t buffer[1024];
strcpy((char*)buffer, "hair");
- size = strlen((char*)buffer);
+ size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -164,7 +180,7 @@ code = '''
lfs_file_close(&lfs, &file) => 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_size(&lfs, &file) => LARGESIZE;
@@ -181,7 +197,7 @@ code = '''
lfs_file_close(&lfs, &file) => 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_size(&lfs, &file) => MEDIUMSIZE;
@@ -196,26 +212,30 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # truncate write under powerloss
-define.SMALLSIZE = [4, 512]
-define.MEDIUMSIZE = [32, 1024]
-define.LARGESIZE = 2048
+# truncate write under powerloss
+[cases.reentrant_truncate_write]
+defines.SMALLSIZE = [4, 512]
+defines.MEDIUMSIZE = [32, 1024]
+defines.LARGESIZE = 2048
reentrant = true
code = '''
- err = lfs_mount(&lfs, &cfg);
+ lfs_t lfs;
+ int err = lfs_mount(&lfs, cfg);
if (err) {
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
}
+ lfs_file_t file;
err = lfs_file_open(&lfs, &file, "baldy", LFS_O_RDONLY);
assert(!err || err == LFS_ERR_NOENT);
if (!err) {
- size = lfs_file_size(&lfs, &file);
+ size_t size = lfs_file_size(&lfs, &file);
assert(size == 0 ||
- size == LARGESIZE ||
- size == MEDIUMSIZE ||
- size == SMALLSIZE);
+ size == (size_t)LARGESIZE ||
+ size == (size_t)MEDIUMSIZE ||
+ size == (size_t)SMALLSIZE);
for (lfs_off_t j = 0; j < size; j += 4) {
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, 4) => 4;
assert(memcmp(buffer, "hair", 4) == 0 ||
memcmp(buffer, "bald", 4) == 0 ||
@@ -227,8 +247,9 @@ code = '''
lfs_file_open(&lfs, &file, "baldy",
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
lfs_file_size(&lfs, &file) => 0;
+ uint8_t buffer[1024];
strcpy((char*)buffer, "hair");
- size = strlen((char*)buffer);
+ size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < LARGESIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -262,12 +283,14 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # more aggressive general truncation tests
-define.CONFIG = 'range(6)'
-define.SMALLSIZE = 32
-define.MEDIUMSIZE = 2048
-define.LARGESIZE = 8192
+# more aggressive general truncation tests
+[cases.aggressive_truncate]
+defines.CONFIG = [0,1,2,3,4,5]
+defines.SMALLSIZE = 32
+defines.MEDIUMSIZE = 2048
+defines.LARGESIZE = 8192
code = '''
+ lfs_t lfs;
#define COUNT 5
const struct {
lfs_off_t startsizes[COUNT];
@@ -312,16 +335,19 @@ code = '''
const lfs_off_t *hotsizes = configs[CONFIG].hotsizes;
const lfs_off_t *coldsizes = configs[CONFIG].coldsizes;
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (unsigned i = 0; i < COUNT; i++) {
+ char path[1024];
sprintf(path, "hairyhead%d", i);
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path,
LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
+ uint8_t buffer[1024];
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) {
lfs_file_write(&lfs, &file, buffer, size) => size;
}
@@ -340,21 +366,25 @@ code = '''
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (unsigned i = 0; i < COUNT; i++) {
+ char path[1024];
sprintf(path, "hairyhead%d", i);
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDWR) => 0;
lfs_file_size(&lfs, &file) => hotsizes[i];
- size = strlen("hair");
+ size_t size = strlen("hair");
lfs_off_t j = 0;
for (; j < startsizes[i] && j < hotsizes[i]; j += size) {
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0;
}
for (; j < hotsizes[i]; j += size) {
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "\0\0\0\0", size) => 0;
}
@@ -367,22 +397,26 @@ code = '''
lfs_unmount(&lfs) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
for (unsigned i = 0; i < COUNT; i++) {
+ char path[1024];
sprintf(path, "hairyhead%d", i);
+ lfs_file_t file;
lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
lfs_file_size(&lfs, &file) => coldsizes[i];
- size = strlen("hair");
+ size_t size = strlen("hair");
lfs_off_t j = 0;
for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i];
j += size) {
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "hair", size) => 0;
}
for (; j < coldsizes[i]; j += size) {
+ uint8_t buffer[1024];
lfs_file_read(&lfs, &file, buffer, size) => size;
memcmp(buffer, "\0\0\0\0", size) => 0;
}
@@ -393,16 +427,20 @@ code = '''
lfs_unmount(&lfs) => 0;
'''
-[[case]] # noop truncate
-define.MEDIUMSIZE = [32, 2048]
+# noop truncate
+[cases.nop_truncate]
+defines.MEDIUMSIZE = [32, 2048]
code = '''
- lfs_format(&lfs, &cfg) => 0;
- lfs_mount(&lfs, &cfg) => 0;
+ lfs_t lfs;
+ lfs_format(&lfs, cfg) => 0;
+ lfs_mount(&lfs, cfg) => 0;
+ lfs_file_t file;
lfs_file_open(&lfs, &file, "baldynoop",
LFS_O_RDWR | LFS_O_CREAT) => 0;
+ uint8_t buffer[1024];
strcpy((char*)buffer, "hair");
- size = strlen((char*)buffer);
+ size_t size = strlen((char*)buffer);
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {
lfs_file_write(&lfs, &file, buffer, size) => size;
@@ -426,7 +464,7 @@ code = '''
lfs_unmount(&lfs) => 0;
// 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_size(&lfs, &file) => MEDIUMSIZE;
for (lfs_off_t j = 0; j < MEDIUMSIZE; j += size) {