From 47416c1115ef91feb3913f1e2b5caac1cb56ac1c Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Tue, 5 Mar 2024 12:52:08 -0600 Subject: [PATCH] Switched to recoloring + red stitching removals due to diverged coloring bug This was a nasty bug. I was initially concerned that this slipped through our rbyd tests until I realized how excruciatingly rare it is. If, during a range remove: 1. There is a pending yellow split immediately after the diverging alt 2. There is a pending yellow split immediately before the diverging alt 3. The diverging alt takes a black alt in the yellow split 4. There is a red node before the pending split before the diverging alt 5. The two alts in the red node point in different directions We can end up violating our yellow node both-alts-point-same-direction invariant. The tree looks like this: .-------------r-------------. .-o-. .----y---+---. .-o-. .o. .o. .-+-y-. .o. .o. .o. .o. .o. a a a a a a a c e e e e e e e e e e '+' remove Though this diagram doesn't capture the actual alt-layout, which does matter here, so the dbgrbyd.py rendering may be more useful: .-> aa .-> aa .-b-> a .-b-> a | .-> a | .-> a .-----------b-b-> a .-----b-b-> a | .-----> a | .-> a | | .---> a | .-----b-> a | .-y-r-b-> a | | .---> a | | '-> cc <- rm | | | r-b-y-r-b-----b-> ee => y-y-r-b-r-b-> ee <- two yellows! | | | '-> e | | '-> e different dirs! | | '-------b-> e | '-b-b-> e should not happen! | | '-> e | | '-> e | '---------b-> e | '-b-> e | '-> e | '-> e | .-> e | .-> e | .-b-> e | .-b-> e | | .-> e | | .-> e '---------b-b-> e '-------+-b-> e If all of these conditions are met, and we are preserving coloring, we can end up with two yellow splits without an intermediate black alt, implying recursion. But we're of course not recursive, so things just break. If we look at the trunk that is being built during our range removal: read [b => [b] read >r => [b >r] read >r => [b >r >r] ^--^------ red+red implies yellow ysplit => [r >b] reorder => [>r >r [>r >r [>r >r [>r >r >r [>r >r [>r >r [b] ^--^---------- yellow-same-dir invariant held ^---^------------- yellow-same-dir invariant NOT held though 2 yellows is also a problem The important thing to note is that the diverging alt is effectively deleted in both search paths. If the diverging alt is between two yellow splits, that's not good. If you think about the mapping to the underlying 2-3-4 tree, append is only guaranteed to be tail-recursive because we eagerly split 4-nodes into 2 2-nodes, ensuring that our parent always has a slot available for a split (this is why 2-3 trees are not tail-recursive). But if we delete one of the 2-nodes, and find another 4-node, the parent's slot has already been taken. This is basically the problem we are running into here. A hypothetical 2-3-4-5 tree however... Probably-isomorphic to a 2-3-4-5 tree, there are a couple of possible solutions to this: 1. Increase the fifo to 5(?) alts and recursively propagate recolorings up 2 nodes. Note this would still be bounded and tail-recursive. Our current implementation is basically an isomorphism of recursively propagating recolorings up 1 node after all, if you want to think about it in about the most complicated way possible... Downsides: The increased fifo size means more RAM cost. And the implementation would be complicated as hell. Not to mention error prone. Imagine ~2x the current 15K lines of rbyd tests. It would be bad. 2. Discard split recolorings after a diverged alt. This would be quite a bit simpler, though would still require some annoying state to know if the previous alt diverged. If this state isn't perfect, the above checklist of conditions would just be incremented by 1, making this bug even harder to track down. I'm starting to think that preserving color during range removals is a bit complicated for its own good. Considering that color-preserving range removals aren't even rigorous and don't guarantee a balanced tree, I think this all just needs to be scrapped until a more rigorous solution is found. --- So this commit drops color-preserving range removals, and moves to a simpler paint it black + stitch together alternating red alt strategy when encountering a diverging range removal. Thanks to the red-stitching, the resulting search path is at least tried to be kept as small as possible. This results in the following, not-broken tree: .-> aa .-> aa .-b-> a .-b-> a | .-> a | .-> a .-----------b-b-> a .-----b-b-> a | .-----> a | .-------> a | | .---> a | | .---> a | .-y-r-b-> a | | | .-> a | | '-> cc <- rm | | | | r-b-y-r-b-----b-> ee => y-r-b-r-b-r-b-> ee | | | '-> e | | '-----> e | | '-------b-> e | '-------b-b-> e | | '-> e | | '-> e | '---------b-> e | '-b-> e | '-> e | '-> e | .-> e | .-> e | .-b-> e | .-b-> e | | .-> e | | .-> e '---------b-b-> e '---------b-b-> e It's interesting to note that this bug is so rare that it was only caught by test_dirs_mv_fuzz after 2180 heuristic powerlosses. But it was caught, so that's a good sign. But it would have been better if this was caught in the rbyd tests. I've gone ahead and added a specialized test, test_rbyd_delete_range_rry (and a few other), to prevent a regression, which is very likely. It's more likely than not we'll revisit range removals in the future. On the plus side, since recoloring is simpler than color-preservation, this means less code: code stack before: 34072 2880 after: 33992 (-0.2%) 2880 (+0.0%) --- lfs.c | 115 ++-- tests/test_rbyd.toml | 1283 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 1338 insertions(+), 60 deletions(-) diff --git a/lfs.c b/lfs.c index 7c7e37ff..fefc7b74 100644 --- a/lfs.c +++ b/lfs.c @@ -2827,6 +2827,41 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd, } } + // if we diverged, paint alts black, this isn't perfect but + // otherwise we run into recoloring issues + if (lfsr_tag_hasdiverged(tag_)) { + alt &= ~LFSR_TAG_R; + + // prune diverged? + if (lfsr_tag_isdivergedupper(tag_) + ^ lfsr_tag_isgt(alt) + ^ lfsr_tag_follow2( + alt, weight, + p_alts[0], p_weights[0], + lower_rid, upper_rid, + rid_, tag_)) { + if (lfsr_tag_follow2( + alt, weight, + p_alts[0], p_weights[0], + lower_rid, upper_rid, + rid_, tag_)) { + lfsr_tag_flip2( + &alt, &weight, + p_alts[0], p_weights[0], + lower_rid, upper_rid); + lfs_swap32(&jump, &branch_); + } + lfsr_tag_trim( + alt, weight, + &lower_rid, &upper_rid, + &lower_tag, &upper_tag); + + graft = branch; + branch = branch_; + continue; + } + } + // prune? // b // .-'| .-'| @@ -2838,62 +2873,20 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd, // | | .----'| | .----'| | // 1 2 3 4 4 1 2 3 4 4 2 if (lfsr_tag_prune2( - alt, weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid, - lower_tag, upper_tag) - // prune because of diverged paths? - || (lfsr_tag_hasdiverged(tag_) - && lfsr_tag_isdivergedupper(tag_) - ^ lfsr_tag_isgt(alt) - ^ lfsr_tag_follow2( - alt, weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid, - rid_, tag_))) { - // note yellow prunes always follow and have no weight, it's - // only the diverged paths that need all these special cases - if (lfsr_tag_follow2( - alt, weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid, - rid_, tag_)) { - lfsr_tag_flip2( - &alt, &weight, - p_alts[0], p_weights[0], - lower_rid, upper_rid); - lfsr_tag_trim( - alt, weight, - &lower_rid, &upper_rid, - &lower_tag, &upper_tag); - - if (lfsr_tag_isred(p_alts[0])) { - alt = p_alts[0] & ~LFSR_TAG_R; - weight = p_weights[0]; - branch_ = jump; - jump = p_jumps[0]; - lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps); - } else { - graft = branch; - branch = jump; - continue; - } + alt, weight, + p_alts[0], p_weights[0], + lower_rid, upper_rid, + lower_tag, upper_tag)) { + if (lfsr_tag_isred(p_alts[0])) { + alt = p_alts[0] & ~LFSR_TAG_R; + weight = p_weights[0]; + branch_ = jump; + jump = p_jumps[0]; + lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps); } else { - lfsr_tag_trim( - alt, weight, - &lower_rid, &upper_rid, - &lower_tag, &upper_tag); - - if (lfsr_tag_isred(p_alts[0])) { - alt = p_alts[0] & ~LFSR_TAG_R; - weight = p_weights[0]; - jump = p_jumps[0]; - lfsr_rbyd_p_pop(p_alts, p_weights, p_jumps); - } else { - graft = branch; - branch = branch_; - continue; - } + graft = branch; + branch = jump; + continue; } } @@ -2998,18 +2991,20 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd, } if (lfsr_tag_isblack(alt)) { - // trim alt from our current bounds + // trim alts from our current bounds lfsr_tag_trim2( alt, weight, p_alts[0], p_weights[0], &lower_rid, &upper_rid, &lower_tag, &upper_tag); - // if diverged, stitch our paths together with alternating - // red alts + // if we diverged, stitch our paths together with alternating + // red alts, this gives us an optimal ternary tree if we + // started with a binary tree, but the above recoloring makes + // this not optimal if (lfsr_tag_hasdiverged(tag_) && p_alts[0] - && !lfsr_tag_isred(p_alts[1])) { + && lfsr_tag_isblack(p_alts[1])) { p_alts[0] |= LFSR_TAG_R; } } @@ -3042,7 +3037,7 @@ static int lfsr_rbyd_appendattr(lfs_t *lfs, lfsr_rbyd_t *rbyd, } // switch to the other path if we have diverged - if (lfsr_tag_hasdiverged(tag_) && lfsr_tag_isblack(p_alts[0])) { + if (lfsr_tag_hasdiverged(tag_)) { lfs_swap16(&tag_, &other_tag_); lfs_sswap32(&rid_, &other_rid_); lfs_swap32(&branch, &other_branch); diff --git a/tests/test_rbyd.toml b/tests/test_rbyd.toml index 0555def8..4cacb412 100644 --- a/tests/test_rbyd.toml +++ b/tests/test_rbyd.toml @@ -7350,6 +7350,1289 @@ code = ''' &data) => LFS_ERR_NOENT; ''' +# some additional delete range special cases +[cases.test_rbyd_delete_range_b] +in = 'lfs.c' +code = ''' + lfs_t lfs; + lfs_init(&lfs, CFG) => 0; + + lfsr_rbyd_t init_rbyd = { + .blocks[0] = 0, + .eoff = 0, + .cksum = 0, + .trunk = 0, + .weight = 0, + }; + lfsr_rbyd_t rbyd; + lfsr_data_t data; + uint8_t buffer[4]; + + // delete inner branches + // + // .-------o-------. + // .---o---. .---o---. + // .-o-. .-o-. .-o-. .-o-. + // .o. .o. .o. .o. .o. .o. .o. .o. + // a a a a a a a c c e e e e e e e + // '-+-' + // remove + // + rbyd = init_rbyd; + lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0; + lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_REG, +1, + LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), + LFSR_ATTR( + LFSR_TAG_UATTR(1), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(2), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(3), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(4), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(5), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(6), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_REG, +1, + LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), + LFSR_ATTR( + LFSR_TAG_UATTR(1), 0, + LFSR_DATA_BUF("\xcc\xcc", 2)), + LFSR_ATTR( + LFSR_TAG_REG, +1, + LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), + LFSR_ATTR( + LFSR_TAG_UATTR(1), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(2), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(3), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(4), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(5), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(6), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + // propagate yellow to the root + LFSR_ATTR( + LFSR_TAG_UATTR(6), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(6), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(6), 0, + LFSR_DATA_BUF("\xee\xee", 2)))) => 0; + + lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS( + LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; + + assert(rbyd.weight == 2); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; + + lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0; + assert(rbyd.weight == 2); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; + + // try to recreate + lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_REG, +1, + LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; + + assert(rbyd.weight == 3); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; + + lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0; + assert(rbyd.weight == 3); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; +''' + +[cases.test_rbyd_delete_range_r] +in = 'lfs.c' +code = ''' + lfs_t lfs; + lfs_init(&lfs, CFG) => 0; + + lfsr_rbyd_t init_rbyd = { + .blocks[0] = 0, + .eoff = 0, + .cksum = 0, + .trunk = 0, + .weight = 0, + }; + lfsr_rbyd_t rbyd; + lfsr_data_t data; + uint8_t buffer[4]; + + // delete inner branches + // + // .-------o-------. + // .---r----. .----r---. + // .o. .o. .-r-. .-r-. .o. .o. + // a a a a a a c c e e e e e e + // '-+-' + // remove + // + rbyd = init_rbyd; + lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0; + lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_REG, +1, + LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), + LFSR_ATTR( + LFSR_TAG_UATTR(1), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(2), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_REG, +1, + LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), + LFSR_ATTR( + LFSR_TAG_UATTR(1), 0, + LFSR_DATA_BUF("\xcc\xcc", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(3), +1, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(4), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(5), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + // propagate yellow to the root + LFSR_ATTR( + LFSR_TAG_UATTR(5), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(5), 0, + LFSR_DATA_BUF("\xee\xee", 2)))) => 0; + // this gets a bit messy as we try to make the rbyd take the right shape + lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_UATTR(3), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(4), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(5), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; + lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_UATTR(2), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(1), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_REG, 0, + LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0; + + lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS( + LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; + + assert(rbyd.weight == 2); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; + + lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0; + assert(rbyd.weight == 2); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; + + // try to recreate + lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_REG, +1, + LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; + + assert(rbyd.weight == 3); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; + + lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0; + assert(rbyd.weight == 3); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; +''' + +[cases.test_rbyd_delete_range_y] +in = 'lfs.c' +code = ''' + lfs_t lfs; + lfs_init(&lfs, CFG) => 0; + + lfsr_rbyd_t init_rbyd = { + .blocks[0] = 0, + .eoff = 0, + .cksum = 0, + .trunk = 0, + .weight = 0, + }; + lfsr_rbyd_t rbyd; + lfsr_data_t data; + uint8_t buffer[4]; + + // delete inner branches + // + // .-------------o-------------. + // .---y---+------. .------+---y---. + // .o. .o. .o. .-+-y-. .-y-+-. .o. .o. .o. + // a a a a a a a a a c c e e e e e e e e e + // '-+-' + // remove + // + rbyd = init_rbyd; + lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0; + lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_REG, +1, + LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), + LFSR_ATTR( + LFSR_TAG_UATTR(3), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(4), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_REG, +1, + LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), + LFSR_ATTR( + LFSR_TAG_UATTR(1), 0, + LFSR_DATA_BUF("\xcc\xcc", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(4), +1, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(5), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(6), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + // propagate yellow to the root + LFSR_ATTR( + LFSR_TAG_UATTR(6), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(6), 0, + LFSR_DATA_BUF("\xee\xee", 2)))) => 0; + // this gets a bit messy as we try to make the rbyd take the right shape + lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_UATTR(5), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(6), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(7), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(8), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; + lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_UATTR(1), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(2), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + // propagate yellow + LFSR_ATTR( + LFSR_TAG_UATTR(2), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; + lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_UATTR(3), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(2), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(1), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_REG, 0, + LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0; + lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_UATTR(8), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(7), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + // propagate yellow + LFSR_ATTR( + LFSR_TAG_UATTR(7), 0, + LFSR_DATA_BUF("\xee\xee", 2)))) => 0; + + lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS( + LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; + + assert(rbyd.weight == 2); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(7), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(8), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; + + lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0; + assert(rbyd.weight == 2); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(7), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(8), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; + + // try to recreate + lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_REG, +1, + LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; + + assert(rbyd.weight == 3); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(7), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(8), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; + + lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0; + assert(rbyd.weight == 3); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(7), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(8), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(7), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(8), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; +''' + +[cases.test_rbyd_delete_range_ryy] +in = 'lfs.c' +code = ''' + lfs_t lfs; + lfs_init(&lfs, CFG) => 0; + + lfsr_rbyd_t init_rbyd = { + .blocks[0] = 0, + .eoff = 0, + .cksum = 0, + .trunk = 0, + .weight = 0, + }; + lfsr_rbyd_t rbyd; + lfsr_data_t data; + uint8_t buffer[4]; + + // delete inner branches + // + // .-------------r-------------. + // .-o-. .----y---+---. .-o-. + // .o. .o. .-+-y-. .o. .o. .o. .o. .o. + // a a a a a a a c e e e e e e e e e e + // '+' + // remove + // + // this is a specific nasty case that can happen if you try to + // preserve coloring during range removes + // + rbyd = init_rbyd; + lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0; + lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_REG, +1, + LFSR_DATA_BUF("\xaa\xaa\xaa\xaa", 4)), + LFSR_ATTR( + LFSR_TAG_UATTR(1), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(2), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(3), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(4), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_REG, +1, + LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)), + LFSR_ATTR( + LFSR_TAG_UATTR(4), +1, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(5), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(6), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(7), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(8), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(9), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + // propagate yellow to the root + LFSR_ATTR( + LFSR_TAG_UATTR(9), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(9), 0, + LFSR_DATA_BUF("\xee\xee", 2)))) => 0; + // this gets a bit messy as we try to make the rbyd take the right shape + lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_UATTR(5), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(6), 0, + LFSR_DATA_BUF("\xaa\xaa", 2)))) => 0; + lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_UATTR(3), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(2), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_UATTR(1), 0, + LFSR_DATA_BUF("\xee\xee", 2)), + LFSR_ATTR( + LFSR_TAG_REG, 0, + LFSR_DATA_BUF("\xee\xee\xee\xee", 4)), + // propagate yellow + LFSR_ATTR( + LFSR_TAG_REG, 0, + LFSR_DATA_BUF("\xee\xee\xee\xee", 4)))) => 0; + + lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS( + LFSR_ATTR(LFSR_TAG_RM, -1, LFSR_DATA_NULL()))) => 0; + + assert(rbyd.weight == 2); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(7), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(8), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(9), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; + + lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0; + assert(rbyd.weight == 2); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(7), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(8), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_UATTR(9), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; + + // try to recreate + lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_ATTRS( + LFSR_ATTR( + LFSR_TAG_REG, +1, + LFSR_DATA_BUF("\xcc\xcc\xcc\xcc", 4)))) => 0; + + assert(rbyd.weight == 3); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(7), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(8), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(9), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; + + lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0; + assert(rbyd.weight == 3); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xaa\xaa", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_REG, &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 4; + assert(memcmp(buffer, "\xee\xee\xee\xee", 4) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(1), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(2), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(3), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(4), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(5), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(6), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(7), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(8), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_UATTR(9), &data) => 0; + lfsr_data_read(&lfs, &data, buffer, 4) => 2; + assert(memcmp(buffer, "\xee\xee", 2) == 0); + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_REG, + &data) => LFS_ERR_NOENT; + lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_UATTR(1), + &data) => LFS_ERR_NOENT; +''' + # NOTE if we separate physical/logical block sizes we may be able to # use emubd's copy-on-write copy to speed this up significantly [cases.test_rbyd_delete_permutations]