Migrated the first of the tests with internal knowledge
Both test_move and test_orphan needed internal knowledge which comes with the addition of the "in" attribute. This was in the plan for the test-revamp from the beginning as it really opens up the ability to write more unit-style-tests using internal knowledge of how littlefs works. More unit-style-tests should help _fix_ bugs by limiting the scope of the test and where the bug could be hiding. The "in" attribute effectively runs tests _inside_ the .c file specified, giving the test access to all static members without needed to change their visibility.
This commit is contained in:
+19
-19
@@ -2,6 +2,8 @@
|
||||
# note for these to work there are many constraints on the device geometry
|
||||
|
||||
[[case]] # parallel allocation test
|
||||
define.FILES = 3
|
||||
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / FILES)'
|
||||
code = '''
|
||||
const char *names[FILES] = {"bacon", "eggs", "pancakes"};
|
||||
lfs_file_t files[FILES];
|
||||
@@ -41,10 +43,10 @@ code = '''
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.FILES = 3
|
||||
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / FILES)'
|
||||
|
||||
[[case]] # serial allocation test
|
||||
define.FILES = 3
|
||||
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / FILES)'
|
||||
code = '''
|
||||
const char *names[FILES] = {"bacon", "eggs", "pancakes"};
|
||||
|
||||
@@ -80,10 +82,11 @@ code = '''
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.FILES = 3
|
||||
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / FILES)'
|
||||
|
||||
[[case]] # parallel allocation reuse test
|
||||
define.FILES = 3
|
||||
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / FILES)'
|
||||
define.CYCLES = [1, 10]
|
||||
code = '''
|
||||
const char *names[FILES] = {"bacon", "eggs", "pancakes"};
|
||||
lfs_file_t files[FILES];
|
||||
@@ -134,11 +137,11 @@ code = '''
|
||||
lfs_unmount(&lfs) => 0;
|
||||
}
|
||||
'''
|
||||
|
||||
[[case]] # serial allocation reuse test
|
||||
define.FILES = 3
|
||||
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / FILES)'
|
||||
define.CYCLES = [1, 10]
|
||||
|
||||
[[case]] # serial allocation reuse test
|
||||
code = '''
|
||||
const char *names[FILES] = {"bacon", "eggs", "pancakes"};
|
||||
|
||||
@@ -185,9 +188,6 @@ code = '''
|
||||
lfs_unmount(&lfs) => 0;
|
||||
}
|
||||
'''
|
||||
define.FILES = 3
|
||||
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / FILES)'
|
||||
define.CYCLES = [1, 10]
|
||||
|
||||
[[case]] # exhaustion test
|
||||
code = '''
|
||||
@@ -226,6 +226,7 @@ code = '''
|
||||
'''
|
||||
|
||||
[[case]] # exhaustion wraparound test
|
||||
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / 3)'
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -271,7 +272,6 @@ code = '''
|
||||
lfs_remove(&lfs, "exhaustion") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.SIZE = '(((LFS_BLOCK_SIZE-8)*(LFS_BLOCK_COUNT-4)) / 3)'
|
||||
|
||||
[[case]] # dir exhaustion test
|
||||
code = '''
|
||||
@@ -327,6 +327,9 @@ code = '''
|
||||
# should be removed and replaced with generalized tests.
|
||||
|
||||
[[case]] # chained dir exhaustion test
|
||||
define.LFS_BLOCK_SIZE = 512
|
||||
define.LFS_BLOCK_COUNT = 1024
|
||||
if = 'LFS_BLOCK_SIZE == 512 and LFS_BLOCK_COUNT == 1024'
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -393,11 +396,11 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # split dir test
|
||||
define.LFS_BLOCK_SIZE = 512
|
||||
define.LFS_BLOCK_COUNT = 1024
|
||||
if = 'LFS_BLOCK_SIZE == 512 and LFS_BLOCK_COUNT == 1024'
|
||||
|
||||
[[case]] # split dir test
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -438,11 +441,11 @@ code = '''
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # outdated lookahead test
|
||||
define.LFS_BLOCK_SIZE = 512
|
||||
define.LFS_BLOCK_COUNT = 1024
|
||||
if = 'LFS_BLOCK_SIZE == 512 and LFS_BLOCK_COUNT == 1024'
|
||||
|
||||
[[case]] # outdated lookahead test
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -501,11 +504,11 @@ code = '''
|
||||
}
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # outdated lookahead and split dir test
|
||||
define.LFS_BLOCK_SIZE = 512
|
||||
define.LFS_BLOCK_COUNT = 1024
|
||||
if = 'LFS_BLOCK_SIZE == 512 and LFS_BLOCK_COUNT == 1024'
|
||||
|
||||
[[case]] # outdated lookahead and split dir test
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -561,6 +564,3 @@ code = '''
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.LFS_BLOCK_SIZE = 512
|
||||
define.LFS_BLOCK_COUNT = 1024
|
||||
if = 'LFS_BLOCK_SIZE == 512 and LFS_BLOCK_COUNT == 1024'
|
||||
|
||||
+13
-13
@@ -15,6 +15,7 @@ code = '''
|
||||
'''
|
||||
|
||||
[[case]] # many directory creation
|
||||
define.N = 'range(0, 100, 3)'
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
|
||||
@@ -43,9 +44,9 @@ code = '''
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.N = 'range(0, 100, 3)'
|
||||
|
||||
[[case]] # many directory removal
|
||||
define.N = 'range(3, 100, 11)'
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
|
||||
@@ -93,9 +94,9 @@ code = '''
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.N = 'range(3, 100, 11)'
|
||||
|
||||
[[case]] # many directory rename
|
||||
define.N = 'range(3, 100, 11)'
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
|
||||
@@ -152,9 +153,10 @@ code = '''
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs);
|
||||
'''
|
||||
define.N = 'range(3, 100, 11)'
|
||||
|
||||
[[case]] # reentrant many directory creation/rename/removal
|
||||
define.N = [5, 25]
|
||||
reentrant = true
|
||||
code = '''
|
||||
err = lfs_mount(&lfs, &cfg);
|
||||
if (err) {
|
||||
@@ -231,10 +233,9 @@ code = '''
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.N = [5, 25]
|
||||
reentrant = true
|
||||
|
||||
[[case]] # file creation
|
||||
define.N = 'range(3, 100, 11)'
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
|
||||
@@ -265,9 +266,9 @@ code = '''
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs);
|
||||
'''
|
||||
define.N = 'range(3, 100, 11)'
|
||||
|
||||
[[case]] # file removal
|
||||
define.N = 'range(0, 100, 3)'
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
|
||||
@@ -317,9 +318,9 @@ code = '''
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.N = 'range(0, 100, 3)'
|
||||
|
||||
[[case]] # file rename
|
||||
define.N = 'range(0, 100, 3)'
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
|
||||
@@ -378,9 +379,10 @@ code = '''
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs);
|
||||
'''
|
||||
define.N = 'range(0, 100, 3)'
|
||||
|
||||
[[case]] # reentrant file creation/rename/removal
|
||||
define.N = [5, 25]
|
||||
reentrant = true
|
||||
code = '''
|
||||
err = lfs_mount(&lfs, &cfg);
|
||||
if (err) {
|
||||
@@ -457,8 +459,6 @@ code = '''
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.N = [5, 25]
|
||||
reentrant = true
|
||||
|
||||
[[case]] # nested directories
|
||||
code = '''
|
||||
@@ -585,6 +585,7 @@ code = '''
|
||||
'''
|
||||
|
||||
[[case]] # recursive remove
|
||||
define.N = [10, 100]
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -639,7 +640,6 @@ code = '''
|
||||
lfs_remove(&lfs, "prickly-pear") => LFS_ERR_NOENT;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.N = [10, 100]
|
||||
|
||||
[[case]] # other error cases
|
||||
code = '''
|
||||
@@ -716,6 +716,7 @@ code = '''
|
||||
'''
|
||||
|
||||
[[case]] # directory seek
|
||||
define.COUNT = [4, 128, 132]
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -774,9 +775,9 @@ code = '''
|
||||
lfs_unmount(&lfs) => 0;
|
||||
}
|
||||
'''
|
||||
define.COUNT = [4, 128, 132]
|
||||
|
||||
[[case]] # root seek
|
||||
define.COUNT = [4, 128, 132]
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -834,5 +835,4 @@ code = '''
|
||||
lfs_unmount(&lfs) => 0;
|
||||
}
|
||||
'''
|
||||
define.COUNT = [4, 128, 132]
|
||||
|
||||
|
||||
+25
-25
@@ -20,6 +20,8 @@ code = '''
|
||||
'''
|
||||
|
||||
[[case]] # larger files
|
||||
define.SIZE = [32, 8192, 262144, 0, 7, 8193]
|
||||
define.CHUNKSIZE = [31, 16, 33, 1, 1023]
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
|
||||
@@ -54,10 +56,11 @@ code = '''
|
||||
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
|
||||
define.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
|
||||
define.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
|
||||
define.CHUNKSIZE = [31, 16, 1, 1025]
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
|
||||
@@ -135,11 +138,11 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # appending files
|
||||
define.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
|
||||
define.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
|
||||
define.CHUNKSIZE = [31, 16, 1, 1025]
|
||||
|
||||
[[case]] # appending files
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
|
||||
@@ -212,11 +215,11 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # truncating files
|
||||
define.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
|
||||
define.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
|
||||
define.CHUNKSIZE = [31, 16, 1, 1025]
|
||||
|
||||
[[case]] # truncating files
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
|
||||
@@ -281,11 +284,11 @@ code = '''
|
||||
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
|
||||
define.SIZE = [32, 0, 7, 2049]
|
||||
define.CHUNKSIZE = [31, 16, 65]
|
||||
reentrant = true
|
||||
code = '''
|
||||
err = lfs_mount(&lfs, &cfg);
|
||||
if (err) {
|
||||
@@ -329,11 +332,17 @@ code = '''
|
||||
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
|
||||
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
|
||||
code = '''
|
||||
err = lfs_mount(&lfs, &cfg);
|
||||
if (err) {
|
||||
@@ -393,17 +402,9 @@ code = '''
|
||||
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
|
||||
define.N = 300
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
// create N files of 7 bytes
|
||||
@@ -426,9 +427,9 @@ code = '''
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.N = 300
|
||||
|
||||
[[case]] # many files with power cycle
|
||||
define.N = 300
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
// create N files of 7 bytes
|
||||
@@ -453,9 +454,10 @@ code = '''
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.N = 300
|
||||
|
||||
[[case]] # many files with power loss
|
||||
define.N = 300
|
||||
reentrant = true
|
||||
code = '''
|
||||
err = lfs_mount(&lfs, &cfg);
|
||||
if (err) {
|
||||
@@ -482,5 +484,3 @@ code = '''
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.N = 300
|
||||
reentrant = true
|
||||
|
||||
@@ -11,6 +11,7 @@ code = '''
|
||||
'''
|
||||
|
||||
[[case]] # reentrant format
|
||||
reentrant = true
|
||||
code = '''
|
||||
err = lfs_mount(&lfs, &cfg);
|
||||
if (err) {
|
||||
@@ -19,7 +20,6 @@ code = '''
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
reentrant = true
|
||||
|
||||
[[case]] # invalid mount
|
||||
code = '''
|
||||
@@ -29,6 +29,8 @@ code = '''
|
||||
# TODO invalid superblock? (corrupt 1, 0)
|
||||
|
||||
[[case]] # expanding superblock
|
||||
define.BLOCK_CYCLES = [32, 33, 1]
|
||||
define.N = [10, 100, 1000]
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -47,10 +49,10 @@ code = '''
|
||||
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
|
||||
define.BLOCK_CYCLES = [32, 33, 1]
|
||||
define.N = [10, 100, 1000]
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
for (int i = 0; i < N; i++) {
|
||||
@@ -71,10 +73,11 @@ code = '''
|
||||
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
|
||||
define.BLOCK_CYCLES = [2, 1]
|
||||
define.N = 24
|
||||
reentrant = true
|
||||
code = '''
|
||||
err = lfs_mount(&lfs, &cfg);
|
||||
if (err) {
|
||||
@@ -100,6 +103,3 @@ code = '''
|
||||
assert(strcmp(info.name, "dummy") == 0);
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.BLOCK_CYCLES = [2, 1]
|
||||
define.N = 24
|
||||
reentrant = true
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
|
||||
[[case]] # interspersed file test
|
||||
# TODO FILES=26 found bug
|
||||
#define.SIZE = [10, 100]
|
||||
#define.FILES = [4, 10, 26]
|
||||
define = [
|
||||
{SIZE=10, FILES=4},
|
||||
{SIZE=10, FILES=10},
|
||||
#{SIZE=10, FILES=26},
|
||||
{SIZE=100, FILES=4},
|
||||
{SIZE=100, FILES=10},
|
||||
#{SIZE=100, FILES=26},
|
||||
]
|
||||
code = '''
|
||||
lfs_file_t files[FILES];
|
||||
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
@@ -56,19 +67,10 @@ code = '''
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
# TODO FILES=26 found bug
|
||||
#define.SIZE = [10, 100]
|
||||
#define.FILES = [4, 10, 26]
|
||||
define = [
|
||||
{SIZE=10, FILES=4},
|
||||
{SIZE=10, FILES=10},
|
||||
#{SIZE=10, FILES=26},
|
||||
{SIZE=100, FILES=4},
|
||||
{SIZE=100, FILES=10},
|
||||
#{SIZE=100, FILES=26},
|
||||
]
|
||||
|
||||
[[case]] # interspersed remove file test
|
||||
define.SIZE = [10, 100]
|
||||
define.FILES = [4, 10, 26]
|
||||
code = '''
|
||||
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
@@ -118,10 +120,9 @@ code = '''
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.SIZE = [10, 100]
|
||||
define.FILES = [4, 10, 26]
|
||||
|
||||
[[case]] # remove inconveniently test
|
||||
define.SIZE = [10, 100]
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -179,9 +180,20 @@ code = '''
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.SIZE = [10, 100]
|
||||
|
||||
[[case]] # reentrant interspersed file test
|
||||
# TODO FILES=26 found bug
|
||||
#define.SIZE = [10, 100]
|
||||
#define.FILES = [4, 10, 26]
|
||||
define = [
|
||||
{SIZE=10, FILES=4},
|
||||
{SIZE=10, FILES=10},
|
||||
#{SIZE=10, FILES=26},
|
||||
{SIZE=100, FILES=4},
|
||||
#{SIZE=100, FILES=10},
|
||||
#{SIZE=100, FILES=26},
|
||||
]
|
||||
reentrant = true
|
||||
code = '''
|
||||
lfs_file_t files[FILES];
|
||||
const char alphas[] = "abcdefghijklmnopqrstuvwxyz";
|
||||
@@ -248,15 +260,3 @@ code = '''
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
# TODO FILES=26 found bug
|
||||
#define.SIZE = [10, 100]
|
||||
#define.FILES = [4, 10, 26]
|
||||
define = [
|
||||
{SIZE=10, FILES=4},
|
||||
{SIZE=10, FILES=10},
|
||||
#{SIZE=10, FILES=26},
|
||||
{SIZE=100, FILES=4},
|
||||
#{SIZE=100, FILES=10},
|
||||
#{SIZE=100, FILES=26},
|
||||
]
|
||||
reentrant = true
|
||||
|
||||
@@ -0,0 +1,957 @@
|
||||
[[case]] # move file
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_mkdir(&lfs, "a") => 0;
|
||||
lfs_mkdir(&lfs, "b") => 0;
|
||||
lfs_mkdir(&lfs, "c") => 0;
|
||||
lfs_mkdir(&lfs, "d") => 0;
|
||||
lfs_file_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;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_rename(&lfs, "a/hello", "c/hello") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
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;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hello") == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(info.size == 5+8+6);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
|
||||
lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 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_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # move file corrupt source
|
||||
in = "lfs.c"
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_mkdir(&lfs, "a") => 0;
|
||||
lfs_mkdir(&lfs, "b") => 0;
|
||||
lfs_mkdir(&lfs, "c") => 0;
|
||||
lfs_mkdir(&lfs, "d") => 0;
|
||||
lfs_file_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;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_rename(&lfs, "a/hello", "c/hello") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// corrupt the source
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_block_t block = dir.m.pair[0];
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
uint8_t bbuffer[LFS_BLOCK_SIZE];
|
||||
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
int off = LFS_BLOCK_SIZE-1;
|
||||
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
|
||||
off -= 1;
|
||||
}
|
||||
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
|
||||
cfg.erase(&cfg, block) => 0;
|
||||
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
cfg.sync(&cfg) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
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;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hello") == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(info.size == 5+8+6);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
|
||||
lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 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_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # move file corrupt source and dest
|
||||
in = "lfs.c"
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_mkdir(&lfs, "a") => 0;
|
||||
lfs_mkdir(&lfs, "b") => 0;
|
||||
lfs_mkdir(&lfs, "c") => 0;
|
||||
lfs_mkdir(&lfs, "d") => 0;
|
||||
lfs_file_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;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_rename(&lfs, "a/hello", "c/hello") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// corrupt the source
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_block_t block = dir.m.pair[0];
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
uint8_t bbuffer[LFS_BLOCK_SIZE];
|
||||
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
int off = LFS_BLOCK_SIZE-1;
|
||||
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
|
||||
off -= 1;
|
||||
}
|
||||
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
|
||||
cfg.erase(&cfg, block) => 0;
|
||||
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
cfg.sync(&cfg) => 0;
|
||||
|
||||
// corrupt the destination
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "c") => 0;
|
||||
block = dir.m.pair[0];
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
off = LFS_BLOCK_SIZE-1;
|
||||
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
|
||||
off -= 1;
|
||||
}
|
||||
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
|
||||
cfg.erase(&cfg, block) => 0;
|
||||
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
cfg.sync(&cfg) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hello") == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(info.size == 5+8+6);
|
||||
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;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
|
||||
lfs_file_open(&lfs, &file, "a/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_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # move file after corrupt
|
||||
in = "lfs.c"
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_mkdir(&lfs, "a") => 0;
|
||||
lfs_mkdir(&lfs, "b") => 0;
|
||||
lfs_mkdir(&lfs, "c") => 0;
|
||||
lfs_mkdir(&lfs, "d") => 0;
|
||||
lfs_file_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;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_rename(&lfs, "a/hello", "c/hello") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// corrupt the source
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_block_t block = dir.m.pair[0];
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
uint8_t bbuffer[LFS_BLOCK_SIZE];
|
||||
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
int off = LFS_BLOCK_SIZE-1;
|
||||
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
|
||||
off -= 1;
|
||||
}
|
||||
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
|
||||
cfg.erase(&cfg, block) => 0;
|
||||
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
cfg.sync(&cfg) => 0;
|
||||
|
||||
// corrupt the destination
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "c") => 0;
|
||||
block = dir.m.pair[0];
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
off = LFS_BLOCK_SIZE-1;
|
||||
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
|
||||
off -= 1;
|
||||
}
|
||||
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
|
||||
cfg.erase(&cfg, block) => 0;
|
||||
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
cfg.sync(&cfg) => 0;
|
||||
|
||||
// continue move
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_rename(&lfs, "a/hello", "c/hello") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
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;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hello") == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(info.size == 5+8+6);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
|
||||
lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => 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_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # simple reentrant move file
|
||||
reentrant = true
|
||||
code = '''
|
||||
err = lfs_mount(&lfs, &cfg);
|
||||
if (err) {
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
}
|
||||
err = lfs_mkdir(&lfs, "a");
|
||||
assert(!err || err == LFS_ERR_EXIST);
|
||||
err = lfs_mkdir(&lfs, "b");
|
||||
assert(!err || err == LFS_ERR_EXIST);
|
||||
err = lfs_mkdir(&lfs, "c");
|
||||
assert(!err || err == LFS_ERR_EXIST);
|
||||
err = lfs_mkdir(&lfs, "d");
|
||||
assert(!err || err == LFS_ERR_EXIST);
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
while (true) {
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
// there should never exist _2_ hello files
|
||||
int count = 0;
|
||||
if (lfs_stat(&lfs, "a/hello", &info) == 0) {
|
||||
assert(strcmp(info.name, "hello") == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(info.size == 5+8+6 || info.size == 0);
|
||||
count += 1;
|
||||
}
|
||||
if (lfs_stat(&lfs, "b/hello", &info) == 0) {
|
||||
assert(strcmp(info.name, "hello") == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(info.size == 5+8+6);
|
||||
count += 1;
|
||||
}
|
||||
if (lfs_stat(&lfs, "c/hello", &info) == 0) {
|
||||
assert(strcmp(info.name, "hello") == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(info.size == 5+8+6);
|
||||
count += 1;
|
||||
}
|
||||
if (lfs_stat(&lfs, "d/hello", &info) == 0) {
|
||||
assert(strcmp(info.name, "hello") == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(info.size == 5+8+6);
|
||||
count += 1;
|
||||
}
|
||||
assert(count <= 1);
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
if (lfs_stat(&lfs, "a/hello", &info) == 0 && info.size > 0) {
|
||||
lfs_rename(&lfs, "a/hello", "b/hello") => 0;
|
||||
} else if (lfs_stat(&lfs, "b/hello", &info) == 0) {
|
||||
lfs_rename(&lfs, "b/hello", "c/hello") => 0;
|
||||
} else if (lfs_stat(&lfs, "c/hello", &info) == 0) {
|
||||
lfs_rename(&lfs, "c/hello", "d/hello") => 0;
|
||||
} else if (lfs_stat(&lfs, "d/hello", &info) == 0) {
|
||||
// success
|
||||
break;
|
||||
} else {
|
||||
// create file
|
||||
lfs_file_open(&lfs, &file, "a/hello",
|
||||
LFS_O_WRONLY | LFS_O_CREAT) => 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;
|
||||
}
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
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;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hello") == 0);
|
||||
assert(info.type == LFS_TYPE_REG);
|
||||
assert(info.size == 5+8+6);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
|
||||
lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0;
|
||||
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;
|
||||
'''
|
||||
|
||||
[[case]] # move dir
|
||||
code = '''
|
||||
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_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_rename(&lfs, "a/hi", "c/hi") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
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;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hi") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 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") => 0;
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "bonjour") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hola") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "ohayo") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # move dir corrupt source
|
||||
in = "lfs.c"
|
||||
code = '''
|
||||
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_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_rename(&lfs, "a/hi", "c/hi") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// corrupt the source
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_block_t block = dir.m.pair[0];
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
uint8_t bbuffer[LFS_BLOCK_SIZE];
|
||||
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
int off = LFS_BLOCK_SIZE-1;
|
||||
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
|
||||
off -= 1;
|
||||
}
|
||||
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
|
||||
cfg.erase(&cfg, block) => 0;
|
||||
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
cfg.sync(&cfg) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
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;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hi") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 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") => 0;
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "bonjour") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hola") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "ohayo") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # move dir corrupt source and dest
|
||||
in = "lfs.c"
|
||||
code = '''
|
||||
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_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_rename(&lfs, "a/hi", "c/hi") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// corrupt the source
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_block_t block = dir.m.pair[0];
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
uint8_t bbuffer[LFS_BLOCK_SIZE];
|
||||
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
int off = LFS_BLOCK_SIZE-1;
|
||||
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
|
||||
off -= 1;
|
||||
}
|
||||
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
|
||||
cfg.erase(&cfg, block) => 0;
|
||||
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
cfg.sync(&cfg) => 0;
|
||||
|
||||
// corrupt the destination
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "c") => 0;
|
||||
block = dir.m.pair[0];
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
off = LFS_BLOCK_SIZE-1;
|
||||
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
|
||||
off -= 1;
|
||||
}
|
||||
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
|
||||
cfg.erase(&cfg, block) => 0;
|
||||
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
cfg.sync(&cfg) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hi") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
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;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
|
||||
lfs_dir_open(&lfs, &dir, "a/hi") => 0;
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "bonjour") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hola") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "ohayo") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
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") => LFS_ERR_NOENT;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # move dir after corrupt
|
||||
in = "lfs.c"
|
||||
code = '''
|
||||
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_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_rename(&lfs, "a/hi", "c/hi") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// corrupt the source
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_block_t block = dir.m.pair[0];
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
uint8_t bbuffer[LFS_BLOCK_SIZE];
|
||||
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
int off = LFS_BLOCK_SIZE-1;
|
||||
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
|
||||
off -= 1;
|
||||
}
|
||||
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
|
||||
cfg.erase(&cfg, block) => 0;
|
||||
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
cfg.sync(&cfg) => 0;
|
||||
|
||||
// corrupt the destination
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "c") => 0;
|
||||
block = dir.m.pair[0];
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
off = LFS_BLOCK_SIZE-1;
|
||||
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
|
||||
off -= 1;
|
||||
}
|
||||
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
|
||||
cfg.erase(&cfg, block) => 0;
|
||||
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
cfg.sync(&cfg) => 0;
|
||||
|
||||
// continue move
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_rename(&lfs, "a/hi", "c/hi") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
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;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hi") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 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") => 0;
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "bonjour") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hola") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "ohayo") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "d/hi") => LFS_ERR_NOENT;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # simple reentrant move dir
|
||||
reentrant = true
|
||||
code = '''
|
||||
err = lfs_mount(&lfs, &cfg);
|
||||
if (err) {
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
}
|
||||
err = lfs_mkdir(&lfs, "a");
|
||||
assert(!err || err == LFS_ERR_EXIST);
|
||||
err = lfs_mkdir(&lfs, "b");
|
||||
assert(!err || err == LFS_ERR_EXIST);
|
||||
err = lfs_mkdir(&lfs, "c");
|
||||
assert(!err || err == LFS_ERR_EXIST);
|
||||
err = lfs_mkdir(&lfs, "d");
|
||||
assert(!err || err == LFS_ERR_EXIST);
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
while (true) {
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
// there should never exist _2_ hi directories
|
||||
int count = 0;
|
||||
if (lfs_stat(&lfs, "a/hi", &info) == 0) {
|
||||
assert(strcmp(info.name, "hi") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
count += 1;
|
||||
}
|
||||
if (lfs_stat(&lfs, "b/hi", &info) == 0) {
|
||||
assert(strcmp(info.name, "hi") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
count += 1;
|
||||
}
|
||||
if (lfs_stat(&lfs, "c/hi", &info) == 0) {
|
||||
assert(strcmp(info.name, "hi") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
count += 1;
|
||||
}
|
||||
if (lfs_stat(&lfs, "d/hi", &info) == 0) {
|
||||
assert(strcmp(info.name, "hi") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
count += 1;
|
||||
}
|
||||
assert(count <= 1);
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
if (lfs_stat(&lfs, "a/hi", &info) == 0) {
|
||||
lfs_rename(&lfs, "a/hi", "b/hi") => 0;
|
||||
} else if (lfs_stat(&lfs, "b/hi", &info) == 0) {
|
||||
lfs_rename(&lfs, "b/hi", "c/hi") => 0;
|
||||
} else if (lfs_stat(&lfs, "c/hi", &info) == 0) {
|
||||
lfs_rename(&lfs, "c/hi", "d/hi") => 0;
|
||||
} else if (lfs_stat(&lfs, "d/hi", &info) == 0) {
|
||||
break; // success
|
||||
} else {
|
||||
// create dir and rename for atomicity
|
||||
err = lfs_mkdir(&lfs, "temp");
|
||||
assert(!err || err == LFS_ERR_EXIST);
|
||||
err = lfs_mkdir(&lfs, "temp/hola");
|
||||
assert(!err || err == LFS_ERR_EXIST);
|
||||
err = lfs_mkdir(&lfs, "temp/bonjour");
|
||||
assert(!err || err == LFS_ERR_EXIST);
|
||||
err = lfs_mkdir(&lfs, "temp/ohayo");
|
||||
assert(!err || err == LFS_ERR_EXIST);
|
||||
lfs_rename(&lfs, "temp", "a/hi") => 0;
|
||||
}
|
||||
lfs_unmount(&lfs) => 0;
|
||||
}
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "a") => 0;
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
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;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hi") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 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;
|
||||
assert(strcmp(info.name, ".") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "..") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "bonjour") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "hola") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 1;
|
||||
assert(strcmp(info.name, "ohayo") == 0);
|
||||
assert(info.type == LFS_TYPE_DIR);
|
||||
lfs_dir_read(&lfs, &dir, &info) => 0;
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # move state stealing
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_mkdir(&lfs, "a") => 0;
|
||||
lfs_mkdir(&lfs, "b") => 0;
|
||||
lfs_mkdir(&lfs, "c") => 0;
|
||||
lfs_mkdir(&lfs, "d") => 0;
|
||||
lfs_file_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;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_rename(&lfs, "a/hello", "b/hello") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_rename(&lfs, "b/hello", "c/hello") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_rename(&lfs, "c/hello", "d/hello") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0;
|
||||
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;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_remove(&lfs, "b") => 0;
|
||||
lfs_remove(&lfs, "c") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_stat(&lfs, "a", &info) => 0;
|
||||
lfs_stat(&lfs, "b", &info) => LFS_ERR_NOENT;
|
||||
lfs_stat(&lfs, "c", &info) => LFS_ERR_NOENT;
|
||||
lfs_stat(&lfs, "d", &info) => 0;
|
||||
lfs_file_open(&lfs, &file, "a/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "b/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "c/hello", LFS_O_RDONLY) => LFS_ERR_NOENT;
|
||||
lfs_file_open(&lfs, &file, "d/hello", LFS_O_RDONLY) => 0;
|
||||
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;
|
||||
'''
|
||||
@@ -0,0 +1,56 @@
|
||||
[[case]] # orphan test
|
||||
in = "lfs.c"
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_mkdir(&lfs, "parent") => 0;
|
||||
lfs_mkdir(&lfs, "parent/orphan") => 0;
|
||||
lfs_mkdir(&lfs, "parent/child") => 0;
|
||||
lfs_remove(&lfs, "parent/orphan") => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
// corrupt the child's most recent commit, this should be the update
|
||||
// to the linked-list entry, which should orphan the orphan. Note this
|
||||
// makes a lot of assumptions about the remove operation.
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_dir_open(&lfs, &dir, "parent/child") => 0;
|
||||
lfs_block_t block = dir.m.pair[0];
|
||||
lfs_dir_close(&lfs, &dir) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
uint8_t bbuffer[LFS_BLOCK_SIZE];
|
||||
cfg.read(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
int off = LFS_BLOCK_SIZE-1;
|
||||
while (off >= 0 && bbuffer[off] == LFS_ERASE_VALUE) {
|
||||
off -= 1;
|
||||
}
|
||||
memset(&bbuffer[off-3], LFS_BLOCK_SIZE, 3);
|
||||
cfg.erase(&cfg, block) => 0;
|
||||
cfg.prog(&cfg, block, 0, bbuffer, LFS_BLOCK_SIZE) => 0;
|
||||
cfg.sync(&cfg) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
|
||||
lfs_stat(&lfs, "parent/child", &info) => 0;
|
||||
lfs_fs_size(&lfs) => 8;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
|
||||
lfs_stat(&lfs, "parent/child", &info) => 0;
|
||||
lfs_fs_size(&lfs) => 8;
|
||||
// this mkdir should both create a dir and deorphan, so size
|
||||
// should be unchanged
|
||||
lfs_mkdir(&lfs, "parent/otherchild") => 0;
|
||||
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
|
||||
lfs_stat(&lfs, "parent/child", &info) => 0;
|
||||
lfs_stat(&lfs, "parent/otherchild", &info) => 0;
|
||||
lfs_fs_size(&lfs) => 8;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
lfs_stat(&lfs, "parent/orphan", &info) => LFS_ERR_NOENT;
|
||||
lfs_stat(&lfs, "parent/child", &info) => 0;
|
||||
lfs_stat(&lfs, "parent/otherchild", &info) => 0;
|
||||
lfs_fs_size(&lfs) => 8;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
+24
-24
@@ -1,5 +1,13 @@
|
||||
|
||||
[[case]] # simple file seek
|
||||
define = [
|
||||
{COUNT=132, SKIP=4},
|
||||
{COUNT=132, SKIP=128},
|
||||
{COUNT=200, SKIP=10},
|
||||
{COUNT=200, SKIP=100},
|
||||
{COUNT=4, SKIP=1},
|
||||
{COUNT=4, SKIP=2},
|
||||
]
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -59,6 +67,8 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
|
||||
[[case]] # simple file seek and write
|
||||
define = [
|
||||
{COUNT=132, SKIP=4},
|
||||
{COUNT=132, SKIP=128},
|
||||
@@ -67,8 +77,6 @@ define = [
|
||||
{COUNT=4, SKIP=1},
|
||||
{COUNT=4, SKIP=2},
|
||||
]
|
||||
|
||||
[[case]] # simple file seek and write
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -120,16 +128,10 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define = [
|
||||
{COUNT=132, SKIP=4},
|
||||
{COUNT=132, SKIP=128},
|
||||
{COUNT=200, SKIP=10},
|
||||
{COUNT=200, SKIP=100},
|
||||
{COUNT=4, SKIP=1},
|
||||
{COUNT=4, SKIP=2},
|
||||
]
|
||||
|
||||
[[case]] # boundary seek and writes
|
||||
define.COUNT = 132
|
||||
define.OFFSETS = '"{512, 1020, 513, 1021, 511, 1019, 1441}"'
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -180,10 +182,16 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.COUNT = 132
|
||||
define.OFFSETS = '"{512, 1020, 513, 1021, 511, 1019, 1441}"'
|
||||
|
||||
[[case]] # out of bounds seek
|
||||
define = [
|
||||
{COUNT=132, SKIP=4},
|
||||
{COUNT=132, SKIP=128},
|
||||
{COUNT=200, SKIP=10},
|
||||
{COUNT=200, SKIP=100},
|
||||
{COUNT=4, SKIP=2},
|
||||
{COUNT=4, SKIP=3},
|
||||
]
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -229,16 +237,9 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define = [
|
||||
{COUNT=132, SKIP=4},
|
||||
{COUNT=132, SKIP=128},
|
||||
{COUNT=200, SKIP=10},
|
||||
{COUNT=200, SKIP=100},
|
||||
{COUNT=4, SKIP=2},
|
||||
{COUNT=4, SKIP=3},
|
||||
]
|
||||
|
||||
[[case]] # inline write and seek
|
||||
define.SIZE = [2, 4, 128, 132]
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -303,9 +304,11 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.SIZE = [2, 4, 128, 132]
|
||||
|
||||
[[case]] # file seek and write with power-loss
|
||||
# must be power-of-2 for quadratic probing to be exhaustive
|
||||
define.COUNT = [4, 64, 128]
|
||||
reentrant = true
|
||||
code = '''
|
||||
err = lfs_mount(&lfs, &cfg);
|
||||
if (err) {
|
||||
@@ -375,6 +378,3 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
# must be power-of-2 for quadratic probing to be exhaustive
|
||||
define.COUNT = [4, 64, 128]
|
||||
reentrant = true
|
||||
|
||||
+14
-15
@@ -1,4 +1,6 @@
|
||||
[[case]] # simple truncate
|
||||
define.MEDIUMSIZE = [32, 2048]
|
||||
define.LARGESIZE = 8192
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -39,10 +41,10 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.MEDIUMSIZE = [32, 2048]
|
||||
define.LARGESIZE = 8192
|
||||
|
||||
[[case]] # truncate and read
|
||||
define.MEDIUMSIZE = [32, 2048]
|
||||
define.LARGESIZE = 8192
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -90,8 +92,6 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.MEDIUMSIZE = [32, 2048]
|
||||
define.LARGESIZE = 8192
|
||||
|
||||
[[case]] # write, truncate, and read
|
||||
code = '''
|
||||
@@ -146,6 +146,8 @@ code = '''
|
||||
'''
|
||||
|
||||
[[case]] # truncate and write
|
||||
define.MEDIUMSIZE = [32, 2048]
|
||||
define.LARGESIZE = 8192
|
||||
code = '''
|
||||
lfs_format(&lfs, &cfg) => 0;
|
||||
lfs_mount(&lfs, &cfg) => 0;
|
||||
@@ -193,10 +195,12 @@ code = '''
|
||||
lfs_file_close(&lfs, &file) => 0;
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.MEDIUMSIZE = [32, 2048]
|
||||
define.LARGESIZE = 8192
|
||||
|
||||
[[case]] # truncate write under powerloss
|
||||
define.SMALLSIZE = [4, 512]
|
||||
define.MEDIUMSIZE = [32, 1024]
|
||||
define.LARGESIZE = 2048
|
||||
reentrant = true
|
||||
code = '''
|
||||
err = lfs_mount(&lfs, &cfg);
|
||||
if (err) {
|
||||
@@ -257,12 +261,12 @@ code = '''
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.SMALLSIZE = [4, 512]
|
||||
define.MEDIUMSIZE = [32, 1024]
|
||||
define.LARGESIZE = 2048
|
||||
reentrant = true
|
||||
|
||||
[[case]] # more aggressive general truncation tests
|
||||
define.CONFIG = 'range(6)'
|
||||
define.SMALLSIZE = 32
|
||||
define.MEDIUMSIZE = 2048
|
||||
define.LARGESIZE = 8192
|
||||
code = '''
|
||||
#define COUNT 5
|
||||
const struct {
|
||||
@@ -388,8 +392,3 @@ code = '''
|
||||
|
||||
lfs_unmount(&lfs) => 0;
|
||||
'''
|
||||
define.CONFIG = 'range(6)'
|
||||
define.SMALLSIZE = 32
|
||||
define.MEDIUMSIZE = 2048
|
||||
define.LARGESIZE = 8192
|
||||
|
||||
|
||||
Reference in New Issue
Block a user