# Test this inner rbyd data-structure # test with a number of different erase values defines.ERASE_VALUE = [0xff, 0x00, 0x1b, -1] [cases.test_rbyd_commit] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; // try an empty commit rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, NULL) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; // commit with one attribute rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; // commit with two attributes rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; ''' [cases.test_rbyd_multi_commit] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; // try an empty commit rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, NULL) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; // commit with one attribute rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, NULL) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; // commit with two attributes rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; ''' [cases.test_rbyd_commit_fetch_commit] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; // commit with one attribute rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; // commit with the second attribute lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; ''' # [cases.test_rbyd_fetchmatch] # [cases.test_rbyd_multi_fetchmatch] # TODO we really need to test dense keys... [cases.test_rbyd_lookup] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // try an empty commit rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_ERR_NOENT; // commit with one attribute rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_ERR_NOENT; // commit with two attributes rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_ERR_NOENT; ''' [cases.test_rbyd_multi_lookup] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // try an empty commit rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_ERR_NOENT; // commit with one attribute rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_ERR_NOENT; // commit with two attributes rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_ERR_NOENT; ''' [cases.test_rbyd_get] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; uint8_t buffer[4]; // try an empty commit rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, NULL) => 0; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) => LFS_ERR_NOENT; // commit with one attribute rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) => LFS_ERR_NOENT; // commit with two attributes rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) => 4; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) => 4; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) => 4; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) => 4; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), buffer, 4) => LFS_ERR_NOENT; ''' [cases.test_rbyd_multi_get] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; uint8_t buffer[4]; // try an empty commit rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, NULL) => 0; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) => LFS_ERR_NOENT; // commit with one attribute rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) => LFS_ERR_NOENT; // commit with two attributes rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) => 4; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) => 4; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), buffer, 4) => 4; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), buffer, 4) => 4; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), buffer, 4) => LFS_ERR_NOENT; ''' [cases.test_rbyd_traverse] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; lfs_srtag_t tag; // traverse requires correct biasing of the weights in the rbyd tree // so that lookups return strictly the tag greater than or equal to // the tag requested rbyd = init_rbyd; rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0; tag = lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size); assert(tag == LFS_MKRTAG(UATTR, 1, 0)); tag = lfs_rbyd_lookup(&lfs, &rbyd, lfs_rtag_inc(tag), &off, &size); assert(tag == LFS_MKRTAG(UATTR, 2, 0)); tag = lfs_rbyd_lookup(&lfs, &rbyd, lfs_rtag_inc(tag), &off, &size); assert(tag == LFS_ERR_NOENT); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; tag = lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size); assert(tag == LFS_MKRTAG(UATTR, 1, 0)); tag = lfs_rbyd_lookup(&lfs, &rbyd, lfs_rtag_inc(tag), &off, &size); assert(tag == LFS_MKRTAG(UATTR, 2, 0)); tag = lfs_rbyd_lookup(&lfs, &rbyd, lfs_rtag_inc(tag), &off, &size); assert(tag == LFS_ERR_NOENT); ''' [cases.test_rbyd_multi_traverse] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; lfs_srtag_t tag; // traverse requires correct biasing of the weights in the rbyd tree // so that lookups return strictly the tag greater than or equal to // the tag requested rbyd = init_rbyd; rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0; tag = lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size); assert(tag == LFS_MKRTAG(UATTR, 1, 0)); tag = lfs_rbyd_lookup(&lfs, &rbyd, lfs_rtag_inc(tag), &off, &size); assert(tag == LFS_MKRTAG(UATTR, 2, 0)); tag = lfs_rbyd_lookup(&lfs, &rbyd, lfs_rtag_inc(tag), &off, &size); assert(tag == LFS_ERR_NOENT); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; tag = lfs_rbyd_lookup(&lfs, &rbyd, 0, &off, &size); assert(tag == LFS_MKRTAG(UATTR, 1, 0)); tag = lfs_rbyd_lookup(&lfs, &rbyd, lfs_rtag_inc(tag), &off, &size); assert(tag == LFS_MKRTAG(UATTR, 2, 0)); tag = lfs_rbyd_lookup(&lfs, &rbyd, lfs_rtag_inc(tag), &off, &size); assert(tag == LFS_ERR_NOENT); ''' [cases.test_rbyd_bifoliate] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // create a split in the leaves // .-'| // 1 1 2 rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); // split the other direction // >b // => .-'| // 2 2 1 rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); ''' [cases.test_rbyd_bflips] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // ignore a black edge // .----'| // 1 2 1 2 2 rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL)))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); // flip a black edge // b // .-'| => .-'| // 1 2 1 2 1 rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); ''' [cases.test_rbyd_trifoliate] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // ignore a black edge // | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, NULL)))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); // flip a black edge // >r // .-'| // | >b // .-'| .--|-'| // 2 3 2 3 1 rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); ''' [cases.test_rbyd_rflips] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // ignore a red edge and black edge // | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, NULL))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); // ignore a red edge, flip a black edge // | >b // | .-'| | .-'| // 1 2 3 1 2 3 2 rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); // flip a red edge and black edge // r // .----'| .-'| // | | >b // | .-'| .--|-'| // 1 2 3 1 2 3 1 rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); // flip a red edge, ignore a black edge // r // .-'| .-------'| // | >b => | >b // .--|-'| | .-'| // 3 1 2 3 1 2 1 rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); ''' [cases.test_rbyd_quadrifoliate] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // ignore a red edge and black edge // | .----'| // | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, NULL))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); // ignore a red edge, flip a black edge // y // .-------'| .-'| // r | >r // .----'| => | .-'| => .--|-'| // | b | | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); // flip a red edge and black edge // >y // .-'| // b // .----'| => .--|-'| // | b // | .-'| .--|--|-'| // 2 3 4 2 3 4 1 rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); // flip a red edge, ignore a black edge // >y // .-------'| // r // .-'| => | .-'| // | >b | | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); ''' [cases.test_rbyd_rotations] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // all three the same // | .----'| // | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, NULL))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); // yellow and red alt the same // | .----'| // | b // | .-'| | | .-'| // 1 2 4 1 2 4 3 rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, NULL))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); // yellow and black alt the same // r | | .----'| => | .-'| // | >b | | b // | .-'| | | .-'| | .--|-'| // 1 4 2 1 4 2 3 1 4 2 3 rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, NULL))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); // red and black alt the same // >y r | | .----'| => | .-'| // | b // | .-'| | | .-'| .--|--|-'| // 4 1 2 4 1 2 3 4 1 2 3 rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, NULL))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); ''' [cases.test_rbyd_ysplits] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // split a yellow triple, not taking any alt // | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, NULL)))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); // split a yellow triple, taking the black alt // | b // | | .-'| | | .-'| // 1 2 3 4 1 2 3 4 3 rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, NULL)))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); // split a yellow triple, taking the red alt // b // .-------'| .-'| // | .--------|-'| // | | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL)))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); // split a yellow triple, taking the yellow alt // b // .-------'| .-'| // | b // | .----'| => .-----|-'| // | | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); ''' [cases.test_rbyd_quintifoliate] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // split a yellow triple, not taking any alt // | .----' | // | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 5, 0, "\xee\xee\xee\xee", 4, NULL)))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 5, 0), &off, &size) => LFS_MKRTAG(UATTR, 5, 0); // split a yellow triple, taking the black alt // | .----' | // | r // | .----'| | | .-'| // | | b // | | .-'| | | .--|-'| // 1 2 4 5 1 2 4 5 3 rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 5, 0, "\xee\xee\xee\xee", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, NULL)))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 5, 0), &off, &size) => LFS_MKRTAG(UATTR, 5, 0); // split a yellow triple, taking the red alt // >b // .-'| // b // | .----'| => | .-----|-'| // | | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 5, 0, "\xee\xee\xee\xee", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL)))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 5, 0), &off, &size) => LFS_MKRTAG(UATTR, 5, 0); // split a yellow triple, taking the yellow alt // >b // .-'| // r // .-------'| .-----|-'| // | b // | .----'| => .--|-----|-'| // | | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 5, 0, "\xee\xee\xee\xee", 4, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 5, 0), &off, &size) => LFS_MKRTAG(UATTR, 5, 0); ''' [cases.test_rbyd_prunes] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // don't prune // | .----' | // | | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 5, 0, "\xee\xee\xee\xee", 4, LFS_MKRATTR(UATTR, 5, 0, "\xee\xee\xee\xee", 4, NULL))))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 5, 0), &off, &size) => LFS_MKRTAG(UATTR, 5, 0); // prune by taking a red alt // b // .-------'| | .-'| // | .-----------|-'| // | | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 5, 0, "\xee\xee\xee\xee", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL))))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 5, 0), &off, &size) => LFS_MKRTAG(UATTR, 5, 0); // prune by taking a yellow alt (this needs to prune during the rflip) // b // .-------'| | .-'| // | b // | .----' | => .--------|-'| // | | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 5, 0, "\xee\xee\xee\xee", 4, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL))))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 5, 0), &off, &size) => LFS_MKRTAG(UATTR, 5, 0); ''' [cases.test_rbyd_sextifoliate] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // don't prune // | | .-------'| // | | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 5, 0, "\xee\xee\xee\xee", 4, LFS_MKRATTR(UATTR, 6, 0, "\xff\xff\xff\xff", 4, NULL))))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 5, 0), &off, &size) => LFS_MKRTAG(UATTR, 5, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 6, 0), &off, &size) => LFS_MKRTAG(UATTR, 6, 0); // prune by taking a red alt // b // .-'| .-'| // b // | .----' | => | .--------|-'| // | | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 5, 0, "\xee\xee\xee\xee", 4, LFS_MKRATTR(UATTR, 6, 0, "\xff\xff\xff\xff", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL))))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 5, 0), &off, &size) => LFS_MKRTAG(UATTR, 5, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 6, 0), &off, &size) => LFS_MKRTAG(UATTR, 6, 0); // prune by taking a yellow alt (this needs to prune during the rflip) // b // .-'| .-'| // r // .-------'| | .--------|-'| // | b // | .----' | => .--|--------|-'| // | | 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 3, 0, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 4, 0, "\xdd\xdd\xdd\xdd", 4, LFS_MKRATTR(UATTR, 5, 0, "\xee\xee\xee\xee", 4, LFS_MKRATTR(UATTR, 6, 0, "\xff\xff\xff\xff", 4, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL))))))) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_MKRTAG(UATTR, 3, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 4, 0), &off, &size) => LFS_MKRTAG(UATTR, 4, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 5, 0), &off, &size) => LFS_MKRTAG(UATTR, 5, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 6, 0), &off, &size) => LFS_MKRTAG(UATTR, 6, 0); ''' [cases.test_rbyd_permutations] defines.N = 'range(1, 8)' in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // test all permutations of a given size uint8_t perm[N]; unsigned stack[N]; for (uint8_t i = 0; i < N; i++) { perm[i] = i; stack[i] = 0; } unsigned i = 1; while (i < N) { // print permutation to help debugging printf("--- permutation: ["); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]+1); } printf("] ---\n"); // build the attribute list for the current permutation struct lfs_rattr attrs[N]; for (unsigned j = 0; j < N; j++) { attrs[j] = *LFS_MKRATTR( UATTR, perm[j]+1, 0, "\xaa\xaa\xaa\xaa", 4, (j+1 < N) ? &attrs[j+1] : NULL); } // test the given permutation rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, attrs) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; for (unsigned j = 0; j < N; j++) { lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, j+1, 0), &off, &size) => LFS_MKRTAG(UATTR, j+1, 0); } // next permutation using Heap's algorithm if (stack[i] < i) { if (i % 2 == 0) { uint8_t t = perm[0]; perm[0] = perm[i]; perm[i] = t; } else { uint8_t t = perm[stack[i]]; perm[stack[i]] = perm[i]; perm[i] = t; } stack[i] += 1; i = 1; } else { stack[i] = 0; i += 1; } } ''' [cases.test_rbyd_multi_permutations] defines.N = 'range(1, 8)' in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // test all permutations of a given size uint8_t perm[N]; unsigned stack[N]; for (uint8_t i = 0; i < N; i++) { perm[i] = i; stack[i] = 0; } unsigned i = 1; while (i < N) { // print permutation to help debugging printf("--- permutation: ["); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]+1); } printf("] ---\n"); // test the given permutation with multiple commits rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; for (unsigned j = 0; j < N; j++) { lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, perm[j]+1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; } lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; for (unsigned j = 0; j < N; j++) { lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, j+1, 0), &off, &size) => LFS_MKRTAG(UATTR, j+1, 0); } // next permutation using Heap's algorithm if (stack[i] < i) { if (i % 2 == 0) { uint8_t t = perm[0]; perm[0] = perm[i]; perm[i] = t; } else { uint8_t t = perm[stack[i]]; perm[stack[i]] = perm[i]; perm[i] = t; } stack[i] += 1; i = 1; } else { stack[i] = 0; i += 1; } } ''' [cases.test_rbyd_large] in = 'lfs.c' # ORDER: # 0 = in-order # 1 = reverse-order # 2 = random-order defines.ORDER = [0, 1, 2] code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // create the rbyd tree rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; // keep appending tags until we run out of space // // note, this will likely repeat tags, but that's ok // lfs_size_t count = 0; uint32_t prng = 42; for (lfs_size_t i = 0;; i++) { uint8_t x = (ORDER == 0) ? (uint8_t)i : (ORDER == 1) ? (uint8_t)(((lfs_size_t)-1) - i) : (uint8_t)TEST_PRNG(&prng); int err = lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, x, 0, "\xaa\xaa\xaa\xaa", 4, NULL)); // if we can't fit an fcrc, erased is set to false, but if we can, // lfs_rbyd_commit may error later with LFS_ERR_RANGE if (!rbyd.erased || err == LFS_ERR_RANGE) { break; } assert(err == 0); count = i; } // check that we can still lookup all the tags prng = 42; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; for (lfs_size_t i = 0; i < count; i++) { uint8_t x = (ORDER == 0) ? (uint8_t)i : (ORDER == 1) ? (uint8_t)(((lfs_size_t)-1) - i) : (uint8_t)TEST_PRNG(&prng); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, x, 0), &off, &size) => LFS_MKRTAG(UATTR, x, 0); } ''' ### Removal testing ### [cases.test_rbyd_remove] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // add and remove one attribute rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRRMATTR(UATTR, 1, 0, NULL)) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_ERR_NOENT; // commit with two attributes, remove the first one rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRRMATTR(UATTR, 1, 0, NULL)) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_MKRTAG(UATTR, 2, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_ERR_NOENT; // commit with two attributes, remove the second one rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRRMATTR(UATTR, 2, 0, NULL)) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_MKRTAG(UATTR, 1, 0); lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 3, 0), &off, &size) => LFS_ERR_NOENT; ''' [cases.test_rbyd_remove_permutations] defines.N = 'range(1, 7)' in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // test all permutations of a given size uint8_t perm[N]; unsigned stack[N]; for (uint8_t i = 0; i < N; i++) { perm[i] = i; stack[i] = 0; } unsigned i = 1; while (i < N) { // print permutation to help debugging printf("--- permutation: ["); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]+1); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; for (unsigned j = 0; j < N; j++) { lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, perm[j]+1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; } // copy block so we can reset after each remove lfs_rbyd_t backup_rbyd = rbyd; uint8_t backup_block[BLOCK_SIZE]; lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off, rbyd.block, 0, backup_block, rbyd.off) => 0; // try removing each tag for (unsigned j = 0; j < N; j++) { // print what we are removing to help debugging printf("--- remove: %d ---\n", j+1); rbyd = backup_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false, rbyd.block, 0, backup_block, rbyd.off) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRRMATTR(UATTR, j+1, 0, NULL)) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; for (unsigned k = 0; k < N; k++) { lfs_srtag_t tag = lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, k+1, 0), &off, &size); if (k == j) { if (j == N-1) { assert(tag == LFS_ERR_NOENT); } else { assert(tag == LFS_MKRTAG(UATTR, j+1+1, 0)); } } else { assert(tag == LFS_MKRTAG(UATTR, k+1, 0)); } } } // next permutation using Heap's algorithm if (stack[i] < i) { if (i % 2 == 0) { uint8_t t = perm[0]; perm[0] = perm[i]; perm[i] = t; } else { uint8_t t = perm[stack[i]]; perm[stack[i]] = perm[i]; perm[i] = t; } stack[i] += 1; i = 1; } else { stack[i] = 0; i += 1; } } ''' [cases.test_rbyd_remove_append_permutations] defines.N = 'range(1, 6)' in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // test all permutations of a given size uint8_t perm[N]; unsigned stack[N]; for (uint8_t i = 0; i < N; i++) { perm[i] = i; stack[i] = 0; } unsigned i = 1; while (i < N) { // print permutation to help debugging printf("--- permutation: ["); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]+1); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; for (unsigned j = 0; j < N; j++) { lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, perm[j]+1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; } // copy block so we can reset after each remove lfs_rbyd_t backup_rbyd = rbyd; uint8_t backup_block[BLOCK_SIZE]; lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off, rbyd.block, 0, backup_block, rbyd.off) => 0; // try removing each tag for (unsigned j = 0; j < N; j++) { for (unsigned l = 0; l < N; l++) { // print what we are removing to help debugging printf("--- remove: %d, append: %d ---\n", j+1, l+1); rbyd = backup_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false, rbyd.block, 0, backup_block, rbyd.off) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRRMATTR(UATTR, j+1, 0, NULL)) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; for (unsigned k = 0; k < N; k++) { lfs_srtag_t tag = lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, k+1, 0), &off, &size); if (k == j) { if (j == N-1) { assert(tag == LFS_ERR_NOENT); } else { assert(tag == LFS_MKRTAG(UATTR, j+1+1, 0)); } } else { assert(tag == LFS_MKRTAG(UATTR, k+1, 0)); assert(size == 4); } } // try appending each tag to make sure the rbyd tree // is still usable lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, l+1, 0, "\xaa\xaa\xaa\xaa\xaa\xaa", 6, NULL)) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; for (unsigned k = 0; k < N; k++) { lfs_srtag_t tag = lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, k+1, 0), &off, &size); if (k == l) { assert(tag == LFS_MKRTAG(UATTR, l+1, 0)); assert(size == 6); } else if (k == j) { if (j == N-1) { assert(tag == LFS_ERR_NOENT); } else { assert(tag == LFS_MKRTAG(UATTR, j+1+1, 0)); } } else { assert(tag == LFS_MKRTAG(UATTR, k+1, 0)); assert(size == 4); } } } } // next permutation using Heap's algorithm if (stack[i] < i) { if (i % 2 == 0) { uint8_t t = perm[0]; perm[0] = perm[i]; perm[i] = t; } else { uint8_t t = perm[stack[i]]; perm[stack[i]] = perm[i]; perm[i] = t; } stack[i] += 1; i = 1; } else { stack[i] = 0; i += 1; } } ''' [cases.test_rbyd_remove_all] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // commit with one attribute, remove it rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRRMATTR(UATTR, 1, 0, NULL)) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_ERR_NOENT; // commit with two attributes, remove both rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRRMATTR(UATTR, 1, 0, LFS_MKRRMATTR(UATTR, 2, 0, NULL))) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_ERR_NOENT; // commit with two attributes, remove both in the other order rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, 1, 0, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 2, 0, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRRMATTR(UATTR, 2, 0, LFS_MKRRMATTR(UATTR, 1, 0, NULL))) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 1, 0), &off, &size) => LFS_ERR_NOENT; lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, 2, 0), &off, &size) => LFS_ERR_NOENT; ''' [cases.test_rbyd_remove_all_permutations] defines.N = 'range(1, 7)' in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; lfs_off_t off; lfs_size_t size; // create one consistent block rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; for (unsigned j = 0; j < N; j++) { lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(UATTR, j+1, 0, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; } // copy block so we can reset after each remove lfs_rbyd_t backup_rbyd = rbyd; uint8_t backup_block[BLOCK_SIZE]; lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off, rbyd.block, 0, backup_block, rbyd.off) => 0; // test all permutations of a given size uint8_t perm[N]; unsigned stack[N]; for (uint8_t i = 0; i < N; i++) { perm[i] = i; stack[i] = 0; } unsigned i = 1; while (i < N) { // print permutation to help debugging printf("--- permutation: ["); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]+1); } printf("] ---\n"); // restore backup rbyd = backup_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false, rbyd.block, 0, backup_block, rbyd.off) => 0; // remove each tag in permutation order for (unsigned j = 0; j < N; j++) { lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRRMATTR(UATTR, perm[j]+1, 0, NULL)) => 0; } // check that all tags are now removed lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; for (unsigned j = 0; j < N; j++) { lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(UATTR, j+1, 0), &off, &size) => LFS_ERR_NOENT; } // next permutation using Heap's algorithm if (stack[i] < i) { if (i % 2 == 0) { uint8_t t = perm[0]; perm[0] = perm[i]; perm[i] = t; } else { uint8_t t = perm[stack[i]]; perm[stack[i]] = perm[i]; perm[i] = t; } stack[i] += 1; i = 1; } else { stack[i] = 0; i += 1; } } ''' ### Insertion testing ### [cases.test_rbyd_create] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; uint8_t buffer[4]; // try to create one id rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; assert(rbyd.count == 1); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 1); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); // try to create two ids rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); // try to create two in the other direction rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL))) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); // create a third to the right rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(CREATEREG, 0, 3, "\xcc\xcc\xcc\xcc", 4, NULL)))) => 0; assert(rbyd.count == 3); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 3); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); // create a third to the left rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(CREATEREG, 0, 2, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)))) => 0; assert(rbyd.count == 3); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 3); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); // create a third in the middle rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(CREATEREG, 0, 2, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, NULL)))) => 0; assert(rbyd.count == 3); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 3); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); ''' [cases.test_rbyd_multi_create] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; uint8_t buffer[4]; // try to create one id rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; assert(rbyd.count == 1); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 1); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); // try to create two ids rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); // try to create two in the other direction rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); // create a third to the right rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 3, "\xcc\xcc\xcc\xcc", 4, NULL)) => 0; assert(rbyd.count == 3); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 3); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); // create a third to the left rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 2, "\xcc\xcc\xcc\xcc", 4, NULL)) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; assert(rbyd.count == 3); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 3); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); // create a third in the middle rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, NULL)) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 2, "\xcc\xcc\xcc\xcc", 4, NULL)) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, NULL)) => 0; assert(rbyd.count == 3); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 3); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); ''' [cases.test_rbyd_create_permutations] defines.N = 'range(1, 8)' in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; uint8_t buffer[4]; // test all permutations of a given size uint16_t perm[N]; unsigned stack[N]; for (uint16_t i = 0; i < N; i++) { perm[i] = i; stack[i] = 0; } unsigned i = 1; while (i < N) { // print permutation to help debugging printf("--- permutation: ["); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]+1); } printf("] ---\n"); // build the attribute list for the current permutation struct lfs_rattr attrs[N]; for (unsigned j = 0; j < N; j++) { // adjust id based on future insertions uint16_t id = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { id -= 1; } } attrs[j] = *LFS_MKRATTR( CREATEREG, 0, id+1, names[perm[j] % 6], 4, (j+1 < N) ? &attrs[j+1] : NULL); } // test the given permutation rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, attrs) => 0; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == N); for (unsigned j = 0; j < N; j++) { lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, j+1), buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); } // next permutation using Heap's algorithm if (stack[i] < i) { if (i % 2 == 0) { uint16_t t = perm[0]; perm[0] = perm[i]; perm[i] = t; } else { uint16_t t = perm[stack[i]]; perm[stack[i]] = perm[i]; perm[i] = t; } stack[i] += 1; i = 1; } else { stack[i] = 0; i += 1; } } ''' [cases.test_rbyd_multi_create_permutations] defines.N = 'range(1, 8)' in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; uint8_t buffer[4]; // test all permutations of a given size uint16_t perm[N]; unsigned stack[N]; for (uint16_t i = 0; i < N; i++) { perm[i] = i; stack[i] = 0; } unsigned i = 1; while (i < N) { // print permutation to help debugging printf("--- permutation: ["); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]+1); } printf("] ---\n"); // test the given permutation with multiple commits rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; for (unsigned j = 0; j < N; j++) { // adjust id based on future insertions uint16_t id = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { id -= 1; } } lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, id+1, names[perm[j] % 6], 4, NULL)) => 0; } lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == N); for (unsigned j = 0; j < N; j++) { lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, j+1), buffer, 4) => 4; assert(memcmp(buffer, names[j % 6], 4) == 0); } // next permutation using Heap's algorithm if (stack[i] < i) { if (i % 2 == 0) { uint16_t t = perm[0]; perm[0] = perm[i]; perm[i] = t; } else { uint16_t t = perm[stack[i]]; perm[stack[i]] = perm[i]; perm[i] = t; } stack[i] += 1; i = 1; } else { stack[i] = 0; i += 1; } } ''' [cases.test_rbyd_create_large] in = 'lfs.c' # ORDER: # 0 = in-order # 1 = reverse-order # 2 = random-order defines.ORDER = [0, 1, 2] code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; // create the rbyd tree rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; // keep inserting tags until we run out of space // // note, the ids we create this way are both sparse and sometimes // repeated, so we need to mod our current rbyd size to avoid invalid // insertions // uint32_t prng = 42; for (lfs_size_t i = 0;; i++) { uint16_t x = (ORDER == 0) ? (uint16_t)i : (ORDER == 1) ? (uint16_t)(((lfs_size_t)-1) - i) : (uint16_t)TEST_PRNG(&prng); x = x % (rbyd.count+1); int err = lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, x+1, names[x % 6], 4, NULL)); // if we can't fit an fcrc, erased is set to false, but if we can, // lfs_rbyd_commit may error later with LFS_ERR_RANGE if (!rbyd.erased || err == LFS_ERR_RANGE) { break; } assert(err == 0); } // check that we can at least lookup all the tags lfs_off_t off; lfs_size_t size; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; for (uint16_t x = 0; x < rbyd.count; x++) { lfs_rbyd_lookup(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, x+1), &off, &size) => LFS_MKRTAG(CREATEREG, 0, x+1); } ''' ### Deletion testing ### [cases.test_rbyd_delete] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; uint8_t buffer[4]; // try to delete one id rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(DELETE, 0, 2, NULL, 0, NULL)) => 0; assert(rbyd.count == 1); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 1); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => LFS_ERR_NOENT; // try to delete the other id rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, NULL))) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(DELETE, 0, 1, NULL, 0, NULL)) => 0; assert(rbyd.count == 1); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 1); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => LFS_ERR_NOENT; // try to delete the largest of three rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(CREATEREG, 0, 3, "\xcc\xcc\xcc\xcc", 4, NULL)))) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(DELETE, 0, 3, NULL, 0, NULL)) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => LFS_ERR_NOENT; // try to delete the smallest of three rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(CREATEREG, 0, 3, "\xcc\xcc\xcc\xcc", 4, NULL)))) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(DELETE, 0, 1, NULL, 0, NULL)) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => LFS_ERR_NOENT; // try to delete the middle rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(CREATEREG, 0, 3, "\xcc\xcc\xcc\xcc", 4, NULL)))) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(DELETE, 0, 2, NULL, 0, NULL)) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => LFS_ERR_NOENT; ''' [cases.test_rbyd_delete_range] in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; uint8_t buffer[4]; // try to delete one id rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 0, 1, "\xaa\xaa", 2, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 0, 2, "\xbb\xbb", 2, NULL))))) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(DELETE, 0, 2, NULL, 0, NULL)) => 0; assert(rbyd.count == 1); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 1), buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 2), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 1); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 1), buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 2), buffer, 4) => LFS_ERR_NOENT; // try to delete the other id rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 0, 1, "\xaa\xaa", 2, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 0, 2, "\xbb\xbb", 2, NULL))))) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(DELETE, 0, 1, NULL, 0, NULL)) => 0; assert(rbyd.count == 1); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 1), buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 2), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 1); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 1), buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 2), buffer, 4) => LFS_ERR_NOENT; // try to delete the largest of three rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 0, 1, "\xaa\xaa", 2, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 0, 2, "\xbb\xbb", 2, LFS_MKRATTR(CREATEREG, 0, 3, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 0, 3, "\xcc\xcc", 2, NULL))))))) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(DELETE, 0, 3, NULL, 0, NULL)) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 1), buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 2), buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 3), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 1), buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 2), buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 3), buffer, 4) => LFS_ERR_NOENT; // try to delete the smallest of three rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 0, 1, "\xaa\xaa", 2, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 0, 2, "\xbb\xbb", 2, LFS_MKRATTR(CREATEREG, 0, 3, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 0, 3, "\xcc\xcc", 2, NULL))))))) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(DELETE, 0, 1, NULL, 0, NULL)) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 1), buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 2), buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 3), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 1), buffer, 4) => 2; assert(memcmp(buffer, "\xbb\xbb", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 2), buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 3), buffer, 4) => LFS_ERR_NOENT; // try to delete the middle rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, 1, "\xaa\xaa\xaa\xaa", 4, LFS_MKRATTR(UATTR, 0, 1, "\xaa\xaa", 2, LFS_MKRATTR(CREATEREG, 0, 2, "\xbb\xbb\xbb\xbb", 4, LFS_MKRATTR(UATTR, 0, 2, "\xbb\xbb", 2, LFS_MKRATTR(CREATEREG, 0, 3, "\xcc\xcc\xcc\xcc", 4, LFS_MKRATTR(UATTR, 0, 3, "\xcc\xcc", 2, NULL))))))) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(DELETE, 0, 2, NULL, 0, NULL)) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 1), buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 2), buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 3), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; assert(rbyd.count == 2); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 1), buffer, 4) => 4; assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 1), buffer, 4) => 2; assert(memcmp(buffer, "\xaa\xaa", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 2), buffer, 4) => 4; assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 2), buffer, 4) => 2; assert(memcmp(buffer, "\xcc\xcc", 2) == 0); lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, 3), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, 3), buffer, 4) => LFS_ERR_NOENT; ''' [cases.test_rbyd_delete_permutations] defines.N = 'range(1, 7)' in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; uint8_t buffer[4]; // test all permutations of a given size uint16_t perm[N]; unsigned stack[N]; for (uint16_t i = 0; i < N; i++) { perm[i] = i; stack[i] = 0; } unsigned i = 1; while (i < N) { // print permutation to help debugging printf("--- permutation: ["); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]+1); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; for (unsigned j = 0; j < N; j++) { // adjust id based on future insertions uint16_t id = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { id -= 1; } } lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, id+1, names[perm[j] % 6], 4, NULL)) => 0; } assert(rbyd.count == N); // copy block so we can reset after each delete lfs_rbyd_t backup_rbyd = rbyd; uint8_t backup_block[BLOCK_SIZE]; lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off, rbyd.block, 0, backup_block, rbyd.off) => 0; // try deleting each id for (unsigned j = 0; j < N; j++) { // print what we are deleting to help debugging printf("--- delete: %d ---\n", j+1); rbyd = backup_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false, rbyd.block, 0, backup_block, rbyd.off) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(DELETE, 0, j+1, NULL, 0, NULL)) => 0; assert(rbyd.count == N-1); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; for (unsigned k = 0; k < N-1; k++) { lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, k+1), buffer, 4) => 4; if (k >= j) { assert(memcmp(buffer, names[(k+1) % 6], 4) == 0); } else { assert(memcmp(buffer, names[k % 6], 4) == 0); } } lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, N-1+1), buffer, 4) => LFS_ERR_NOENT; } // next permutation using Heap's algorithm if (stack[i] < i) { if (i % 2 == 0) { uint16_t t = perm[0]; perm[0] = perm[i]; perm[i] = t; } else { uint16_t t = perm[stack[i]]; perm[stack[i]] = perm[i]; perm[i] = t; } stack[i] += 1; i = 1; } else { stack[i] = 0; i += 1; } } ''' [cases.test_rbyd_delete_range_permutations] defines.N = 'range(1, 7)' in = 'lfs.c' code = ''' lfs_t lfs; lfs_init(&lfs, cfg) => 0; lfs_rbyd_t init_rbyd = { .block = 0, .trunk = 0, .off = 0, .rev = 1, .crc = 0, .count = 0, .erased = true, }; lfs_rbyd_t rbyd; const uint8_t names[6][4] = { "\xaa\xaa\xaa\xaa", "\xbb\xbb\xbb\xbb", "\xcc\xcc\xcc\xcc", "\xdd\xdd\xdd\xdd", "\xee\xee\xee\xee", "\xff\xff\xff\xff", }; uint8_t buffer[4]; // test all permutations of a given size uint16_t perm[N]; unsigned stack[N]; for (uint16_t i = 0; i < N; i++) { perm[i] = i; stack[i] = 0; } unsigned i = 1; while (i < N) { // print permutation to help debugging printf("--- permutation: ["); for (unsigned j = 0; j < N; j++) { if (j > 0) { printf(", "); } printf("%d", perm[j]+1); } printf("] ---\n"); // create given permutation with multiple commits rbyd = init_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; for (unsigned j = 0; j < N; j++) { // adjust id based on future insertions uint16_t id = perm[j]; for (unsigned k = j+1; k < N; k++) { if (perm[j] > perm[k]) { id -= 1; } } lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(CREATEREG, 0, id+1, names[perm[j] % 6], 4, // note uattrs have a smaller size LFS_MKRATTR(UATTR, 0, id+1, names[perm[j] % 6], 2, NULL))) => 0; } assert(rbyd.count == N); // copy block so we can reset after each delete lfs_rbyd_t backup_rbyd = rbyd; uint8_t backup_block[BLOCK_SIZE]; lfs_bd_read(&lfs, NULL, &lfs.rcache, rbyd.off, rbyd.block, 0, backup_block, rbyd.off) => 0; // try deleting each id for (unsigned j = 0; j < N; j++) { // print what we are deleting to help debugging printf("--- delete: %d ---\n", j+1); rbyd = backup_rbyd; lfs_bd_erase(&lfs, rbyd.block) => 0; lfs_bd_prog(&lfs, &lfs.pcache, &lfs.rcache, false, rbyd.block, 0, backup_block, rbyd.off) => 0; lfs_rbyd_commit(&lfs, &rbyd, LFS_MKRATTR(DELETE, 0, j+1, NULL, 0, NULL)) => 0; assert(rbyd.count == N-1); lfs_rbyd_fetch(&lfs, &rbyd, rbyd.block, NULL) => 0; for (unsigned k = 0; k < N-1; k++) { lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, k+1), buffer, 4) => 4; if (k >= j) { assert(memcmp(buffer, names[(k+1) % 6], 4) == 0); } else { assert(memcmp(buffer, names[k % 6], 4) == 0); } lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, k+1), buffer, 4) => 2; if (k >= j) { assert(memcmp(buffer, names[(k+1) % 6], 2) == 0); } else { assert(memcmp(buffer, names[k % 6], 2) == 0); } } lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(CREATEREG, 0, N-1+1), buffer, 4) => LFS_ERR_NOENT; lfs_rbyd_get(&lfs, &rbyd, LFS_MKRTAG(UATTR, 0, N-1+1), buffer, 4) => LFS_ERR_NOENT; } // next permutation using Heap's algorithm if (stack[i] < i) { if (i % 2 == 0) { uint16_t t = perm[0]; perm[0] = perm[i]; perm[i] = t; } else { uint16_t t = perm[stack[i]]; perm[stack[i]] = perm[i]; perm[i] = t; } stack[i] += 1; i = 1; } else { stack[i] = 0; i += 1; } } '''