mirror of
				https://github.com/eledio-devices/thirdparty-littlefs.git
				synced 2025-10-31 08:42:40 +01:00 
			
		
		
		
	Cleaned up test script and directory naming
- Removed old tests and test scripts
- Reorganize the block devices to live under one directory
- Plugged new test framework into Makefile
renamed:
- scripts/test_.py -> scripts/test.py
- tests_ -> tests
- {file,ram,test}bd/* -> bd/*
It took a surprising amount of effort to make the Makefile behave since
it turns out the "test_%" rule could override "tests/test_%.toml.test"
which is generated as part of test.py.
			
			
This commit is contained in:
		
							
								
								
									
										46
									
								
								Makefile
									
									
									
									
									
								
							
							
						
						
									
										46
									
								
								Makefile
									
									
									
									
									
								
							| @@ -7,15 +7,11 @@ CC ?= gcc | |||||||
| AR ?= ar | AR ?= ar | ||||||
| SIZE ?= size | SIZE ?= size | ||||||
|  |  | ||||||
| SRC += $(wildcard *.c rambd/*.c filebd/*.c testbd/*.c) | SRC += $(wildcard *.c bd/*.c) | ||||||
| OBJ := $(SRC:.c=.o) | OBJ := $(SRC:.c=.o) | ||||||
| DEP := $(SRC:.c=.d) | DEP := $(SRC:.c=.d) | ||||||
| ASM := $(SRC:.c=.s) | ASM := $(SRC:.c=.s) | ||||||
|  |  | ||||||
| TEST := $(patsubst tests/%.sh,%,$(wildcard tests/test_*)) |  | ||||||
|  |  | ||||||
| SHELL = /bin/bash -o pipefail |  | ||||||
|  |  | ||||||
| ifdef DEBUG | ifdef DEBUG | ||||||
| override CFLAGS += -O0 -g3 | override CFLAGS += -O0 -g3 | ||||||
| else | else | ||||||
| @@ -33,6 +29,10 @@ override CFLAGS += -Wextra -Wshadow -Wjump-misses-init -Wundef | |||||||
| # Remove missing-field-initializers because of GCC bug | # Remove missing-field-initializers because of GCC bug | ||||||
| override CFLAGS += -Wno-missing-field-initializers | override CFLAGS += -Wno-missing-field-initializers | ||||||
|  |  | ||||||
|  | ifdef VERBOSE | ||||||
|  | override TFLAGS += -v | ||||||
|  | endif | ||||||
|  |  | ||||||
|  |  | ||||||
| all: $(TARGET) | all: $(TARGET) | ||||||
|  |  | ||||||
| @@ -41,38 +41,14 @@ asm: $(ASM) | |||||||
| size: $(OBJ) | size: $(OBJ) | ||||||
| 	$(SIZE) -t $^ | 	$(SIZE) -t $^ | ||||||
|  |  | ||||||
| .SUFFIXES: | test: | ||||||
| test: \ | 	./scripts/test.py $(TFLAGS) | ||||||
| 	test_format \ | .SECONDEXPANSION: | ||||||
| 	test_dirs \ | test%: tests/test$$(firstword $$(subst \#, ,%)).toml | ||||||
| 	test_files \ | 	./scripts/test.py $(TFLAGS) $@ | ||||||
| 	test_seek \ |  | ||||||
| 	test_truncate \ |  | ||||||
| 	test_entries \ |  | ||||||
| 	test_interspersed \ |  | ||||||
| 	test_alloc \ |  | ||||||
| 	test_paths \ |  | ||||||
| 	test_attrs \ |  | ||||||
| 	test_move \ |  | ||||||
| 	test_orphan \ |  | ||||||
| 	test_relocations \ |  | ||||||
| 	test_corrupt |  | ||||||
| 	@rm test.c |  | ||||||
| test_%: tests/test_%.sh |  | ||||||
| ifdef QUIET |  | ||||||
| 	@./$< | sed -nu '/^[-=]/p' |  | ||||||
| else |  | ||||||
| 	./$< |  | ||||||
| endif |  | ||||||
|  |  | ||||||
| test_: |  | ||||||
| 	./scripts/test_.py $(TFLAGS) |  | ||||||
|  |  | ||||||
| -include $(DEP) | -include $(DEP) | ||||||
|  |  | ||||||
| %?: |  | ||||||
| 	@echo '$($*)' |  | ||||||
|  |  | ||||||
| lfs: $(OBJ) | lfs: $(OBJ) | ||||||
| 	$(CC) $(CFLAGS) $^ $(LFLAGS) -o $@ | 	$(CC) $(CFLAGS) $^ $(LFLAGS) -o $@ | ||||||
|  |  | ||||||
| @@ -90,4 +66,4 @@ clean: | |||||||
| 	rm -f $(OBJ) | 	rm -f $(OBJ) | ||||||
| 	rm -f $(DEP) | 	rm -f $(DEP) | ||||||
| 	rm -f $(ASM) | 	rm -f $(ASM) | ||||||
| 	rm -f tests_/test_*.toml.* | 	rm -f tests/*.toml.* | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. |  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||||
|  * SPDX-License-Identifier: BSD-3-Clause |  * SPDX-License-Identifier: BSD-3-Clause | ||||||
|  */ |  */ | ||||||
| #include "filebd/lfs_filebd.h" | #include "bd/lfs_filebd.h" | ||||||
| 
 | 
 | ||||||
| #include <fcntl.h> | #include <fcntl.h> | ||||||
| #include <unistd.h> | #include <unistd.h> | ||||||
| @@ -4,7 +4,7 @@ | |||||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. |  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||||
|  * SPDX-License-Identifier: BSD-3-Clause |  * SPDX-License-Identifier: BSD-3-Clause | ||||||
|  */ |  */ | ||||||
| #include "rambd/lfs_rambd.h" | #include "bd/lfs_rambd.h" | ||||||
| 
 | 
 | ||||||
