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