Skip to content

Commit 2e1df68

Browse files
committed
Generated v2 prefixes
2 parents e35c270 + 8ed63b2 commit 2e1df68

7 files changed

Lines changed: 173 additions & 35 deletions

File tree

.github/workflows/test.yml

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,29 @@ jobs:
374374
run: |
375375
CFLAGS="$CFLAGS -DLFS2_NO_INTRINSICS" make test
376376
377+
# run with all trace options enabled to at least make sure these
378+
# all compile
379+
test-yes-trace:
380+
runs-on: ubuntu-latest
381+
steps:
382+
- uses: actions/checkout@v4
383+
- name: install
384+
run: |
385+
# need a few things
386+
sudo apt-get update -qq
387+
sudo apt-get install -qq gcc python3 python3-pip
388+
pip3 install toml
389+
gcc --version
390+
python3 --version
391+
- name: test-yes-trace
392+
run: |
393+
CFLAGS="$CFLAGS \
394+
-DLFS2_YES_TRACE \
395+
-DLFS2_RAMBD_YES_TRACE \
396+
-DLFS2_FILEBD_YES_TRACE \
397+
-DLFS2_RAMBD_YES_TRACE" \
398+
make test
399+
377400
# run LFS2_MULTIVERSION tests
378401
test-multiversion:
379402
runs-on: ubuntu-latest

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,47 @@ The tests assume a Linux environment and can be started with make:
199199
make test
200200
```
201201

202+
Tests are implemented in C in the .toml files found in the `tests` directory.
203+
When developing a feature or fixing a bug, it is frequently useful to run a
204+
single test case or suite of tests:
205+
206+
``` bash
207+
./scripts/test.py -l runners/test_runner # list available test suites
208+
./scripts/test.py -L runners/test_runner test_dirs # list available test cases
209+
./scripts/test.py runners/test_runner test_dirs # run a specific test suite
210+
```
211+
212+
If an assert fails in a test, test.py will try to print information about the
213+
failure:
214+
215+
``` bash
216+
tests/test_dirs.toml:1:failure: test_dirs_root:1g12gg2 (PROG_SIZE=16, ERASE_SIZE=512) failed
217+
tests/test_dirs.toml:5:assert: assert failed with 0, expected eq 42
218+
lfs2_mount(&lfs2, cfg) => 42;
219+
```
220+
221+
This includes the test id, which can be passed to test.py to run only that
222+
specific test permutation:
223+
224+
``` bash
225+
./scripts/test.py runners/test_runner test_dirs_root:1g12gg2 # run a specific test permutation
226+
./scripts/test.py runners/test_runner test_dirs_root:1g12gg2 --gdb # drop into gdb on failure
227+
```
228+
229+
Some other flags that may be useful:
230+
231+
```bash
232+
./scripts/test.py runners/test_runner -b -j # run tests in parallel
233+
./scripts/test.py runners/test_runner -v -O- # redirect stdout to stdout
234+
./scripts/test.py runners/test_runner -ddisk # capture resulting disk image
235+
```
236+
237+
See `-h/--help` for a full list of available flags:
238+
239+
``` bash
240+
./scripts/test.py --help
241+
```
242+
202243
## License
203244

204245
The littlefs is provided under the [BSD-3-Clause] license. See

bd/lfs2_filebd.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ int lfs2_filebd_prog(const struct lfs2_config *cfg, lfs2_block_t block,
133133

134134
int lfs2_filebd_erase(const struct lfs2_config *cfg, lfs2_block_t block) {
135135
LFS2_FILEBD_TRACE("lfs2_filebd_erase(%p, 0x%"PRIx32" (%"PRIu32"))",
136-
(void*)cfg, block, ((lfs2_file_t*)cfg->context)->cfg->erase_size);
136+
(void*)cfg, block, ((lfs2_filebd_t*)cfg->context)->cfg->erase_size);
137137
lfs2_filebd_t *bd = cfg->context;
138138

139139
// check if erase is valid

lfs2.c

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -404,18 +404,15 @@ struct lfs2_diskoff {
404404

405405
// operations on global state
406406
static inline void lfs2_gstate_xor(lfs2_gstate_t *a, const lfs2_gstate_t *b) {
407-
for (int i = 0; i < 3; i++) {
408-
((uint32_t*)a)[i] ^= ((const uint32_t*)b)[i];
409-
}
407+
a->tag ^= b->tag;
408+
a->pair[0] ^= b->pair[0];
409+
a->pair[1] ^= b->pair[1];
410410
}
411411

412412
static inline bool lfs2_gstate_iszero(const lfs2_gstate_t *a) {
413-
for (int i = 0; i < 3; i++) {
414-
if (((uint32_t*)a)[i] != 0) {
415-
return false;
416-
}
417-
}
418-
return true;
413+
return a->tag == 0
414+
&& a->pair[0] == 0
415+
&& a->pair[1] == 0;
419416
}
420417

421418
#ifndef LFS2_READONLY
@@ -2369,7 +2366,8 @@ fixmlist:;
23692366
if (d->m.pair != pair) {
23702367
for (int i = 0; i < attrcount; i++) {
23712368
if (lfs2_tag_type3(attrs[i].tag) == LFS2_TYPE_DELETE &&
2372-
d->id == lfs2_tag_id(attrs[i].tag)) {
2369+
d->id == lfs2_tag_id(attrs[i].tag) &&
2370+
d->type != LFS2_TYPE_DIR) {
23732371
d->m.pair[0] = LFS2_BLOCK_NULL;
23742372
d->m.pair[1] = LFS2_BLOCK_NULL;
23752373
} else if (lfs2_tag_type3(attrs[i].tag) == LFS2_TYPE_DELETE &&
@@ -2558,7 +2556,7 @@ static int lfs2_dir_orphaningcommit(lfs2_t *lfs2, lfs2_mdir_t *dir,
25582556
if (err != LFS2_ERR_NOENT) {
25592557
if (lfs2_gstate_hasorphans(&lfs2->gstate)) {
25602558
// next step, clean up orphans
2561-
err = lfs2_fs_preporphans(lfs2, -hasparent);
2559+
err = lfs2_fs_preporphans(lfs2, -(int8_t)hasparent);
25622560
if (err) {
25632561
return err;
25642562
}
@@ -6288,7 +6286,7 @@ lfs2_soff_t lfs2_file_size(lfs2_t *lfs2, lfs2_file_t *file) {
62886286

62896287
lfs2_soff_t res = lfs2_file_size_(lfs2, file);
62906288

6291-
LFS2_TRACE("lfs2_file_size -> %"PRId32, res);
6289+
LFS2_TRACE("lfs2_file_size -> %"PRIu32, res);
62926290
LFS2_UNLOCK(lfs2->cfg);
62936291
return res;
62946292
}

scripts/prettyasserts.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@
3535
'assert': ['assert'],
3636
'arrow': ['=>'],
3737
'string': [r'"(?:\\.|[^"])*"', r"'(?:\\.|[^'])\'"],
38-
'paren': ['\(', '\)'],
38+
'paren': [r'\(', r'\)'],
3939
'cmp': CMP.keys(),
40-
'logic': ['\&\&', '\|\|'],
41-
'sep': [':', ';', '\{', '\}', ','],
40+
'logic': [r'\&\&', r'\|\|'],
41+
'sep': [':', ';', r'\{', r'\}', ','],
4242
'op': ['->'], # specifically ops that conflict with cmp
4343
}
4444

scripts/test.py

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ def parse_define(v):
102102
# the runner itself.
103103
for v_ in csplit(v):
104104
m = re.search(r'\brange\b\s*\('
105-
'(?P<start>[^,\s]*)'
106-
'\s*(?:,\s*(?P<stop>[^,\s]*)'
107-
'\s*(?:,\s*(?P<step>[^,\s]*)\s*)?)?\)',
105+
r'(?P<start>[^,\s]*)'
106+
r'\s*(?:,\s*(?P<stop>[^,\s]*)'
107+
r'\s*(?:,\s*(?P<step>[^,\s]*)\s*)?)?\)',
108108
v_)
109109
if m:
110110
start = (int(m.group('start'), 0)
@@ -163,8 +163,8 @@ def __init__(self, path, args={}):
163163
code_linenos = []
164164
for i, line in enumerate(f):
165165
match = re.match(
166-
'(?P<case>\[\s*cases\s*\.\s*(?P<name>\w+)\s*\])'
167-
'|' '(?P<code>code\s*=)',
166+
r'(?P<case>\[\s*cases\s*\.\s*(?P<name>\w+)\s*\])'
167+
r'|' r'(?P<code>code\s*=)',
168168
line)
169169
if match and match.group('case'):
170170
case_linenos.append((i+1, match.group('name')))
@@ -602,9 +602,9 @@ def find_perms(runner_, ids=[], **args):
602602
errors='replace',
603603
close_fds=False)
604604
pattern = re.compile(
605-
'^(?P<case>[^\s]+)'
606-
'\s+(?P<flags>[^\s]+)'
607-
'\s+(?P<filtered>\d+)/(?P<perms>\d+)')
605+
r'^(?P<case>[^\s]+)'
606+
r'\s+(?P<flags>[^\s]+)'
607+
r'\s+(?P<filtered>\d+)/(?P<perms>\d+)')
608608
# skip the first line
609609
for line in it.islice(proc.stdout, 1, None):
610610
m = pattern.match(line)
@@ -632,8 +632,8 @@ def find_perms(runner_, ids=[], **args):
632632
errors='replace',
633633
close_fds=False)
634634
pattern = re.compile(
635-
'^(?P<case>[^\s]+)'
636-
'\s+(?P<path>[^:]+):(?P<lineno>\d+)')
635+
r'^(?P<case>[^\s]+)'
636+
r'\s+(?P<path>[^:]+):(?P<lineno>\d+)')
637637
# skip the first line
638638
for line in it.islice(proc.stdout, 1, None):
639639
m = pattern.match(line)
@@ -676,8 +676,8 @@ def find_path(runner_, id, **args):
676676
errors='replace',
677677
close_fds=False)
678678
pattern = re.compile(
679-
'^(?P<case>[^\s]+)'
680-
'\s+(?P<path>[^:]+):(?P<lineno>\d+)')
679+
r'^(?P<case>[^\s]+)'
680+
r'\s+(?P<path>[^:]+):(?P<lineno>\d+)')
681681
# skip the first line
682682
for line in it.islice(proc.stdout, 1, None):
683683
m = pattern.match(line)
@@ -706,7 +706,7 @@ def find_defines(runner_, id, **args):
706706
errors='replace',
707707
close_fds=False)
708708
defines = co.OrderedDict()
709-
pattern = re.compile('^(?P<define>\w+)=(?P<value>.+)')
709+
pattern = re.compile(r'^(?P<define>\w+)=(?P<value>.+)')
710710
for line in proc.stdout:
711711
m = pattern.match(line)
712712
if m:
@@ -781,12 +781,12 @@ def run_stage(name, runner_, ids, stdout_, trace_, output_, **args):
781781
failures = []
782782
killed = False
783783

784-
pattern = re.compile('^(?:'
785-
'(?P<op>running|finished|skipped|powerloss) '
786-
'(?P<id>(?P<case>[^:]+)[^\s]*)'
787-
'|' '(?P<path>[^:]+):(?P<lineno>\d+):(?P<op_>assert):'
788-
' *(?P<message>.*)'
789-
')$')
784+
pattern = re.compile(r'^(?:'
785+
r'(?P<op>running|finished|skipped|powerloss) '
786+
r'(?P<id>(?P<case>[^:]+)[^\s]*)'
787+
r'|' r'(?P<path>[^:]+):(?P<lineno>\d+):(?P<op_>assert):'
788+
r' *(?P<message>.*)'
789+
r')$')
790790
locals = th.local()
791791
children = set()
792792

tests/test_dirs.toml

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,82 @@ code = '''
725725
lfs2_unmount(&lfs2) => 0;
726726
'''
727727

728+
[cases.test_dirs_remove_read]
729+
defines.N = 10
730+
if = 'N < BLOCK_COUNT/2'
731+
code = '''
732+
lfs2_t lfs2;
733+
lfs2_format(&lfs2, cfg) => 0;
734+
lfs2_mount(&lfs2, cfg) => 0;
735+
lfs2_mkdir(&lfs2, "prickly-pear") => 0;
736+
for (int i = 0; i < N; i++) {
737+
char path[1024];
738+
sprintf(path, "prickly-pear/cactus%03d", i);
739+
lfs2_mkdir(&lfs2, path) => 0;
740+
}
741+
lfs2_dir_t dir;
742+
lfs2_dir_open(&lfs2, &dir, "prickly-pear") => 0;
743+
struct lfs2_info info;
744+
lfs2_dir_read(&lfs2, &dir, &info) => 1;
745+
assert(info.type == LFS2_TYPE_DIR);
746+
assert(strcmp(info.name, ".") == 0);
747+
lfs2_dir_read(&lfs2, &dir, &info) => 1;
748+
assert(info.type == LFS2_TYPE_DIR);
749+
assert(strcmp(info.name, "..") == 0);
750+
for (int i = 0; i < N; i++) {
751+
char path[1024];
752+
sprintf(path, "cactus%03d", i);
753+
lfs2_dir_read(&lfs2, &dir, &info) => 1;
754+
assert(info.type == LFS2_TYPE_DIR);
755+
assert(strcmp(info.name, path) == 0);
756+
}
757+
lfs2_dir_read(&lfs2, &dir, &info) => 0;
758+
lfs2_dir_close(&lfs2, &dir) => 0;
759+
lfs2_unmount(&lfs2);
760+
761+
for (lfs2_size_t k = 0; k < N; k++) {
762+
for (lfs2_size_t j = 0; j < N; j++) {
763+
lfs2_mount(&lfs2, cfg) => 0;
764+
lfs2_dir_open(&lfs2, &dir, "prickly-pear") => 0;
765+
lfs2_dir_read(&lfs2, &dir, &info) => 1;
766+
assert(info.type == LFS2_TYPE_DIR);
767+
assert(strcmp(info.name, ".") == 0);
768+
lfs2_dir_read(&lfs2, &dir, &info) => 1;
769+
assert(info.type == LFS2_TYPE_DIR);
770+
assert(strcmp(info.name, "..") == 0);
771+
// iterate over dirs < j
772+
for (unsigned i = 0; i < j; i++) {
773+
char path[1024];
774+
sprintf(path, "cactus%03d", i);
775+
lfs2_dir_read(&lfs2, &dir, &info) => 1;
776+
assert(info.type == LFS2_TYPE_DIR);
777+
assert(strcmp(info.name, path) == 0);
778+
}
779+
780+
// remove k while iterating
781+
char path[1024];
782+
sprintf(path, "prickly-pear/cactus%03d", k);
783+
lfs2_remove(&lfs2, path) => 0;
784+
785+
// iterate over dirs >= j
786+
for (unsigned i = j; i < ((k >= j) ? N-1 : N); i++) {
787+
char path[1024];
788+
sprintf(path, "cactus%03d", (k >= j && i >= k) ? i+1 : i);
789+
lfs2_dir_read(&lfs2, &dir, &info) => 1;
790+
assert(info.type == LFS2_TYPE_DIR);
791+
assert(strcmp(info.name, path) == 0);
792+
}
793+
lfs2_dir_read(&lfs2, &dir, &info) => 0;
794+
lfs2_dir_close(&lfs2, &dir) => 0;
795+
796+
// recreate k
797+
sprintf(path, "prickly-pear/cactus%03d", k);
798+
lfs2_mkdir(&lfs2, path) => 0;
799+
lfs2_unmount(&lfs2) => 0;
800+
}
801+
}
802+
'''
803+
728804
[cases.test_dirs_other_errors]
729805
code = '''
730806
lfs2_t lfs2;

0 commit comments

Comments
 (0)