# 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; '''