| # Test for compatibility between different littlefs versions |
| # |
| # Note, these tests are a bit special. They expect to be linked against two |
| # different versions of littlefs: |
| # - lfs => the new/current version of littlefs |
| # - lfsp => the previous version of littlefs |
| # |
| # If lfsp is not linked, and LFSP is not defined, these tests will alias |
| # the relevant lfs types/functions as necessary so at least the tests can |
| # themselves be tested locally. |
| # |
| # But to get value from these tests, it's expected that the previous version |
| # of littlefs be linked in during CI, with the help of scripts/changeprefix.py |
| # |
| |
| # alias littlefs symbols as needed |
| # |
| # there may be a better way to do this, but oh well, explicit aliases works |
| code = ''' |
| #ifdef LFSP |
| #define STRINGIZE(x) STRINGIZE_(x) |
| #define STRINGIZE_(x) #x |
| #include STRINGIZE(LFSP) |
| #else |
| #define LFSP_VERSION LFS_VERSION |
| #define LFSP_VERSION_MAJOR LFS_VERSION_MAJOR |
| #define LFSP_VERSION_MINOR LFS_VERSION_MINOR |
| #define lfsp_t lfs_t |
| #define lfsp_config lfs_config |
| #define lfsp_format lfs_format |
| #define lfsp_mount lfs_mount |
| #define lfsp_unmount lfs_unmount |
| #define lfsp_dir_t lfs_dir_t |
| #define lfsp_info lfs_info |
| #define LFSP_TYPE_REG LFS_TYPE_REG |
| #define LFSP_TYPE_DIR LFS_TYPE_DIR |
| #define lfsp_mkdir lfs_mkdir |
| #define lfsp_dir_open lfs_dir_open |
| #define lfsp_dir_read lfs_dir_read |
| #define lfsp_dir_close lfs_dir_close |
| #define lfsp_file_t lfs_file_t |
| #define LFSP_O_RDONLY LFS_O_RDONLY |
| #define LFSP_O_WRONLY LFS_O_WRONLY |
| #define LFSP_O_CREAT LFS_O_CREAT |
| #define LFSP_O_EXCL LFS_O_EXCL |
| #define LFSP_SEEK_SET LFS_SEEK_SET |
| #define lfsp_file_open lfs_file_open |
| #define lfsp_file_write lfs_file_write |
| #define lfsp_file_read lfs_file_read |
| #define lfsp_file_seek lfs_file_seek |
| #define lfsp_file_close lfs_file_close |
| #endif |
| ''' |
| |
| |
| |
| ## forward-compatibility tests ## |
| |
| # test we can mount in a new version |
| [cases.test_compat_forward_mount] |
| if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR' |
| code = ''' |
| // create the previous version |
| struct lfsp_config cfgp; |
| memcpy(&cfgp, cfg, sizeof(cfgp)); |
| lfsp_t lfsp; |
| lfsp_format(&lfsp, &cfgp) => 0; |
| |
| // confirm the previous mount works |
| lfsp_mount(&lfsp, &cfgp) => 0; |
| lfsp_unmount(&lfsp) => 0; |
| |
| |
| // now test the new mount |
| lfs_t lfs; |
| lfs_mount(&lfs, cfg) => 0; |
| lfs_unmount(&lfs) => 0; |
| ''' |
| |
| # test we can read dirs in a new version |
| [cases.test_compat_forward_read_dirs] |
| defines.COUNT = 5 |
| if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR' |
| code = ''' |
| // create the previous version |
| struct lfsp_config cfgp; |
| memcpy(&cfgp, cfg, sizeof(cfgp)); |
| lfsp_t lfsp; |
| lfsp_format(&lfsp, &cfgp) => 0; |
| |
| // write COUNT dirs |
| lfsp_mount(&lfsp, &cfgp) => 0; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| lfsp_mkdir(&lfsp, name) => 0; |
| } |
| lfsp_unmount(&lfsp) => 0; |
| |
| |
| // mount the new version |
| lfs_t lfs; |
| lfs_mount(&lfs, cfg) => 0; |
| |
| // can we list the directories? |
| lfs_dir_t dir; |
| lfs_dir_open(&lfs, &dir, "/") => 0; |
| struct lfs_info info; |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| assert(strcmp(info.name, ".") == 0); |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| assert(strcmp(info.name, "..") == 0); |
| |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| } |
| |
| lfs_dir_read(&lfs, &dir, &info) => 0; |
| lfs_dir_close(&lfs, &dir) => 0; |
| |
| lfs_unmount(&lfs) => 0; |
| ''' |
| |
| # test we can read files in a new version |
| [cases.test_compat_forward_read_files] |
| defines.COUNT = 5 |
| defines.SIZE = [4, 32, 512, 8192] |
| defines.CHUNK = 4 |
| if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR' |
| code = ''' |
| // create the previous version |
| struct lfsp_config cfgp; |
| memcpy(&cfgp, cfg, sizeof(cfgp)); |
| lfsp_t lfsp; |
| lfsp_format(&lfsp, &cfgp) => 0; |
| |
| // write COUNT files |
| lfsp_mount(&lfsp, &cfgp) => 0; |
| uint32_t prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfsp_file_t file; |
| char name[8]; |
| sprintf(name, "file%03d", i); |
| lfsp_file_open(&lfsp, &file, name, |
| LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0; |
| for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| chunk[k] = TEST_PRNG(&prng) & 0xff; |
| } |
| |
| lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK; |
| } |
| lfsp_file_close(&lfsp, &file) => 0; |
| } |
| lfsp_unmount(&lfsp) => 0; |
| |
| |
| // mount the new version |
| lfs_t lfs; |
| lfs_mount(&lfs, cfg) => 0; |
| |
| // can we list the files? |
| lfs_dir_t dir; |
| lfs_dir_open(&lfs, &dir, "/") => 0; |
| struct lfs_info info; |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| assert(strcmp(info.name, ".") == 0); |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| assert(strcmp(info.name, "..") == 0); |
| |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_REG); |
| char name[8]; |
| sprintf(name, "file%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| assert(info.size == SIZE); |
| } |
| |
| lfs_dir_read(&lfs, &dir, &info) => 0; |
| |
| // now can we read the files? |
| prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfs_file_t file; |
| char name[8]; |
| sprintf(name, "file%03d", i); |
| lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0; |
| for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK; |
| |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| assert(chunk[k] == TEST_PRNG(&prng) & 0xff); |
| } |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| } |
| |
| lfs_unmount(&lfs) => 0; |
| ''' |
| |
| # test we can read files in dirs in a new version |
| [cases.test_compat_forward_read_files_in_dirs] |
| defines.COUNT = 5 |
| defines.SIZE = [4, 32, 512, 8192] |
| defines.CHUNK = 4 |
| if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR' |
| code = ''' |
| // create the previous version |
| struct lfsp_config cfgp; |
| memcpy(&cfgp, cfg, sizeof(cfgp)); |
| lfsp_t lfsp; |
| lfsp_format(&lfsp, &cfgp) => 0; |
| |
| // write COUNT files+dirs |
| lfsp_mount(&lfsp, &cfgp) => 0; |
| uint32_t prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| char name[16]; |
| sprintf(name, "dir%03d", i); |
| lfsp_mkdir(&lfsp, name) => 0; |
| |
| lfsp_file_t file; |
| sprintf(name, "dir%03d/file%03d", i, i); |
| lfsp_file_open(&lfsp, &file, name, |
| LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0; |
| for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| chunk[k] = TEST_PRNG(&prng) & 0xff; |
| } |
| |
| lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK; |
| } |
| lfsp_file_close(&lfsp, &file) => 0; |
| } |
| lfsp_unmount(&lfsp) => 0; |
| |
| |
| // mount the new version |
| lfs_t lfs; |
| lfs_mount(&lfs, cfg) => 0; |
| |
| // can we list the directories? |
| lfs_dir_t dir; |
| lfs_dir_open(&lfs, &dir, "/") => 0; |
| struct lfs_info info; |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| assert(strcmp(info.name, ".") == 0); |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| assert(strcmp(info.name, "..") == 0); |
| |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| } |
| |
| lfs_dir_read(&lfs, &dir, &info) => 0; |
| lfs_dir_close(&lfs, &dir) => 0; |
| |
| // can we list the files? |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| lfs_dir_t dir; |
| lfs_dir_open(&lfs, &dir, name) => 0; |
| struct lfs_info info; |
| 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); |
| sprintf(name, "file%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| assert(info.size == SIZE); |
| |
| lfs_dir_read(&lfs, &dir, &info) => 0; |
| lfs_dir_close(&lfs, &dir) => 0; |
| } |
| |
| // now can we read the files? |
| prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfs_file_t file; |
| char name[16]; |
| sprintf(name, "dir%03d/file%03d", i, i); |
| lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0; |
| for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK; |
| |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| assert(chunk[k] == TEST_PRNG(&prng) & 0xff); |
| } |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| } |
| |
| lfs_unmount(&lfs) => 0; |
| ''' |
| |
| # test we can write dirs in a new version |
| [cases.test_compat_forward_write_dirs] |
| defines.COUNT = 10 |
| if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR' |
| code = ''' |
| // create the previous version |
| struct lfsp_config cfgp; |
| memcpy(&cfgp, cfg, sizeof(cfgp)); |
| lfsp_t lfsp; |
| lfsp_format(&lfsp, &cfgp) => 0; |
| |
| // write COUNT/2 dirs |
| lfsp_mount(&lfsp, &cfgp) => 0; |
| for (lfs_size_t i = 0; i < COUNT/2; i++) { |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| lfsp_mkdir(&lfsp, name) => 0; |
| } |
| lfsp_unmount(&lfsp) => 0; |
| |
| |
| // mount the new version |
| lfs_t lfs; |
| lfs_mount(&lfs, cfg) => 0; |
| |
| // write another COUNT/2 dirs |
| for (lfs_size_t i = COUNT/2; i < COUNT; i++) { |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| lfs_mkdir(&lfs, name) => 0; |
| } |
| |
| // can we list the directories? |
| lfs_dir_t dir; |
| lfs_dir_open(&lfs, &dir, "/") => 0; |
| struct lfs_info info; |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| assert(strcmp(info.name, ".") == 0); |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| assert(strcmp(info.name, "..") == 0); |
| |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| } |
| |
| lfs_dir_read(&lfs, &dir, &info) => 0; |
| lfs_dir_close(&lfs, &dir) => 0; |
| |
| lfs_unmount(&lfs) => 0; |
| ''' |
| |
| # test we can write files in a new version |
| [cases.test_compat_forward_write_files] |
| defines.COUNT = 5 |
| defines.SIZE = [4, 32, 512, 8192] |
| defines.CHUNK = 2 |
| if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR' |
| code = ''' |
| // create the previous version |
| struct lfsp_config cfgp; |
| memcpy(&cfgp, cfg, sizeof(cfgp)); |
| lfsp_t lfsp; |
| lfsp_format(&lfsp, &cfgp) => 0; |
| |
| // write half COUNT files |
| lfsp_mount(&lfsp, &cfgp) => 0; |
| uint32_t prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| // write half |
| lfsp_file_t file; |
| char name[8]; |
| sprintf(name, "file%03d", i); |
| lfsp_file_open(&lfsp, &file, name, |
| LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0; |
| for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| chunk[k] = TEST_PRNG(&prng) & 0xff; |
| } |
| |
| lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK; |
| } |
| lfsp_file_close(&lfsp, &file) => 0; |
| |
| // skip the other half but keep our prng reproducible |
| for (lfs_size_t j = SIZE/2; j < SIZE; j++) { |
| TEST_PRNG(&prng); |
| } |
| } |
| lfsp_unmount(&lfsp) => 0; |
| |
| |
| // mount the new version |
| lfs_t lfs; |
| lfs_mount(&lfs, cfg) => 0; |
| |
| // write half COUNT files |
| prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| // skip half but keep our prng reproducible |
| for (lfs_size_t j = 0; j < SIZE/2; j++) { |
| TEST_PRNG(&prng); |
| } |
| |
| // write the other half |
| lfs_file_t file; |
| char name[8]; |
| sprintf(name, "file%03d", i); |
| lfs_file_open(&lfs, &file, name, LFS_O_WRONLY) => 0; |
| lfs_file_seek(&lfs, &file, SIZE/2, LFS_SEEK_SET) => SIZE/2; |
| |
| for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| chunk[k] = TEST_PRNG(&prng) & 0xff; |
| } |
| |
| lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK; |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| } |
| |
| // can we list the files? |
| lfs_dir_t dir; |
| lfs_dir_open(&lfs, &dir, "/") => 0; |
| struct lfs_info info; |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| assert(strcmp(info.name, ".") == 0); |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| assert(strcmp(info.name, "..") == 0); |
| |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_REG); |
| char name[8]; |
| sprintf(name, "file%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| assert(info.size == SIZE); |
| } |
| |
| lfs_dir_read(&lfs, &dir, &info) => 0; |
| |
| // now can we read the files? |
| prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfs_file_t file; |
| char name[8]; |
| sprintf(name, "file%03d", i); |
| lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0; |
| for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK; |
| |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| assert(chunk[k] == TEST_PRNG(&prng) & 0xff); |
| } |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| } |
| |
| lfs_unmount(&lfs) => 0; |
| ''' |
| |
| # test we can write files in dirs in a new version |
| [cases.test_compat_forward_write_files_in_dirs] |
| defines.COUNT = 5 |
| defines.SIZE = [4, 32, 512, 8192] |
| defines.CHUNK = 2 |
| if = 'LFS_VERSION_MAJOR == LFSP_VERSION_MAJOR' |
| code = ''' |
| // create the previous version |
| struct lfsp_config cfgp; |
| memcpy(&cfgp, cfg, sizeof(cfgp)); |
| lfsp_t lfsp; |
| lfsp_format(&lfsp, &cfgp) => 0; |
| |
| // write half COUNT files |
| lfsp_mount(&lfsp, &cfgp) => 0; |
| uint32_t prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| char name[16]; |
| sprintf(name, "dir%03d", i); |
| lfsp_mkdir(&lfsp, name) => 0; |
| |
| // write half |
| lfsp_file_t file; |
| sprintf(name, "dir%03d/file%03d", i, i); |
| lfsp_file_open(&lfsp, &file, name, |
| LFSP_O_WRONLY | LFSP_O_CREAT | LFSP_O_EXCL) => 0; |
| for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| chunk[k] = TEST_PRNG(&prng) & 0xff; |
| } |
| |
| lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK; |
| } |
| lfsp_file_close(&lfsp, &file) => 0; |
| |
| // skip the other half but keep our prng reproducible |
| for (lfs_size_t j = SIZE/2; j < SIZE; j++) { |
| TEST_PRNG(&prng); |
| } |
| } |
| lfsp_unmount(&lfsp) => 0; |
| |
| |
| // mount the new version |
| lfs_t lfs; |
| lfs_mount(&lfs, cfg) => 0; |
| |
| // write half COUNT files |
| prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| // skip half but keep our prng reproducible |
| for (lfs_size_t j = 0; j < SIZE/2; j++) { |
| TEST_PRNG(&prng); |
| } |
| |
| // write the other half |
| lfs_file_t file; |
| char name[16]; |
| sprintf(name, "dir%03d/file%03d", i, i); |
| lfs_file_open(&lfs, &file, name, LFS_O_WRONLY) => 0; |
| lfs_file_seek(&lfs, &file, SIZE/2, LFS_SEEK_SET) => SIZE/2; |
| |
| for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| chunk[k] = TEST_PRNG(&prng) & 0xff; |
| } |
| |
| lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK; |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| } |
| |
| // can we list the directories? |
| lfs_dir_t dir; |
| lfs_dir_open(&lfs, &dir, "/") => 0; |
| struct lfs_info info; |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| assert(strcmp(info.name, ".") == 0); |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| assert(strcmp(info.name, "..") == 0); |
| |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfs_dir_read(&lfs, &dir, &info) => 1; |
| assert(info.type == LFS_TYPE_DIR); |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| } |
| |
| lfs_dir_read(&lfs, &dir, &info) => 0; |
| lfs_dir_close(&lfs, &dir) => 0; |
| |
| // can we list the files? |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| lfs_dir_t dir; |
| lfs_dir_open(&lfs, &dir, name) => 0; |
| struct lfs_info info; |
| 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); |
| sprintf(name, "file%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| assert(info.size == SIZE); |
| |
| lfs_dir_read(&lfs, &dir, &info) => 0; |
| lfs_dir_close(&lfs, &dir) => 0; |
| } |
| |
| // now can we read the files? |
| prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfs_file_t file; |
| char name[16]; |
| sprintf(name, "dir%03d/file%03d", i, i); |
| lfs_file_open(&lfs, &file, name, LFS_O_RDONLY) => 0; |
| for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| lfs_file_read(&lfs, &file, chunk, CHUNK) => CHUNK; |
| |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| assert(chunk[k] == TEST_PRNG(&prng) & 0xff); |
| } |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| } |
| |
| lfs_unmount(&lfs) => 0; |
| ''' |
| |
| |
| |
| ## backwards-compatibility tests ## |
| |
| # test we can mount in an old version |
| [cases.test_compat_backward_mount] |
| if = 'LFS_VERSION == LFSP_VERSION' |
| code = ''' |
| // create the new version |
| lfs_t lfs; |
| lfs_format(&lfs, cfg) => 0; |
| |
| // confirm the new mount works |
| lfs_mount(&lfs, cfg) => 0; |
| lfs_unmount(&lfs) => 0; |
| |
| // now test the previous mount |
| struct lfsp_config cfgp; |
| memcpy(&cfgp, cfg, sizeof(cfgp)); |
| lfsp_t lfsp; |
| lfsp_mount(&lfsp, &cfgp) => 0; |
| lfsp_unmount(&lfsp) => 0; |
| ''' |
| |
| # test we can read dirs in an old version |
| [cases.test_compat_backward_read_dirs] |
| defines.COUNT = 5 |
| if = 'LFS_VERSION == LFSP_VERSION' |
| code = ''' |
| // create the new version |
| lfs_t lfs; |
| lfs_format(&lfs, cfg) => 0; |
| |
| // write COUNT dirs |
| lfs_mount(&lfs, cfg) => 0; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| lfs_mkdir(&lfs, name) => 0; |
| } |
| lfs_unmount(&lfs) => 0; |
| |
| |
| // mount the new version |
| struct lfsp_config cfgp; |
| memcpy(&cfgp, cfg, sizeof(cfgp)); |
| lfsp_t lfsp; |
| lfsp_mount(&lfsp, &cfgp) => 0; |
| |
| // can we list the directories? |
| lfsp_dir_t dir; |
| lfsp_dir_open(&lfsp, &dir, "/") => 0; |
| struct lfsp_info info; |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, ".") == 0); |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, "..") == 0); |
| |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| } |
| |
| lfsp_dir_read(&lfsp, &dir, &info) => 0; |
| lfsp_dir_close(&lfsp, &dir) => 0; |
| |
| lfsp_unmount(&lfsp) => 0; |
| ''' |
| |
| # test we can read files in an old version |
| [cases.test_compat_backward_read_files] |
| defines.COUNT = 5 |
| defines.SIZE = [4, 32, 512, 8192] |
| defines.CHUNK = 4 |
| if = 'LFS_VERSION == LFSP_VERSION' |
| code = ''' |
| // create the new version |
| lfs_t lfs; |
| lfs_format(&lfs, cfg) => 0; |
| |
| // write COUNT files |
| lfs_mount(&lfs, cfg) => 0; |
| uint32_t prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfs_file_t file; |
| char name[8]; |
| sprintf(name, "file%03d", i); |
| lfs_file_open(&lfs, &file, name, |
| LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; |
| for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| chunk[k] = TEST_PRNG(&prng) & 0xff; |
| } |
| |
| lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK; |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| } |
| lfs_unmount(&lfs) => 0; |
| |
| |
| // mount the previous version |
| struct lfsp_config cfgp; |
| memcpy(&cfgp, cfg, sizeof(cfgp)); |
| lfsp_t lfsp; |
| lfsp_mount(&lfsp, &cfgp) => 0; |
| |
| // can we list the files? |
| lfsp_dir_t dir; |
| lfsp_dir_open(&lfsp, &dir, "/") => 0; |
| struct lfsp_info info; |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, ".") == 0); |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, "..") == 0); |
| |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_REG); |
| char name[8]; |
| sprintf(name, "file%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| assert(info.size == SIZE); |
| } |
| |
| lfsp_dir_read(&lfsp, &dir, &info) => 0; |
| |
| // now can we read the files? |
| prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfsp_file_t file; |
| char name[8]; |
| sprintf(name, "file%03d", i); |
| lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0; |
| for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK; |
| |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| assert(chunk[k] == TEST_PRNG(&prng) & 0xff); |
| } |
| } |
| lfsp_file_close(&lfsp, &file) => 0; |
| } |
| |
| lfsp_unmount(&lfsp) => 0; |
| ''' |
| |
| # test we can read files in dirs in an old version |
| [cases.test_compat_backward_read_files_in_dirs] |
| defines.COUNT = 5 |
| defines.SIZE = [4, 32, 512, 8192] |
| defines.CHUNK = 4 |
| if = 'LFS_VERSION == LFSP_VERSION' |
| code = ''' |
| // create the new version |
| lfs_t lfs; |
| lfs_format(&lfs, cfg) => 0; |
| |
| // write COUNT files+dirs |
| lfs_mount(&lfs, cfg) => 0; |
| uint32_t prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| char name[16]; |
| sprintf(name, "dir%03d", i); |
| lfs_mkdir(&lfs, name) => 0; |
| |
| lfs_file_t file; |
| sprintf(name, "dir%03d/file%03d", i, i); |
| lfs_file_open(&lfs, &file, name, |
| LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; |
| for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| chunk[k] = TEST_PRNG(&prng) & 0xff; |
| } |
| |
| lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK; |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| } |
| lfs_unmount(&lfs) => 0; |
| |
| |
| // mount the previous version |
| struct lfsp_config cfgp; |
| memcpy(&cfgp, cfg, sizeof(cfgp)); |
| lfsp_t lfsp; |
| lfsp_mount(&lfsp, &cfgp) => 0; |
| |
| // can we list the directories? |
| lfsp_dir_t dir; |
| lfsp_dir_open(&lfsp, &dir, "/") => 0; |
| struct lfsp_info info; |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, ".") == 0); |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, "..") == 0); |
| |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| } |
| |
| lfsp_dir_read(&lfsp, &dir, &info) => 0; |
| lfsp_dir_close(&lfsp, &dir) => 0; |
| |
| // can we list the files? |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| lfsp_dir_t dir; |
| lfsp_dir_open(&lfsp, &dir, name) => 0; |
| struct lfsp_info info; |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, ".") == 0); |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, "..") == 0); |
| |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_REG); |
| sprintf(name, "file%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| assert(info.size == SIZE); |
| |
| lfsp_dir_read(&lfsp, &dir, &info) => 0; |
| lfsp_dir_close(&lfsp, &dir) => 0; |
| } |
| |
| // now can we read the files? |
| prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfsp_file_t file; |
| char name[16]; |
| sprintf(name, "dir%03d/file%03d", i, i); |
| lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0; |
| for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK; |
| |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| assert(chunk[k] == TEST_PRNG(&prng) & 0xff); |
| } |
| } |
| lfsp_file_close(&lfsp, &file) => 0; |
| } |
| |
| lfsp_unmount(&lfsp) => 0; |
| ''' |
| |
| # test we can write dirs in an old version |
| [cases.test_compat_backward_write_dirs] |
| defines.COUNT = 10 |
| if = 'LFS_VERSION == LFSP_VERSION' |
| code = ''' |
| // create the new version |
| lfs_t lfs; |
| lfs_format(&lfs, cfg) => 0; |
| |
| // write COUNT/2 dirs |
| lfs_mount(&lfs, cfg) => 0; |
| for (lfs_size_t i = 0; i < COUNT/2; i++) { |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| lfs_mkdir(&lfs, name) => 0; |
| } |
| lfs_unmount(&lfs) => 0; |
| |
| |
| // mount the previous version |
| struct lfsp_config cfgp; |
| memcpy(&cfgp, cfg, sizeof(cfgp)); |
| lfsp_t lfsp; |
| lfsp_mount(&lfsp, &cfgp) => 0; |
| |
| // write another COUNT/2 dirs |
| for (lfs_size_t i = COUNT/2; i < COUNT; i++) { |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| lfsp_mkdir(&lfsp, name) => 0; |
| } |
| |
| // can we list the directories? |
| lfsp_dir_t dir; |
| lfsp_dir_open(&lfsp, &dir, "/") => 0; |
| struct lfsp_info info; |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, ".") == 0); |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, "..") == 0); |
| |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| } |
| |
| lfsp_dir_read(&lfsp, &dir, &info) => 0; |
| lfsp_dir_close(&lfsp, &dir) => 0; |
| |
| lfsp_unmount(&lfsp) => 0; |
| ''' |
| |
| # test we can write files in an old version |
| [cases.test_compat_backward_write_files] |
| defines.COUNT = 5 |
| defines.SIZE = [4, 32, 512, 8192] |
| defines.CHUNK = 2 |
| if = 'LFS_VERSION == LFSP_VERSION' |
| code = ''' |
| // create the previous version |
| lfs_t lfs; |
| lfs_format(&lfs, cfg) => 0; |
| |
| // write half COUNT files |
| lfs_mount(&lfs, cfg) => 0; |
| uint32_t prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| // write half |
| lfs_file_t file; |
| char name[8]; |
| sprintf(name, "file%03d", i); |
| lfs_file_open(&lfs, &file, name, |
| LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; |
| for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| chunk[k] = TEST_PRNG(&prng) & 0xff; |
| } |
| |
| lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK; |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| |
| // skip the other half but keep our prng reproducible |
| for (lfs_size_t j = SIZE/2; j < SIZE; j++) { |
| TEST_PRNG(&prng); |
| } |
| } |
| lfs_unmount(&lfs) => 0; |
| |
| |
| // mount the new version |
| struct lfsp_config cfgp; |
| memcpy(&cfgp, cfg, sizeof(cfgp)); |
| lfsp_t lfsp; |
| lfsp_mount(&lfsp, &cfgp) => 0; |
| |
| // write half COUNT files |
| prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| // skip half but keep our prng reproducible |
| for (lfs_size_t j = 0; j < SIZE/2; j++) { |
| TEST_PRNG(&prng); |
| } |
| |
| // write the other half |
| lfsp_file_t file; |
| char name[8]; |
| sprintf(name, "file%03d", i); |
| lfsp_file_open(&lfsp, &file, name, LFSP_O_WRONLY) => 0; |
| lfsp_file_seek(&lfsp, &file, SIZE/2, LFSP_SEEK_SET) => SIZE/2; |
| |
| for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| chunk[k] = TEST_PRNG(&prng) & 0xff; |
| } |
| |
| lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK; |
| } |
| lfsp_file_close(&lfsp, &file) => 0; |
| } |
| |
| // can we list the files? |
| lfsp_dir_t dir; |
| lfsp_dir_open(&lfsp, &dir, "/") => 0; |
| struct lfsp_info info; |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, ".") == 0); |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, "..") == 0); |
| |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_REG); |
| char name[8]; |
| sprintf(name, "file%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| assert(info.size == SIZE); |
| } |
| |
| lfsp_dir_read(&lfsp, &dir, &info) => 0; |
| |
| // now can we read the files? |
| prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfsp_file_t file; |
| char name[8]; |
| sprintf(name, "file%03d", i); |
| lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0; |
| for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK; |
| |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| assert(chunk[k] == TEST_PRNG(&prng) & 0xff); |
| } |
| } |
| lfsp_file_close(&lfsp, &file) => 0; |
| } |
| |
| lfsp_unmount(&lfsp) => 0; |
| ''' |
| |
| # test we can write files in dirs in an old version |
| [cases.test_compat_backward_write_files_in_dirs] |
| defines.COUNT = 5 |
| defines.SIZE = [4, 32, 512, 8192] |
| defines.CHUNK = 2 |
| if = 'LFS_VERSION == LFSP_VERSION' |
| code = ''' |
| // create the previous version |
| lfs_t lfs; |
| lfs_format(&lfs, cfg) => 0; |
| |
| // write half COUNT files |
| lfs_mount(&lfs, cfg) => 0; |
| uint32_t prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| char name[16]; |
| sprintf(name, "dir%03d", i); |
| lfs_mkdir(&lfs, name) => 0; |
| |
| // write half |
| lfs_file_t file; |
| sprintf(name, "dir%03d/file%03d", i, i); |
| lfs_file_open(&lfs, &file, name, |
| LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; |
| for (lfs_size_t j = 0; j < SIZE/2; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| chunk[k] = TEST_PRNG(&prng) & 0xff; |
| } |
| |
| lfs_file_write(&lfs, &file, chunk, CHUNK) => CHUNK; |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| |
| // skip the other half but keep our prng reproducible |
| for (lfs_size_t j = SIZE/2; j < SIZE; j++) { |
| TEST_PRNG(&prng); |
| } |
| } |
| lfs_unmount(&lfs) => 0; |
| |
| |
| // mount the new version |
| struct lfsp_config cfgp; |
| memcpy(&cfgp, cfg, sizeof(cfgp)); |
| lfsp_t lfsp; |
| lfsp_mount(&lfsp, &cfgp) => 0; |
| |
| // write half COUNT files |
| prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| // skip half but keep our prng reproducible |
| for (lfs_size_t j = 0; j < SIZE/2; j++) { |
| TEST_PRNG(&prng); |
| } |
| |
| // write the other half |
| lfsp_file_t file; |
| char name[16]; |
| sprintf(name, "dir%03d/file%03d", i, i); |
| lfsp_file_open(&lfsp, &file, name, LFSP_O_WRONLY) => 0; |
| lfsp_file_seek(&lfsp, &file, SIZE/2, LFSP_SEEK_SET) => SIZE/2; |
| |
| for (lfs_size_t j = SIZE/2; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| chunk[k] = TEST_PRNG(&prng) & 0xff; |
| } |
| |
| lfsp_file_write(&lfsp, &file, chunk, CHUNK) => CHUNK; |
| } |
| lfsp_file_close(&lfsp, &file) => 0; |
| } |
| |
| // can we list the directories? |
| lfsp_dir_t dir; |
| lfsp_dir_open(&lfsp, &dir, "/") => 0; |
| struct lfsp_info info; |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, ".") == 0); |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, "..") == 0); |
| |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| } |
| |
| lfsp_dir_read(&lfsp, &dir, &info) => 0; |
| lfsp_dir_close(&lfsp, &dir) => 0; |
| |
| // can we list the files? |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| char name[8]; |
| sprintf(name, "dir%03d", i); |
| lfsp_dir_t dir; |
| lfsp_dir_open(&lfsp, &dir, name) => 0; |
| struct lfsp_info info; |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, ".") == 0); |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_DIR); |
| assert(strcmp(info.name, "..") == 0); |
| |
| lfsp_dir_read(&lfsp, &dir, &info) => 1; |
| assert(info.type == LFSP_TYPE_REG); |
| sprintf(name, "file%03d", i); |
| assert(strcmp(info.name, name) == 0); |
| assert(info.size == SIZE); |
| |
| lfsp_dir_read(&lfsp, &dir, &info) => 0; |
| lfsp_dir_close(&lfsp, &dir) => 0; |
| } |
| |
| // now can we read the files? |
| prng = 42; |
| for (lfs_size_t i = 0; i < COUNT; i++) { |
| lfsp_file_t file; |
| char name[16]; |
| sprintf(name, "dir%03d/file%03d", i, i); |
| lfsp_file_open(&lfsp, &file, name, LFSP_O_RDONLY) => 0; |
| for (lfs_size_t j = 0; j < SIZE; j += CHUNK) { |
| uint8_t chunk[CHUNK]; |
| lfsp_file_read(&lfsp, &file, chunk, CHUNK) => CHUNK; |
| |
| for (lfs_size_t k = 0; k < CHUNK; k++) { |
| assert(chunk[k] == TEST_PRNG(&prng) & 0xff); |
| } |
| } |
| lfsp_file_close(&lfsp, &file) => 0; |
| } |
| |
| lfsp_unmount(&lfsp) => 0; |
| ''' |
| |
| |
| |
| ## incompatiblity tests ## |
| |
| # test that we fail to mount after a major version bump |
| [cases.test_compat_major_incompat] |
| in = 'lfs.c' |
| code = ''' |
| // create a superblock |
| lfs_t lfs; |
| lfs_format(&lfs, cfg) => 0; |
| |
| // bump the major version |
| // |
| // note we're messing around with internals to do this! this |
| // is not a user API |
| lfs_mount(&lfs, cfg) => 0; |
| lfs_mdir_t mdir; |
| lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; |
| lfs_superblock_t superblock = { |
| .version = LFS_DISK_VERSION + 0x00010000, |
| .block_size = lfs.cfg->block_size, |
| .block_count = lfs.cfg->block_count, |
| .name_max = lfs.name_max, |
| .file_max = lfs.file_max, |
| .attr_max = lfs.attr_max, |
| }; |
| lfs_superblock_tole32(&superblock); |
| lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( |
| {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), |
| &superblock})) => 0; |
| lfs_unmount(&lfs) => 0; |
| |
| // mount should now fail |
| lfs_mount(&lfs, cfg) => LFS_ERR_INVAL; |
| ''' |
| |
| # test that we fail to mount after a minor version bump |
| [cases.test_compat_minor_incompat] |
| in = 'lfs.c' |
| code = ''' |
| // create a superblock |
| lfs_t lfs; |
| lfs_format(&lfs, cfg) => 0; |
| |
| // bump the minor version |
| // |
| // note we're messing around with internals to do this! this |
| // is not a user API |
| lfs_mount(&lfs, cfg) => 0; |
| lfs_mdir_t mdir; |
| lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; |
| lfs_superblock_t superblock = { |
| .version = LFS_DISK_VERSION + 0x00000001, |
| .block_size = lfs.cfg->block_size, |
| .block_count = lfs.cfg->block_count, |
| .name_max = lfs.name_max, |
| .file_max = lfs.file_max, |
| .attr_max = lfs.attr_max, |
| }; |
| lfs_superblock_tole32(&superblock); |
| lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( |
| {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), |
| &superblock})) => 0; |
| lfs_unmount(&lfs) => 0; |
| |
| // mount should now fail |
| lfs_mount(&lfs, cfg) => LFS_ERR_INVAL; |
| ''' |
| |
| # test that we correctly bump the minor version |
| [cases.test_compat_minor_bump] |
| in = 'lfs.c' |
| if = 'LFS_DISK_VERSION_MINOR > 0' |
| code = ''' |
| // create a superblock |
| lfs_t lfs; |
| lfs_format(&lfs, cfg) => 0; |
| lfs_mount(&lfs, cfg) => 0; |
| lfs_file_t file; |
| lfs_file_open(&lfs, &file, "test", |
| LFS_O_WRONLY | LFS_O_CREAT | LFS_O_EXCL) => 0; |
| lfs_file_write(&lfs, &file, "testtest", 8) => 8; |
| lfs_file_close(&lfs, &file) => 0; |
| lfs_unmount(&lfs) => 0; |
| |
| // write an old minor version |
| // |
| // note we're messing around with internals to do this! this |
| // is not a user API |
| lfs_mount(&lfs, cfg) => 0; |
| lfs_mdir_t mdir; |
| lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; |
| lfs_superblock_t superblock = { |
| .version = LFS_DISK_VERSION - 0x00000001, |
| .block_size = lfs.cfg->block_size, |
| .block_count = lfs.cfg->block_count, |
| .name_max = lfs.name_max, |
| .file_max = lfs.file_max, |
| .attr_max = lfs.attr_max, |
| }; |
| lfs_superblock_tole32(&superblock); |
| lfs_dir_commit(&lfs, &mdir, LFS_MKATTRS( |
| {LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), |
| &superblock})) => 0; |
| lfs_unmount(&lfs) => 0; |
| |
| // mount should still work |
| lfs_mount(&lfs, cfg) => 0; |
| lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0; |
| uint8_t buffer[8]; |
| lfs_file_read(&lfs, &file, buffer, 8) => 8; |
| assert(memcmp(buffer, "testtest", 8) == 0); |
| lfs_file_close(&lfs, &file) => 0; |
| lfs_unmount(&lfs) => 0; |
| |
| // if we write, we need to bump the minor version |
| lfs_mount(&lfs, cfg) => 0; |
| lfs_file_open(&lfs, &file, "test", LFS_O_WRONLY | LFS_O_TRUNC) => 0; |
| lfs_file_write(&lfs, &file, "teeeeest", 8) => 8; |
| lfs_file_close(&lfs, &file) => 0; |
| |
| // minor version should have changed |
| lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; |
| lfs_dir_get(&lfs, &mdir, LFS_MKTAG(0x7ff, 0x3ff, 0), |
| LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), |
| &superblock) |
| => LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)); |
| lfs_superblock_fromle32(&superblock); |
| assert((superblock.version >> 16) & 0xffff == LFS_DISK_VERSION_MAJOR); |
| assert((superblock.version >> 0) & 0xffff == LFS_DISK_VERSION_MINOR); |
| lfs_unmount(&lfs) => 0; |
| |
| // and of course mount should still work |
| lfs_mount(&lfs, cfg) => 0; |
| lfs_file_open(&lfs, &file, "test", LFS_O_RDONLY) => 0; |
| lfs_file_read(&lfs, &file, buffer, 8) => 8; |
| assert(memcmp(buffer, "teeeeest", 8) == 0); |
| lfs_file_close(&lfs, &file) => 0; |
| |
| // minor version should have changed |
| lfs_dir_fetch(&lfs, &mdir, (lfs_block_t[2]){0, 1}) => 0; |
| lfs_dir_get(&lfs, &mdir, LFS_MKTAG(0x7ff, 0x3ff, 0), |
| LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)), |
| &superblock) |
| => LFS_MKTAG(LFS_TYPE_INLINESTRUCT, 0, sizeof(superblock)); |
| lfs_superblock_fromle32(&superblock); |
| assert((superblock.version >> 16) & 0xffff == LFS_DISK_VERSION_MAJOR); |
| assert((superblock.version >> 0) & 0xffff == LFS_DISK_VERSION_MINOR); |
| lfs_unmount(&lfs) => 0; |
| ''' |