| int lfs_rambd_createcfg(const struct lfs_config *cfg, | int lfs_rambd_createcfg(const struct lfs_config *cfg, | ||||||
|         const struct lfs_rambd_config *bdcfg) { |         const struct lfs_rambd_config *bdcfg) { | ||||||
| @@ -5,7 +5,7 @@ | |||||||
|  * Copyright (c) 2017, Arm Limited. All rights reserved. |  * Copyright (c) 2017, Arm Limited. All rights reserved. | ||||||
|  * SPDX-License-Identifier: BSD-3-Clause |  * SPDX-License-Identifier: BSD-3-Clause | ||||||
|  */ |  */ | ||||||
| #include "testbd/lfs_testbd.h" | #include "bd/lfs_testbd.h" | ||||||
| 
 | 
 | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| 
 | 
 | ||||||
| @@ -10,8 +10,8 @@ | |||||||
| 
 | 
 | ||||||
| #include "lfs.h" | #include "lfs.h" | ||||||
| #include "lfs_util.h" | #include "lfs_util.h" | ||||||
| #include "rambd/lfs_rambd.h" | #include "bd/lfs_rambd.h" | ||||||
| #include "filebd/lfs_filebd.h" | #include "bd/lfs_filebd.h" | ||||||
| 
 | 
 | ||||||
| #ifdef __cplusplus | #ifdef __cplusplus | ||||||
| extern "C" | extern "C" | ||||||
| @@ -1,44 +0,0 @@ | |||||||
| #!/usr/bin/env python2 |  | ||||||
|  |  | ||||||
| import struct |  | ||||||
| import sys |  | ||||||
| import os |  | ||||||
| import argparse |  | ||||||
|  |  | ||||||
| def corrupt(block): |  | ||||||
|     with open(block, 'r+b') as file: |  | ||||||
|         # skip rev |  | ||||||
|         file.read(4) |  | ||||||
|  |  | ||||||
|         # go to last commit |  | ||||||
|         tag = 0xffffffff |  | ||||||
|         while True: |  | ||||||
|             try: |  | ||||||
|                 ntag, = struct.unpack('>I', file.read(4)) |  | ||||||
|             except struct.error: |  | ||||||
|                 break |  | ||||||
|  |  | ||||||
|             tag ^= ntag |  | ||||||
|             size = (tag & 0x3ff) if (tag & 0x3ff) != 0x3ff else 0 |  | ||||||
|             file.seek(size, os.SEEK_CUR) |  | ||||||
|  |  | ||||||
|         # lob off last 3 bytes |  | ||||||
|         file.seek(-(size + 3), os.SEEK_CUR) |  | ||||||
|         file.truncate() |  | ||||||
|  |  | ||||||
| def main(args): |  | ||||||
|     if args.n or not args.blocks: |  | ||||||
|         with open('blocks/.history', 'rb') as file: |  | ||||||
|             for i in range(int(args.n or 1)): |  | ||||||
|                 last, = struct.unpack('<I', file.read(4)) |  | ||||||
|                 args.blocks.append('blocks/%x' % last) |  | ||||||
|  |  | ||||||
|     for block in args.blocks: |  | ||||||
|         print 'corrupting %s' % block |  | ||||||
|         corrupt(block) |  | ||||||
|  |  | ||||||
| if __name__ == "__main__": |  | ||||||
|     parser = argparse.ArgumentParser() |  | ||||||
|     parser.add_argument('-n') |  | ||||||
|     parser.add_argument('blocks', nargs='*') |  | ||||||
|     main(parser.parse_args()) |  | ||||||
							
								
								
									
										112
									
								
								scripts/debug.py
									
									
									
									
									
								
							
							
						
						
									
										112
									
								
								scripts/debug.py
									
									
									
									
									
								
							| @@ -1,112 +0,0 @@ | |||||||
| #!/usr/bin/env python2 |  | ||||||
|  |  | ||||||
| import struct |  | ||||||
| import binascii |  | ||||||
|  |  | ||||||
| TYPES = { |  | ||||||
|     (0x700, 0x400): 'splice', |  | ||||||
|     (0x7ff, 0x401): 'create', |  | ||||||
|     (0x7ff, 0x4ff): 'delete', |  | ||||||
|     (0x700, 0x000): 'name', |  | ||||||
|     (0x7ff, 0x001): 'name reg', |  | ||||||
|     (0x7ff, 0x002): 'name dir', |  | ||||||
|     (0x7ff, 0x0ff): 'name superblock', |  | ||||||
|     (0x700, 0x200): 'struct', |  | ||||||
|     (0x7ff, 0x200): 'struct dir', |  | ||||||
|     (0x7ff, 0x202): 'struct ctz', |  | ||||||
|     (0x7ff, 0x201): 'struct inline', |  | ||||||
|     (0x700, 0x300): 'userattr', |  | ||||||
|     (0x700, 0x600): 'tail', |  | ||||||
|     (0x7ff, 0x600): 'tail soft', |  | ||||||
|     (0x7ff, 0x601): 'tail hard', |  | ||||||
|     (0x700, 0x700): 'gstate', |  | ||||||
|     (0x7ff, 0x7ff): 'gstate move', |  | ||||||
|     (0x700, 0x500): 'crc', |  | ||||||
| } |  | ||||||
|  |  | ||||||
| def typeof(type): |  | ||||||
|     for prefix in range(12): |  | ||||||
|         mask = 0x7ff & ~((1 << prefix)-1) |  | ||||||
|         if (mask, type & mask) in TYPES: |  | ||||||
|             return TYPES[mask, type & mask] + ( |  | ||||||
|                 ' %0*x' % (prefix/4, type & ((1 << prefix)-1)) |  | ||||||
|                 if prefix else '') |  | ||||||
|     else: |  | ||||||
|         return '%02x' % type |  | ||||||
|  |  | ||||||
| def main(*blocks): |  | ||||||
|     # find most recent block |  | ||||||
|     file = None |  | ||||||
|     rev = None |  | ||||||
|     crc = None |  | ||||||
|     versions = [] |  | ||||||
|  |  | ||||||
|     for block in blocks: |  | ||||||
|         try: |  | ||||||
|             nfile = open(block, 'rb') |  | ||||||
|             ndata = nfile.read(4) |  | ||||||
|             ncrc = binascii.crc32(ndata) |  | ||||||
|             nrev, = struct.unpack('<I', ndata) |  | ||||||
|  |  | ||||||
|             assert rev != nrev |  | ||||||
|             if not file or ((rev - nrev) & 0x80000000): |  | ||||||
|                 file = nfile |  | ||||||
|                 rev = nrev |  | ||||||
|                 crc = ncrc |  | ||||||
|  |  | ||||||
|             versions.append((nrev, '%s (rev %d)' % (block, nrev))) |  | ||||||
|         except (IOError, struct.error): |  | ||||||
|             pass |  | ||||||
|  |  | ||||||
|     if not file: |  | ||||||
|         print 'Bad metadata pair {%s}' % ', '.join(blocks) |  | ||||||
|         return 1 |  | ||||||
|  |  | ||||||
|     print "--- %s ---" % ', '.join(v for _,v in sorted(versions, reverse=True)) |  | ||||||
|  |  | ||||||
|     # go through each tag, print useful information |  | ||||||
|     print "%-4s  %-8s  %-14s  %3s %4s  %s" % ( |  | ||||||
|         'off', 'tag', 'type', 'id', 'len', 'dump') |  | ||||||
|  |  | ||||||
|     tag = 0xffffffff |  | ||||||
|     off = 4 |  | ||||||
|     while True: |  | ||||||
|         try: |  | ||||||
|             data = file.read(4) |  | ||||||
|             crc = binascii.crc32(data, crc) |  | ||||||
|             ntag, = struct.unpack('>I', data) |  | ||||||
|         except struct.error: |  | ||||||
|             break |  | ||||||
|  |  | ||||||
|         tag ^= ntag |  | ||||||
|         off += 4 |  | ||||||
|  |  | ||||||
|         type = (tag & 0x7ff00000) >> 20 |  | ||||||
|         id   = (tag & 0x000ffc00) >> 10 |  | ||||||
|         size = (tag & 0x000003ff) >> 0 |  | ||||||
|         iscrc = (type & 0x700) == 0x500 |  | ||||||
|  |  | ||||||
|         data = file.read(size if size != 0x3ff else 0) |  | ||||||
|         if iscrc: |  | ||||||
|             crc = binascii.crc32(data[:4], crc) |  | ||||||
|         else: |  | ||||||
|             crc = binascii.crc32(data, crc) |  | ||||||
|  |  | ||||||
|         print '%04x: %08x  %-15s %3s %4s  %-23s  %-8s' % ( |  | ||||||
|             off, tag, |  | ||||||
|             typeof(type) + (' bad!' if iscrc and ~crc else ''), |  | ||||||
|             hex(id)[2:] if id != 0x3ff else '.', |  | ||||||
|             size if size != 0x3ff else 'x', |  | ||||||
|             ' '.join('%02x' % ord(c) for c in data[:8]), |  | ||||||
|             ''.join(c if c >= ' ' and c <= '~' else '.' for c in data[:8])) |  | ||||||
|  |  | ||||||
|         off += size if size != 0x3ff else 0 |  | ||||||
|         if iscrc: |  | ||||||
|             crc = 0 |  | ||||||
|             tag ^= (type & 1) << 31 |  | ||||||
|  |  | ||||||
|     return 0 |  | ||||||
|  |  | ||||||
| if __name__ == "__main__": |  | ||||||
|     import sys |  | ||||||
|     sys.exit(main(*sys.argv[1:])) |  | ||||||
| @@ -1,28 +0,0 @@ | |||||||
| #!/usr/bin/env python2 |  | ||||||
|  |  | ||||||
| import struct |  | ||||||
| import sys |  | ||||||
| import time |  | ||||||
| import os |  | ||||||
| import re |  | ||||||
|  |  | ||||||
| def main(): |  | ||||||
|     with open('blocks/.config') as file: |  | ||||||
|         read_size, prog_size, block_size, block_count = ( |  | ||||||
|             struct.unpack('<LLLL', file.read())) |  | ||||||
|  |  | ||||||
|     real_size = sum( |  | ||||||
|         os.path.getsize(os.path.join('blocks', f)) |  | ||||||
|         for f in os.listdir('blocks') if re.match('\d+', f)) |  | ||||||
|  |  | ||||||
|     with open('blocks/.stats') as file: |  | ||||||
|         read_count, prog_count, erase_count = ( |  | ||||||
|             struct.unpack('<QQQ', file.read())) |  | ||||||
|  |  | ||||||
|     runtime = time.time() - os.stat('blocks').st_ctime |  | ||||||
|  |  | ||||||
|     print 'results: %dB %dB %dB %.3fs' % ( |  | ||||||
|         read_count, prog_count, erase_count, runtime) |  | ||||||
|  |  | ||||||
| if __name__ == "__main__": |  | ||||||
|     main(*sys.argv[1:]) |  | ||||||
| @@ -1,96 +0,0 @@ | |||||||
| /// AUTOGENERATED TEST /// |  | ||||||
| #include "lfs.h" |  | ||||||
| #include "emubd/lfs_emubd.h" |  | ||||||
| #include <stdio.h> |  | ||||||
| #include <string.h> |  | ||||||
| #include <stdlib.h> |  | ||||||
|  |  | ||||||
|  |  | ||||||
| // test stuff |  | ||||||
| static void test_assert(const char *file, unsigned line, |  | ||||||
|         const char *s, uintmax_t v, uintmax_t e) {{ |  | ||||||
|     if (v != e) {{ |  | ||||||
|         fprintf(stderr, "\033[97m%s:%u: \033[91m" |  | ||||||
|                 "assert failed with %jd, expected %jd\033[0m\n" |  | ||||||
|                 "    %s\n\n", file, line, v, e, s); |  | ||||||
|         exit(-2); |  | ||||||
|     }} |  | ||||||
| }} |  | ||||||
|  |  | ||||||
| #define test_assert(v, e) \ |  | ||||||
|         test_assert(__FILE__, __LINE__, #v " => " #e, v, e) |  | ||||||
|  |  | ||||||
| // implicit variable for asserts |  | ||||||
| uintmax_t test; |  | ||||||
|  |  | ||||||
| // utility functions for traversals |  | ||||||
| static int __attribute__((used)) test_count(void *p, lfs_block_t b) {{ |  | ||||||
|     (void)b; |  | ||||||
|     unsigned *u = (unsigned*)p; |  | ||||||
|     *u += 1; |  | ||||||
|     return 0; |  | ||||||
| }} |  | ||||||
|  |  | ||||||
| // lfs declarations |  | ||||||
| lfs_t lfs; |  | ||||||
| lfs_emubd_t bd; |  | ||||||
| // other declarations for convenience |  | ||||||
| lfs_file_t file; |  | ||||||
| lfs_dir_t dir; |  | ||||||
| struct lfs_info info; |  | ||||||
| uint8_t buffer[1024]; |  | ||||||
| char path[1024]; |  | ||||||
|  |  | ||||||
| // test configuration options |  | ||||||
| #ifndef LFS_READ_SIZE |  | ||||||
| #define LFS_READ_SIZE 16 |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef LFS_PROG_SIZE |  | ||||||
| #define LFS_PROG_SIZE LFS_READ_SIZE |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef LFS_BLOCK_SIZE |  | ||||||
| #define LFS_BLOCK_SIZE 512 |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef LFS_BLOCK_COUNT |  | ||||||
| #define LFS_BLOCK_COUNT 1024 |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef LFS_BLOCK_CYCLES |  | ||||||
| #define LFS_BLOCK_CYCLES 1024 |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef LFS_CACHE_SIZE |  | ||||||
| #define LFS_CACHE_SIZE (64 % LFS_PROG_SIZE == 0 ? 64 : LFS_PROG_SIZE) |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef LFS_LOOKAHEAD_SIZE |  | ||||||
| #define LFS_LOOKAHEAD_SIZE 16 |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| const struct lfs_config cfg = {{ |  | ||||||
|     .context = &bd, |  | ||||||
|     .read  = &lfs_emubd_read, |  | ||||||
|     .prog  = &lfs_emubd_prog, |  | ||||||
|     .erase = &lfs_emubd_erase, |  | ||||||
|     .sync  = &lfs_emubd_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, |  | ||||||
| }}; |  | ||||||
|  |  | ||||||
|  |  | ||||||
| // Entry point |  | ||||||
| int main(void) {{ |  | ||||||
|     lfs_emubd_create(&cfg, "blocks"); |  | ||||||
|  |  | ||||||
| {tests} |  | ||||||
|     lfs_emubd_destroy(&cfg); |  | ||||||
| }} |  | ||||||
							
								
								
									
										787
									
								
								scripts/test.py
									
									
									
									
									
								
							
							
						
						
									
										787
									
								
								scripts/test.py
									
									
									
									
									
								
							| @@ -1,81 +1,744 @@ | |||||||
| #!/usr/bin/env python2 | #!/usr/bin/env python3 | ||||||
|  |  | ||||||
|  | # This script manages littlefs tests, which are configured with | ||||||
|  | # .toml files stored in the tests directory. | ||||||
|  | # | ||||||
|  |  | ||||||
|  | import toml | ||||||
|  | import glob | ||||||
| import re | import re | ||||||
| import sys |  | ||||||
| import subprocess |  | ||||||
| import os | 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 pty | ||||||
|  | import errno | ||||||
|  | import signal | ||||||
|  |  | ||||||
|  | TESTDIR = 'tests' | ||||||
|  | RULES = """ | ||||||
|  | define FLATTEN | ||||||
|  | tests/%$(subst /,.,$(target)): $(target) | ||||||
|  |     ./scripts/explode_asserts.py $$< -o $$@ | ||||||
|  | endef | ||||||
|  | $(foreach target,$(SRC),$(eval $(FLATTEN))) | ||||||
|  |  | ||||||
| def generate(test): | -include tests/*.d | ||||||
|     with open("scripts/template.fmt") as file: |  | ||||||
|         template = file.read() |  | ||||||
|  |  | ||||||
|     haslines = 'TEST_LINE' in os.environ and 'TEST_FILE' in os.environ | .SECONDARY: | ||||||
|  | %.test: %.test.o $(foreach f,$(subst /,.,$(SRC:.c=.o)),%.$f) | ||||||
|  |     $(CC) $(CFLAGS) $^ $(LFLAGS) -o $@ | ||||||
|  | """ | ||||||
|  | GLOBALS = """ | ||||||
|  | //////////////// AUTOGENERATED TEST //////////////// | ||||||
|  | #include "lfs.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_NOPROG', | ||||||
|  | } | ||||||
|  | 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; | ||||||
|      |      | ||||||
|     lines = [] |     __attribute__((unused)) const struct lfs_config cfg = { | ||||||
|     for offset, line in enumerate( |         .context        = &bd, | ||||||
|             re.split('(?<=(?:.;| [{}]))\n', test.read())): |         .read           = lfs_testbd_read, | ||||||
|         match = re.match('((?: *\n)*)( *)(.*)=>(.*);', |         .prog           = lfs_testbd_prog, | ||||||
|                 line, re.DOTALL | re.MULTILINE) |         .erase          = lfs_testbd_erase, | ||||||
|         if match: |         .sync           = lfs_testbd_sync, | ||||||
|             preface, tab, test, expect = match.groups() |         .read_size      = LFS_READ_SIZE, | ||||||
|             lines.extend(['']*preface.count('\n')) |         .prog_size      = LFS_PROG_SIZE, | ||||||
|             lines.append(tab+'test_assert({test}, {expect});'.format( |         .block_size     = LFS_BLOCK_SIZE, | ||||||
|                 test=test.strip(), expect=expect.strip())) |         .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; | ||||||
|  | """ | ||||||
|  | EPILOGUE = """ | ||||||
|  |     // epilogue | ||||||
|  |     lfs_testbd_destroy(&cfg) => 0; | ||||||
|  | """ | ||||||
|  | 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) | ||||||
|  |  | ||||||
|  |     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: |         else: | ||||||
|             lines.append(line) |             return '%s#%d' % ( | ||||||
|  |                 self.suite.name, self.caseno) | ||||||
|  |  | ||||||
|     # Create test file |     def permute(self, class_=None, defines={}, permno=None, **_): | ||||||
|     with open('test.c', 'w') as file: |         ncase = (class_ or type(self))(self.config) | ||||||
|         if 'TEST_LINE' in os.environ and 'TEST_FILE' in os.environ: |         for k, v in self.__dict__.items(): | ||||||
|             lines.insert(0, '#line %d "%s"' % ( |             setattr(ncase, k, v) | ||||||
|                     int(os.environ['TEST_LINE']) + 1, |         ncase.case = self | ||||||
|                     os.environ['TEST_FILE'])) |         ncase.perms = [ncase] | ||||||
|             lines.append('#line %d "test.c"' % ( |         ncase.permno = permno | ||||||
|                     template[:template.find('{tests}')].count('\n') |         ncase.defines = defines | ||||||
|                     + len(lines) + 2)) |         return ncase | ||||||
|  |  | ||||||
|         file.write(template.format(tests='\n'.join(lines))) |     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)) | ||||||
|  |  | ||||||
|     # Remove build artifacts to force rebuild |         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', False) and self.in_ is not None: | ||||||
|  |             return False | ||||||
|  |         elif self.if_ is not None: | ||||||
|  |             return eval(self.if_, None, self.defines.copy()) | ||||||
|  |         else: | ||||||
|  |             return True | ||||||
|  |  | ||||||
|  |     def test(self, exec=[], persist=False, cycles=None, | ||||||
|  |             gdb=False, failure=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 persist != 'noerase': | ||||||
|  |                 try: | ||||||
|  |                     os.remove(self.suite.path + '.disk') | ||||||
|  |                     if args.get('verbose', False): | ||||||
|  |                         print('rm', self.suite.path + '.disk') | ||||||
|  |                 except FileNotFoundError: | ||||||
|  |                     pass | ||||||
|  |  | ||||||
|  |             cmd.append(self.suite.path + '.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 == 'start': | ||||||
|  |                 ncmd.extend([ | ||||||
|  |                     '-ex', 'b %s:%d' % (self.suite.path, self.code_lineno), | ||||||
|  |                     '-ex', 'r']) | ||||||
|  |             ncmd.extend(['--args'] + cmd) | ||||||
|  |  | ||||||
|  |             if args.get('verbose', False): | ||||||
|  |                 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', False): | ||||||
|  |             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 | ||||||
|  |         while True: | ||||||
|  |             try: | ||||||
|  |                 line = mpty.readline() | ||||||
|  |             except OSError as e: | ||||||
|  |                 if e.errno == errno.EIO: | ||||||
|  |                     break | ||||||
|  |                 raise | ||||||
|  |             stdout.append(line) | ||||||
|  |             if args.get('verbose', False): | ||||||
|  |                 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 | ||||||
|  |         proc.wait() | ||||||
|  |  | ||||||
|  |         # did we pass? | ||||||
|  |         if proc.returncode != 0: | ||||||
|  |             raise TestFailure(self, proc.returncode, stdout, assert_) | ||||||
|  |         else: | ||||||
|  |             return PASS | ||||||
|  |  | ||||||
|  | class ValgrindTestCase(TestCase): | ||||||
|  |     def __init__(self, config, **args): | ||||||
|  |         self.leaky = config.get('leaky', False) | ||||||
|  |         super().__init__(config, **args) | ||||||
|  |  | ||||||
|  |     def shouldtest(self, **args): | ||||||
|  |         return not self.leaky and super().shouldtest(**args) | ||||||
|  |  | ||||||
|  |     def test(self, exec=[], **args): | ||||||
|  |         exec = exec + [ | ||||||
|  |             'valgrind', | ||||||
|  |             '--leak-check=full', | ||||||
|  |             '--error-exitcode=4', | ||||||
|  |             '-q'] | ||||||
|  |         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, exec=[], 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' | ||||||
|  |  | ||||||
|  |             # 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) | ||||||
|  |  | ||||||
|  |             # 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')] | ||||||
|  |         self.path = path | ||||||
|  |         self.classes = classes | ||||||
|  |         self.defines = defines.copy() | ||||||
|  |         self.filter = filter | ||||||
|  |  | ||||||
|  |         with open(path) as f: | ||||||
|  |             # load tests | ||||||
|  |             config = toml.load(f) | ||||||
|  |  | ||||||
|  |             # find line numbers | ||||||
|  |             f.seek(0) | ||||||
|  |             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): | ||||||
|  |                     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() | ||||||
|  |             # give our case's config a copy of our "global" config | ||||||
|  |             for k, v in config.items(): | ||||||
|  |                 if k not in case: | ||||||
|  |                     case[k] = v | ||||||
|  |             # initialize test case | ||||||
|  |             self.cases.append(TestCase(case, filter=filter, | ||||||
|  |                 suite=self, caseno=i+1, lineno=lineno, **args)) | ||||||
|  |  | ||||||
|  |     def __str__(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.c.t', '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+'.'+ | ||||||
|  |                     case.in_.replace('/', '.')+'.t', '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')) | ||||||
|  |             mk.write('\n') | ||||||
|  |  | ||||||
|  |             # add truely global defines globally | ||||||
|  |             for k, v in sorted(self.defines.items()): | ||||||
|  |                 mk.write('%s: override CFLAGS += -D%s=%r\n' % ( | ||||||
|  |                     self.path+'.test', k, v)) | ||||||
|  |  | ||||||
|  |             for path in tfs: | ||||||
|  |                 if path is None: | ||||||
|  |                     mk.write('%s: %s | %s\n' % ( | ||||||
|  |                         self.path+'.test.c', | ||||||
|  |                         self.path, | ||||||
|  |                         self.path+'.test.c.t')) | ||||||
|  |                 else: | ||||||
|  |                     mk.write('%s: %s %s | %s\n' % ( | ||||||
|  |                         self.path+'.'+path.replace('/', '.'), | ||||||
|  |                         self.path, path, | ||||||
|  |                         self.path+'.'+path.replace('/', '.')+'.t')) | ||||||
|  |                 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', False): | ||||||
|  |                     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 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', False): | ||||||
|  |         classes.append(TestCase) | ||||||
|  |     if args.get('reentrant', False): | ||||||
|  |         classes.append(ReentrantTestCase) | ||||||
|  |     if args.get('valgrind', False): | ||||||
|  |         classes.append(ValgrindTestCase) | ||||||
|  |     if not classes: | ||||||
|  |         classes = [TestCase] | ||||||
|  |  | ||||||
|  |     suites = [] | ||||||
|  |     for testpath in args['testpaths']: | ||||||
|  |         # 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 + '/test_*.toml' | ||||||
|  |         elif os.path.isfile(testpath): | ||||||
|  |             testpath = testpath | ||||||
|  |         elif testpath.endswith('.toml'): | ||||||
|  |             testpath = TESTDIR + '/' + testpath | ||||||
|  |         else: | ||||||
|  |             testpath = TESTDIR + '/' + testpath + '.toml' | ||||||
|  |  | ||||||
|  |         # find tests | ||||||
|  |         for path in glob.glob(testpath): | ||||||
|  |             suites.append(TestSuite(path, classes, defines, filter, **args)) | ||||||
|  |  | ||||||
|  |     # sort for reproducability | ||||||
|  |     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() | ||||||
|  |     if args.get('verbose', False): | ||||||
|  |         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 | ||||||
|  |         stdout.append(line) | ||||||
|  |         if args.get('verbose', False): | ||||||
|  |             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', False): | ||||||
|  |             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 | ||||||
|  |     proc.wait() | ||||||
|  |  | ||||||
|  |     if proc.returncode != 0: | ||||||
|  |         if not args.get('verbose', False): | ||||||
|  |             for line in stdout: | ||||||
|  |                 sys.stdout.write(line) | ||||||
|  |         sys.exit(-3) | ||||||
|  |  | ||||||
|  |     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))) | ||||||
|  |  | ||||||
|  |     filtered = 0 | ||||||
|  |     for suite in suites: | ||||||
|  |         for perm in suite.perms: | ||||||
|  |             filtered += perm.shouldtest(**args) | ||||||
|  |     if filtered != sum(len(suite.perms) for suite in suites): | ||||||
|  |         print('filtered down to %d permutations' % filtered) | ||||||
|  |  | ||||||
|  |     print('====== testing ======') | ||||||
|     try: |     try: | ||||||
|         os.remove('test.o') |         for suite in suites: | ||||||
|         os.remove('lfs') |             suite.test(**args) | ||||||
|     except OSError: |     except TestFailure: | ||||||
|         pass |         pass | ||||||
|  |  | ||||||
| def compile(): |     print('====== results ======') | ||||||
|     subprocess.check_call([ |     passed = 0 | ||||||
|             os.environ.get('MAKE', 'make'), |     failed = 0 | ||||||
|             '--no-print-directory', '-s']) |     for suite in suites: | ||||||
|  |         for perm in suite.perms: | ||||||
|  |             if not hasattr(perm, 'result'): | ||||||
|  |                 continue | ||||||
|  |  | ||||||
| def execute(): |             if perm.result == PASS: | ||||||
|     if 'EXEC' in os.environ: |                 passed += 1 | ||||||
|         subprocess.check_call([os.environ['EXEC'], "./lfs"]) |             else: | ||||||
|     else: |                 sys.stdout.write( | ||||||
|         subprocess.check_call(["./lfs"]) |                     "\033[01m{path}:{lineno}:\033[01;31mfailure:\033[m " | ||||||
|  |                     "{perm} failed with {returncode}\n".format( | ||||||
|  |                         perm=perm, path=perm.suite.path, lineno=perm.lineno, | ||||||
|  |                         returncode=perm.result.returncode or 0)) | ||||||
|  |                 if perm.result.stdout: | ||||||
|  |                     for line in (perm.result.stdout | ||||||
|  |                             if not perm.result.assert_ | ||||||
|  |                             else perm.result.stdout[:-1]): | ||||||
|  |                         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_)) | ||||||
|  |                 else: | ||||||
|  |                     for line in perm.result.stdout: | ||||||
|  |                         sys.stdout.write(line) | ||||||
|  |                 sys.stdout.write('\n') | ||||||
|  |                 failed += 1 | ||||||
|  |  | ||||||
| def main(test=None): |     if args.get('gdb', False): | ||||||
|     try: |         failure = None | ||||||
|         if test and not test.startswith('-'): |         for suite in suites: | ||||||
|             with open(test) as file: |             for perm in suite.perms: | ||||||
|                 generate(file) |                 if getattr(perm, 'result', PASS) != PASS: | ||||||
|         else: |                     failure = perm.result | ||||||
|             generate(sys.stdin) |         if failure is not None: | ||||||
|  |             print('======= gdb ======') | ||||||
|  |             # drop into gdb | ||||||
|  |             failure.case.test(failure=failure, **args) | ||||||
|  |             sys.exit(0) | ||||||
|  |  | ||||||
|         compile() |     print('tests passed: %d' % passed) | ||||||
|  |     print('tests failed: %d' % failed) | ||||||
|         if test == '-s': |     return 1 if failed > 0 else 0 | ||||||
|             sys.exit(1) |  | ||||||
|  |  | ||||||
|         execute() |  | ||||||
|  |  | ||||||
|     except subprocess.CalledProcessError: |  | ||||||
|         # Python stack trace is counterproductive, just exit |  | ||||||
|         sys.exit(2) |  | ||||||
|     except KeyboardInterrupt: |  | ||||||
|         # Python stack trace is counterproductive, just exit |  | ||||||
|         sys.exit(3) |  | ||||||
|  |  | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     main(*sys.argv[1:]) |     import argparse | ||||||
|  |     parser = argparse.ArgumentParser( | ||||||
|  |         description="Run parameterized tests in various configurations.") | ||||||
|  |     parser.add_argument('testpaths', nargs='*', default=[TESTDIR], | ||||||
|  |         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 a \ | ||||||
|  |             specific test case by adding brackets. For example \ | ||||||
|  |             \"test_dirs[0]\" or \"{0}/test_dirs.toml[0]\".".format(TESTDIR)) | ||||||
|  |     parser.add_argument('-D', action='append', default=[], | ||||||
|  |         help="Overriding parameter definitions.") | ||||||
|  |     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('-g', '--gdb', choices=['init', 'start', 'assert'], | ||||||
|  |         nargs='?', const='assert', | ||||||
|  |         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('-V', '--valgrind', action='store_true', | ||||||
|  |         help="Run non-leaky tests under valgrind to check for memory leaks.") | ||||||
|  |     parser.add_argument('-e', '--exec', default=[], type=lambda e: e.split(' '), | ||||||
|  |         help="Run tests with another executable prefixed on the command line.") | ||||||
|  |     sys.exit(main(**vars(parser.parse_args()))) | ||||||
|   | |||||||
							
								
								
									
										744
									
								
								scripts/test_.py
									
									
									
									
									
								
							
							
						
						
									
										744
									
								
								scripts/test_.py
									
									
									
									
									
								
							| @@ -1,744 +0,0 @@ | |||||||
| #!/usr/bin/env python3 |  | ||||||
|  |  | ||||||
| # This script manages littlefs tests, which are configured with |  | ||||||
| # .toml files stored in the tests directory. |  | ||||||
| # |  | ||||||
|  |  | ||||||
| import toml |  | ||||||
| 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 pty |  | ||||||
| import errno |  | ||||||
| import signal |  | ||||||
|  |  | ||||||
| TESTDIR = 'tests_' |  | ||||||
| RULES = """ |  | ||||||
| define FLATTEN |  | ||||||
| tests_/%$(subst /,.,$(target)): $(target) |  | ||||||
|     ./scripts/explode_asserts.py $$< -o $$@ |  | ||||||
| endef |  | ||||||
| $(foreach target,$(SRC),$(eval $(FLATTEN))) |  | ||||||
|  |  | ||||||
| -include tests_/*.d |  | ||||||
|  |  | ||||||
| .SECONDARY: |  | ||||||
| %.test: %.test.o $(foreach f,$(subst /,.,$(SRC:.c=.o)),%.$f) |  | ||||||
|     $(CC) $(CFLAGS) $^ $(LFLAGS) -o $@ |  | ||||||
| """ |  | ||||||
| GLOBALS = """ |  | ||||||
| //////////////// AUTOGENERATED TEST //////////////// |  | ||||||
| #include "lfs.h" |  | ||||||
| #include "testbd/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_NOPROG', |  | ||||||
| } |  | ||||||
| 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; |  | ||||||
| """ |  | ||||||
| EPILOGUE = """ |  | ||||||
|     // epilogue |  | ||||||
|     lfs_testbd_destroy(&cfg) => 0; |  | ||||||
| """ |  | ||||||
| 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) |  | ||||||
|  |  | ||||||
|     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', False) and self.in_ is not None: |  | ||||||
|             return False |  | ||||||
|         elif self.if_ is not None: |  | ||||||
|             return eval(self.if_, None, self.defines.copy()) |  | ||||||
|         else: |  | ||||||
|             return True |  | ||||||
|  |  | ||||||
|     def test(self, exec=[], persist=False, cycles=None, |  | ||||||
|             gdb=False, failure=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 persist != 'noerase': |  | ||||||
|                 try: |  | ||||||
|                     os.remove(self.suite.path + '.disk') |  | ||||||
|                     if args.get('verbose', False): |  | ||||||
|                         print('rm', self.suite.path + '.disk') |  | ||||||
|                 except FileNotFoundError: |  | ||||||
|                     pass |  | ||||||
|  |  | ||||||
|             cmd.append(self.suite.path + '.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 == 'start': |  | ||||||
|                 ncmd.extend([ |  | ||||||
|                     '-ex', 'b %s:%d' % (self.suite.path, self.code_lineno), |  | ||||||
|                     '-ex', 'r']) |  | ||||||
|             ncmd.extend(['--args'] + cmd) |  | ||||||
|  |  | ||||||
|             if args.get('verbose', False): |  | ||||||
|                 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', False): |  | ||||||
|             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 |  | ||||||
|         while True: |  | ||||||
|             try: |  | ||||||
|                 line = mpty.readline() |  | ||||||
|             except OSError as e: |  | ||||||
|                 if e.errno == errno.EIO: |  | ||||||
|                     break |  | ||||||
|                 raise |  | ||||||
|             stdout.append(line) |  | ||||||
|             if args.get('verbose', False): |  | ||||||
|                 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 |  | ||||||
|         proc.wait() |  | ||||||
|  |  | ||||||
|         # did we pass? |  | ||||||
|         if proc.returncode != 0: |  | ||||||
|             raise TestFailure(self, proc.returncode, stdout, assert_) |  | ||||||
|         else: |  | ||||||
|             return PASS |  | ||||||
|  |  | ||||||
| class ValgrindTestCase(TestCase): |  | ||||||
|     def __init__(self, config, **args): |  | ||||||
|         self.leaky = config.get('leaky', False) |  | ||||||
|         super().__init__(config, **args) |  | ||||||
|  |  | ||||||
|     def shouldtest(self, **args): |  | ||||||
|         return not self.leaky and super().shouldtest(**args) |  | ||||||
|  |  | ||||||
|     def test(self, exec=[], **args): |  | ||||||
|         exec = exec + [ |  | ||||||
|             'valgrind', |  | ||||||
|             '--leak-check=full', |  | ||||||
|             '--error-exitcode=4', |  | ||||||
|             '-q'] |  | ||||||
|         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, exec=[], 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' |  | ||||||
|  |  | ||||||
|             # 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) |  | ||||||
|  |  | ||||||
|             # 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')] |  | ||||||
|         self.path = path |  | ||||||
|         self.classes = classes |  | ||||||
|         self.defines = defines.copy() |  | ||||||
|         self.filter = filter |  | ||||||
|  |  | ||||||
|         with open(path) as f: |  | ||||||
|             # load tests |  | ||||||
|             config = toml.load(f) |  | ||||||
|  |  | ||||||
|             # find line numbers |  | ||||||
|             f.seek(0) |  | ||||||
|             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): |  | ||||||
|                     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() |  | ||||||
|             # give our case's config a copy of our "global" config |  | ||||||
|             for k, v in config.items(): |  | ||||||
|                 if k not in case: |  | ||||||
|                     case[k] = v |  | ||||||
|             # initialize test case |  | ||||||
|             self.cases.append(TestCase(case, filter=filter, |  | ||||||
|                 suite=self, caseno=i+1, lineno=lineno, **args)) |  | ||||||
|  |  | ||||||
|     def __str__(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.c.t', '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+'.'+ |  | ||||||
|                     case.in_.replace('/', '.')+'.t', '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')) |  | ||||||
|             mk.write('\n') |  | ||||||
|  |  | ||||||
|             # add truely global defines globally |  | ||||||
|             for k, v in sorted(self.defines.items()): |  | ||||||
|                 mk.write('%s: override CFLAGS += -D%s=%r\n' % ( |  | ||||||
|                     self.path+'.test', k, v)) |  | ||||||
|  |  | ||||||
|             for path in tfs: |  | ||||||
|                 if path is None: |  | ||||||
|                     mk.write('%s: %s | %s\n' % ( |  | ||||||
|                         self.path+'.test.c', |  | ||||||
|                         self.path, |  | ||||||
|                         self.path+'.test.c.t')) |  | ||||||
|                 else: |  | ||||||
|                     mk.write('%s: %s %s | %s\n' % ( |  | ||||||
|                         self.path+'.'+path.replace('/', '.'), |  | ||||||
|                         self.path, path, |  | ||||||
|                         self.path+'.'+path.replace('/', '.')+'.t')) |  | ||||||
|                 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', False): |  | ||||||
|                     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 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', False): |  | ||||||
|         classes.append(TestCase) |  | ||||||
|     if args.get('reentrant', False): |  | ||||||
|         classes.append(ReentrantTestCase) |  | ||||||
|     if args.get('valgrind', False): |  | ||||||
|         classes.append(ValgrindTestCase) |  | ||||||
|     if not classes: |  | ||||||
|         classes = [TestCase] |  | ||||||
|  |  | ||||||
|     suites = [] |  | ||||||
|     for testpath in args['testpaths']: |  | ||||||
|         # 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 + '/test_*.toml' |  | ||||||
|         elif os.path.isfile(testpath): |  | ||||||
|             testpath = testpath |  | ||||||
|         elif testpath.endswith('.toml'): |  | ||||||
|             testpath = TESTDIR + '/' + testpath |  | ||||||
|         else: |  | ||||||
|             testpath = TESTDIR + '/' + testpath + '.toml' |  | ||||||
|  |  | ||||||
|         # find tests |  | ||||||
|         for path in glob.glob(testpath): |  | ||||||
|             suites.append(TestSuite(path, classes, defines, filter, **args)) |  | ||||||
|  |  | ||||||
|     # sort for reproducability |  | ||||||
|     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() |  | ||||||
|     if args.get('verbose', False): |  | ||||||
|         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 |  | ||||||
|         stdout.append(line) |  | ||||||
|         if args.get('verbose', False): |  | ||||||
|             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', False): |  | ||||||
|             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 |  | ||||||
|     proc.wait() |  | ||||||
|  |  | ||||||
|     if proc.returncode != 0: |  | ||||||
|         if not args.get('verbose', False): |  | ||||||
|             for line in stdout: |  | ||||||
|                 sys.stdout.write(line) |  | ||||||
|         sys.exit(-3) |  | ||||||
|  |  | ||||||
|     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))) |  | ||||||
|  |  | ||||||
|     filtered = 0 |  | ||||||
|     for suite in suites: |  | ||||||
|         for perm in suite.perms: |  | ||||||
|             filtered += perm.shouldtest(**args) |  | ||||||
|     if filtered != sum(len(suite.perms) for suite in suites): |  | ||||||
|         print('filtered down to %d permutations' % filtered) |  | ||||||
|  |  | ||||||
|     print('====== testing ======') |  | ||||||
|     try: |  | ||||||
|         for suite in suites: |  | ||||||
|             suite.test(**args) |  | ||||||
|     except TestFailure: |  | ||||||
|         pass |  | ||||||
|  |  | ||||||
|     print('====== results ======') |  | ||||||
|     passed = 0 |  | ||||||
|     failed = 0 |  | ||||||
|     for suite in suites: |  | ||||||
|         for perm in suite.perms: |  | ||||||
|             if not hasattr(perm, 'result'): |  | ||||||
|                 continue |  | ||||||
|  |  | ||||||
|             if perm.result == PASS: |  | ||||||
|                 passed += 1 |  | ||||||
|             else: |  | ||||||
|                 sys.stdout.write( |  | ||||||
|                     "\033[01m{path}:{lineno}:\033[01;31mfailure:\033[m " |  | ||||||
|                     "{perm} failed with {returncode}\n".format( |  | ||||||
|                         perm=perm, path=perm.suite.path, lineno=perm.lineno, |  | ||||||
|                         returncode=perm.result.returncode or 0)) |  | ||||||
|                 if perm.result.stdout: |  | ||||||
|                     for line in (perm.result.stdout |  | ||||||
|                             if not perm.result.assert_ |  | ||||||
|                             else perm.result.stdout[:-1]): |  | ||||||
|                         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_)) |  | ||||||
|                 else: |  | ||||||
|                     for line in perm.result.stdout: |  | ||||||
|                         sys.stdout.write(line) |  | ||||||
|                 sys.stdout.write('\n') |  | ||||||
|                 failed += 1 |  | ||||||
|  |  | ||||||
|     if args.get('gdb', False): |  | ||||||
|         failure = None |  | ||||||
|         for suite in suites: |  | ||||||
|             for perm in suite.perms: |  | ||||||
|                 if getattr(perm, 'result', PASS) != PASS: |  | ||||||
|                     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' % passed) |  | ||||||
|     print('tests failed: %d' % failed) |  | ||||||
|     return 1 if failed > 0 else 0 |  | ||||||
|  |  | ||||||
| if __name__ == "__main__": |  | ||||||
|     import argparse |  | ||||||
|     parser = argparse.ArgumentParser( |  | ||||||
|         description="Run parameterized tests in various configurations.") |  | ||||||
|     parser.add_argument('testpaths', nargs='*', default=[TESTDIR], |  | ||||||
|         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 a \ |  | ||||||
|             specific test case by adding brackets. For example \ |  | ||||||
|             \"test_dirs[0]\" or \"{0}/test_dirs.toml[0]\".".format(TESTDIR)) |  | ||||||
|     parser.add_argument('-D', action='append', default=[], |  | ||||||
|         help="Overriding parameter definitions.") |  | ||||||
|     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('-g', '--gdb', choices=['init', 'start', 'assert'], |  | ||||||
|         nargs='?', const='assert', |  | ||||||
|         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('-V', '--valgrind', action='store_true', |  | ||||||
|         help="Run non-leaky tests under valgrind to check for memory leaks.") |  | ||||||
|     parser.add_argument('-e', '--exec', default=[], type=lambda e: e.split(' '), |  | ||||||
|         help="Run tests with another executable prefixed on the command line.") |  | ||||||
|     sys.exit(main(**vars(parser.parse_args()))) |  | ||||||
| @@ -1,494 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| set -euE |  | ||||||
| export TEST_FILE=$0 |  | ||||||
| trap 'export TEST_LINE=$LINENO' DEBUG |  | ||||||
|  |  | ||||||
| echo "=== Allocator tests ===" |  | ||||||
| rm -rf blocks |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| SIZE=15000 |  | ||||||
|  |  | ||||||
| lfs_mkdir() { |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "$1") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| } |  | ||||||
|  |  | ||||||
| lfs_remove() { |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_remove(&lfs, "$1/eggs") => 0; |  | ||||||
|     lfs_remove(&lfs, "$1/bacon") => 0; |  | ||||||
|     lfs_remove(&lfs, "$1/pancakes") => 0; |  | ||||||
|     lfs_remove(&lfs, "$1") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| } |  | ||||||
|  |  | ||||||
| lfs_alloc_singleproc() { |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     const char *names[] = {"bacon", "eggs", "pancakes"}; |  | ||||||
|     lfs_file_t files[sizeof(names)/sizeof(names[0])]; |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { |  | ||||||
|         sprintf(path, "$1/%s", names[n]); |  | ||||||
|         lfs_file_open(&lfs, &files[n], path, |  | ||||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; |  | ||||||
|     } |  | ||||||
|     for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { |  | ||||||
|         lfs_size_t size = strlen(names[n]); |  | ||||||
|         for (int i = 0; i < $SIZE; i++) { |  | ||||||
|             lfs_file_write(&lfs, &files[n], names[n], size) => size; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     for (unsigned n = 0; n < sizeof(names)/sizeof(names[0]); n++) { |  | ||||||
|         lfs_file_close(&lfs, &files[n]) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| } |  | ||||||
|  |  | ||||||
| lfs_alloc_multiproc() { |  | ||||||
| for name in bacon eggs pancakes |  | ||||||
| do |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "$1/$name", |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; |  | ||||||
|     lfs_size_t size = strlen("$name"); |  | ||||||
|     memcpy(buffer, "$name", size); |  | ||||||
|     for (int i = 0; i < $SIZE; i++) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| done |  | ||||||
| } |  | ||||||
|  |  | ||||||
| lfs_verify() { |  | ||||||
| for name in bacon eggs pancakes |  | ||||||
| do |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "$1/$name", LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_size_t size = strlen("$name"); |  | ||||||
|     for (int i = 0; i < $SIZE; i++) { |  | ||||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|         memcmp(buffer, "$name", size) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| done |  | ||||||
| } |  | ||||||
|  |  | ||||||
| echo "--- Single-process allocation test ---" |  | ||||||
| lfs_mkdir singleproc |  | ||||||
| lfs_alloc_singleproc singleproc |  | ||||||
| lfs_verify singleproc |  | ||||||
|  |  | ||||||
| echo "--- Multi-process allocation test ---" |  | ||||||
| lfs_mkdir multiproc |  | ||||||
| lfs_alloc_multiproc multiproc |  | ||||||
| lfs_verify multiproc |  | ||||||
| lfs_verify singleproc |  | ||||||
|  |  | ||||||
| echo "--- Single-process reuse test ---" |  | ||||||
| lfs_remove singleproc |  | ||||||
| lfs_mkdir singleprocreuse |  | ||||||
| lfs_alloc_singleproc singleprocreuse |  | ||||||
| lfs_verify singleprocreuse |  | ||||||
| lfs_verify multiproc |  | ||||||
|  |  | ||||||
| echo "--- Multi-process reuse test ---" |  | ||||||
| lfs_remove multiproc |  | ||||||
| lfs_mkdir multiprocreuse |  | ||||||
| lfs_alloc_singleproc multiprocreuse |  | ||||||
| lfs_verify multiprocreuse |  | ||||||
| lfs_verify singleprocreuse |  | ||||||
|  |  | ||||||
| echo "--- Cleanup ---" |  | ||||||
| lfs_remove multiprocreuse |  | ||||||
| lfs_remove singleprocreuse |  | ||||||
|  |  | ||||||
| echo "--- Exhaustion test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); |  | ||||||
|     lfs_size_t size = strlen("exhaustion"); |  | ||||||
|     memcpy(buffer, "exhaustion", size); |  | ||||||
|     lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     lfs_file_sync(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     size = strlen("blahblahblahblah"); |  | ||||||
|     memcpy(buffer, "blahblahblahblah", size); |  | ||||||
|     lfs_ssize_t res; |  | ||||||
|     while (true) { |  | ||||||
|         res = lfs_file_write(&lfs, &file, buffer, size); |  | ||||||
|         if (res < 0) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         res => size; |  | ||||||
|     } |  | ||||||
|     res => LFS_ERR_NOSPC; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); |  | ||||||
|     lfs_size_t size = strlen("exhaustion"); |  | ||||||
|     lfs_file_size(&lfs, &file) => size; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "exhaustion", size) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Exhaustion wraparound test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_remove(&lfs, "exhaustion") => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_open(&lfs, &file, "padding", LFS_O_WRONLY | LFS_O_CREAT); |  | ||||||
|     lfs_size_t size = strlen("buffering"); |  | ||||||
|     memcpy(buffer, "buffering", size); |  | ||||||
|     for (int i = 0; i < $SIZE; i++) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_remove(&lfs, "padding") => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); |  | ||||||
|     size = strlen("exhaustion"); |  | ||||||
|     memcpy(buffer, "exhaustion", size); |  | ||||||
|     lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     lfs_file_sync(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     size = strlen("blahblahblahblah"); |  | ||||||
|     memcpy(buffer, "blahblahblahblah", size); |  | ||||||
|     lfs_ssize_t res; |  | ||||||
|     while (true) { |  | ||||||
|         res = lfs_file_write(&lfs, &file, buffer, size); |  | ||||||
|         if (res < 0) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         res => size; |  | ||||||
|     } |  | ||||||
|     res => LFS_ERR_NOSPC; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_RDONLY); |  | ||||||
|     lfs_size_t size = strlen("exhaustion"); |  | ||||||
|     lfs_file_size(&lfs, &file) => size; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "exhaustion", size) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_remove(&lfs, "exhaustion") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Dir exhaustion test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     // find out max file size |  | ||||||
|     lfs_mkdir(&lfs, "exhaustiondir") => 0; |  | ||||||
|     lfs_size_t size = strlen("blahblahblahblah"); |  | ||||||
|     memcpy(buffer, "blahblahblahblah", size); |  | ||||||
|     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) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         count += 1; |  | ||||||
|     } |  | ||||||
|     err => LFS_ERR_NOSPC; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "exhaustion") => 0; |  | ||||||
|     lfs_remove(&lfs, "exhaustiondir") => 0; |  | ||||||
|  |  | ||||||
|     // see if dir fits with max file size |  | ||||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); |  | ||||||
|     for (int i = 0; i < count; i++) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     lfs_mkdir(&lfs, "exhaustiondir") => 0; |  | ||||||
|     lfs_remove(&lfs, "exhaustiondir") => 0; |  | ||||||
|     lfs_remove(&lfs, "exhaustion") => 0; |  | ||||||
|  |  | ||||||
|     // see if dir fits with > max file size |  | ||||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); |  | ||||||
|     for (int i = 0; i < count+1; i++) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "exhaustion") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| ## Below, these tests depend _very_ heavily on the geometry of the |  | ||||||
| ## block device being tested, they should be removed and replaced |  | ||||||
| ## by generalized tests. For now we'll just skip if the geometry |  | ||||||
| ## is customized. |  | ||||||
|  |  | ||||||
| if [[ ! $MAKEFLAGS =~ "LFS_BLOCK_CYCLES" ]] |  | ||||||
| then |  | ||||||
|  |  | ||||||
| echo "--- Chained dir exhaustion test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     // find out max file size |  | ||||||
|     lfs_mkdir(&lfs, "exhaustiondir") => 0; |  | ||||||
|     for (int i = 0; i < 10; i++) { |  | ||||||
|         sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); |  | ||||||
|         lfs_mkdir(&lfs, path) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_size_t size = strlen("blahblahblahblah"); |  | ||||||
|     memcpy(buffer, "blahblahblahblah", size); |  | ||||||
|     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) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         count += 1; |  | ||||||
|     } |  | ||||||
|     err => LFS_ERR_NOSPC; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "exhaustion") => 0; |  | ||||||
|     lfs_remove(&lfs, "exhaustiondir") => 0; |  | ||||||
|     for (int i = 0; i < 10; i++) { |  | ||||||
|         sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); |  | ||||||
|         lfs_remove(&lfs, path) => 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     // see that chained dir fails |  | ||||||
|     lfs_file_open(&lfs, &file, "exhaustion", LFS_O_WRONLY | LFS_O_CREAT); |  | ||||||
|     for (int i = 0; i < count+1; i++) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_sync(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < 10; i++) { |  | ||||||
|         sprintf(path, "dirwithanexhaustivelylongnameforpadding%d", i); |  | ||||||
|         lfs_mkdir(&lfs, path) => 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_mkdir(&lfs, "exhaustiondir") => LFS_ERR_NOSPC; |  | ||||||
|  |  | ||||||
|     // shorten file to try a second chained dir |  | ||||||
|     while (true) { |  | ||||||
|         err = lfs_mkdir(&lfs, "exhaustiondir"); |  | ||||||
|         if (err != LFS_ERR_NOSPC) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         lfs_ssize_t filesize = lfs_file_size(&lfs, &file); |  | ||||||
|         filesize > 0 => true; |  | ||||||
|  |  | ||||||
|         lfs_file_truncate(&lfs, &file, filesize - size) => 0; |  | ||||||
|         lfs_file_sync(&lfs, &file) => 0; |  | ||||||
|     } |  | ||||||
|     err => 0; |  | ||||||
|  |  | ||||||
|     lfs_mkdir(&lfs, "exhaustiondir2") => LFS_ERR_NOSPC; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Split dir test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     // create one block hole for half a directory |  | ||||||
|     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) { |  | ||||||
|         memcpy(&buffer[i], "hi", 2); |  | ||||||
|     } |  | ||||||
|     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); |  | ||||||
|     lfs_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 += size) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     // remount to force reset of lookahead |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     // open hole |  | ||||||
|     lfs_remove(&lfs, "bump") => 0; |  | ||||||
|  |  | ||||||
|     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) { |  | ||||||
|         memcpy(&buffer[i], "hi", 2); |  | ||||||
|     } |  | ||||||
|     lfs_file_write(&lfs, &file, buffer, 2*cfg.block_size) => LFS_ERR_NOSPC; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Outdated lookahead test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     // fill completely with two files |  | ||||||
|     lfs_file_open(&lfs, &file, "exhaustion1", |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     lfs_size_t size = strlen("blahblahblahblah"); |  | ||||||
|     memcpy(buffer, "blahblahblahblah", size); |  | ||||||
|     for (lfs_size_t i = 0; |  | ||||||
|             i < ((cfg.block_count-2)/2)*(cfg.block_size-8); |  | ||||||
|             i += size) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_open(&lfs, &file, "exhaustion2", |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     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 += size) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     // remount to force reset of lookahead |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     // rewrite one file |  | ||||||
|     lfs_file_open(&lfs, &file, "exhaustion1", |  | ||||||
|             LFS_O_WRONLY | LFS_O_TRUNC) => 0; |  | ||||||
|     lfs_file_sync(&lfs, &file) => 0; |  | ||||||
|     size = strlen("blahblahblahblah"); |  | ||||||
|     memcpy(buffer, "blahblahblahblah", size); |  | ||||||
|     for (lfs_size_t i = 0; |  | ||||||
|             i < ((cfg.block_count-2)/2)*(cfg.block_size-8); |  | ||||||
|             i += size) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     // rewrite second file, this requires lookahead does not |  | ||||||
|     // use old population |  | ||||||
|     lfs_file_open(&lfs, &file, "exhaustion2", |  | ||||||
|             LFS_O_WRONLY | LFS_O_TRUNC) => 0; |  | ||||||
|     lfs_file_sync(&lfs, &file) => 0; |  | ||||||
|     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 += size) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Outdated lookahead and split dir test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     // fill completely with two files |  | ||||||
|     lfs_file_open(&lfs, &file, "exhaustion1", |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     lfs_size_t size = strlen("blahblahblahblah"); |  | ||||||
|     memcpy(buffer, "blahblahblahblah", size); |  | ||||||
|     for (lfs_size_t i = 0; |  | ||||||
|             i < ((cfg.block_count-2)/2)*(cfg.block_size-8); |  | ||||||
|             i += size) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_open(&lfs, &file, "exhaustion2", |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     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 += size) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     // remount to force reset of lookahead |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     // rewrite one file with a hole of one block |  | ||||||
|     lfs_file_open(&lfs, &file, "exhaustion1", |  | ||||||
|             LFS_O_WRONLY | LFS_O_TRUNC) => 0; |  | ||||||
|     lfs_file_sync(&lfs, &file) => 0; |  | ||||||
|     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 += size) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     // try to allocate a directory, should fail! |  | ||||||
|     lfs_mkdir(&lfs, "split") => LFS_ERR_NOSPC; |  | ||||||
|  |  | ||||||
|     // file should not fail |  | ||||||
|     lfs_file_open(&lfs, &file, "notasplit", |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     lfs_file_write(&lfs, &file, "hi", 2) => 2; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| fi |  | ||||||
|  |  | ||||||
| scripts/results.py |  | ||||||
| @@ -1,294 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| set -eu |  | ||||||
| export TEST_FILE=$0 |  | ||||||
| trap 'export TEST_LINE=$LINENO' DEBUG |  | ||||||
|  |  | ||||||
| echo "=== Attr tests ===" |  | ||||||
| rm -rf blocks |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "hello") => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "hello/hello", |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     lfs_file_write(&lfs, &file, "hello", strlen("hello")) |  | ||||||
|             => strlen("hello"); |  | ||||||
|     lfs_file_close(&lfs, &file); |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Set/get attribute ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     memset(buffer, 0, sizeof(buffer)); |  | ||||||
|     lfs_setattr(&lfs, "hello", 'A', "aaaa",   4) => 0; |  | ||||||
|     lfs_setattr(&lfs, "hello", 'B', "bbbbbb", 6) => 0; |  | ||||||
|     lfs_setattr(&lfs, "hello", 'C', "ccccc",  5) => 0; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 6; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; |  | ||||||
|     memcmp(buffer,    "aaaa",   4) => 0; |  | ||||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; |  | ||||||
|     memcmp(buffer+10, "ccccc",  5) => 0; |  | ||||||
|  |  | ||||||
|     lfs_setattr(&lfs, "hello", 'B', "", 0) => 0; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 0; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; |  | ||||||
|     memcmp(buffer,    "aaaa",         4) => 0; |  | ||||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; |  | ||||||
|     memcmp(buffer+10, "ccccc",        5) => 0; |  | ||||||
|  |  | ||||||
|     lfs_removeattr(&lfs, "hello", 'B') => 0; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => LFS_ERR_NOATTR; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; |  | ||||||
|     memcmp(buffer,    "aaaa",         4) => 0; |  | ||||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; |  | ||||||
|     memcmp(buffer+10, "ccccc",        5) => 0; |  | ||||||
|  |  | ||||||
|     lfs_setattr(&lfs, "hello", 'B', "dddddd", 6) => 0; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 6; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; |  | ||||||
|     memcmp(buffer,    "aaaa",   4) => 0; |  | ||||||
|     memcmp(buffer+4,  "dddddd", 6) => 0; |  | ||||||
|     memcmp(buffer+10, "ccccc",  5) => 0; |  | ||||||
|  |  | ||||||
|     lfs_setattr(&lfs, "hello", 'B', "eee", 3) => 0; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 3; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; |  | ||||||
|     memcmp(buffer,    "aaaa",      4) => 0; |  | ||||||
|     memcmp(buffer+4,  "eee\0\0\0", 6) => 0; |  | ||||||
|     memcmp(buffer+10, "ccccc",     5) => 0; |  | ||||||
|  |  | ||||||
|     lfs_setattr(&lfs, "hello", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; |  | ||||||
|     lfs_setattr(&lfs, "hello", 'B', "fffffffff", 9) => 0; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'A', buffer,    4) => 4; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'B', buffer+4,  6) => 9; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+10, 5) => 5; |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     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; |  | ||||||
|     lfs_getattr(&lfs, "hello", 'C', buffer+13, 5) => 5; |  | ||||||
|     memcmp(buffer,    "aaaa",      4) => 0; |  | ||||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; |  | ||||||
|     memcmp(buffer+13, "ccccc",     5) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); |  | ||||||
|     memcmp(buffer, "hello", strlen("hello")) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file); |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Set/get root attribute ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     memset(buffer, 0, sizeof(buffer)); |  | ||||||
|     lfs_setattr(&lfs, "/", 'A', "aaaa",   4) => 0; |  | ||||||
|     lfs_setattr(&lfs, "/", 'B', "bbbbbb", 6) => 0; |  | ||||||
|     lfs_setattr(&lfs, "/", 'C', "ccccc",  5) => 0; |  | ||||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; |  | ||||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 6; |  | ||||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; |  | ||||||
|     memcmp(buffer,    "aaaa",   4) => 0; |  | ||||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; |  | ||||||
|     memcmp(buffer+10, "ccccc",  5) => 0; |  | ||||||
|  |  | ||||||
|     lfs_setattr(&lfs, "/", 'B', "", 0) => 0; |  | ||||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; |  | ||||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 0; |  | ||||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; |  | ||||||
|     memcmp(buffer,    "aaaa",         4) => 0; |  | ||||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; |  | ||||||
|     memcmp(buffer+10, "ccccc",        5) => 0; |  | ||||||
|  |  | ||||||
|     lfs_removeattr(&lfs, "/", 'B') => 0; |  | ||||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; |  | ||||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => LFS_ERR_NOATTR; |  | ||||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; |  | ||||||
|     memcmp(buffer,    "aaaa",         4) => 0; |  | ||||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; |  | ||||||
|     memcmp(buffer+10, "ccccc",        5) => 0; |  | ||||||
|  |  | ||||||
|     lfs_setattr(&lfs, "/", 'B', "dddddd", 6) => 0; |  | ||||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; |  | ||||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 6; |  | ||||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; |  | ||||||
|     memcmp(buffer,    "aaaa",   4) => 0; |  | ||||||
|     memcmp(buffer+4,  "dddddd", 6) => 0; |  | ||||||
|     memcmp(buffer+10, "ccccc",  5) => 0; |  | ||||||
|  |  | ||||||
|     lfs_setattr(&lfs, "/", 'B', "eee", 3) => 0; |  | ||||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; |  | ||||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 3; |  | ||||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; |  | ||||||
|     memcmp(buffer,    "aaaa",      4) => 0; |  | ||||||
|     memcmp(buffer+4,  "eee\0\0\0", 6) => 0; |  | ||||||
|     memcmp(buffer+10, "ccccc",     5) => 0; |  | ||||||
|  |  | ||||||
|     lfs_setattr(&lfs, "/", 'A', buffer, LFS_ATTR_MAX+1) => LFS_ERR_NOSPC; |  | ||||||
|     lfs_setattr(&lfs, "/", 'B', "fffffffff", 9) => 0; |  | ||||||
|     lfs_getattr(&lfs, "/", 'A', buffer,    4) => 4; |  | ||||||
|     lfs_getattr(&lfs, "/", 'B', buffer+4,  6) => 9; |  | ||||||
|     lfs_getattr(&lfs, "/", 'C', buffer+10, 5) => 5; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     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; |  | ||||||
|     lfs_getattr(&lfs, "/", 'C', buffer+13, 5) => 5; |  | ||||||
|     memcmp(buffer,    "aaaa",      4) => 0; |  | ||||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; |  | ||||||
|     memcmp(buffer+13, "ccccc",     5) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); |  | ||||||
|     memcmp(buffer, "hello", strlen("hello")) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file); |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Set/get file attribute ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     memset(buffer, 0, sizeof(buffer)); |  | ||||||
|     struct lfs_attr attrs1[] = { |  | ||||||
|         {'A', buffer,    4}, |  | ||||||
|         {'B', buffer+4,  6}, |  | ||||||
|         {'C', buffer+10, 5}, |  | ||||||
|     }; |  | ||||||
|     struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; |  | ||||||
|  |  | ||||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; |  | ||||||
|     memcpy(buffer,    "aaaa",   4); |  | ||||||
|     memcpy(buffer+4,  "bbbbbb", 6); |  | ||||||
|     memcpy(buffer+10, "ccccc",  5); |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     memset(buffer, 0, 15); |  | ||||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     memcmp(buffer,    "aaaa",   4) => 0; |  | ||||||
|     memcmp(buffer+4,  "bbbbbb", 6) => 0; |  | ||||||
|     memcmp(buffer+10, "ccccc",  5) => 0; |  | ||||||
|  |  | ||||||
|     attrs1[1].size = 0; |  | ||||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     memset(buffer, 0, 15); |  | ||||||
|     attrs1[1].size = 6; |  | ||||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     memcmp(buffer,    "aaaa",         4) => 0; |  | ||||||
|     memcmp(buffer+4,  "\0\0\0\0\0\0", 6) => 0; |  | ||||||
|     memcmp(buffer+10, "ccccc",        5) => 0; |  | ||||||
|  |  | ||||||
|     attrs1[1].size = 6; |  | ||||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; |  | ||||||
|     memcpy(buffer+4,  "dddddd", 6); |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     memset(buffer, 0, 15); |  | ||||||
|     attrs1[1].size = 6; |  | ||||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     memcmp(buffer,    "aaaa",   4) => 0; |  | ||||||
|     memcmp(buffer+4,  "dddddd", 6) => 0; |  | ||||||
|     memcmp(buffer+10, "ccccc",  5) => 0; |  | ||||||
|  |  | ||||||
|     attrs1[1].size = 3; |  | ||||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; |  | ||||||
|     memcpy(buffer+4,  "eee", 3); |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     memset(buffer, 0, 15); |  | ||||||
|     attrs1[1].size = 6; |  | ||||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     memcmp(buffer,    "aaaa",      4) => 0; |  | ||||||
|     memcmp(buffer+4,  "eee\0\0\0", 6) => 0; |  | ||||||
|     memcmp(buffer+10, "ccccc",     5) => 0; |  | ||||||
|  |  | ||||||
|     attrs1[0].size = LFS_ATTR_MAX+1; |  | ||||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) |  | ||||||
|         => LFS_ERR_NOSPC; |  | ||||||
|  |  | ||||||
|     struct lfs_attr attrs2[] = { |  | ||||||
|         {'A', buffer,    4}, |  | ||||||
|         {'B', buffer+4,  9}, |  | ||||||
|         {'C', buffer+13, 5}, |  | ||||||
|     }; |  | ||||||
|     struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3}; |  | ||||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDWR, &cfg2) => 0; |  | ||||||
|     memcpy(buffer+4,  "fffffffff", 9); |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     attrs1[0].size = 4; |  | ||||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg1) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     memset(buffer, 0, sizeof(buffer)); |  | ||||||
|     struct lfs_attr attrs2[] = { |  | ||||||
|         {'A', buffer,    4}, |  | ||||||
|         {'B', buffer+4,  9}, |  | ||||||
|         {'C', buffer+13, 5}, |  | ||||||
|     }; |  | ||||||
|     struct lfs_file_config cfg2 = {.attrs=attrs2, .attr_count=3}; |  | ||||||
|  |  | ||||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_RDONLY, &cfg2) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     memcmp(buffer,    "aaaa",      4) => 0; |  | ||||||
|     memcmp(buffer+4,  "fffffffff", 9) => 0; |  | ||||||
|     memcmp(buffer+13, "ccccc",     5) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_open(&lfs, &file, "hello/hello", LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, sizeof(buffer)) => strlen("hello"); |  | ||||||
|     memcmp(buffer, "hello", strlen("hello")) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file); |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Deferred file attributes ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     memset(buffer, 0, sizeof(buffer)); |  | ||||||
|     struct lfs_attr attrs1[] = { |  | ||||||
|         {'B', "gggg", 4}, |  | ||||||
|         {'C', "",     0}, |  | ||||||
|         {'D', "hhhh", 4}, |  | ||||||
|     }; |  | ||||||
|     struct lfs_file_config cfg1 = {.attrs=attrs1, .attr_count=3}; |  | ||||||
|  |  | ||||||
|     lfs_file_opencfg(&lfs, &file, "hello/hello", LFS_O_WRONLY, &cfg1) => 0; |  | ||||||
|  |  | ||||||
|     lfs_getattr(&lfs, "hello/hello", 'B', buffer,    9) => 9; |  | ||||||
|     lfs_getattr(&lfs, "hello/hello", 'C', buffer+9,  9) => 5; |  | ||||||
|     lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => LFS_ERR_NOATTR; |  | ||||||
|     memcmp(buffer,    "fffffffff",          9) => 0; |  | ||||||
|     memcmp(buffer+9,  "ccccc\0\0\0\0",      9) => 0; |  | ||||||
|     memcmp(buffer+18, "\0\0\0\0\0\0\0\0\0", 9) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_sync(&lfs, &file) => 0; |  | ||||||
|     lfs_getattr(&lfs, "hello/hello", 'B', buffer,    9) => 4; |  | ||||||
|     lfs_getattr(&lfs, "hello/hello", 'C', buffer+9,  9) => 0; |  | ||||||
|     lfs_getattr(&lfs, "hello/hello", 'D', buffer+18, 9) => 4; |  | ||||||
|     memcmp(buffer,    "gggg\0\0\0\0\0",     9) => 0; |  | ||||||
|     memcmp(buffer+9,  "\0\0\0\0\0\0\0\0\0", 9) => 0; |  | ||||||
|     memcmp(buffer+18, "hhhh\0\0\0\0\0",     9) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| scripts/results.py |  | ||||||
| @@ -1,120 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| set -eu |  | ||||||
| export TEST_FILE=$0 |  | ||||||
| trap 'export TEST_LINE=$LINENO' DEBUG |  | ||||||
|  |  | ||||||
| echo "=== Corrupt tests ===" |  | ||||||
|  |  | ||||||
| NAMEMULT=64 |  | ||||||
| FILEMULT=1 |  | ||||||
|  |  | ||||||
| lfs_mktree() { |  | ||||||
| scripts/test.py ${1:-} << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     for (int i = 1; i < 10; i++) { |  | ||||||
|         for (int j = 0; j < $NAMEMULT; j++) { |  | ||||||
|             buffer[j] = '0'+i; |  | ||||||
|         } |  | ||||||
|         buffer[$NAMEMULT] = '\0'; |  | ||||||
|         lfs_mkdir(&lfs, (char*)buffer) => 0; |  | ||||||
|  |  | ||||||
|         buffer[$NAMEMULT] = '/'; |  | ||||||
|         for (int j = 0; j < $NAMEMULT; j++) { |  | ||||||
|             buffer[j+$NAMEMULT+1] = '0'+i; |  | ||||||
|         } |  | ||||||
|         buffer[2*$NAMEMULT+1] = '\0'; |  | ||||||
|         lfs_file_open(&lfs, &file, (char*)buffer, |  | ||||||
|                 LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|          |  | ||||||
|         lfs_size_t size = $NAMEMULT; |  | ||||||
|         for (int j = 0; j < i*$FILEMULT; j++) { |  | ||||||
|             lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| } |  | ||||||
|  |  | ||||||
| lfs_chktree() { |  | ||||||
| scripts/test.py ${1:-} << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     for (int i = 1; i < 10; i++) { |  | ||||||
|         for (int j = 0; j < $NAMEMULT; j++) { |  | ||||||
|             buffer[j] = '0'+i; |  | ||||||
|         } |  | ||||||
|         buffer[$NAMEMULT] = '\0'; |  | ||||||
|         lfs_stat(&lfs, (char*)buffer, &info) => 0; |  | ||||||
|         info.type => LFS_TYPE_DIR; |  | ||||||
|  |  | ||||||
|         buffer[$NAMEMULT] = '/'; |  | ||||||
|         for (int j = 0; j < $NAMEMULT; j++) { |  | ||||||
|             buffer[j+$NAMEMULT+1] = '0'+i; |  | ||||||
|         } |  | ||||||
|         buffer[2*$NAMEMULT+1] = '\0'; |  | ||||||
|         lfs_file_open(&lfs, &file, (char*)buffer, LFS_O_RDONLY) => 0; |  | ||||||
|          |  | ||||||
|         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; |  | ||||||
|             memcmp(buffer, rbuffer, size) => 0; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| } |  | ||||||
|  |  | ||||||
| echo "--- Sanity check ---" |  | ||||||
| rm -rf blocks |  | ||||||
| lfs_mktree |  | ||||||
| lfs_chktree |  | ||||||
| BLOCKS="$(ls blocks | grep -vw '[01]')" |  | ||||||
|  |  | ||||||
| echo "--- Block corruption ---" |  | ||||||
| for b in $BLOCKS |  | ||||||
| do  |  | ||||||
|     rm -rf blocks |  | ||||||
|     mkdir blocks |  | ||||||
|     ln -s /dev/zero blocks/$b |  | ||||||
|     lfs_mktree |  | ||||||
|     lfs_chktree |  | ||||||
| done |  | ||||||
|  |  | ||||||
| echo "--- Block persistance ---" |  | ||||||
| for b in $BLOCKS |  | ||||||
| do  |  | ||||||
|     rm -rf blocks |  | ||||||
|     mkdir blocks |  | ||||||
|     lfs_mktree |  | ||||||
|     chmod a-w blocks/$b || true |  | ||||||
|     lfs_mktree |  | ||||||
|     lfs_chktree |  | ||||||
| done |  | ||||||
|  |  | ||||||
| echo "--- Big region corruption ---" |  | ||||||
| rm -rf blocks |  | ||||||
| mkdir blocks |  | ||||||
| for i in {2..512} |  | ||||||
| do |  | ||||||
|     ln -s /dev/zero blocks/$(printf '%x' $i) |  | ||||||
| done |  | ||||||
| lfs_mktree |  | ||||||
| lfs_chktree |  | ||||||
|  |  | ||||||
| echo "--- Alternating corruption ---" |  | ||||||
| rm -rf blocks |  | ||||||
| mkdir blocks |  | ||||||
| for i in {2..1024..2} |  | ||||||
| do |  | ||||||
|     ln -s /dev/zero blocks/$(printf '%x' $i) |  | ||||||
| done |  | ||||||
| lfs_mktree |  | ||||||
| lfs_chktree |  | ||||||
|  |  | ||||||
| scripts/results.py |  | ||||||
| @@ -1,489 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| set -eu |  | ||||||
| export TEST_FILE=$0 |  | ||||||
| trap 'export TEST_LINE=$LINENO' DEBUG |  | ||||||
|  |  | ||||||
| echo "=== Directory tests ===" |  | ||||||
|  |  | ||||||
| LARGESIZE=128 |  | ||||||
|  |  | ||||||
| rm -rf blocks |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Root directory ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Directory creation ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "potato") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- File creation ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "burito", LFS_O_CREAT | LFS_O_WRONLY) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Directory iteration ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "burito") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "potato") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Directory failures ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST; |  | ||||||
|     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; |  | ||||||
|     lfs_file_open(&lfs, &file, "potato", LFS_O_RDONLY) => LFS_ERR_ISDIR; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Nested directories ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     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; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "potato") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "baked") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "fried") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "sweet") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Multi-block directory ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "cactus") => 0; |  | ||||||
|     for (int i = 0; i < $LARGESIZE; i++) { |  | ||||||
|         sprintf(path, "cactus/test%03d", i); |  | ||||||
|         lfs_mkdir(&lfs, path) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "cactus") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     for (int i = 0; i < $LARGESIZE; i++) { |  | ||||||
|         sprintf(path, "test%03d", i); |  | ||||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|         strcmp(info.name, path) => 0; |  | ||||||
|         info.type => LFS_TYPE_DIR; |  | ||||||
|     } |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Directory remove ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY; |  | ||||||
|     lfs_remove(&lfs, "potato/sweet") => 0; |  | ||||||
|     lfs_remove(&lfs, "potato/baked") => 0; |  | ||||||
|     lfs_remove(&lfs, "potato/fried") => 0; |  | ||||||
|  |  | ||||||
|     lfs_dir_open(&lfs, &dir, "potato") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "potato") => 0; |  | ||||||
|  |  | ||||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "burito") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "cactus") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "burito") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "cactus") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Directory rename ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "coldpotato") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "coldpotato/baked") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "coldpotato/sweet") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "coldpotato/fried") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_rename(&lfs, "coldpotato", "hotpotato") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "hotpotato") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "baked") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "fried") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "sweet") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "warmpotato") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "warmpotato/mushy") => 0; |  | ||||||
|     lfs_rename(&lfs, "hotpotato", "warmpotato") => LFS_ERR_NOTEMPTY; |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "warmpotato/mushy") => 0; |  | ||||||
|     lfs_rename(&lfs, "hotpotato", "warmpotato") => 0; |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "warmpotato") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "baked") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "fried") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "sweet") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "coldpotato") => 0; |  | ||||||
|     lfs_rename(&lfs, "warmpotato/baked", "coldpotato/baked") => 0; |  | ||||||
|     lfs_rename(&lfs, "warmpotato/sweet", "coldpotato/sweet") => 0; |  | ||||||
|     lfs_rename(&lfs, "warmpotato/fried", "coldpotato/fried") => 0; |  | ||||||
|     lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; |  | ||||||
|     lfs_remove(&lfs, "warmpotato") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "coldpotato") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "baked") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "fried") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "sweet") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Recursive remove ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; |  | ||||||
|  |  | ||||||
|     lfs_dir_open(&lfs, &dir, "coldpotato") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|  |  | ||||||
|     while (true) { |  | ||||||
|         int err = lfs_dir_read(&lfs, &dir, &info); |  | ||||||
|         err >= 0 => 1; |  | ||||||
|         if (err == 0) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         strcpy(path, "coldpotato/"); |  | ||||||
|         strcat(path, info.name); |  | ||||||
|         lfs_remove(&lfs, path) => 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "coldpotato") => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "burito") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "cactus") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Multi-block rename ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     for (int i = 0; i < $LARGESIZE; i++) { |  | ||||||
|         char oldpath[1024]; |  | ||||||
|         char newpath[1024]; |  | ||||||
|         sprintf(oldpath, "cactus/test%03d", i); |  | ||||||
|         sprintf(newpath, "cactus/tedd%03d", i); |  | ||||||
|         lfs_rename(&lfs, oldpath, newpath) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "cactus") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     for (int i = 0; i < $LARGESIZE; i++) { |  | ||||||
|         sprintf(path, "tedd%03d", i); |  | ||||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|         strcmp(info.name, path) => 0; |  | ||||||
|         info.type => LFS_TYPE_DIR; |  | ||||||
|     } |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Multi-block remove ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_remove(&lfs, "cactus") => LFS_ERR_NOTEMPTY; |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < $LARGESIZE; i++) { |  | ||||||
|         sprintf(path, "cactus/tedd%03d", i); |  | ||||||
|         lfs_remove(&lfs, path) => 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "cactus") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "burito") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Multi-block directory with files ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "prickly-pear") => 0; |  | ||||||
|     for (int i = 0; i < $LARGESIZE; i++) { |  | ||||||
|         sprintf(path, "prickly-pear/test%03d", i); |  | ||||||
|         lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|         lfs_size_t size = 6; |  | ||||||
|         memcpy(buffer, "Hello", size); |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|         lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     for (int i = 0; i < $LARGESIZE; i++) { |  | ||||||
|         sprintf(path, "test%03d", i); |  | ||||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|         strcmp(info.name, path) => 0; |  | ||||||
|         info.type => LFS_TYPE_REG; |  | ||||||
|         info.size => 6; |  | ||||||
|     } |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Multi-block rename with files ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     for (int i = 0; i < $LARGESIZE; i++) { |  | ||||||
|         char oldpath[1024]; |  | ||||||
|         char newpath[1024]; |  | ||||||
|         sprintf(oldpath, "prickly-pear/test%03d", i); |  | ||||||
|         sprintf(newpath, "prickly-pear/tedd%03d", i); |  | ||||||
|         lfs_rename(&lfs, oldpath, newpath) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     for (int i = 0; i < $LARGESIZE; i++) { |  | ||||||
|         sprintf(path, "tedd%03d", i); |  | ||||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|         strcmp(info.name, path) => 0; |  | ||||||
|         info.type => LFS_TYPE_REG; |  | ||||||
|         info.size => 6; |  | ||||||
|     } |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Multi-block remove with files ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY; |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < $LARGESIZE; i++) { |  | ||||||
|         sprintf(path, "prickly-pear/tedd%03d", i); |  | ||||||
|         lfs_remove(&lfs, path) => 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "prickly-pear") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "burito") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| scripts/results.py |  | ||||||
| @@ -1,251 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| set -eu |  | ||||||
| export TEST_FILE=$0 |  | ||||||
| trap 'export TEST_LINE=$LINENO' DEBUG |  | ||||||
|  |  | ||||||
| echo "=== Entry tests ===" |  | ||||||
|  |  | ||||||
| # Note: These tests are intended for 512 byte inline size at different |  | ||||||
| # inline sizes they should still pass, but won't be testing anything |  | ||||||
|  |  | ||||||
| rm -rf blocks |  | ||||||
| function read_file { |  | ||||||
| cat << TEST |  | ||||||
|  |  | ||||||
|     size = $2; |  | ||||||
|     lfs_file_open(&lfs, &file, "$1", LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; |  | ||||||
|     memcmp(rbuffer, wbuffer, size) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
| TEST |  | ||||||
| } |  | ||||||
|  |  | ||||||
| function write_file { |  | ||||||
| cat << TEST |  | ||||||
|  |  | ||||||
|     size = $2; |  | ||||||
|     lfs_file_open(&lfs, &file, "$1", |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; |  | ||||||
|     memset(wbuffer, 'c', size); |  | ||||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
| TEST |  | ||||||
| } |  | ||||||
|  |  | ||||||
| echo "--- Entry grow test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     uint8_t wbuffer[1024]; |  | ||||||
|     uint8_t rbuffer[1024]; |  | ||||||
|     lfs_size_t size; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     $(write_file "hi0" 20) |  | ||||||
|     $(write_file "hi1" 20) |  | ||||||
|     $(write_file "hi2" 20) |  | ||||||
|     $(write_file "hi3" 20) |  | ||||||
|  |  | ||||||
|     $(read_file "hi1" 20) |  | ||||||
|     $(write_file "hi1" 200) |  | ||||||
|  |  | ||||||
|     $(read_file "hi0" 20) |  | ||||||
|     $(read_file "hi1" 200) |  | ||||||
|     $(read_file "hi2" 20) |  | ||||||
|     $(read_file "hi3" 20) |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Entry shrink test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     uint8_t wbuffer[1024]; |  | ||||||
|     uint8_t rbuffer[1024]; |  | ||||||
|     lfs_size_t size; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     $(write_file "hi0" 20) |  | ||||||
|     $(write_file "hi1" 200) |  | ||||||
|     $(write_file "hi2" 20) |  | ||||||
|     $(write_file "hi3" 20) |  | ||||||
|  |  | ||||||
|     $(read_file "hi1" 200) |  | ||||||
|     $(write_file "hi1" 20) |  | ||||||
|  |  | ||||||
|     $(read_file "hi0" 20) |  | ||||||
|     $(read_file "hi1" 20) |  | ||||||
|     $(read_file "hi2" 20) |  | ||||||
|     $(read_file "hi3" 20) |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Entry spill test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     uint8_t wbuffer[1024]; |  | ||||||
|     uint8_t rbuffer[1024]; |  | ||||||
|     lfs_size_t size; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     $(write_file "hi0" 200) |  | ||||||
|     $(write_file "hi1" 200) |  | ||||||
|     $(write_file "hi2" 200) |  | ||||||
|     $(write_file "hi3" 200) |  | ||||||
|  |  | ||||||
|     $(read_file "hi0" 200) |  | ||||||
|     $(read_file "hi1" 200) |  | ||||||
|     $(read_file "hi2" 200) |  | ||||||
|     $(read_file "hi3" 200) |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Entry push spill test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     uint8_t wbuffer[1024]; |  | ||||||
|     uint8_t rbuffer[1024]; |  | ||||||
|     lfs_size_t size; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     $(write_file "hi0" 200) |  | ||||||
|     $(write_file "hi1" 20) |  | ||||||
|     $(write_file "hi2" 200) |  | ||||||
|     $(write_file "hi3" 200) |  | ||||||
|  |  | ||||||
|     $(read_file "hi1" 20) |  | ||||||
|     $(write_file "hi1" 200) |  | ||||||
|  |  | ||||||
|     $(read_file "hi0" 200) |  | ||||||
|     $(read_file "hi1" 200) |  | ||||||
|     $(read_file "hi2" 200) |  | ||||||
|     $(read_file "hi3" 200) |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Entry push spill two test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     uint8_t wbuffer[1024]; |  | ||||||
|     uint8_t rbuffer[1024]; |  | ||||||
|     lfs_size_t size; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     $(write_file "hi0" 200) |  | ||||||
|     $(write_file "hi1" 20) |  | ||||||
|     $(write_file "hi2" 200) |  | ||||||
|     $(write_file "hi3" 200) |  | ||||||
|     $(write_file "hi4" 200) |  | ||||||
|  |  | ||||||
|     $(read_file "hi1" 20) |  | ||||||
|     $(write_file "hi1" 200) |  | ||||||
|  |  | ||||||
|     $(read_file "hi0" 200) |  | ||||||
|     $(read_file "hi1" 200) |  | ||||||
|     $(read_file "hi2" 200) |  | ||||||
|     $(read_file "hi3" 200) |  | ||||||
|     $(read_file "hi4" 200) |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Entry drop test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     uint8_t wbuffer[1024]; |  | ||||||
|     uint8_t rbuffer[1024]; |  | ||||||
|     lfs_size_t size; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     $(write_file "hi0" 200) |  | ||||||
|     $(write_file "hi1" 200) |  | ||||||
|     $(write_file "hi2" 200) |  | ||||||
|     $(write_file "hi3" 200) |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "hi1") => 0; |  | ||||||
|     lfs_stat(&lfs, "hi1", &info) => LFS_ERR_NOENT; |  | ||||||
|     $(read_file "hi0" 200) |  | ||||||
|     $(read_file "hi2" 200) |  | ||||||
|     $(read_file "hi3" 200) |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "hi2") => 0; |  | ||||||
|     lfs_stat(&lfs, "hi2", &info) => LFS_ERR_NOENT; |  | ||||||
|     $(read_file "hi0" 200) |  | ||||||
|     $(read_file "hi3" 200) |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "hi3") => 0; |  | ||||||
|     lfs_stat(&lfs, "hi3", &info) => LFS_ERR_NOENT; |  | ||||||
|     $(read_file "hi0" 200) |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "hi0") => 0; |  | ||||||
|     lfs_stat(&lfs, "hi0", &info) => LFS_ERR_NOENT; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Create too big ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     memset(path, 'm', 200); |  | ||||||
|     path[200] = '\0'; |  | ||||||
|  |  | ||||||
|     lfs_size_t size = 400; |  | ||||||
|     lfs_file_open(&lfs, &file, path, |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; |  | ||||||
|     uint8_t wbuffer[1024]; |  | ||||||
|     memset(wbuffer, 'c', size); |  | ||||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     size = 400; |  | ||||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; |  | ||||||
|     uint8_t rbuffer[1024]; |  | ||||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; |  | ||||||
|     memcmp(rbuffer, wbuffer, size) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Resize too big ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     memset(path, 'm', 200); |  | ||||||
|     path[200] = '\0'; |  | ||||||
|  |  | ||||||
|     lfs_size_t size = 40; |  | ||||||
|     lfs_file_open(&lfs, &file, path, |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; |  | ||||||
|     uint8_t wbuffer[1024]; |  | ||||||
|     memset(wbuffer, 'c', size); |  | ||||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     size = 40; |  | ||||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; |  | ||||||
|     uint8_t rbuffer[1024]; |  | ||||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; |  | ||||||
|     memcmp(rbuffer, wbuffer, size) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     size = 400; |  | ||||||
|     lfs_file_open(&lfs, &file, path, |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; |  | ||||||
|     memset(wbuffer, 'c', size); |  | ||||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     size = 400; |  | ||||||
|     lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; |  | ||||||
|     memcmp(rbuffer, wbuffer, size) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| scripts/results.py |  | ||||||
| @@ -1,221 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| set -eu |  | ||||||
| export TEST_FILE=$0 |  | ||||||
| trap 'export TEST_LINE=$LINENO' DEBUG |  | ||||||
|  |  | ||||||
| echo "=== File tests ===" |  | ||||||
|  |  | ||||||
| SMALLSIZE=32 |  | ||||||
| MEDIUMSIZE=8192 |  | ||||||
| LARGESIZE=262144 |  | ||||||
|  |  | ||||||
| rm -rf blocks |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Simple file test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "hello", LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     lfs_size_t size = strlen("Hello World!\n"); |  | ||||||
|     uint8_t wbuffer[1024]; |  | ||||||
|     memcpy(wbuffer, "Hello World!\n", size); |  | ||||||
|     lfs_file_write(&lfs, &file, wbuffer, size) => size; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0; |  | ||||||
|     size = strlen("Hello World!\n"); |  | ||||||
|     uint8_t rbuffer[1024]; |  | ||||||
|     lfs_file_read(&lfs, &file, rbuffer, size) => size; |  | ||||||
|     memcmp(rbuffer, wbuffer, size) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| w_test() { |  | ||||||
| scripts/test.py ${4:-} << TEST |  | ||||||
|     lfs_size_t size = $1; |  | ||||||
|     lfs_size_t chunk = 31; |  | ||||||
|     srand(0); |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "$2", |  | ||||||
|         ${3:-LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC}) => 0; |  | ||||||
|     for (lfs_size_t i = 0; i < size; i += chunk) { |  | ||||||
|         chunk = (chunk < size - i) ? chunk : size - i; |  | ||||||
|         for (lfs_size_t b = 0; b < chunk; b++) { |  | ||||||
|             buffer[b] = rand() & 0xff; |  | ||||||
|         } |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, chunk) => chunk; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| } |  | ||||||
|  |  | ||||||
| r_test() { |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_size_t size = $1; |  | ||||||
|     lfs_size_t chunk = 29; |  | ||||||
|     srand(0); |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_stat(&lfs, "$2", &info) => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     info.size => size; |  | ||||||
|     lfs_file_open(&lfs, &file, "$2", ${3:-LFS_O_RDONLY}) => 0; |  | ||||||
|     for (lfs_size_t i = 0; i < size; i += chunk) { |  | ||||||
|         chunk = (chunk < size - i) ? chunk : size - i; |  | ||||||
|         lfs_file_read(&lfs, &file, buffer, chunk) => chunk; |  | ||||||
|         for (lfs_size_t b = 0; b < chunk && i+b < size; b++) { |  | ||||||
|             buffer[b] => rand() & 0xff; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| } |  | ||||||
|  |  | ||||||
| echo "--- Small file test ---" |  | ||||||
| w_test $SMALLSIZE smallavacado |  | ||||||
| r_test $SMALLSIZE smallavacado |  | ||||||
|  |  | ||||||
| echo "--- Medium file test ---" |  | ||||||
| w_test $MEDIUMSIZE mediumavacado |  | ||||||
| r_test $MEDIUMSIZE mediumavacado |  | ||||||
|  |  | ||||||
| echo "--- Large file test ---" |  | ||||||
| w_test $LARGESIZE largeavacado |  | ||||||
| r_test $LARGESIZE largeavacado |  | ||||||
|  |  | ||||||
| echo "--- Zero file test ---" |  | ||||||
| w_test 0 noavacado |  | ||||||
| r_test 0 noavacado |  | ||||||
|  |  | ||||||
| echo "--- Truncate small test ---" |  | ||||||
| w_test $SMALLSIZE mediumavacado |  | ||||||
| r_test $SMALLSIZE mediumavacado |  | ||||||
| w_test $MEDIUMSIZE mediumavacado |  | ||||||
| r_test $MEDIUMSIZE mediumavacado |  | ||||||
|  |  | ||||||
| echo "--- Truncate zero test ---" |  | ||||||
| w_test $SMALLSIZE noavacado |  | ||||||
| r_test $SMALLSIZE noavacado |  | ||||||
| w_test 0 noavacado |  | ||||||
| r_test 0 noavacado |  | ||||||
|  |  | ||||||
| echo "--- Non-overlap check ---" |  | ||||||
| r_test $SMALLSIZE smallavacado |  | ||||||
| r_test $MEDIUMSIZE mediumavacado |  | ||||||
| r_test $LARGESIZE largeavacado |  | ||||||
| r_test 0 noavacado |  | ||||||
|  |  | ||||||
| echo "--- Dir check ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "hello") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     info.size => strlen("Hello World!\n"); |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "largeavacado") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     info.size => $LARGESIZE; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "mediumavacado") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     info.size => $MEDIUMSIZE; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "noavacado") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     info.size => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "smallavacado") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     info.size => $SMALLSIZE; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Many files test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     // Create 300 files of 7 bytes |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     for (unsigned i = 0; i < 300; i++) { |  | ||||||
|         sprintf(path, "file_%03d", i); |  | ||||||
|         lfs_file_open(&lfs, &file, path, |  | ||||||
|                 LFS_O_RDWR | LFS_O_CREAT | LFS_O_EXCL) => 0; |  | ||||||
|         lfs_size_t size = 7; |  | ||||||
|         uint8_t wbuffer[1024]; |  | ||||||
|         uint8_t rbuffer[1024]; |  | ||||||
|         snprintf((char*)wbuffer, size, "Hi %03d", i); |  | ||||||
|         lfs_file_write(&lfs, &file, wbuffer, size) => size; |  | ||||||
|         lfs_file_rewind(&lfs, &file) => 0; |  | ||||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; |  | ||||||
|         memcmp(wbuffer, rbuffer, size) => 0; |  | ||||||
|         lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Many files with flush test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     // Create 300 files of 7 bytes |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     for (unsigned i = 0; i < 300; i++) { |  | ||||||
|         sprintf(path, "file_%03d", i); |  | ||||||
|         lfs_file_open(&lfs, &file, path, |  | ||||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; |  | ||||||
|         lfs_size_t size = 7; |  | ||||||
|         uint8_t wbuffer[1024]; |  | ||||||
|         uint8_t rbuffer[1024]; |  | ||||||
|         snprintf((char*)wbuffer, size, "Hi %03d", i); |  | ||||||
|         lfs_file_write(&lfs, &file, wbuffer, size) => size; |  | ||||||
|         lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|         lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; |  | ||||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; |  | ||||||
|         memcmp(wbuffer, rbuffer, size) => 0; |  | ||||||
|         lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Many files with power cycle test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     // Create 300 files of 7 bytes |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     for (unsigned i = 0; i < 300; i++) { |  | ||||||
|         sprintf(path, "file_%03d", i); |  | ||||||
|         lfs_file_open(&lfs, &file, path, |  | ||||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; |  | ||||||
|         lfs_size_t size = 7; |  | ||||||
|         uint8_t wbuffer[1024]; |  | ||||||
|         uint8_t rbuffer[1024]; |  | ||||||
|         snprintf((char*)wbuffer, size, "Hi %03d", i); |  | ||||||
|         lfs_file_write(&lfs, &file, wbuffer, size) => size; |  | ||||||
|         lfs_file_close(&lfs, &file) => 0; |  | ||||||
|         lfs_unmount(&lfs) => 0; |  | ||||||
|  |  | ||||||
|         lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|         lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; |  | ||||||
|         lfs_file_read(&lfs, &file, rbuffer, size) => size; |  | ||||||
|         memcmp(wbuffer, rbuffer, size) => 0; |  | ||||||
|         lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| scripts/results.py |  | ||||||
| @@ -1,51 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| set -eu |  | ||||||
| export TEST_FILE=$0 |  | ||||||
| trap 'export TEST_LINE=$LINENO' DEBUG |  | ||||||
|  |  | ||||||
| echo "=== Formatting tests ===" |  | ||||||
| rm -rf blocks |  | ||||||
|  |  | ||||||
| echo "--- Basic formatting ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Basic mounting ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Invalid superblocks ---" |  | ||||||
| ln -f -s /dev/zero blocks/0 |  | ||||||
| ln -f -s /dev/zero blocks/1 |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => LFS_ERR_NOSPC; |  | ||||||
| TEST |  | ||||||
| rm blocks/0 blocks/1 |  | ||||||
|  |  | ||||||
| echo "--- Invalid mount ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Expanding superblock ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     for (int i = 0; i < 100; i++) { |  | ||||||
|         lfs_mkdir(&lfs, "dummy") => 0; |  | ||||||
|         lfs_remove(&lfs, "dummy") => 0; |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "dummy") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| scripts/results.py |  | ||||||
| @@ -1,190 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| set -eu |  | ||||||
| export TEST_FILE=$0 |  | ||||||
| trap 'export TEST_LINE=$LINENO' DEBUG |  | ||||||
|  |  | ||||||
| echo "=== Interspersed tests ===" |  | ||||||
| rm -rf blocks |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Interspersed file test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_t files[4]; |  | ||||||
|     lfs_file_open(&lfs, &files[0], "a", LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     lfs_file_open(&lfs, &files[1], "b", LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     lfs_file_open(&lfs, &files[2], "c", LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     lfs_file_open(&lfs, &files[3], "d", LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < 10; i++) { |  | ||||||
|         lfs_file_write(&lfs, &files[0], (const void*)"a", 1) => 1; |  | ||||||
|         lfs_file_write(&lfs, &files[1], (const void*)"b", 1) => 1; |  | ||||||
|         lfs_file_write(&lfs, &files[2], (const void*)"c", 1) => 1; |  | ||||||
|         lfs_file_write(&lfs, &files[3], (const void*)"d", 1) => 1; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &files[0]); |  | ||||||
|     lfs_file_close(&lfs, &files[1]); |  | ||||||
|     lfs_file_close(&lfs, &files[2]); |  | ||||||
|     lfs_file_close(&lfs, &files[3]); |  | ||||||
|  |  | ||||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "a") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     info.size => 10; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "b") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     info.size => 10; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "c") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     info.size => 10; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "d") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     info.size => 10; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_open(&lfs, &files[0], "a", LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_file_open(&lfs, &files[1], "b", LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_file_open(&lfs, &files[2], "c", LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_file_open(&lfs, &files[3], "d", LFS_O_RDONLY) => 0; |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < 10; i++) { |  | ||||||
|         lfs_file_read(&lfs, &files[0], buffer, 1) => 1; |  | ||||||
|         buffer[0] => 'a'; |  | ||||||
|         lfs_file_read(&lfs, &files[1], buffer, 1) => 1; |  | ||||||
|         buffer[0] => 'b'; |  | ||||||
|         lfs_file_read(&lfs, &files[2], buffer, 1) => 1; |  | ||||||
|         buffer[0] => 'c'; |  | ||||||
|         lfs_file_read(&lfs, &files[3], buffer, 1) => 1; |  | ||||||
|         buffer[0] => 'd'; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &files[0]); |  | ||||||
|     lfs_file_close(&lfs, &files[1]); |  | ||||||
|     lfs_file_close(&lfs, &files[2]); |  | ||||||
|     lfs_file_close(&lfs, &files[3]); |  | ||||||
|      |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Interspersed remove file test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_t files[4]; |  | ||||||
|     lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < 5; i++) { |  | ||||||
|         lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "a") => 0; |  | ||||||
|     lfs_remove(&lfs, "b") => 0; |  | ||||||
|     lfs_remove(&lfs, "c") => 0; |  | ||||||
|     lfs_remove(&lfs, "d") => 0; |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < 5; i++) { |  | ||||||
|         lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &files[0]); |  | ||||||
|  |  | ||||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "e") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     info.size => 10; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_open(&lfs, &files[0], "e", LFS_O_RDONLY) => 0; |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < 10; i++) { |  | ||||||
|         lfs_file_read(&lfs, &files[0], buffer, 1) => 1; |  | ||||||
|         buffer[0] => 'e'; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &files[0]); |  | ||||||
|      |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Remove inconveniently test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_t files[4]; |  | ||||||
|     lfs_file_open(&lfs, &files[0], "e", LFS_O_WRONLY | LFS_O_TRUNC) => 0; |  | ||||||
|     lfs_file_open(&lfs, &files[1], "f", LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     lfs_file_open(&lfs, &files[2], "g", LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < 5; i++) { |  | ||||||
|         lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; |  | ||||||
|         lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1; |  | ||||||
|         lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "f") => 0; |  | ||||||
|  |  | ||||||
|     for (int i = 0; i < 5; i++) { |  | ||||||
|         lfs_file_write(&lfs, &files[0], (const void*)"e", 1) => 1; |  | ||||||
|         lfs_file_write(&lfs, &files[1], (const void*)"f", 1) => 1; |  | ||||||
|         lfs_file_write(&lfs, &files[2], (const void*)"g", 1) => 1; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &files[0]); |  | ||||||
|     lfs_file_close(&lfs, &files[1]); |  | ||||||
|     lfs_file_close(&lfs, &files[2]); |  | ||||||
|  |  | ||||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "e") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     info.size => 10; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "g") => 0; |  | ||||||
|     info.type => LFS_TYPE_REG; |  | ||||||
|     info.size => 10; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|  |  | ||||||
|     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 < 10; i++) { |  | ||||||
|         lfs_file_read(&lfs, &files[0], buffer, 1) => 1; |  | ||||||
|         buffer[0] => 'e'; |  | ||||||
|         lfs_file_read(&lfs, &files[1], buffer, 1) => 1; |  | ||||||
|         buffer[0] => 'g'; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &files[0]); |  | ||||||
|     lfs_file_close(&lfs, &files[1]); |  | ||||||
|      |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| scripts/results.py |  | ||||||
| @@ -1,333 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| set -eu |  | ||||||
| export TEST_FILE=$0 |  | ||||||
| trap 'export TEST_LINE=$LINENO' DEBUG |  | ||||||
|  |  | ||||||
| echo "=== Move tests ===" |  | ||||||
| rm -rf blocks |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     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_mkdir(&lfs, "a/hi") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "a/hi/hola") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "a/hi/bonjour") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "a/hi/ohayo") => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_open(&lfs, &file, "a/hello", LFS_O_CREAT | LFS_O_WRONLY) => 0; |  | ||||||
|     lfs_file_write(&lfs, &file, "hola\n", 5) => 5; |  | ||||||
|     lfs_file_write(&lfs, &file, "bonjour\n", 8) => 8; |  | ||||||
|     lfs_file_write(&lfs, &file, "ohayo\n", 6) => 6; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Move file ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_rename(&lfs, "a/hello", "b/hello") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "a") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "hi") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "b") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "hello") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Move file corrupt source ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_rename(&lfs, "b/hello", "c/hello") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/corrupt.py -n 1 |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "b") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "c") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "hello") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Move file corrupt source and dest ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_rename(&lfs, "c/hello", "d/hello") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/corrupt.py -n 2 |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "c") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "hello") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "d") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Move file after corrupt ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_rename(&lfs, "c/hello", "d/hello") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "c") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "d") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "hello") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Move dir ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_rename(&lfs, "a/hi", "b/hi") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "a") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "b") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "hi") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Move dir corrupt source ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_rename(&lfs, "b/hi", "c/hi") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/corrupt.py -n 1 |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "b") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "c") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "hi") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Move dir corrupt source and dest ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_rename(&lfs, "c/hi", "d/hi") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/corrupt.py -n 2 |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "c") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "hi") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "d") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "hello") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Move dir after corrupt ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_rename(&lfs, "c/hi", "d/hi") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "c") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "d") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "hello") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "hi") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Move check ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "b/hi") => LFS_ERR_NOENT; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "c/hi") => LFS_ERR_NOENT; |  | ||||||
|  |  | ||||||
|     lfs_dir_open(&lfs, &dir, "d/hi") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "bonjour") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "hola") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "ohayo") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|  |  | ||||||
|     lfs_dir_open(&lfs, &dir, "a/hello") => LFS_ERR_NOENT; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "b/hello") => LFS_ERR_NOENT; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "c/hello") => LFS_ERR_NOENT; |  | ||||||
|  |  | ||||||
|     lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, 5) => 5; |  | ||||||
|     memcmp(buffer, "hola\n", 5) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, 8) => 8; |  | ||||||
|     memcmp(buffer, "bonjour\n", 8) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, 6) => 6; |  | ||||||
|     memcmp(buffer, "ohayo\n", 6) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Move state stealing ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     lfs_remove(&lfs, "b") => 0; |  | ||||||
|     lfs_remove(&lfs, "c") => 0; |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     lfs_dir_open(&lfs, &dir, "a/hi") => LFS_ERR_NOENT; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "b") => LFS_ERR_NOENT; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "c") => LFS_ERR_NOENT; |  | ||||||
|  |  | ||||||
|     lfs_dir_open(&lfs, &dir, "d/hi") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "bonjour") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "hola") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "ohayo") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|  |  | ||||||
|     lfs_dir_open(&lfs, &dir, "a/hello") => LFS_ERR_NOENT; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "b") => LFS_ERR_NOENT; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "c") => LFS_ERR_NOENT; |  | ||||||
|  |  | ||||||
|     lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, 5) => 5; |  | ||||||
|     memcmp(buffer, "hola\n", 5) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, 8) => 8; |  | ||||||
|     memcmp(buffer, "bonjour\n", 8) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, 6) => 6; |  | ||||||
|     memcmp(buffer, "ohayo\n", 6) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
|  |  | ||||||
| scripts/results.py |  | ||||||
| @@ -1,46 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| set -eu |  | ||||||
| export TEST_FILE=$0 |  | ||||||
| trap 'export TEST_LINE=$LINENO' DEBUG |  | ||||||
|  |  | ||||||
| echo "=== Orphan tests ===" |  | ||||||
| rm -rf blocks |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Orphan test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "parent") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "parent/orphan") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "parent/child") => 0; |  | ||||||
|     lfs_remove(&lfs, "parent/orphan") => 0; |  | ||||||
| TEST |  | ||||||
| # corrupt most recent commit, this should be the update to the previous |  | ||||||
| # linked-list entry and should orphan the child |  | ||||||
| scripts/corrupt.py |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; |  | ||||||
|     lfs_ssize_t before = lfs_fs_size(&lfs); |  | ||||||
|     before => 8; |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; |  | ||||||
|     lfs_ssize_t orphaned = lfs_fs_size(&lfs); |  | ||||||
|     orphaned => 8; |  | ||||||
|  |  | ||||||
|     lfs_mkdir(&lfs, "parent/otherchild") => 0; |  | ||||||
|  |  | ||||||
|     lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT; |  | ||||||
|     lfs_ssize_t deorphaned = lfs_fs_size(&lfs); |  | ||||||
|     deorphaned => 8; |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| scripts/results.py |  | ||||||
| @@ -1,202 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| set -eu |  | ||||||
| export TEST_FILE=$0 |  | ||||||
| trap 'export TEST_LINE=$LINENO' DEBUG |  | ||||||
|  |  | ||||||
| echo "=== Path tests ===" |  | ||||||
| rm -rf blocks |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "tea") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "coffee") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "soda") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "tea/hottea") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "tea/warmtea") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "tea/coldtea") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "coffee/hotcoffee") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "coffee/warmcoffee") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "coffee/coldcoffee") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "soda/hotsoda") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "soda/warmsoda") => 0; |  | ||||||
|     lfs_mkdir(&lfs, "soda/coldsoda") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Root path tests ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_stat(&lfs, "tea/hottea", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|     lfs_stat(&lfs, "/tea/hottea", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|  |  | ||||||
|     lfs_mkdir(&lfs, "/milk1") => 0; |  | ||||||
|     lfs_stat(&lfs, "/milk1", &info) => 0; |  | ||||||
|     strcmp(info.name, "milk1") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Redundant slash path tests ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_stat(&lfs, "/tea/hottea", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|     lfs_stat(&lfs, "//tea//hottea", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|     lfs_stat(&lfs, "///tea///hottea", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|  |  | ||||||
|     lfs_mkdir(&lfs, "///milk2") => 0; |  | ||||||
|     lfs_stat(&lfs, "///milk2", &info) => 0; |  | ||||||
|     strcmp(info.name, "milk2") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Dot path tests ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_stat(&lfs, "./tea/hottea", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|     lfs_stat(&lfs, "/./tea/hottea", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|     lfs_stat(&lfs, "/././tea/hottea", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|     lfs_stat(&lfs, "/./tea/./hottea", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|  |  | ||||||
|     lfs_mkdir(&lfs, "/./milk3") => 0; |  | ||||||
|     lfs_stat(&lfs, "/./milk3", &info) => 0; |  | ||||||
|     strcmp(info.name, "milk3") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Dot dot path tests ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_stat(&lfs, "coffee/../tea/hottea", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|     lfs_stat(&lfs, "tea/coldtea/../hottea", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|     lfs_stat(&lfs, "coffee/coldcoffee/../../tea/hottea", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|     lfs_stat(&lfs, "coffee/../soda/../tea/hottea", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|  |  | ||||||
|     lfs_mkdir(&lfs, "coffee/../milk4") => 0; |  | ||||||
|     lfs_stat(&lfs, "coffee/../milk4", &info) => 0; |  | ||||||
|     strcmp(info.name, "milk4") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Trailing dot path tests ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_stat(&lfs, "tea/hottea/", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|     lfs_stat(&lfs, "tea/hottea/.", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|     lfs_stat(&lfs, "tea/hottea/./.", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|     lfs_stat(&lfs, "tea/hottea/..", &info) => 0; |  | ||||||
|     strcmp(info.name, "tea") => 0; |  | ||||||
|     lfs_stat(&lfs, "tea/hottea/../.", &info) => 0; |  | ||||||
|     strcmp(info.name, "tea") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Root dot dot path tests ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_stat(&lfs, "coffee/../../../../../../tea/hottea", &info) => 0; |  | ||||||
|     strcmp(info.name, "hottea") => 0; |  | ||||||
|  |  | ||||||
|     lfs_mkdir(&lfs, "coffee/../../../../../../milk5") => 0; |  | ||||||
|     lfs_stat(&lfs, "coffee/../../../../../../milk5", &info) => 0; |  | ||||||
|     strcmp(info.name, "milk5") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Root tests ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_stat(&lfs, "/", &info) => 0; |  | ||||||
|     info.type => LFS_TYPE_DIR; |  | ||||||
|     strcmp(info.name, "/") => 0; |  | ||||||
|  |  | ||||||
|     lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; |  | ||||||
|     lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY | LFS_O_CREAT) |  | ||||||
|         => LFS_ERR_ISDIR; |  | ||||||
|  |  | ||||||
|     // more corner cases |  | ||||||
|     lfs_remove(&lfs, "") => LFS_ERR_INVAL; |  | ||||||
|     lfs_remove(&lfs, ".") => LFS_ERR_INVAL; |  | ||||||
|     lfs_remove(&lfs, "..") => LFS_ERR_INVAL; |  | ||||||
|     lfs_remove(&lfs, "/") => LFS_ERR_INVAL; |  | ||||||
|     lfs_remove(&lfs, "//") => LFS_ERR_INVAL; |  | ||||||
|     lfs_remove(&lfs, "./") => LFS_ERR_INVAL; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Sketchy path tests ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "dirt/ground") => LFS_ERR_NOENT; |  | ||||||
|     lfs_mkdir(&lfs, "dirt/ground/earth") => LFS_ERR_NOENT; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Superblock conflict test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "littlefs") => 0; |  | ||||||
|     lfs_remove(&lfs, "littlefs") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Max path test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     memset(path, 'w', LFS_NAME_MAX+1); |  | ||||||
|     path[LFS_NAME_MAX+2] = '\0'; |  | ||||||
|     lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; |  | ||||||
|     lfs_file_open(&lfs, &file, path, |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NAMETOOLONG; |  | ||||||
|  |  | ||||||
|     memcpy(path, "coffee/", strlen("coffee/")); |  | ||||||
|     memset(path+strlen("coffee/"), 'w', LFS_NAME_MAX+1); |  | ||||||
|     path[strlen("coffee/")+LFS_NAME_MAX+2] = '\0'; |  | ||||||
|     lfs_mkdir(&lfs, path) => LFS_ERR_NAMETOOLONG; |  | ||||||
|     lfs_file_open(&lfs, &file, path, |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_NAMETOOLONG; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Really big path test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     memset(path, 'w', LFS_NAME_MAX); |  | ||||||
|     path[LFS_NAME_MAX] = '\0'; |  | ||||||
|     lfs_mkdir(&lfs, path) => 0; |  | ||||||
|     lfs_remove(&lfs, path) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, path, |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_remove(&lfs, path) => 0; |  | ||||||
|  |  | ||||||
|     memcpy(path, "coffee/", strlen("coffee/")); |  | ||||||
|     memset(path+strlen("coffee/"), 'w', LFS_NAME_MAX); |  | ||||||
|     path[strlen("coffee/")+LFS_NAME_MAX] = '\0'; |  | ||||||
|     lfs_mkdir(&lfs, path) => 0; |  | ||||||
|     lfs_remove(&lfs, path) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, path, |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_remove(&lfs, path) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| scripts/results.py |  | ||||||
| @@ -1,139 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| set -eu |  | ||||||
| export TEST_FILE=$0 |  | ||||||
| trap 'export TEST_LINE=$LINENO' DEBUG |  | ||||||
|  |  | ||||||
| ITERATIONS=20 |  | ||||||
| COUNT=10 |  | ||||||
|  |  | ||||||
| echo "=== Relocation tests ===" |  | ||||||
| rm -rf blocks |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|     // fill up filesystem so only ~16 blocks are left |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "padding", LFS_O_CREAT | LFS_O_WRONLY) => 0; |  | ||||||
|     memset(buffer, 0, 512); |  | ||||||
|     while (LFS_BLOCK_COUNT - lfs_fs_size(&lfs) > 16) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, 512) => 512; |  | ||||||
|     } |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     // make a child dir to use in bounded space |  | ||||||
|     lfs_mkdir(&lfs, "child") => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Dangling split dir test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     for (int j = 0; j < $ITERATIONS; j++) { |  | ||||||
|         for (int i = 0; i < $COUNT; i++) { |  | ||||||
|             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_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++) { |  | ||||||
|             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; |  | ||||||
|  |  | ||||||
|         if (j == $ITERATIONS-1) { |  | ||||||
|             break; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         for (int i = 0; i < $COUNT; i++) { |  | ||||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); |  | ||||||
|             lfs_remove(&lfs, path) => 0; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     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++) { |  | ||||||
|         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++) { |  | ||||||
|         sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); |  | ||||||
|         lfs_remove(&lfs, path) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Outdated head test ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     for (int j = 0; j < $ITERATIONS; j++) { |  | ||||||
|         for (int i = 0; i < $COUNT; i++) { |  | ||||||
|             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_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++) { |  | ||||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); |  | ||||||
|             lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|             strcmp(info.name, path) => 0; |  | ||||||
|             info.size => 0; |  | ||||||
|  |  | ||||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); |  | ||||||
|             lfs_file_open(&lfs, &file, path, LFS_O_WRONLY) => 0; |  | ||||||
|             lfs_file_write(&lfs, &file, "hi", 2) => 2; |  | ||||||
|             lfs_file_close(&lfs, &file) => 0; |  | ||||||
|         } |  | ||||||
|         lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|  |  | ||||||
|         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++) { |  | ||||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); |  | ||||||
|             lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|             strcmp(info.name, path) => 0; |  | ||||||
|             info.size => 2; |  | ||||||
|  |  | ||||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); |  | ||||||
|             lfs_file_open(&lfs, &file, path, LFS_O_WRONLY) => 0; |  | ||||||
|             lfs_file_write(&lfs, &file, "hi", 2) => 2; |  | ||||||
|             lfs_file_close(&lfs, &file) => 0; |  | ||||||
|         } |  | ||||||
|         lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|  |  | ||||||
|         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++) { |  | ||||||
|             sprintf(path, "test%03d_loooooooooooooooooong_name", i); |  | ||||||
|             lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|             strcmp(info.name, path) => 0; |  | ||||||
|             info.size => 2; |  | ||||||
|         } |  | ||||||
|         lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|         lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|  |  | ||||||
|         for (int i = 0; i < $COUNT; i++) { |  | ||||||
|             sprintf(path, "child/test%03d_loooooooooooooooooong_name", i); |  | ||||||
|             lfs_remove(&lfs, path) => 0; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| scripts/results.py |  | ||||||
| @@ -1,505 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| set -eu |  | ||||||
| export TEST_FILE=$0 |  | ||||||
| trap 'export TEST_LINE=$LINENO' DEBUG |  | ||||||
|  |  | ||||||
| echo "=== Seek tests ===" |  | ||||||
|  |  | ||||||
| SMALLSIZE=4 |  | ||||||
| MEDIUMSIZE=128 |  | ||||||
| LARGESIZE=132 |  | ||||||
|  |  | ||||||
| rm -rf blocks |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_mkdir(&lfs, "hello") => 0; |  | ||||||
|     for (int i = 0; i < $LARGESIZE; i++) { |  | ||||||
|         sprintf(path, "hello/kitty%03d", i); |  | ||||||
|         lfs_file_open(&lfs, &file, path, |  | ||||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; |  | ||||||
|  |  | ||||||
|         lfs_size_t size = strlen("kittycatcat"); |  | ||||||
|         memcpy(buffer, "kittycatcat", size); |  | ||||||
|         for (int j = 0; j < $LARGESIZE; j++) { |  | ||||||
|             lfs_file_write(&lfs, &file, buffer, size); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Simple dir seek ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "hello") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|  |  | ||||||
|     lfs_soff_t pos; |  | ||||||
|     int i; |  | ||||||
|     for (i = 0; i < $SMALLSIZE; i++) { |  | ||||||
|         sprintf(path, "kitty%03d", i); |  | ||||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|         strcmp(info.name, path) => 0; |  | ||||||
|         pos = lfs_dir_tell(&lfs, &dir); |  | ||||||
|     } |  | ||||||
|     pos >= 0 => 1; |  | ||||||
|  |  | ||||||
|     lfs_dir_seek(&lfs, &dir, pos) => 0; |  | ||||||
|     sprintf(path, "kitty%03d", i); |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, path) => 0; |  | ||||||
|  |  | ||||||
|     lfs_dir_rewind(&lfs, &dir) => 0; |  | ||||||
|     sprintf(path, "kitty%03d", 0); |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, path) => 0; |  | ||||||
|  |  | ||||||
|     lfs_dir_seek(&lfs, &dir, pos) => 0; |  | ||||||
|     sprintf(path, "kitty%03d", i); |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, path) => 0; |  | ||||||
|  |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Large dir seek ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_dir_open(&lfs, &dir, "hello") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|  |  | ||||||
|     lfs_soff_t pos; |  | ||||||
|     int i; |  | ||||||
|     for (i = 0; i < $MEDIUMSIZE; i++) { |  | ||||||
|         sprintf(path, "kitty%03d", i); |  | ||||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|         strcmp(info.name, path) => 0; |  | ||||||
|         pos = lfs_dir_tell(&lfs, &dir); |  | ||||||
|     } |  | ||||||
|     pos >= 0 => 1; |  | ||||||
|  |  | ||||||
|     lfs_dir_seek(&lfs, &dir, pos) => 0; |  | ||||||
|     sprintf(path, "kitty%03d", i); |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, path) => 0; |  | ||||||
|  |  | ||||||
|     lfs_dir_rewind(&lfs, &dir) => 0; |  | ||||||
|     sprintf(path, "kitty%03d", 0); |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, ".") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, "..") => 0; |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, path) => 0; |  | ||||||
|  |  | ||||||
|     lfs_dir_seek(&lfs, &dir, pos) => 0; |  | ||||||
|     sprintf(path, "kitty%03d", i); |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|     strcmp(info.name, path) => 0; |  | ||||||
|  |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Simple file seek ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "hello/kitty042", LFS_O_RDONLY) => 0; |  | ||||||
|  |  | ||||||
|     lfs_soff_t pos; |  | ||||||
|     lfs_size_t size = strlen("kittycatcat"); |  | ||||||
|     for (int i = 0; i < $SMALLSIZE; i++) { |  | ||||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|         memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|         pos = lfs_file_tell(&lfs, &file); |  | ||||||
|     } |  | ||||||
|     pos >= 0 => 1; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_rewind(&lfs, &file) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, size, LFS_SEEK_CUR) => 3*size; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, -size, LFS_SEEK_CUR) => pos; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     size = lfs_file_size(&lfs, &file); |  | ||||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Large file seek ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "hello/kitty042", LFS_O_RDONLY) => 0; |  | ||||||
|  |  | ||||||
|     lfs_soff_t pos; |  | ||||||
|     lfs_size_t size = strlen("kittycatcat"); |  | ||||||
|     for (int i = 0; i < $MEDIUMSIZE; i++) { |  | ||||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|         memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|         pos = lfs_file_tell(&lfs, &file); |  | ||||||
|     } |  | ||||||
|     pos >= 0 => 1; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_rewind(&lfs, &file) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, size, LFS_SEEK_CUR) => 3*size; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, -size, LFS_SEEK_CUR) => pos; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     size = lfs_file_size(&lfs, &file); |  | ||||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Simple file seek and write ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "hello/kitty042", LFS_O_RDWR) => 0; |  | ||||||
|  |  | ||||||
|     lfs_soff_t pos; |  | ||||||
|     lfs_size_t size = strlen("kittycatcat"); |  | ||||||
|     for (int i = 0; i < $SMALLSIZE; i++) { |  | ||||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|         memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|         pos = lfs_file_tell(&lfs, &file); |  | ||||||
|     } |  | ||||||
|     pos >= 0 => 1; |  | ||||||
|  |  | ||||||
|     memcpy(buffer, "doggodogdog", size); |  | ||||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; |  | ||||||
|     lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "doggodogdog", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_rewind(&lfs, &file) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "doggodogdog", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     size = lfs_file_size(&lfs, &file); |  | ||||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Large file seek and write ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "hello/kitty042", LFS_O_RDWR) => 0; |  | ||||||
|  |  | ||||||
|     lfs_soff_t pos; |  | ||||||
|     lfs_size_t size = strlen("kittycatcat"); |  | ||||||
|     for (int i = 0; i < $MEDIUMSIZE; i++) { |  | ||||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|         if (i != $SMALLSIZE) { |  | ||||||
|             memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|         } |  | ||||||
|         pos = lfs_file_tell(&lfs, &file); |  | ||||||
|     } |  | ||||||
|     pos >= 0 => 1; |  | ||||||
|  |  | ||||||
|     memcpy(buffer, "doggodogdog", size); |  | ||||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; |  | ||||||
|     lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "doggodogdog", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_rewind(&lfs, &file) => 0; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, pos, LFS_SEEK_SET) => pos; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "doggodogdog", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, -size, LFS_SEEK_END) >= 0 => 1; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|     size = lfs_file_size(&lfs, &file); |  | ||||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_CUR) => size; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Boundary seek and write ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "hello/kitty042", LFS_O_RDWR) => 0; |  | ||||||
|  |  | ||||||
|     lfs_size_t size = strlen("hedgehoghog"); |  | ||||||
|     const lfs_soff_t offsets[] = {512, 1020, 513, 1021, 511, 1019}; |  | ||||||
|  |  | ||||||
|     for (unsigned i = 0; i < sizeof(offsets) / sizeof(offsets[0]); i++) { |  | ||||||
|         lfs_soff_t off = offsets[i]; |  | ||||||
|         memcpy(buffer, "hedgehoghog", size); |  | ||||||
|         lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|         lfs_file_seek(&lfs, &file, off, LFS_SEEK_SET) => off; |  | ||||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|         memcmp(buffer, "hedgehoghog", size) => 0; |  | ||||||
|  |  | ||||||
|         lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; |  | ||||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|         memcmp(buffer, "kittycatcat", size) => 0; |  | ||||||
|  |  | ||||||
|         lfs_file_sync(&lfs, &file) => 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Out-of-bounds seek ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "hello/kitty042", LFS_O_RDWR) => 0; |  | ||||||
|  |  | ||||||
|     lfs_size_t size = strlen("kittycatcat"); |  | ||||||
|     lfs_file_size(&lfs, &file) => $LARGESIZE*size; |  | ||||||
|     lfs_file_seek(&lfs, &file, ($LARGESIZE+$SMALLSIZE)*size, |  | ||||||
|             LFS_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => 0; |  | ||||||
|  |  | ||||||
|     memcpy(buffer, "porcupineee", size); |  | ||||||
|     lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, ($LARGESIZE+$SMALLSIZE)*size, |  | ||||||
|             LFS_SEEK_SET) => ($LARGESIZE+$SMALLSIZE)*size; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "porcupineee", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, $LARGESIZE*size, |  | ||||||
|             LFS_SEEK_SET) => $LARGESIZE*size; |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|     memcmp(buffer, "\0\0\0\0\0\0\0\0\0\0\0", size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, -(($LARGESIZE+$SMALLSIZE)*size), |  | ||||||
|             LFS_SEEK_CUR) => LFS_ERR_INVAL; |  | ||||||
|     lfs_file_tell(&lfs, &file) => ($LARGESIZE+1)*size; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, -(($LARGESIZE+2*$SMALLSIZE)*size), |  | ||||||
|             LFS_SEEK_END) => LFS_ERR_INVAL; |  | ||||||
|     lfs_file_tell(&lfs, &file) => ($LARGESIZE+1)*size; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Inline write and seek ---" |  | ||||||
| for SIZE in $SMALLSIZE $MEDIUMSIZE $LARGESIZE |  | ||||||
| do |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "hello/tinykitty$SIZE", |  | ||||||
|             LFS_O_RDWR | LFS_O_CREAT) => 0; |  | ||||||
|     int j = 0; |  | ||||||
|     int k = 0; |  | ||||||
|  |  | ||||||
|     memcpy(buffer, "abcdefghijklmnopqrstuvwxyz", 26); |  | ||||||
|     for (unsigned i = 0; i < $SIZE; i++) { |  | ||||||
|         lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1; |  | ||||||
|         lfs_file_tell(&lfs, &file) => i+1; |  | ||||||
|         lfs_file_size(&lfs, &file) => i+1; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; |  | ||||||
|     lfs_file_tell(&lfs, &file) => 0; |  | ||||||
|     lfs_file_size(&lfs, &file) => $SIZE; |  | ||||||
|     for (unsigned i = 0; i < $SIZE; i++) { |  | ||||||
|         uint8_t c; |  | ||||||
|         lfs_file_read(&lfs, &file, &c, 1) => 1; |  | ||||||
|         c => buffer[k++ % 26]; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_file_sync(&lfs, &file) => 0; |  | ||||||
|     lfs_file_tell(&lfs, &file) => $SIZE; |  | ||||||
|     lfs_file_size(&lfs, &file) => $SIZE; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; |  | ||||||
|     for (unsigned i = 0; i < $SIZE; i++) { |  | ||||||
|         lfs_file_write(&lfs, &file, &buffer[j++ % 26], 1) => 1; |  | ||||||
|         lfs_file_tell(&lfs, &file) => i+1; |  | ||||||
|         lfs_file_size(&lfs, &file) => $SIZE; |  | ||||||
|         lfs_file_sync(&lfs, &file) => 0; |  | ||||||
|         lfs_file_tell(&lfs, &file) => i+1; |  | ||||||
|         lfs_file_size(&lfs, &file) => $SIZE; |  | ||||||
|         if (i < $SIZE-2) { |  | ||||||
|             uint8_t c[3]; |  | ||||||
|             lfs_file_seek(&lfs, &file, -1, LFS_SEEK_CUR) => i; |  | ||||||
|             lfs_file_read(&lfs, &file, &c, 3) => 3; |  | ||||||
|             lfs_file_tell(&lfs, &file) => i+3; |  | ||||||
|             lfs_file_size(&lfs, &file) => $SIZE; |  | ||||||
|             lfs_file_seek(&lfs, &file, i+1, LFS_SEEK_SET) => i+1; |  | ||||||
|             lfs_file_tell(&lfs, &file) => i+1; |  | ||||||
|             lfs_file_size(&lfs, &file) => $SIZE; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; |  | ||||||
|     lfs_file_tell(&lfs, &file) => 0; |  | ||||||
|     lfs_file_size(&lfs, &file) => $SIZE; |  | ||||||
|     for (unsigned i = 0; i < $SIZE; i++) { |  | ||||||
|         uint8_t c; |  | ||||||
|         lfs_file_read(&lfs, &file, &c, 1) => 1; |  | ||||||
|         c => buffer[k++ % 26]; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_file_sync(&lfs, &file) => 0; |  | ||||||
|     lfs_file_tell(&lfs, &file) => $SIZE; |  | ||||||
|     lfs_file_size(&lfs, &file) => $SIZE; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| done |  | ||||||
|  |  | ||||||
| echo "--- Root seek test ---" |  | ||||||
| ./scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     for (int i = 3; i < $MEDIUMSIZE; i++) { |  | ||||||
|         sprintf(path, "hi%03d", i); |  | ||||||
|         lfs_mkdir(&lfs, path) => 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_dir_open(&lfs, &dir, "/") => 0; |  | ||||||
|     for (int i = 0; i < $MEDIUMSIZE; i++) { |  | ||||||
|         if (i == 0) { |  | ||||||
|             sprintf(path, "."); |  | ||||||
|         } else if (i == 1) { |  | ||||||
|             sprintf(path, ".."); |  | ||||||
|         } else if (i == 2) { |  | ||||||
|             sprintf(path, "hello"); |  | ||||||
|         } else { |  | ||||||
|             sprintf(path, "hi%03d", i); |  | ||||||
|         } |  | ||||||
|         lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|         strcmp(path, info.name) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|     lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|  |  | ||||||
|     for (int j = 0; j < $MEDIUMSIZE; j++) { |  | ||||||
|         lfs_soff_t off = -1; |  | ||||||
|  |  | ||||||
|         lfs_dir_open(&lfs, &dir, "/") => 0; |  | ||||||
|         for (int i = 0; i < $MEDIUMSIZE; i++) { |  | ||||||
|             if (i == 0) { |  | ||||||
|                 sprintf(path, "."); |  | ||||||
|             } else if (i == 1) { |  | ||||||
|                 sprintf(path, ".."); |  | ||||||
|             } else if (i == 2) { |  | ||||||
|                 sprintf(path, "hello"); |  | ||||||
|             } else { |  | ||||||
|                 sprintf(path, "hi%03d", i); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if (i == j) { |  | ||||||
|                 off = lfs_dir_tell(&lfs, &dir); |  | ||||||
|                 off >= 0 => true; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|             strcmp(path, info.name) => 0; |  | ||||||
|         } |  | ||||||
|         lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|         lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|  |  | ||||||
|         lfs_dir_open(&lfs, &dir, "/") => 0; |  | ||||||
|         lfs_dir_seek(&lfs, &dir, off) => 0; |  | ||||||
|         for (int i = j; i < $MEDIUMSIZE; i++) { |  | ||||||
|             if (i == 0) { |  | ||||||
|                 sprintf(path, "."); |  | ||||||
|             } else if (i == 1) { |  | ||||||
|                 sprintf(path, ".."); |  | ||||||
|             } else if (i == 2) { |  | ||||||
|                 sprintf(path, "hello"); |  | ||||||
|             } else { |  | ||||||
|                 sprintf(path, "hi%03d", i); |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             lfs_dir_read(&lfs, &dir, &info) => 1; |  | ||||||
|             strcmp(path, info.name) => 0; |  | ||||||
|         } |  | ||||||
|         lfs_dir_read(&lfs, &dir, &info) => 0; |  | ||||||
|         lfs_dir_close(&lfs, &dir) => 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| scripts/results.py |  | ||||||
| @@ -1,355 +0,0 @@ | |||||||
| #!/bin/bash |  | ||||||
| set -eu |  | ||||||
| export TEST_FILE=$0 |  | ||||||
| trap 'export TEST_LINE=$LINENO' DEBUG |  | ||||||
|  |  | ||||||
| echo "=== Truncate tests ===" |  | ||||||
|  |  | ||||||
| SMALLSIZE=32 |  | ||||||
| MEDIUMSIZE=2048 |  | ||||||
| LARGESIZE=8192 |  | ||||||
|  |  | ||||||
| rm -rf blocks |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_format(&lfs, &cfg) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Simple truncate ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "baldynoop", |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|  |  | ||||||
|     strcpy((char*)buffer, "hair"); |  | ||||||
|     lfs_size_t size = strlen((char*)buffer); |  | ||||||
|     for (lfs_off_t j = 0; j < $LARGESIZE; j += size) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_size(&lfs, &file) => $LARGESIZE; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDWR) => 0; |  | ||||||
|     lfs_file_size(&lfs, &file) => $LARGESIZE; |  | ||||||
|  |  | ||||||
|     lfs_file_truncate(&lfs, &file, $MEDIUMSIZE) => 0; |  | ||||||
|     lfs_file_size(&lfs, &file) => $MEDIUMSIZE; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "baldynoop", LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_file_size(&lfs, &file) => $MEDIUMSIZE; |  | ||||||
|  |  | ||||||
|     lfs_size_t size = strlen("hair"); |  | ||||||
|     for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) { |  | ||||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|         memcmp(buffer, "hair", size) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Truncate and read ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "baldyread", |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|  |  | ||||||
|     strcpy((char*)buffer, "hair"); |  | ||||||
|     lfs_size_t size = strlen((char*)buffer); |  | ||||||
|     for (lfs_off_t j = 0; j < $LARGESIZE; j += size) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_size(&lfs, &file) => $LARGESIZE; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDWR) => 0; |  | ||||||
|     lfs_file_size(&lfs, &file) => $LARGESIZE; |  | ||||||
|  |  | ||||||
|     lfs_file_truncate(&lfs, &file, $MEDIUMSIZE) => 0; |  | ||||||
|     lfs_file_size(&lfs, &file) => $MEDIUMSIZE; |  | ||||||
|  |  | ||||||
|     lfs_size_t size = strlen("hair"); |  | ||||||
|     for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) { |  | ||||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|         memcmp(buffer, "hair", size) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "baldyread", LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_file_size(&lfs, &file) => $MEDIUMSIZE; |  | ||||||
|  |  | ||||||
|     lfs_size_t size = strlen("hair"); |  | ||||||
|     for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) { |  | ||||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|         memcmp(buffer, "hair", size) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Write, truncate, and read ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "sequence", |  | ||||||
|             LFS_O_RDWR | LFS_O_CREAT | LFS_O_TRUNC) => 0; |  | ||||||
|  |  | ||||||
|     lfs_size_t size = lfs.cfg->cache_size; |  | ||||||
|     lfs_size_t qsize = size / 4; |  | ||||||
|     uint8_t *wb = buffer; |  | ||||||
|     uint8_t *rb = buffer + size; |  | ||||||
|     for (lfs_off_t j = 0; j < size; ++j) { |  | ||||||
|         wb[j] = j; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     /* Spread sequence over size */ |  | ||||||
|     lfs_file_write(&lfs, &file, wb, size) => size; |  | ||||||
|     lfs_file_size(&lfs, &file) => size; |  | ||||||
|     lfs_file_tell(&lfs, &file) => size; |  | ||||||
|  |  | ||||||
|     lfs_file_seek(&lfs, &file, 0, LFS_SEEK_SET) => 0; |  | ||||||
|     lfs_file_tell(&lfs, &file) => 0; |  | ||||||
|  |  | ||||||
|     /* Chop off the last quarter */ |  | ||||||
|     lfs_size_t trunc = size - qsize; |  | ||||||
|     lfs_file_truncate(&lfs, &file, trunc) => 0; |  | ||||||
|     lfs_file_tell(&lfs, &file) => 0; |  | ||||||
|     lfs_file_size(&lfs, &file) => trunc; |  | ||||||
|  |  | ||||||
|     /* Read should produce first 3/4 */ |  | ||||||
|     lfs_file_read(&lfs, &file, rb, size) => trunc; |  | ||||||
|     memcmp(rb, wb, trunc) => 0; |  | ||||||
|  |  | ||||||
|     /* Move to 1/4 */ |  | ||||||
|     lfs_file_size(&lfs, &file) => trunc; |  | ||||||
|     lfs_file_seek(&lfs, &file, qsize, LFS_SEEK_SET) => qsize; |  | ||||||
|     lfs_file_tell(&lfs, &file) => qsize; |  | ||||||
|  |  | ||||||
|     /* Chop to 1/2 */ |  | ||||||
|     trunc -= qsize; |  | ||||||
|     lfs_file_truncate(&lfs, &file, trunc) => 0; |  | ||||||
|     lfs_file_tell(&lfs, &file) => qsize; |  | ||||||
|     lfs_file_size(&lfs, &file) => trunc; |  | ||||||
|      |  | ||||||
|     /* Read should produce second quarter */ |  | ||||||
|     lfs_file_read(&lfs, &file, rb, size) => trunc - qsize; |  | ||||||
|     memcmp(rb, wb + qsize, trunc - qsize) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| echo "--- Truncate and write ---" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "baldywrite", |  | ||||||
|             LFS_O_WRONLY | LFS_O_CREAT) => 0; |  | ||||||
|  |  | ||||||
|     strcpy((char*)buffer, "hair"); |  | ||||||
|     lfs_size_t size = strlen((char*)buffer); |  | ||||||
|     for (lfs_off_t j = 0; j < $LARGESIZE; j += size) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_size(&lfs, &file) => $LARGESIZE; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDWR) => 0; |  | ||||||
|     lfs_file_size(&lfs, &file) => $LARGESIZE; |  | ||||||
|  |  | ||||||
|     lfs_file_truncate(&lfs, &file, $MEDIUMSIZE) => 0; |  | ||||||
|     lfs_file_size(&lfs, &file) => $MEDIUMSIZE; |  | ||||||
|  |  | ||||||
|     strcpy((char*)buffer, "bald"); |  | ||||||
|     lfs_size_t size = strlen((char*)buffer); |  | ||||||
|     for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) { |  | ||||||
|         lfs_file_write(&lfs, &file, buffer, size) => size; |  | ||||||
|     } |  | ||||||
|     lfs_file_size(&lfs, &file) => $MEDIUMSIZE; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|     lfs_file_open(&lfs, &file, "baldywrite", LFS_O_RDONLY) => 0; |  | ||||||
|     lfs_file_size(&lfs, &file) => $MEDIUMSIZE; |  | ||||||
|  |  | ||||||
|     lfs_size_t size = strlen("bald"); |  | ||||||
|     for (lfs_off_t j = 0; j < $MEDIUMSIZE; j += size) { |  | ||||||
|         lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|         memcmp(buffer, "bald", size) => 0; |  | ||||||
|     } |  | ||||||
|     lfs_file_read(&lfs, &file, buffer, size) => 0; |  | ||||||
|  |  | ||||||
|     lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
|  |  | ||||||
| # More aggressive general truncation tests |  | ||||||
| truncate_test() { |  | ||||||
| STARTSIZES="$1" |  | ||||||
| STARTSEEKS="$2" |  | ||||||
| HOTSIZES="$3" |  | ||||||
| COLDSIZES="$4" |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     static const lfs_off_t startsizes[] = {$STARTSIZES}; |  | ||||||
|     static const lfs_off_t startseeks[] = {$STARTSEEKS}; |  | ||||||
|     static const lfs_off_t hotsizes[]   = {$HOTSIZES}; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { |  | ||||||
|         sprintf(path, "hairyhead%d", i); |  | ||||||
|         lfs_file_open(&lfs, &file, path, |  | ||||||
|                 LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0; |  | ||||||
|  |  | ||||||
|         strcpy((char*)buffer, "hair"); |  | ||||||
|         lfs_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; |  | ||||||
|         } |  | ||||||
|         lfs_file_size(&lfs, &file) => startsizes[i]; |  | ||||||
|  |  | ||||||
|         if (startseeks[i] != startsizes[i]) { |  | ||||||
|             lfs_file_seek(&lfs, &file, |  | ||||||
|                     startseeks[i], LFS_SEEK_SET) => startseeks[i]; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         lfs_file_truncate(&lfs, &file, hotsizes[i]) => 0; |  | ||||||
|         lfs_file_size(&lfs, &file) => hotsizes[i]; |  | ||||||
|  |  | ||||||
|         lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     static const lfs_off_t startsizes[] = {$STARTSIZES}; |  | ||||||
|     static const lfs_off_t hotsizes[]   = {$HOTSIZES}; |  | ||||||
|     static const lfs_off_t coldsizes[]  = {$COLDSIZES}; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { |  | ||||||
|         sprintf(path, "hairyhead%d", i); |  | ||||||
|         lfs_file_open(&lfs, &file, path, LFS_O_RDWR) => 0; |  | ||||||
|         lfs_file_size(&lfs, &file) => hotsizes[i]; |  | ||||||
|  |  | ||||||
|         lfs_size_t size = strlen("hair"); |  | ||||||
|         lfs_off_t j = 0; |  | ||||||
|         for (; j < startsizes[i] && j < hotsizes[i]; j += size) { |  | ||||||
|             lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|             memcmp(buffer, "hair", size) => 0; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         for (; j < hotsizes[i]; j += size) { |  | ||||||
|             lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|             memcmp(buffer, "\0\0\0\0", size) => 0; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         lfs_file_truncate(&lfs, &file, coldsizes[i]) => 0; |  | ||||||
|         lfs_file_size(&lfs, &file) => coldsizes[i]; |  | ||||||
|  |  | ||||||
|         lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| scripts/test.py << TEST |  | ||||||
|     static const lfs_off_t startsizes[] = {$STARTSIZES}; |  | ||||||
|     static const lfs_off_t hotsizes[]   = {$HOTSIZES}; |  | ||||||
|     static const lfs_off_t coldsizes[]  = {$COLDSIZES}; |  | ||||||
|  |  | ||||||
|     lfs_mount(&lfs, &cfg) => 0; |  | ||||||
|  |  | ||||||
|     for (unsigned i = 0; i < sizeof(startsizes)/sizeof(startsizes[0]); i++) { |  | ||||||
|         sprintf(path, "hairyhead%d", i); |  | ||||||
|         lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; |  | ||||||
|         lfs_file_size(&lfs, &file) => coldsizes[i]; |  | ||||||
|  |  | ||||||
|         lfs_size_t size = strlen("hair"); |  | ||||||
|         lfs_off_t j = 0; |  | ||||||
|         for (; j < startsizes[i] && j < hotsizes[i] && j < coldsizes[i]; |  | ||||||
|                 j += size) { |  | ||||||
|             lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|             memcmp(buffer, "hair", size) => 0; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         for (; j < coldsizes[i]; j += size) { |  | ||||||
|             lfs_file_read(&lfs, &file, buffer, size) => size; |  | ||||||
|             memcmp(buffer, "\0\0\0\0", size) => 0; |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         lfs_file_close(&lfs, &file) => 0; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     lfs_unmount(&lfs) => 0; |  | ||||||
| TEST |  | ||||||
| } |  | ||||||
|  |  | ||||||
| echo "--- Cold shrinking truncate ---" |  | ||||||
| truncate_test \ |  | ||||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" |  | ||||||
|  |  | ||||||
| echo "--- Cold expanding truncate ---" |  | ||||||
| truncate_test \ |  | ||||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" |  | ||||||
|  |  | ||||||
| echo "--- Warm shrinking truncate ---" |  | ||||||
| truncate_test \ |  | ||||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "           0,            0,            0,            0,            0" |  | ||||||
|  |  | ||||||
| echo "--- Warm expanding truncate ---" |  | ||||||
| truncate_test \ |  | ||||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" |  | ||||||
|  |  | ||||||
| echo "--- Mid-file shrinking truncate ---" |  | ||||||
| truncate_test \ |  | ||||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "  $LARGESIZE,   $LARGESIZE,   $LARGESIZE,   $LARGESIZE,   $LARGESIZE" \ |  | ||||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "           0,            0,            0,            0,            0" |  | ||||||
|  |  | ||||||
| echo "--- Mid-file expanding truncate ---" |  | ||||||
| truncate_test \ |  | ||||||
|     "           0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "           0,            0,   $SMALLSIZE,  $MEDIUMSIZE,   $LARGESIZE" \ |  | ||||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" \ |  | ||||||
|     "2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE, 2*$LARGESIZE" |  | ||||||
|  |  | ||||||
| scripts/results.py |  | ||||||
		Reference in New Issue
	
	Block a user