| # There are already a number of tests that test general operations under |
| # power-loss (see the reentrant attribute). These tests are for explicitly |
| # testing specific corner cases. |
| |
| # only a revision count |
| [cases.test_powerloss_only_rev] |
| code = ''' |
| lfs_t lfs; |
| lfs_format(&lfs, cfg) => 0; |
| |
| lfs_mount(&lfs, cfg) => 0; |
| lfs_mkdir(&lfs, "notebook") => 0; |
| lfs_file_t file; |
| lfs_file_open(&lfs, &file, "notebook/paper", |
| LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; |
| char buffer[256]; |
| strcpy(buffer, "hello"); |
| lfs_size_t size = strlen("hello"); |
| for (int i = 0; i < 5; i++) { |
| lfs_file_write(&lfs, &file, buffer, size) => size; |
| lfs_file_sync(&lfs, &file) => 0; |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| |
| char rbuffer[256]; |
| lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; |
| for (int i = 0; i < 5; i++) { |
| lfs_file_read(&lfs, &file, rbuffer, size) => size; |
| assert(memcmp(rbuffer, buffer, size) == 0); |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| lfs_unmount(&lfs) => 0; |
| |
| // get pair/rev count |
| lfs_mount(&lfs, cfg) => 0; |
| lfs_dir_t dir; |
| lfs_dir_open(&lfs, &dir, "notebook") => 0; |
| lfs_block_t pair[2] = {dir.m.pair[0], dir.m.pair[1]}; |
| uint32_t rev = dir.m.rev; |
| lfs_dir_close(&lfs, &dir) => 0; |
| lfs_unmount(&lfs) => 0; |
| |
| // write just the revision count |
| uint8_t bbuffer[BLOCK_SIZE]; |
| cfg->read(cfg, pair[1], 0, bbuffer, BLOCK_SIZE) => 0; |
| |
| memcpy(bbuffer, &(uint32_t){lfs_tole32(rev+1)}, sizeof(uint32_t)); |
| |
| cfg->erase(cfg, pair[1]) => 0; |
| cfg->prog(cfg, pair[1], 0, bbuffer, BLOCK_SIZE) => 0; |
| |
| lfs_mount(&lfs, cfg) => 0; |
| |
| // can read? |
| lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; |
| for (int i = 0; i < 5; i++) { |
| lfs_file_read(&lfs, &file, rbuffer, size) => size; |
| assert(memcmp(rbuffer, buffer, size) == 0); |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| |
| // can write? |
| lfs_file_open(&lfs, &file, "notebook/paper", |
| LFS_O_WRONLY | LFS_O_APPEND) => 0; |
| strcpy(buffer, "goodbye"); |
| size = strlen("goodbye"); |
| for (int i = 0; i < 5; i++) { |
| lfs_file_write(&lfs, &file, buffer, size) => size; |
| lfs_file_sync(&lfs, &file) => 0; |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| |
| lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; |
| strcpy(buffer, "hello"); |
| size = strlen("hello"); |
| for (int i = 0; i < 5; i++) { |
| lfs_file_read(&lfs, &file, rbuffer, size) => size; |
| assert(memcmp(rbuffer, buffer, size) == 0); |
| } |
| strcpy(buffer, "goodbye"); |
| size = strlen("goodbye"); |
| for (int i = 0; i < 5; i++) { |
| lfs_file_read(&lfs, &file, rbuffer, size) => size; |
| assert(memcmp(rbuffer, buffer, size) == 0); |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| |
| lfs_unmount(&lfs) => 0; |
| ''' |
| |
| # partial prog, may not be byte in order! |
| [cases.test_powerloss_partial_prog] |
| if = ''' |
| PROG_SIZE < BLOCK_SIZE |
| && (DISK_VERSION == 0 || DISK_VERSION >= 0x00020001) |
| ''' |
| defines.BYTE_OFF = ["0", "PROG_SIZE-1", "PROG_SIZE/2"] |
| defines.BYTE_VALUE = [0x33, 0xcc] |
| in = "lfs.c" |
| code = ''' |
| lfs_t lfs; |
| lfs_format(&lfs, cfg) => 0; |
| |
| lfs_mount(&lfs, cfg) => 0; |
| lfs_mkdir(&lfs, "notebook") => 0; |
| lfs_file_t file; |
| lfs_file_open(&lfs, &file, "notebook/paper", |
| LFS_O_WRONLY | LFS_O_CREAT | LFS_O_APPEND) => 0; |
| char buffer[256]; |
| strcpy(buffer, "hello"); |
| lfs_size_t size = strlen("hello"); |
| for (int i = 0; i < 5; i++) { |
| lfs_file_write(&lfs, &file, buffer, size) => size; |
| lfs_file_sync(&lfs, &file) => 0; |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| |
| char rbuffer[256]; |
| lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; |
| for (int i = 0; i < 5; i++) { |
| lfs_file_read(&lfs, &file, rbuffer, size) => size; |
| assert(memcmp(rbuffer, buffer, size) == 0); |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| lfs_unmount(&lfs) => 0; |
| |
| // imitate a partial prog, value should not matter, if littlefs |
| // doesn't notice the partial prog testbd will assert |
| |
| // get offset to next prog |
| lfs_mount(&lfs, cfg) => 0; |
| lfs_dir_t dir; |
| lfs_dir_open(&lfs, &dir, "notebook") => 0; |
| lfs_block_t block = dir.m.pair[0]; |
| lfs_off_t off = dir.m.off; |
| lfs_dir_close(&lfs, &dir) => 0; |
| lfs_unmount(&lfs) => 0; |
| |
| // tweak byte |
| uint8_t bbuffer[BLOCK_SIZE]; |
| cfg->read(cfg, block, 0, bbuffer, BLOCK_SIZE) => 0; |
| |
| bbuffer[off + BYTE_OFF] = BYTE_VALUE; |
| |
| cfg->erase(cfg, block) => 0; |
| cfg->prog(cfg, block, 0, bbuffer, BLOCK_SIZE) => 0; |
| |
| lfs_mount(&lfs, cfg) => 0; |
| |
| // can read? |
| lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; |
| for (int i = 0; i < 5; i++) { |
| lfs_file_read(&lfs, &file, rbuffer, size) => size; |
| assert(memcmp(rbuffer, buffer, size) == 0); |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| |
| // can write? |
| lfs_file_open(&lfs, &file, "notebook/paper", |
| LFS_O_WRONLY | LFS_O_APPEND) => 0; |
| strcpy(buffer, "goodbye"); |
| size = strlen("goodbye"); |
| for (int i = 0; i < 5; i++) { |
| lfs_file_write(&lfs, &file, buffer, size) => size; |
| lfs_file_sync(&lfs, &file) => 0; |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| |
| lfs_file_open(&lfs, &file, "notebook/paper", LFS_O_RDONLY) => 0; |
| strcpy(buffer, "hello"); |
| size = strlen("hello"); |
| for (int i = 0; i < 5; i++) { |
| lfs_file_read(&lfs, &file, rbuffer, size) => size; |
| assert(memcmp(rbuffer, buffer, size) == 0); |
| } |
| strcpy(buffer, "goodbye"); |
| size = strlen("goodbye"); |
| for (int i = 0; i < 5; i++) { |
| lfs_file_read(&lfs, &file, rbuffer, size) => size; |
| assert(memcmp(rbuffer, buffer, size) == 0); |
| } |
| lfs_file_close(&lfs, &file) => 0; |
| |
| lfs_unmount(&lfs) => 0; |
| ''' |