From 1d2688a7714d2d0d560dc47acc87b19ed03dba9f Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Sat, 11 Jan 2020 15:58:17 -0600 Subject: [PATCH] Migrated test_files, test_dirs, test_format suites to new framework Also some tweaks to test_.py to capture Makefile warnings and print test locations a bit better. --- scripts/test_.py | 54 +++- tests_/test_dirs.toml | 638 +++++++++++++++++++++++++++++++++++----- tests_/test_files.toml | 486 ++++++++++++++++++++++++++++++ tests_/test_format.toml | 105 +++++++ 4 files changed, 1201 insertions(+), 82 deletions(-) create mode 100644 tests_/test_files.toml create mode 100644 tests_/test_format.toml diff --git a/scripts/test_.py b/scripts/test_.py index 27002d9..2f016e4 100755 --- a/scripts/test_.py +++ b/scripts/test_.py @@ -62,8 +62,10 @@ PROLOGUE = """ __attribute__((unused)) lfs_file_t file; __attribute__((unused)) lfs_dir_t dir; __attribute__((unused)) struct lfs_info info; - __attribute__((unused)) uint8_t buffer[1024]; __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 = LFS_DISK ? (void*)&filebd : (void*)&rambd, @@ -124,9 +126,11 @@ class TestCase: def __str__(self): if hasattr(self, 'permno'): - return '%s[%d,%d]' % (self.suite.name, self.caseno, self.permno) + return '%s[%d,%d]' % ( + self.suite.name, self.caseno, self.permno) else: - return '%s[%d]' % (self.suite.name, self.caseno) + return '%s[%d]' % ( + self.suite.name, self.caseno) def permute(self, defines, permno=None, **_): ncase = copy.copy(self) @@ -211,7 +215,10 @@ class TestCase: if args.get('verbose', False): sys.stdout.write(line) # intercept asserts - m = re.match('^([^:]+):([0-9]+):(assert): (.*)$', line) + 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: @@ -221,7 +228,7 @@ class TestCase: 'path': m.group(1), 'line': line, 'lineno': lineno, - 'message': m.group(4)} + 'message': m.group(3)} except: pass proc.wait() @@ -385,7 +392,7 @@ class TestSuite: self.defines = {} for k, v in self.perms[0].defines.items(): - if all(perm.defines[k] == v for perm in self.perms): + if all(perm.defines.get(k, None) == v for perm in self.perms): self.defines[k] = v return self.perms @@ -401,7 +408,7 @@ class TestSuite: f.write('\n') f.write('int main(int argc, char **argv) {\n') - f.write(4*' '+'int case_ = (argc >= 3) ? atoi(argv[1]) : 0;\n') + f.write(4*' '+'int case_ = (argc >= 2) ? atoi(argv[1]) : 0;\n') f.write(4*' '+'int perm = (argc >= 3) ? atoi(argv[2]) : 0;\n') f.write(4*' '+'LFS_DISK = (argc >= 4) ? argv[3] : NULL;\n') for perm in self.perms: @@ -544,6 +551,23 @@ def main(**args): 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: @@ -587,12 +611,20 @@ def main(**args): if perm.result == PASS: passed += 1 else: - sys.stdout.write("--- %s ---\n" % perm) - if perm.result.assert_: - for line in perm.result.stdout[:-1]: + #sys.stdout.write("--- %s ---\n" % perm) + 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-2, + 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[97m{path}:{lineno}:\033[91massert:\033[0m " + "\033[01m{path}:{lineno}:\033[01;31massert:\033[m " "{message}\n{line}\n".format( **perm.result.assert_)) else: diff --git a/tests_/test_dirs.toml b/tests_/test_dirs.toml index 41789d5..e3e0453 100644 --- a/tests_/test_dirs.toml +++ b/tests_/test_dirs.toml @@ -1,54 +1,179 @@ -[[case]] # format -code = """ - lfs_format(&lfs, &cfg) => 0; -""" - -[[case]] # mount/unmount -code = """ +[[case]] # root +code = ''' lfs_format(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0; + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; -""" +''' -[[case]] # reentrant format -code = """ - int err = lfs_mount(&lfs, &cfg); +[[case]] # many directory creation +code = ''' + lfs_format(&lfs, &cfg) => 0; + + lfs_mount(&lfs, &cfg) => 0; + for (int i = 0; i < N; i++) { + sprintf(path, "dir%03d", i); + lfs_mkdir(&lfs, path) => 0; + } + lfs_unmount(&lfs) => 0; + + lfs_mount(&lfs, &cfg) => 0; + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + for (int i = 0; i < N; i++) { + sprintf(path, "dir%03d", i); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, path) == 0); + } + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_unmount(&lfs) => 0; +''' +define.N = 'range(0, 100, 3)' + +[[case]] # many directory removal +code = ''' + lfs_format(&lfs, &cfg) => 0; + + lfs_mount(&lfs, &cfg) => 0; + for (int i = 0; i < N; i++) { + sprintf(path, "removeme%03d", i); + lfs_mkdir(&lfs, path) => 0; + } + lfs_unmount(&lfs) => 0; + + lfs_mount(&lfs, &cfg) => 0; + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + for (int i = 0; i < N; i++) { + sprintf(path, "removeme%03d", i); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, path) == 0); + } + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_unmount(&lfs); + + lfs_mount(&lfs, &cfg) => 0; + for (int i = 0; i < N; i++) { + sprintf(path, "removeme%03d", i); + lfs_remove(&lfs, path) => 0; + } + lfs_unmount(&lfs); + + lfs_mount(&lfs, &cfg) => 0; + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_unmount(&lfs) => 0; +''' +define.N = 'range(3, 100, 11)' + +[[case]] # many directory rename +code = ''' + lfs_format(&lfs, &cfg) => 0; + + lfs_mount(&lfs, &cfg) => 0; + for (int i = 0; i < N; i++) { + sprintf(path, "test%03d", i); + lfs_mkdir(&lfs, path) => 0; + } + lfs_unmount(&lfs) => 0; + + lfs_mount(&lfs, &cfg) => 0; + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + for (int i = 0; i < N; i++) { + sprintf(path, "test%03d", i); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, path) == 0); + } + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_unmount(&lfs); + + lfs_mount(&lfs, &cfg) => 0; + for (int i = 0; i < N; i++) { + char oldpath[128]; + char newpath[128]; + sprintf(oldpath, "test%03d", i); + sprintf(newpath, "tedd%03d", i); + lfs_rename(&lfs, oldpath, newpath) => 0; + } + lfs_unmount(&lfs); + + lfs_mount(&lfs, &cfg) => 0; + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + for (int i = 0; i < N; i++) { + sprintf(path, "tedd%03d", i); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, path) == 0); + } + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_unmount(&lfs); +''' +define.N = 'range(3, 100, 11)' + +[[case]] # reentrant many directory creation/rename/removal +code = ''' + err = lfs_mount(&lfs, &cfg); if (err) { lfs_format(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0; } - lfs_unmount(&lfs) => 0; -""" -reentrant = true -[[case]] # root -code = """ - lfs_format(&lfs, &cfg) => 0; - lfs_mount(&lfs, &cfg) => 0; - lfs_dir_open(&lfs, &dir, "/") => 0; - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, ".") == 0); - lfs_dir_read(&lfs, &dir, &info) => 1; - assert(info.type == LFS_TYPE_DIR); - assert(strcmp(info.name, "..") == 0); - lfs_dir_read(&lfs, &dir, &info) => 0; - lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; -""" - -[[case]] # directory creation -code = """ - lfs_format(&lfs, &cfg) => 0; - - lfs_mount(&lfs, &cfg) => 0; for (int i = 0; i < N; i++) { - sprintf(path, "dir%03d", i); - lfs_mkdir(&lfs, path) => 0; + sprintf(path, "hi%03d", i); + err = lfs_mkdir(&lfs, path); + assert(err == 0 || err == LFS_ERR_EXIST); + } + + for (int i = 0; i < N; i++) { + sprintf(path, "hello%03d", i); + err = lfs_remove(&lfs, path); + assert(err == 0 || err == LFS_ERR_NOENT); } - lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -57,29 +182,23 @@ code = """ assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { - sprintf(path, "dir%03d", i); + sprintf(path, "hi%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, path) == 0); } lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs) => 0; -""" -define.N = 'range(0, 100, 3)' -[[case]] # directory removal -code = """ - lfs_format(&lfs, &cfg) => 0; - - lfs_mount(&lfs, &cfg) => 0; for (int i = 0; i < N; i++) { - sprintf(path, "removeme%03d", i); - lfs_mkdir(&lfs, path) => 0; + char oldpath[128]; + char newpath[128]; + sprintf(oldpath, "hi%03d", i); + sprintf(newpath, "hello%03d", i); + // YES this can overwrite an existing newpath + lfs_rename(&lfs, oldpath, newpath) => 0; } - lfs_unmount(&lfs) => 0; - lfs_mount(&lfs, &cfg) => 0; lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -88,23 +207,19 @@ code = """ assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, "..") == 0); for (int i = 0; i < N; i++) { - sprintf(path, "removeme%03d", i); + sprintf(path, "hello%03d", i); lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); assert(strcmp(info.name, path) == 0); } lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_close(&lfs, &dir) => 0; - lfs_unmount(&lfs); - lfs_mount(&lfs, &cfg) => 0; for (int i = 0; i < N; i++) { - sprintf(path, "removeme%03d", i); + sprintf(path, "hello%03d", i); lfs_remove(&lfs, path) => 0; } - lfs_unmount(&lfs); - lfs_mount(&lfs, &cfg) => 0; lfs_dir_open(&lfs, &dir, "/") => 0; lfs_dir_read(&lfs, &dir, &info) => 1; assert(info.type == LFS_TYPE_DIR); @@ -115,19 +230,21 @@ code = """ lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; -""" -define.N = 'range(3, 100, 11)' +''' +define.N = [5, 25] +reentrant = true [[case]] # file creation -code = """ +code = ''' lfs_format(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0; for (int i = 0; i < N; i++) { sprintf(path, "file%03d", i); - lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfs_file_close(&lfs, &file) => 0; - } + } lfs_unmount(&lfs) => 0; lfs_mount(&lfs, &cfg) => 0; @@ -147,17 +264,18 @@ code = """ lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs); -""" +''' define.N = 'range(3, 100, 11)' [[case]] # file removal -code = """ +code = ''' lfs_format(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0; for (int i = 0; i < N; i++) { sprintf(path, "removeme%03d", i); - lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfs_file_close(&lfs, &file) => 0; } lfs_unmount(&lfs) => 0; @@ -198,23 +316,401 @@ code = """ lfs_dir_read(&lfs, &dir, &info) => 0; lfs_dir_close(&lfs, &dir) => 0; lfs_unmount(&lfs) => 0; -""" +''' define.N = 'range(0, 100, 3)' -[[case]] # error cases -code = """ +[[case]] # file rename +code = ''' + lfs_format(&lfs, &cfg) => 0; + + lfs_mount(&lfs, &cfg) => 0; + for (int i = 0; i < N; i++) { + sprintf(path, "test%03d", i); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + } + lfs_unmount(&lfs) => 0; + + lfs_mount(&lfs, &cfg) => 0; + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + for (int i = 0; i < N; i++) { + sprintf(path, "test%03d", i); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_REG); + assert(strcmp(info.name, path) == 0); + } + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_unmount(&lfs); + + lfs_mount(&lfs, &cfg) => 0; + for (int i = 0; i < N; i++) { + char oldpath[128]; + char newpath[128]; + sprintf(oldpath, "test%03d", i); + sprintf(newpath, "tedd%03d", i); + lfs_rename(&lfs, oldpath, newpath) => 0; + } + lfs_unmount(&lfs); + + lfs_mount(&lfs, &cfg) => 0; + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + for (int i = 0; i < N; i++) { + sprintf(path, "tedd%03d", i); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_REG); + assert(strcmp(info.name, path) == 0); + } + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_unmount(&lfs); +''' +define.N = 'range(0, 100, 3)' + +[[case]] # reentrant file creation/rename/removal +code = ''' + err = lfs_mount(&lfs, &cfg); + if (err) { + lfs_format(&lfs, &cfg) => 0; + lfs_mount(&lfs, &cfg) => 0; + } + + for (int i = 0; i < N; i++) { + sprintf(path, "hi%03d", i); + lfs_file_open(&lfs, &file, path, LFS_O_CREAT | LFS_O_WRONLY) => 0; + lfs_file_close(&lfs, &file) => 0; + } + + for (int i = 0; i < N; i++) { + sprintf(path, "hello%03d", i); + err = lfs_remove(&lfs, path); + assert(err == 0 || err == LFS_ERR_NOENT); + } + + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + for (int i = 0; i < N; i++) { + sprintf(path, "hi%03d", i); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_REG); + assert(strcmp(info.name, path) == 0); + } + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + + for (int i = 0; i < N; i++) { + char oldpath[128]; + char newpath[128]; + sprintf(oldpath, "hi%03d", i); + sprintf(newpath, "hello%03d", i); + // YES this can overwrite an existing newpath + lfs_rename(&lfs, oldpath, newpath) => 0; + } + + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + for (int i = 0; i < N; i++) { + sprintf(path, "hello%03d", i); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_REG); + assert(strcmp(info.name, path) == 0); + } + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + + for (int i = 0; i < N; i++) { + sprintf(path, "hello%03d", i); + lfs_remove(&lfs, path) => 0; + } + + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_unmount(&lfs) => 0; +''' +define.N = [5, 25] +reentrant = true + +[[case]] # nested directories +code = ''' lfs_format(&lfs, &cfg) => 0; lfs_mount(&lfs, &cfg) => 0; lfs_mkdir(&lfs, "potato") => 0; - lfs_file_open(&lfs, &file, "burito", LFS_O_CREAT | LFS_O_WRONLY) => 0; + lfs_file_open(&lfs, &file, "burito", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; lfs_file_close(&lfs, &file) => 0; lfs_unmount(&lfs) => 0; lfs_mount(&lfs, &cfg) => 0; + lfs_mkdir(&lfs, "potato/baked") => 0; + lfs_mkdir(&lfs, "potato/sweet") => 0; + lfs_mkdir(&lfs, "potato/fried") => 0; + lfs_unmount(&lfs) => 0; + + lfs_mount(&lfs, &cfg) => 0; + lfs_dir_open(&lfs, &dir, "potato") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(strcmp(info.name, ".") == 0); + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(strcmp(info.name, "..") == 0); + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(strcmp(info.name, "baked") == 0); + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(strcmp(info.name, "fried") == 0); + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(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; + + // try removing? + lfs_mount(&lfs, &cfg) => 0; + lfs_remove(&lfs, "potato") => LFS_ERR_NOTEMPTY; + lfs_unmount(&lfs) => 0; + + // try renaming? + lfs_mount(&lfs, &cfg) => 0; + lfs_rename(&lfs, "potato", "coldpotato") => 0; + lfs_unmount(&lfs) => 0; + + lfs_mount(&lfs, &cfg) => 0; + lfs_rename(&lfs, "coldpotato", "warmpotato") => 0; + lfs_rename(&lfs, "warmpotato", "hotpotato") => 0; + lfs_unmount(&lfs) => 0; + + lfs_mount(&lfs, &cfg) => 0; + lfs_remove(&lfs, "potato") => LFS_ERR_NOENT; + lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT; + lfs_remove(&lfs, "warmpotato") => LFS_ERR_NOENT; + lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; + lfs_unmount(&lfs) => 0; + + // try cross-directory renaming + lfs_mount(&lfs, &cfg) => 0; + lfs_mkdir(&lfs, "coldpotato") => 0; + lfs_rename(&lfs, "hotpotato/baked", "coldpotato/baked") => 0; + lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY; + lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; + lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; + lfs_rename(&lfs, "hotpotato/fried", "coldpotato/fried") => 0; + lfs_rename(&lfs, "coldpotato", "hotpotato") => LFS_ERR_NOTEMPTY; + lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOTEMPTY; + lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; + lfs_rename(&lfs, "hotpotato/sweet", "coldpotato/sweet") => 0; + lfs_rename(&lfs, "coldpotato", "hotpotato") => 0; + lfs_remove(&lfs, "coldpotato") => LFS_ERR_NOENT; + lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; + lfs_unmount(&lfs) => 0; + + lfs_mount(&lfs, &cfg) => 0; + lfs_dir_open(&lfs, &dir, "hotpotato") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(strcmp(info.name, ".") == 0); + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(strcmp(info.name, "..") == 0); + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(strcmp(info.name, "baked") == 0); + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(strcmp(info.name, "fried") == 0); + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(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; + + // final remove + lfs_mount(&lfs, &cfg) => 0; + lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; + lfs_remove(&lfs, "hotpotato/baked") => 0; + lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; + lfs_remove(&lfs, "hotpotato/fried") => 0; + lfs_remove(&lfs, "hotpotato") => LFS_ERR_NOTEMPTY; + lfs_remove(&lfs, "hotpotato/sweet") => 0; + lfs_remove(&lfs, "hotpotato") => 0; + lfs_unmount(&lfs) => 0; + + lfs_mount(&lfs, &cfg) => 0; + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(strcmp(info.name, ".") == 0); + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(strcmp(info.name, "..") == 0); + info.type => LFS_TYPE_DIR; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(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; +''' + +[[case]] # recursive remove +code = ''' + lfs_format(&lfs, &cfg) => 0; + lfs_mount(&lfs, &cfg) => 0; + lfs_mkdir(&lfs, "prickly-pear") => 0; + for (int i = 0; i < N; i++) { + sprintf(path, "prickly-pear/cactus%03d", i); + lfs_mkdir(&lfs, path) => 0; + } + lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + for (int i = 0; i < N; i++) { + sprintf(path, "cactus%03d", i); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, path) == 0); + } + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_unmount(&lfs); + + lfs_mount(&lfs, &cfg) => 0; + lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOTEMPTY; + + lfs_dir_open(&lfs, &dir, "prickly-pear") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + for (int i = 0; i < N; i++) { + sprintf(path, "cactus%03d", i); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, path) == 0); + sprintf(path, "prickly-pear/%s", info.name); + lfs_remove(&lfs, path) => 0; + } + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + + lfs_remove(&lfs, "prickly-pear") => 0; + lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT; + lfs_unmount(&lfs) => 0; + + lfs_mount(&lfs, &cfg) => 0; + lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT; + lfs_unmount(&lfs) => 0; +''' +define.N = [10, 100] + +[[case]] # other error cases +code = ''' + lfs_format(&lfs, &cfg) => 0; + lfs_mount(&lfs, &cfg) => 0; + lfs_mkdir(&lfs, "potato") => 0; + lfs_file_open(&lfs, &file, "burito", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; + + lfs_mount(&lfs, &cfg) => 0; + lfs_mkdir(&lfs, "potato") => LFS_ERR_EXIST; + lfs_mkdir(&lfs, "burito") => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "burito", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "potato", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; lfs_dir_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_file_open(&lfs, &file, "tomato", LFS_O_WRONLY) => LFS_ERR_NOENT; + lfs_file_open(&lfs, &file, "potato", LFS_O_WRONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "potato", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + lfs_mkdir(&lfs, "/") => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => LFS_ERR_EXIST; + lfs_file_open(&lfs, &file, "/", LFS_O_RDONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/", LFS_O_WRONLY) => LFS_ERR_ISDIR; + lfs_file_open(&lfs, &file, "/", + LFS_O_WRONLY | LFS_O_CREAT) => LFS_ERR_ISDIR; + + // check that errors did not corrupt directory + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_REG); + assert(strcmp(info.name, "burito") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "potato") == 0); + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_unmount(&lfs) => 0; -""" + + // or on disk + lfs_mount(&lfs, &cfg) => 0; + lfs_dir_open(&lfs, &dir, "/") => 0; + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, ".") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "..") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_REG); + assert(strcmp(info.name, "burito") == 0); + lfs_dir_read(&lfs, &dir, &info) => 1; + assert(info.type == LFS_TYPE_DIR); + assert(strcmp(info.name, "potato") == 0); + lfs_dir_read(&lfs, &dir, &info) => 0; + lfs_dir_close(&lfs, &dir) => 0; + lfs_unmount(&lfs) => 0; +''' diff --git a/tests_/test_files.toml b/tests_/test_files.toml new file mode 100644 index 0000000..ce16178 --- /dev/null +++ b/tests_/test_files.toml @@ -0,0 +1,486 @@ + +[[case]] # simple file test +code = ''' + lfs_format(&lfs, &cfg) => 0; + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "hello", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + size = strlen("Hello World!")+1; + strcpy((char*)buffer, "Hello World!"); + lfs_file_write(&lfs, &file, buffer, size) => size; + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; + + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "hello", LFS_O_RDONLY) => 0; + lfs_file_read(&lfs, &file, buffer, size) => size; + assert(strcmp((char*)buffer, "Hello World!") == 0); + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; +''' + +[[case]] # larger files +code = ''' + lfs_format(&lfs, &cfg) => 0; + + // write + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "avacado", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + srand(1); + for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); + for (lfs_size_t b = 0; b < chunk; b++) { + buffer[b] = rand() & 0xff; + } + lfs_file_write(&lfs, &file, buffer, chunk) => chunk; + } + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; + + // read + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; + lfs_file_size(&lfs, &file) => SIZE; + srand(1); + for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); + lfs_file_read(&lfs, &file, buffer, chunk) => chunk; + for (lfs_size_t b = 0; b < chunk; b++) { + assert(buffer[b] == (rand() & 0xff)); + } + } + lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; +''' +define.SIZE = [32, 8192, 262144, 0, 7, 8193] +define.CHUNKSIZE = [31, 16, 33, 1, 1023] + +[[case]] # rewriting files +code = ''' + lfs_format(&lfs, &cfg) => 0; + + // write + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "avacado", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + srand(1); + for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-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; + + // read + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; + lfs_file_size(&lfs, &file) => SIZE1; + srand(1); + for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); + lfs_file_read(&lfs, &file, buffer, chunk) => chunk; + for (lfs_size_t b = 0; b < chunk; b++) { + assert(buffer[b] == (rand() & 0xff)); + } + } + lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; + + // rewrite + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY) => 0; + srand(2); + for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-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; + + // read + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; + lfs_file_size(&lfs, &file) => lfs_max(SIZE1, SIZE2); + srand(2); + for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); + lfs_file_read(&lfs, &file, buffer, chunk) => chunk; + for (lfs_size_t b = 0; b < chunk; b++) { + assert(buffer[b] == (rand() & 0xff)); + } + } + if (SIZE1 > SIZE2) { + srand(1); + for (lfs_size_t b = 0; b < SIZE2; b++) { + rand(); + } + for (lfs_size_t i = SIZE2; i < SIZE1; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); + lfs_file_read(&lfs, &file, buffer, chunk) => chunk; + for (lfs_size_t b = 0; b < chunk; b++) { + assert(buffer[b] == (rand() & 0xff)); + } + } + } + lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; +''' +define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] +define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] +define.CHUNKSIZE = [31, 16, 1, 1025] + +[[case]] # appending files +code = ''' + lfs_format(&lfs, &cfg) => 0; + + // write + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "avacado", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + srand(1); + for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-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; + + // read + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; + lfs_file_size(&lfs, &file) => SIZE1; + srand(1); + for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); + lfs_file_read(&lfs, &file, buffer, chunk) => chunk; + for (lfs_size_t b = 0; b < chunk; b++) { + assert(buffer[b] == (rand() & 0xff)); + } + } + lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; + + // append + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_APPEND) => 0; + srand(2); + for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-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; + + // read + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; + lfs_file_size(&lfs, &file) => SIZE1 + SIZE2; + srand(1); + for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); + lfs_file_read(&lfs, &file, buffer, chunk) => chunk; + for (lfs_size_t b = 0; b < chunk; b++) { + assert(buffer[b] == (rand() & 0xff)); + } + } + srand(2); + for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); + lfs_file_read(&lfs, &file, buffer, chunk) => chunk; + for (lfs_size_t b = 0; b < chunk; b++) { + assert(buffer[b] == (rand() & 0xff)); + } + } + lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; +''' +define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] +define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] +define.CHUNKSIZE = [31, 16, 1, 1025] + +[[case]] # truncating files +code = ''' + lfs_format(&lfs, &cfg) => 0; + + // write + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "avacado", + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + srand(1); + for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-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; + + // read + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; + lfs_file_size(&lfs, &file) => SIZE1; + srand(1); + for (lfs_size_t i = 0; i < SIZE1; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE1-i); + lfs_file_read(&lfs, &file, buffer, chunk) => chunk; + for (lfs_size_t b = 0; b < chunk; b++) { + assert(buffer[b] == (rand() & 0xff)); + } + } + lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; + + // truncate + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_TRUNC) => 0; + srand(2); + for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-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; + + // read + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; + lfs_file_size(&lfs, &file) => SIZE2; + srand(2); + for (lfs_size_t i = 0; i < SIZE2; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE2-i); + lfs_file_read(&lfs, &file, buffer, chunk) => chunk; + for (lfs_size_t b = 0; b < chunk; b++) { + assert(buffer[b] == (rand() & 0xff)); + } + } + lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; +''' +define.SIZE1 = [32, 8192, 131072, 0, 7, 8193] +define.SIZE2 = [32, 8192, 131072, 0, 7, 8193] +define.CHUNKSIZE = [31, 16, 1, 1025] + +[[case]] # reentrant file writing +code = ''' + err = lfs_mount(&lfs, &cfg); + if (err) { + lfs_format(&lfs, &cfg) => 0; + lfs_mount(&lfs, &cfg) => 0; + } + + err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY); + assert(err == LFS_ERR_NOENT || err == 0); + if (err == 0) { + // can only be 0 (new file) or full size + size = lfs_file_size(&lfs, &file); + assert(size == 0 || size == SIZE); + lfs_file_close(&lfs, &file) => 0; + } + + // write + lfs_file_open(&lfs, &file, "avacado", LFS_O_WRONLY | LFS_O_CREAT) => 0; + srand(1); + for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); + for (lfs_size_t b = 0; b < chunk; b++) { + buffer[b] = rand() & 0xff; + } + lfs_file_write(&lfs, &file, buffer, chunk) => chunk; + } + lfs_file_close(&lfs, &file) => 0; + + // read + lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; + lfs_file_size(&lfs, &file) => SIZE; + srand(1); + for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); + lfs_file_read(&lfs, &file, buffer, chunk) => chunk; + for (lfs_size_t b = 0; b < chunk; b++) { + assert(buffer[b] == (rand() & 0xff)); + } + } + lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; +''' +define.SIZE = [32, 0, 7, 2049] +define.CHUNKSIZE = [31, 16, 65] +reentrant = true + +[[case]] # reentrant file writing with syncs +code = ''' + err = lfs_mount(&lfs, &cfg); + if (err) { + lfs_format(&lfs, &cfg) => 0; + lfs_mount(&lfs, &cfg) => 0; + } + + err = lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY); + assert(err == LFS_ERR_NOENT || err == 0); + if (err == 0) { + // with syncs we could be any size, but it at least must be valid data + size = lfs_file_size(&lfs, &file); + assert(size <= SIZE); + srand(1); + for (lfs_size_t i = 0; i < size; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, size-i); + lfs_file_read(&lfs, &file, buffer, chunk) => chunk; + for (lfs_size_t b = 0; b < chunk; b++) { + assert(buffer[b] == (rand() & 0xff)); + } + } + lfs_file_close(&lfs, &file) => 0; + } + + // write + lfs_file_open(&lfs, &file, "avacado", + LFS_O_WRONLY | LFS_O_CREAT | MODE) => 0; + size = lfs_file_size(&lfs, &file); + assert(size <= SIZE); + srand(1); + lfs_size_t skip = (MODE == LFS_O_APPEND) ? size : 0; + for (lfs_size_t b = 0; b < skip; b++) { + rand(); + } + for (lfs_size_t i = skip; i < SIZE; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, 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_sync(&lfs, &file) => 0; + } + lfs_file_close(&lfs, &file) => 0; + + // read + lfs_file_open(&lfs, &file, "avacado", LFS_O_RDONLY) => 0; + lfs_file_size(&lfs, &file) => SIZE; + srand(1); + for (lfs_size_t i = 0; i < SIZE; i += CHUNKSIZE) { + lfs_size_t chunk = lfs_min(CHUNKSIZE, SIZE-i); + lfs_file_read(&lfs, &file, buffer, chunk) => chunk; + for (lfs_size_t b = 0; b < chunk; b++) { + assert(buffer[b] == (rand() & 0xff)); + } + } + lfs_file_read(&lfs, &file, buffer, CHUNKSIZE) => 0; + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; +''' +define = [ + # append (O(n)) + {MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]}, + # truncate (O(n^2)) + {MODE='LFS_O_TRUNC', SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]}, + # rewrite (O(n^2)) + {MODE=0, SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]}, +] +reentrant = true + +[[case]] # many files +code = ''' + lfs_format(&lfs, &cfg) => 0; + // create N files of 7 bytes + lfs_mount(&lfs, &cfg) => 0; + for (int i = 0; i < N; i++) { + sprintf(path, "file_%03d", i); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + char wbuffer[1024]; + size = 7; + snprintf(wbuffer, size, "Hi %03d", i); + lfs_file_write(&lfs, &file, wbuffer, size) => size; + lfs_file_close(&lfs, &file) => 0; + + char rbuffer[1024]; + lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; + lfs_file_read(&lfs, &file, rbuffer, size) => size; + assert(strcmp(rbuffer, wbuffer) == 0); + lfs_file_close(&lfs, &file) => 0; + } + lfs_unmount(&lfs) => 0; +''' +define.N = 300 + +[[case]] # many files with power cycle +code = ''' + lfs_format(&lfs, &cfg) => 0; + // create N files of 7 bytes + lfs_mount(&lfs, &cfg) => 0; + for (int i = 0; i < N; i++) { + sprintf(path, "file_%03d", i); + lfs_file_open(&lfs, &file, path, + LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; + char wbuffer[1024]; + size = 7; + snprintf(wbuffer, size, "Hi %03d", i); + lfs_file_write(&lfs, &file, wbuffer, size) => size; + lfs_file_close(&lfs, &file) => 0; + lfs_unmount(&lfs) => 0; + + char rbuffer[1024]; + lfs_mount(&lfs, &cfg) => 0; + lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; + lfs_file_read(&lfs, &file, rbuffer, size) => size; + assert(strcmp(rbuffer, wbuffer) == 0); + lfs_file_close(&lfs, &file) => 0; + } + lfs_unmount(&lfs) => 0; +''' +define.N = 300 + +[[case]] # many files with power loss +code = ''' + err = lfs_mount(&lfs, &cfg); + if (err) { + lfs_format(&lfs, &cfg) => 0; + lfs_mount(&lfs, &cfg) => 0; + } + // create N files of 7 bytes + for (int i = 0; i < N; i++) { + sprintf(path, "file_%03d", i); + err = lfs_file_open(&lfs, &file, path, LFS_O_WRONLY | LFS_O_CREAT); + char wbuffer[1024]; + size = 7; + snprintf(wbuffer, size, "Hi %03d", i); + if ((lfs_size_t)lfs_file_size(&lfs, &file) != size) { + lfs_file_write(&lfs, &file, wbuffer, size) => size; + } + lfs_file_close(&lfs, &file) => 0; + + char rbuffer[1024]; + lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0; + lfs_file_read(&lfs, &file, rbuffer, size) => size; + assert(strcmp(rbuffer, wbuffer) == 0); + lfs_file_close(&lfs, &file) => 0; + } + lfs_unmount(&lfs) => 0; +''' +define.N = 300 +reentrant = true diff --git a/tests_/test_format.toml b/tests_/test_format.toml new file mode 100644 index 0000000..c52db2a --- /dev/null +++ b/tests_/test_format.toml @@ -0,0 +1,105 @@ +[[case]] # simple formatting test +code = ''' + lfs_format(&lfs, &cfg) => 0; +''' + +[[case]] # mount/unmount +code = ''' + lfs_format(&lfs, &cfg) => 0; + lfs_mount(&lfs, &cfg) => 0; + lfs_unmount(&lfs) => 0; +''' + +[[case]] # reentrant format +code = ''' + err = lfs_mount(&lfs, &cfg); + if (err) { + lfs_format(&lfs, &cfg) => 0; + lfs_mount(&lfs, &cfg) => 0; + } + lfs_unmount(&lfs) => 0; +''' +reentrant = true + +[[case]] # invalid mount +code = ''' + lfs_mount(&lfs, &cfg) => LFS_ERR_CORRUPT; +''' + +# TODO invalid superblock? (corrupt 1, 0) + +[[case]] # expanding superblock +code = ''' + lfs_format(&lfs, &cfg) => 0; + lfs_mount(&lfs, &cfg) => 0; + for (int i = 0; i < N; i++) { + lfs_mkdir(&lfs, "dummy") => 0; + lfs_stat(&lfs, "dummy", &info) => 0; + assert(strcmp(info.name, "dummy") == 0); + lfs_remove(&lfs, "dummy") => 0; + } + lfs_unmount(&lfs) => 0; + + // one last check after power-cycle + lfs_mount(&lfs, &cfg) => 0; + lfs_mkdir(&lfs, "dummy") => 0; + lfs_stat(&lfs, "dummy", &info) => 0; + assert(strcmp(info.name, "dummy") == 0); + lfs_unmount(&lfs) => 0; +''' +define.BLOCK_CYCLES = [32, 33, 1] +define.N = [10, 100, 1000] + +[[case]] # expanding superblock with power cycle +code = ''' + lfs_format(&lfs, &cfg) => 0; + for (int i = 0; i < N; i++) { + lfs_mount(&lfs, &cfg) => 0; + // remove lingering dummy? + err = lfs_remove(&lfs, "dummy"); + assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); + + lfs_mkdir(&lfs, "dummy") => 0; + lfs_stat(&lfs, "dummy", &info) => 0; + assert(strcmp(info.name, "dummy") == 0); + lfs_unmount(&lfs) => 0; + } + + // one last check after power-cycle + lfs_mount(&lfs, &cfg) => 0; + lfs_stat(&lfs, "dummy", &info) => 0; + assert(strcmp(info.name, "dummy") == 0); + lfs_unmount(&lfs) => 0; +''' +define.BLOCK_CYCLES = [32, 33, 1] +define.N = [10, 100, 1000] + +[[case]] # reentrant expanding superblock +code = ''' + err = lfs_mount(&lfs, &cfg); + if (err) { + lfs_format(&lfs, &cfg) => 0; + lfs_mount(&lfs, &cfg) => 0; + } + + for (int i = 0; i < N; i++) { + // remove lingering dummy? + err = lfs_remove(&lfs, "dummy"); + assert(err == 0 || (err == LFS_ERR_NOENT && i == 0)); + + lfs_mkdir(&lfs, "dummy") => 0; + lfs_stat(&lfs, "dummy", &info) => 0; + assert(strcmp(info.name, "dummy") == 0); + } + + lfs_unmount(&lfs) => 0; + + // one last check after power-cycle + lfs_mount(&lfs, &cfg) => 0; + lfs_stat(&lfs, "dummy", &info) => 0; + assert(strcmp(info.name, "dummy") == 0); + lfs_unmount(&lfs) => 0; +''' +define.BLOCK_CYCLES = [2, 1] +define.N = 24 +reentrant = true