Files
littlefs/tests/test_rbyd.toml
T
Christopher Haster 7d45ca0892 tests: Big test cleanup!
Removing the vestiges of v2 tests.
2025-05-27 21:05:53 -05:00

17116 lines
634 KiB
TOML

# Test the low-level rbyd data-structure
after = 'test_bd'
# test with a number of different erase values
defines.ERASE_VALUE = [0xff, 0x00, -1]
# set block_size to the full size of disk so we can test arbitrarily
# large rbyd trees, we don't really care about block sizes at this
# abstraction level
#
# ok not quite full disk size (we do use the full disk size in bench_rbyd),
# but a bit less since erasing the full disk takes time and we don't want to
# waste time when testing
defines.BLOCK_SIZE = 32768
[cases.test_rbyd_atomic_commit]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
// commit with one attribute
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
// commit with two attributes
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
'''
[cases.test_rbyd_commit]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
// commit with one attribute
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
// commit with two attributes
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
'''
[cases.test_rbyd_commit_fetch_commit]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
// commit with one attribute
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
// fetch
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
// commit with the second attribute
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
'''
[cases.test_rbyd_atomic_lookup]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// commit with one attribute
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// commit with two attributes
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// commit with two attributes, in the other direction
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_lookup]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// commit with one attribute
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// commit with two attributes
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// commit with two attributes, in the other direction
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_atomic_get]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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];
// commit with one attribute
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
NULL, &data) => LFS_ERR_NOENT;
// commit with two attributes
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
NULL, &data) => LFS_ERR_NOENT;
// commit with two attributes, in the other direction
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
NULL, &data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_get]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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];
// commit with one attribute
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
NULL, &data) => LFS_ERR_NOENT;
// commit with two attributes
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
NULL, &data) => LFS_ERR_NOENT;
// commit with two attributes, in the other direction
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
NULL, &data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_bifoliate]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// create a split in the leaves
// <b
// => .-'|
// 1 1 2
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// split the other direction
// >b
// => .-'|
// 2 2 1
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
'''
[cases.test_rbyd_bflips]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// ignore a black edge
// <b <b
// .-'| => .----'|
// 1 2 1 2 2
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// flip a black edge
// <b >b
// .-'| => .-'|
// 1 2 1 2 1
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
'''
[cases.test_rbyd_trifoliate]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// ignore a black edge
// <r
// .----'|
// <b => | <b
// .-'| | .-'|
// 1 2 1 2 3
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// flip a black edge
// >r
// .-'|
// <b => | >b
// .-'| .--|-'|
// 2 3 2 3 1
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
'''
[cases.test_rbyd_rflips]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// ignore a red edge and black edge
// <r <r
// .----'| .-------'|
// | <b => | <b
// | .-'| | .----'|
// 1 2 3 1 2 3 3
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// ignore a red edge, flip a black edge
// <r <r
// .----'| .-------'|
// | <b => | >b
// | .-'| | .-'|
// 1 2 3 1 2 3 2
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// flip a red edge and black edge
// <r >r
// .----'| .-'|
// | <b => | >b
// | .-'| .--|-'|
// 1 2 3 1 2 3 1
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// flip a red edge, ignore a black edge
// <r >r
// .-'| .-------'|
// | >b => | >b
// .--|-'| | .-'|
// 3 1 2 3 1 2 1
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
'''
[cases.test_rbyd_quadrifoliate]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// ignore a red edge and black edge
// <y
// .-------'|
// <r | <r
// .----'| => | .----'|
// | <b | | <b
// | .-'| | | .-'|
// 1 2 3 1 2 3 4
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// ignore a red edge, flip a black edge
// <y >y
// .-------'| .-'|
// <r | >r | >r
// .----'| => | .-'| => .--|-'|
// | <b | | >b | | <b
// | .-'| | .--|-'| .--|--|-'|
// 1 3 4 1 3 4 2 1 3 4 2
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// flip a red edge and black edge
// >y
// .-'|
// <r | >b
// .----'| => .--|-'|
// | <b | | >b
// | .-'| .--|--|-'|
// 2 3 4 2 3 4 1
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// flip a red edge, ignore a black edge
// >y
// .-------'|
// <r | >r
// .-'| => | .-'|
// | >b | | <b
// .--|-'| | .--|-'|
// 4 2 3 4 2 3 1
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
'''
[cases.test_rbyd_rotations]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// all three the same
// <y
// .-------'|
// <r | <r
// .----'| => | .----'|
// | <b | | <b
// | .-'| | | .-'|
// 1 2 3 1 2 3 4
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// yellow and red alt the same
// <y
// .-------'|
// <r | <r
// .----'| => | .----'|
// | <b | | >b
// | .-'| | | .-'|
// 1 2 4 1 2 4 3
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// yellow and black alt the same
// <y <y
// .-------'| .-------'|
// <r | >r | <r
// .----'| => | .----'| => | .-'|
// | >b | | <b | | >b
// | .-'| | | .-'| | .--|-'|
// 1 4 2 1 4 2 3 1 4 2 3
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// red and black alt the same
// >y <y
// .-------'| .----'|
// >r | <r | <r
// .----'| => | .----'| => | .-'|
// | <b | | <b | | >b
// | .-'| | | .-'| .--|--|-'|
// 4 1 2 4 1 2 3 4 1 2 3
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
'''
[cases.test_rbyd_ysplits]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// split a yellow triple, not taking any alt
// <b
// .-'|
// <y <y |
// .-------'| .-------'| |
// | <r => | <r |
// | .----'| | .----' |
// | | <b | | <b
// | | .-'| | | .----'|
// 1 2 3 4 1 2 3 4 4
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// split a yellow triple, taking the black alt
// <b
// .-'|
// <y <y |
// .-------'| .-------'| |
// | <r => | <r |
// | .----'| | .----' |
// | | <b | | >b
// | | .-'| | | .-'|
// 1 2 3 4 1 2 3 4 3
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// split a yellow triple, taking the red alt
// <y >b
// .-------'| .-'|
// | <r | <b
// | .----'| => .--------|-'|
// | | <b | <b |
// | | .-'| | .-'| |
// 1 2 3 4 1 2 3 4 2
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// split a yellow triple, taking the yellow alt
// <y >b
// .-------'| .-'|
// | <r | >b
// | .----'| => .-----|-'|
// | | <b | <b |
// | | .-'| | .-'| |
// 1 2 3 4 1 2 3 4 1
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
'''
[cases.test_rbyd_quintifoliate]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// split a yellow triple, not taking any alt
// <b
// .-'|
// <y |
// .-------'| |
// <y | <r |
// .-------'| => | .----' |
// | <r | | <r
// | .----'| | | .----'|
// | | <b | | | <b
// | | .-'| | | | .-'|
// 1 2 3 4 1 2 3 4 5
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee\xee\xee", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(5));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// split a yellow triple, taking the black alt
// <b
// .-'|
// <y |
// .-------'| |
// <y | <r |
// .-------'| => | .----' |
// | <r | | >r
// | .----'| | | .-'|
// | | <b | | | >b
// | | .-'| | | .--|-'|
// 1 2 4 5 1 2 4 5 3
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee\xee\xee", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(5));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// split a yellow triple, taking the red alt
// >b
// .-'|
// <y | <r
// .-------'| .--------|-'|
// | <r | | >b
// | .----'| => | .-----|-'|
// | | <b | | <b |
// | | .-'| | | .-'| |
// 1 3 4 5 1 3 4 5 2
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee\xee\xee", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(5));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// split a yellow triple, taking the yellow alt
// >b
// .-'|
// <y | >r
// .-------'| .-----|-'|
// | <r | | >b
// | .----'| => .--|-----|-'|
// | | <b | | <b |
// | | .-'| | | .-'| |
// 2 3 4 5 2 3 4 5 1
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee\xee\xee", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(5));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
'''
[cases.test_rbyd_prunes]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// don't prune
// <b <b
// .-'| .----'|
// <y | <y |
// .-------'| | .-------'| |
// | <r | | <r |
// | .----' | => | .----' |
// | | <r | | <r
// | | .----'| | | .-------'|
// | | | <b | | | <b
// | | | .-'| | | | .----'|
// 1 2 3 4 5 1 2 3 4 5 5
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee\xee\xee", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee\xee\xee", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(5));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// prune by taking a red alt
// <b
// .-'|
// <y | >b
// .-------'| | .-'|
// | <r | | <b
// | .----' | => .-----------|-'|
// | | <r | <r |
// | | .----'| | .----'| |
// | | | <b | | <b |
// | | | .-'| | | .-'| |
// 1 2 3 4 5 1 2 3 4 5 2
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee\xee\xee", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(5));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// prune by taking a yellow alt (this needs to prune during the rflip)
// <b
// .-'|
// <y | >b
// .-------'| | .-'|
// | <r | | >b
// | .----' | => .--------|-'|
// | | <r | <r |
// | | .----'| | .----'| |
// | | | <b | | <b |
// | | | .-'| | | .-'| |
// 1 2 3 4 5 1 2 3 4 5 1
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee\xee\xee", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(5));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
'''
[cases.test_rbyd_sextifoliate]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// don't prune
// <b
// .----'|
// <b <y |
// .-'| .-------'| |
// <y | | <r |
// .-------'| | | .----' |
// | <r | | | <y
// | .----' | => | | .-------'|
// | | <r | | | <r
// | | .----'| | | | .----'|
// | | | <b | | | | <b
// | | | .-'| | | | | .-'|
// 1 2 3 4 5 1 2 3 4 5 6
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee\xee\xee", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xff\xff\xff\xff", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(5));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(6),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(6));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// prune by taking a red alt
// <b >b
// .-'| .-'|
// <y | | <r
// .-------'| | .-----------|-'|
// | <r | | | >b
// | .----' | => | .--------|-'|
// | | <r | | <r |
// | | .----'| | | .----'| |
// | | | <b | | | <b |
// | | | .-'| | | | .-'| |
// 1 3 4 5 6 1 3 4 5 6 2
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee\xee\xee", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xff\xff\xff\xff", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(5));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(6),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(6));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
// prune by taking a yellow alt (this needs to prune during the rflip)
// <b >b
// .-'| .-'|
// <y | | >r
// .-------'| | .--------|-'|
// | <r | | | >b
// | .----' | => .--|--------|-'|
// | | <r | | <r |
// | | .----'| | | .----'| |
// | | | <b | | | <b |
// | | | .-'| | | | .-'| |
// 2 3 4 5 6 2 3 4 5 6 1
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee\xee\xee", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xff\xff\xff\xff", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(5));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(6),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(6));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
'''
[cases.test_rbyd_atomic_permutations]
defines.N = 'range(1, 8)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// build the attribute list for the current permutation
struct lfsr_rattr rattrs[N];
for (unsigned j = 0; j < N; j++) {
rattrs[j] = LFSR_RATTR_BUF(
LFSR_TAG_ATTR(perm[j]+1), 0,
"\xaa\xaa\xaa\xaa", 4);
}
// test the given permutation
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, rattrs, N) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(j+1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(j+1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
}
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N;
printf("--- summary --\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
[cases.test_rbyd_permutations]
defines.N = 'range(1, 8)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// test the given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(perm[j]+1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
}
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(j+1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(j+1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
}
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N;
printf("--- summary --\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
[cases.test_rbyd_atomic_traverse]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// 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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// also try the other direction
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_traverse]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// 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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// also try the other direction
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_atomic_traverse_permutations]
defines.N = 'range(1, 8)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// build the attribute list for the current permutation
struct lfsr_rattr rattrs[N];
for (unsigned j = 0; j < N; j++) {
rattrs[j] = LFSR_RATTR_BUF(
LFSR_TAG_ATTR(perm[j]+1), 0,
"\xaa\xaa\xaa\xaa", 4);
}
// test the given permutation
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, rattrs, N) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
// try traversing all tags
tag_ = 0;
rid_ = -1;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(j+1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
}
'''
[cases.test_rbyd_traverse_permutations]
defines.N = 'range(1, 8)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// test the given permutation
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(perm[j]+1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
}
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
// try traversing all tags
tag_ = 0;
rid_ = -1;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(j+1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &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_update_permutations]
defines.N = 'range(1, 8)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// create one consistent block
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(j+1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
}
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// restore backup
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
// update each tag in permutation order
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(perm[j]+1), 0,
"\xaa\xaa\xaa\xaa\xaa\xaa", 6))) => 0;
}
// check that all tags have been updated
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(j+1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(j+1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 6);
}
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// cleanup
free(backup_block);
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N + N;
printf("--- summary --\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
[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, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// create the rbyd tree
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 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++) {
lfs_size_t x
= (ORDER == 0) ? i
: (ORDER == 1) ? (((lfs_size_t)-1) - i)
: TEST_PRNG(&prng);
int err = lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(x & 0x7f), 0,
"\xaa\xaa\xaa\xaa", 4)));
if (err == LFS_ERR_RANGE) {
break;
}
assert(err == 0);
count = i;
}
// check that we can still lookup all the tags
prng = 42;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
for (lfs_size_t i = 0; i < count; i++) {
lfs_size_t x
= (ORDER == 0) ? i
: (ORDER == 1) ? (((lfs_size_t)-1) - i)
: TEST_PRNG(&prng);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(x & 0x7f),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(x & 0x7f));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
}
'''
### Removal testing ###
[cases.test_rbyd_remove]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// add and remove one attribute
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// commit with two attributes, remove the first one
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// commit with two attributes, remove the second one
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(2), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &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_remove_permutations]
defines.N = 'range(1, 7)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(perm[j]+1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
}
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 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);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(j+1), 0))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
for (unsigned k = 0; k < N; k++) {
int err = lfsr_rbyd_lookupnext(&lfs, &rbyd,
-1, LFSR_TAG_ATTR(k+1),
&rid_, &tag_, NULL, &data_);
assert(!err || err == LFS_ERR_NOENT);
if (k == j) {
if (j == N-1) {
assert(err == LFS_ERR_NOENT);
} else {
assert(err == 0);
assert(tag_ == LFSR_TAG_ATTR(j+1+1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
}
} else {
assert(tag_ == LFSR_TAG_ATTR(k+1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
}
}
// try appending the tag back to make sure things still work
printf("--- append: %d ---\n", j);
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(j+1), 0,
"\xaa\xaa\xaa\xaa\xaa\xaa", 6))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd,
-1, LFSR_TAG_ATTR(k+1),
&rid_, &tag_, NULL, &data_) => 0;
if (k == j) {
assert(tag_ == LFSR_TAG_ATTR(k+1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 6);
} else {
assert(tag_ == LFSR_TAG_ATTR(k+1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
}
}
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// cleanup
free(backup_block);
}
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N + 2;
printf("--- summary --\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
# 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_remove_traverse_permutations]
defines.N = 'range(1, 7)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(perm[j]+1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
}
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 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);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(j+1), 0))) => 0;
// try traversing over the tags
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
tag_ = 0;
rid_ = -1;
for (unsigned k = 0; k < N-1; k++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
if (k >= j) {
assert(tag_ == LFSR_TAG_ATTR(k+1+1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
} else {
assert(tag_ == LFSR_TAG_ATTR(k+1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
}
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
}
// cleanup
free(backup_block);
}
'''
[cases.test_rbyd_remove_missing]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// create a tree two attributes
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// try to remove tags that aren't there, this should do nothing
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(3), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(5), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// one last fetch to make sure nothing was broken
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_remove_again]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// create a tree
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee\xee\xee", 4))) => 0;
// remove several attributes
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0),
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(3), 0),
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(5), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// try to remove tags that aren't there, this should do nothing
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(3), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(5), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// try to remove the tags again, just to make sure (keep in mind
// these removes still commit to the rbyd)
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(3), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(5), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// one last fetch to make sure nothing was broken
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(4),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(4));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(5),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_remove_all]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// commit with one attribute, remove it
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// commit with two attributes, remove both
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0),
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(2), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// commit with two attributes, remove both in the other order
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(2), 0),
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2),
&rid_, &tag_, NULL, &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_remove_all_permutations]
defines.N = 'range(1, 7)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// create one consistent block
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(j+1), 0,
"\xaa\xaa\xaa\xaa", 4))) => 0;
}
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// restore backup
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
// remove each tag in permutation order
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(perm[j]+1), 0))) => 0;
}
// check that all tags are now removed
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(j+1),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
}
// try resuming from all tags being removed
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa\xaa\xaa\xaa\xaa", 6))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 6);
for (unsigned j = 1; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(j+1),
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
}
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// cleanup
free(backup_block);
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N + N + 1;
printf("--- summary --\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
# the main purpose of this test is to try to fuzz for failures in the
# balancing algorithm
[cases.test_rbyd_fuzz_append_removes]
defines.N = 'range(1, 33)'
defines.SEED = 'range(1000)'
fuzz = 'SEED'
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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];
printf("perm: [");
uint32_t prng = SEED;
for (unsigned i = 0; i < N; i++) {
// choose an rattr
uint8_t rattr = TEST_PRNG(&prng) % N;
// choose append or remove
if (TEST_PRNG(&prng) & 1) {
printf("a0x%02x=%c", rattr, 'a'+(i % 26));
} else {
printf("r0x%02x", rattr);
}
if (i < N-1) {
printf(", ");
}
}
printf("]\n");
// set up a simulation to compare against
char *sim = malloc(N);
memset(sim, 0, N);
// set up rbyd block
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
prng = SEED;
for (unsigned i = 0; i < N; i++) {
// choose an rattr
uint8_t rattr = TEST_PRNG(&prng) % N;
// choose append or remove
if (TEST_PRNG(&prng) & 1) {
// update our sim
sim[rattr] = 'a'+(i % 26);
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(rattr), 0,
&(uint8_t){'a'+(i % 26)}, 1))) => 0;
} else {
// update our sim
sim[rattr] = '\0';
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(rattr), 0))) => 0;
}
}
// compare rbyd vs simulation
printf("expd: [");
bool first = true;
for (unsigned rattr = 0; rattr < N; rattr++) {
if (sim[rattr]) {
if (!first) {
printf(", ");
}
first = false;
printf("0x%02x=%c", rattr, sim[rattr]);
}
}
printf("]\n");
printf("rbyd: [");
first = true;
for (unsigned rattr = 0; rattr < N; rattr++) {
int err = lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(rattr),
NULL, &data);
if (!err) {
lfs_ssize_t size = lfsr_data_read(&lfs, &data, buffer, 4);
if (!first) {
printf(", ");
}
first = false;
printf("0x%02x=%.*s", rattr, size, buffer);
}
}
printf("]\n");
for (unsigned rattr = 0; rattr < N; rattr++) {
int err = lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(rattr),
NULL, &data);
if (sim[rattr]) {
assert(err == 0);
lfs_ssize_t size = lfsr_data_read(&lfs, &data, buffer, 4);
assert(size == 1);
assert(memcmp(&sim[rattr], buffer, 1) == 0);
} else {
assert(err == LFS_ERR_NOENT);
}
}
// cleanup
free(sim);
'''
### Insertion testing ###
[cases.test_rbyd_atomic_create]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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];
// try to create one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
// try to create two ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
// create a third to the right
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
'''
[cases.test_rbyd_create]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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];
// try to create one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
// try to create two ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
// try to create two in the other direction
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
// create a third to the right
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
// create a third to the left
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
// create a third in the middle
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
'''
[cases.test_rbyd_create_permutations]
defines.N = 'range(1, 8)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_data_t data;
uint8_t buffer[4];
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// test the given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4))) => 0;
}
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == N);
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
}
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N;
printf("--- summary ---\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
[cases.test_rbyd_atomic_create_traverse]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// 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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 00000000, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_create_traverse]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// 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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// also try the other direction
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_create_traverse_permutations]
defines.N = 'range(1, 8)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// test the given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4))) => 0;
}
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == N);
// try traversing all tags
tag_ = 0;
rid_ = -1;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == j);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
}
'''
[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, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 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.weight+1);
int err = lfsr_rbyd_commit(&lfs, &rbyd, x, LFSR_RATTRS(
LFSR_RATTR_BUF(LFSR_TAG_DATA, +1, names[x % 6], 4)));
if (err == LFS_ERR_RANGE) {
break;
}
assert(err == 0);
}
// check that we can at least lookup all the tags
//
// note with random order we can't check that stored values reliably
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
for (uint16_t x = 0; x < rbyd.weight; x++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, x, LFSR_TAG_DATA,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == x);
assert(lfsr_data_size(data_) == 4);
}
'''
### Mixed create and rattr testing ###
[cases.test_rbyd_atomic_mixed]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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];
// try to create one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
// try to create two ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
// create a third to the right
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
'''
[cases.test_rbyd_mixed]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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];
// try to create one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
// try to create two ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
// try to create two in the other direction
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
// create a third to the right
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
// create a third to the left
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
// create a third in the middle
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
'''
[cases.test_rbyd_mixed_permutations]
defines.N = 'range(1, 7)'
defines.M = 'range(1, 4)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_data_t data;
uint8_t buffer[4];
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// test the given permutation
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4))) => 0;
// note uattrs have a smaller size to help debugging
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(u+1), 0,
names[perm[j] % 6], 2))) => 0;
}
}
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == N);
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_ATTR(u+1),
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, names[j % 6], 2) == 0);
}
}
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N + N*M;
printf("--- summary ---\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
[cases.test_rbyd_atomic_mixed_traverse]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// 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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_mixed_traverse]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// 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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// also try the other direction
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xaa\xaa", 2) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 1);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_mixed_traverse_permutations]
defines.N = 'range(1, 7)'
defines.M = 'range(1, 4)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// test the given permutation
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4))) => 0;
// note uattrs have a smaller size to help debugging
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(u+1), 0,
names[perm[j] % 6], 2))) => 0;
}
}
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == N);
// try traversing all tags
tag_ = 0;
rid_ = -1;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == j);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(u+1));
assert(rid_ == j);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, names[j % 6], 2) == 0);
}
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &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_mixed_update_permutations]
defines.N = 'range(1, 4)'
defines.M = 'range(1, 3)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
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",
};
lfsr_rbyd_t rbyd;
lfsr_data_t data;
uint8_t buffer[4];
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// create one consistent block
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[j % 6], 4))) => 0;
// note uattrs have a smaller size to help debugging
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(u+1), 0,
names[j % 6], 2))) => 0;
}
}
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N*M);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N*M];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N*M);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N*M; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// restore backup
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
// update each tag in permutation order
for (unsigned j = 0; j < N*M; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, perm[j]/M, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(perm[j]%M+1), 0,
names[(perm[j]/M) % 6], 3))) => 0;
}
// check that all tags have been updated
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_ATTR(u+1),
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 3;
assert(memcmp(buffer, names[j % 6], 3) == 0);
}
}
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// cleanup
free(backup_block);
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N + N*M + N*M;
printf("--- summary ---\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
# 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_mixed_remove_permutations]
defines.N = 'range(1, 7)'
defines.M = 'range(1, 4)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
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",
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4))) => 0;
// note uattrs have a smaller size to help debugging
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(u+1), 0,
names[perm[j] % 6], 2))) => 0;
}
}
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try removing each tag
for (unsigned j = 0; j < N*M; j++) {
// print what we are removing to help debugging
printf("--- remove: rid%jd, %jd ---\n", j/M, (j%M)+1);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j/M, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR((j%M)+1), 0))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_DATA,
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
for (unsigned u = 0; u < M; u++) {
int err = lfsr_rbyd_lookupnext(&lfs, &rbyd,
k, LFSR_TAG_ATTR(u+1),
&rid_, &tag_, NULL, &data_);
assert(!err || err == LFS_ERR_NOENT);
if (k == j/M && u == j%M) {
if (u == M-1 && k == N-1) {
assert(err == LFS_ERR_NOENT);
} else if (u == M-1) {
assert(err == 0);
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k+1);
assert(lfsr_data_size(data_) == 4);
} else {
assert(err == 0);
assert(tag_ == LFSR_TAG_ATTR(u+1+1));
assert(rid_ == k);
assert(lfsr_data_size(data_) == 2);
}
} else {
assert(tag_ == LFSR_TAG_ATTR(u+1));
assert(rid_ == k);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_,
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, names[k % 6], 2) == 0);
}
}
}
// try append the tag back to make sure things still work
printf("--- append: rid%jd, %jd ---\n", j/M, (j%M)+1);
lfsr_rbyd_commit(&lfs, &rbyd, j/M, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR((j%M)+1), 0,
names[(j/M)%6], 3))) => 0;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_DATA,
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd,
k, LFSR_TAG_ATTR(u+1),
&rid_, &tag_, NULL, &data_) => 0;
if (k == j/M && u == j%M) {
assert(tag_ == LFSR_TAG_ATTR(u+1));
assert(rid_ == k);
assert(lfsr_data_size(data_) == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_,
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 3;
assert(memcmp(buffer, names[k % 6], 3) == 0);
} else {
assert(tag_ == LFSR_TAG_ATTR(u+1));
assert(rid_ == k);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_,
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, names[k % 6], 2) == 0);
}
}
}
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// cleanup
free(backup_block);
}
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N+N*M + 2;
printf("--- summary ---\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
# 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_mixed_remove_all_permutations]
defines.N = 'range(1, 4)'
defines.M = 'range(1, 3)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
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",
};
lfsr_rbyd_t rbyd;
lfsr_data_t data;
uint8_t buffer[4];
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// create one consistent block
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[j % 6], 4))) => 0;
// note uattrs have a smaller size to help debugging
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(u+1), 0,
names[j % 6], 2))) => 0;
}
}
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N*M);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N*M];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N*M);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N*M; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// restore backup
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
// remove each tag in permutation order
for (unsigned j = 0; j < N*M; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, perm[j]/M, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(perm[j]%M+1), 0))) => 0;
}
// check that all tags have been removed
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_ATTR(u+1),
NULL, &data) => LFS_ERR_NOENT;
}
}
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// cleanup
free(backup_block);
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N + N*M + N*M;
printf("--- summary ---\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
[cases.test_rbyd_mixed_large]
in = 'lfs.c'
# ORDER:
# 0 = in-order
# 1 = reverse-order
# 2 = random-order
defines.ORDER = [0, 1, 2]
defines.M = 'range(1, 4)'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 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.weight+1);
// build a single attribute list with all ratibutes, if this fails
// it should fail atomically
struct lfsr_rattr rattrs[1+M];
rattrs[0] = LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[x % 6], 4);
for (unsigned u = 0; u < M; u++) {
rattrs[1+u] = LFSR_RATTR_BUF(
LFSR_TAG_ATTR(u+1), 0,
names[x % 6], 2);
}
int err = lfsr_rbyd_commit(&lfs, &rbyd, x, rattrs, 1+M);
if (err == LFS_ERR_RANGE) {
break;
}
assert(err == 0);
}
// check that we can at least lookup all the tags
//
// note with random order we can't check that stored values reliably
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
for (uint16_t x = 0; x < rbyd.weight; x++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, x, LFSR_TAG_DATA,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == x);
assert(lfsr_data_size(data_) == 4);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, x, LFSR_TAG_ATTR(u+1),
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(u+1));
assert(rid_ == x);
assert(lfsr_data_size(data_) == 2);
}
}
'''
### Test unrelated no-rid tags ###
[cases.test_rbyd_unrelated_create_permutations]
defines.N = 'range(1, 8)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_data_t data;
uint8_t buffer[4];
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// test the given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
// note the data size differences here
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(perm[j]+1), 0,
names[perm[j] % 6], 1))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4))) => 0;
}
// try looking up each tag
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == N);
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(j+1),
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 1;
assert(memcmp(buffer, names[j % 6], 1) == 0);
}
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
}
// try traversing tags
lfsr_tag_t tag_ = 0;
lfs_ssize_t rid_ = -1;
lfsr_data_t data_;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(j+1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 1;
assert(memcmp(buffer, names[j % 6], 1) == 0);
}
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == j);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N;
printf("--- summary ---\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
[cases.test_rbyd_unrelated_mixed_permutations]
defines.N = 'range(1, 7)'
defines.M = 'range(1, 4)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_data_t data;
uint8_t buffer[4];
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// test the given permutation
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
// note the data size differences here
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(perm[j]+1), 0,
names[perm[j] % 6], 1))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4))) => 0;
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(u+1), 0,
names[perm[j] % 6], 2))) => 0;
}
}
// try looking up each tag
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == N);
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookup(&lfs, &rbyd, -1, LFSR_TAG_ATTR(j+1),
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 1;
assert(memcmp(buffer, names[j % 6], 1) == 0);
}
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_ATTR(u+1),
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, names[j % 6], 2) == 0);
}
}
// try traversing tags
lfsr_tag_t tag_ = 0;
lfs_ssize_t rid_ = -1;
lfsr_data_t data_;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(j+1));
assert(rid_ == -1);
assert(lfsr_data_size(data_) == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 1;
assert(memcmp(buffer, names[j % 6], 1) == 0);
}
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == j);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(u+1));
assert(rid_ == j);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, names[j % 6], 2) == 0);
}
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N + N*M;
printf("--- summary ---\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
### Deletion testing ###
[cases.test_rbyd_delete]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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];
// try to delete one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
// try to delete the other rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
// try to delete the largest of three
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
// try to delete the smallest of three
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
// try to delete the middle
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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];
// try to delete one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// try to delete the other rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// try to delete the largest of three
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// try to delete the smallest of three
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xbb\xbb", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// try to delete the middle
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1), NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
assert(memcmp(buffer, "\xcc\xcc", 2) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &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, LFS_M_RDWR, 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_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xee\xee\xee\xee", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2),
// propagate yellow to the root
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(3), NULL, &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_ATTR(3), NULL, &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_ATTR(3), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(3), NULL, &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_ATTR(3), NULL, &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_ATTR(3), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(3), NULL, &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_ATTR(3), NULL, &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_ATTR(3), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(3), NULL, &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_ATTR(3), NULL, &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_ATTR(3), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_r]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), +1,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee", 2),
// propagate yellow to the root
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\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_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, 0,
"\xee\xee\xee\xee", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_y]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), +1,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2),
// propagate yellow to the root
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\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_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(7), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(8), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xaa\xaa", 2),
// propagate yellow
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, 0,
"\xee\xee\xee\xee", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(8), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(7), 0,
"\xee\xee", 2),
// propagate yellow
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(7), 0,
"\xee\xee", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_rydy]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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 where tail-recursion can be
// violated if you preserve coloring during range removes
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), +1,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(7), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(8), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(9), 0,
"\xee\xee", 2),
// propagate yellow to the root
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(9), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(9), 0,
"\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_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, 0,
"\xee\xee\xee\xee", 4),
// propagate yellow
LFSR_RATTR_BUF(
LFSR_TAG_DATA, 0,
"\xee\xee\xee\xee", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_rydy_backwards]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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. .o. .o. .o. .-y-+-. .o. .o.
// a a a a a a a a a a c e e e e e e e
// '+'
// remove
//
// this is a specific nasty case where tail-recursion can be
// violated if you preserve coloring during range removes
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(9), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), +1,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2),
// propagate yellow to the root
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\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, 2, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, 0,
"\xee\xee\xee\xee", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(7), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(8), 0,
"\xaa\xaa", 2),
// propagate yellow
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(8), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_rydye]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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 c c e e e e e e e e
// '--+--'
// remove
//
// this is a specific nasty case where tail-recursion can be
// violated if you preserve coloring during range removes
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), +1,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(7), 0,
"\xee\xee", 2),
// propagate yellow to the root
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(7), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(7), 0,
"\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_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, 0,
"\xee\xee\xee\xee", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xcc\xcc", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2),
// propagate yellow
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_rydye_backwards]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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. .o. .o. .o. .-y-+-. .o. .o.
// a a a a a a a a c c c e e e e e e e
// '--+--'
// remove
//
// this is a specific nasty case where tail-recursion can be
// violated if you preserve coloring during range removes
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), +1,
"\xcc\xcc", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xcc\xcc", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), +1,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2),
// propagate yellow to the root
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\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, 2, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, 0,
"\xee\xee\xee\xee", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(7), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, 0,
"\xcc\xcc\xcc\xcc", 4),
// propagate yellow
LFSR_RATTR_BUF(
LFSR_TAG_DATA, 0,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_dryy]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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 .---o---.
// .-o-. .-o-. .---y------+----. .-o-. .-o-.
// .o. .o. .o. .o. .o. .o. .-+-y-. .o. .o. .o. .o. .o.
// a a a a a a a a a a a a a a a c c c c e e e e e e e
// '---+---'
// remove
//
// this is an attempt at colliding two splits by pruning after
// diverging, in theory this can lead to tail-recursion violations,
// but no violations have been found to be possible yet
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), +1,
"\xcc\xcc", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xee\xee\xee\xee", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2),
// propagate yellow to the root
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\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_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(7), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(8), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(11), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2),
// propagate yellow
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(12), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, 0,
"\xcc\xcc\xcc\xcc", 4),
// propagate yellow
LFSR_RATTR_BUF(
LFSR_TAG_DATA, 0,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(13), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(14), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(9), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(10), 0,
"\xaa\xaa", 2),
// propagate yellow
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(10), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_ATTR(10), NULL, &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_ATTR(11), NULL, &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_ATTR(12), NULL, &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_ATTR(13), NULL, &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_ATTR(14), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_ATTR(10), NULL, &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_ATTR(11), NULL, &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_ATTR(12), NULL, &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_ATTR(13), NULL, &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_ATTR(14), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_ATTR(10), NULL, &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_ATTR(11), NULL, &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_ATTR(12), NULL, &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_ATTR(13), NULL, &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_ATTR(14), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_ATTR(10), NULL, &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_ATTR(11), NULL, &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_ATTR(12), NULL, &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_ATTR(13), NULL, &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_ATTR(14), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_range_dryy_backwards]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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---. r---------+-------.
// .-o-. .-o-. .----+------y---. .-o-. .-o-.
// .o. .o. .o. .o. .o. .-y-+-. .o. .o. .o. .o. .o. .o.
// a a a a a a a c c c c e e e e e e e e e e e e e e e
// '---+---'
// remove
//
// this is an attempt at colliding two splits by pruning after
// diverging, in theory this can lead to tail-recursion violations,
// but no violations have been found to be possible yet
//
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xcc\xcc", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xcc\xcc", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(6), +1,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(7), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(8), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(9), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(10), 0,
"\xee\xee", 2),
// propagate yellow to the root
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(10), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(10), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(10), 0,
"\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, 2, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(11), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(12), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(13), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(14), 0,
"\xee\xee", 2),
// propagate yellow
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(14), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(14), 0,
"\xee\xee", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xee\xee", 2),
// propagate yellow
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"\xee\xee", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, 0,
"\xee\xee\xee\xee", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(5), 0,
"\xee\xee", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xee\xee", 2),
// propagate yellow
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(4), 0,
"\xee\xee", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_ATTR(10), NULL, &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_ATTR(11), NULL, &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_ATTR(12), NULL, &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_ATTR(13), NULL, &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_ATTR(14), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_ATTR(10), NULL, &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_ATTR(11), NULL, &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_ATTR(12), NULL, &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_ATTR(13), NULL, &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_ATTR(14), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// try to recreate
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
assert(rbyd.weight == 3);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_ATTR(10), NULL, &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_ATTR(11), NULL, &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_ATTR(12), NULL, &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_ATTR(13), NULL, &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_ATTR(14), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_DATA, NULL, &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_DATA, NULL, &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_ATTR(1), NULL, &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_ATTR(2), NULL, &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_ATTR(3), NULL, &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_ATTR(4), NULL, &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_ATTR(5), NULL, &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_ATTR(6), NULL, &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_ATTR(7), NULL, &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_ATTR(8), NULL, &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_ATTR(9), NULL, &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_ATTR(10), NULL, &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_ATTR(11), NULL, &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_ATTR(12), NULL, &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_ATTR(13), NULL, &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_ATTR(14), NULL, &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_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 3, LFSR_TAG_ATTR(1),
NULL, &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]
defines.N = 'range(1, 7)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
const uint8_t names[6][6] = {
"\xaa\xaa\xaa\xaa\xaa\xaa",
"\xbb\xbb\xbb\xbb\xbb\xbb",
"\xcc\xcc\xcc\xcc\xcc\xcc",
"\xdd\xdd\xdd\xdd\xdd\xdd",
"\xee\xee\xee\xee\xee\xee",
"\xff\xff\xff\xff\xff\xff",
};
lfsr_data_t data;
uint8_t buffer[6];
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4))) => 0;
}
assert(rbyd.weight == N);
// copy block so we can reset after each delete
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try deleting each rid
for (unsigned j = 0; j < N; j++) {
// print what we are deleting to help debugging
printf("--- delete: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == N-1);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N-1);
for (unsigned k = 0; k < N-1; k++) {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_DATA,
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
if (k >= j) {
assert(memcmp(buffer, names[(k+1) % 6], 4) == 0);
} else {
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
}
lfsr_rbyd_lookup(&lfs, &rbyd, N-1, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
// try recreating the rid to make sure things still work
printf("--- create: %d ---\n", j);
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[j % 6], 6))) => 0;
assert(rbyd.weight == N);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N);
for (unsigned k = 0; k < N; k++) {
if (k == j) {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_DATA,
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 6;
assert(memcmp(buffer, names[k % 6], 6) == 0);
} else {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_DATA,
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
}
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// cleanup
free(backup_block);
}
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N + 2;
printf("--- summary ---\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
# 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_range_permutations]
defines.N = 'range(1, 7)'
defines.M = 'range(1, 4)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
const uint8_t names[6][6] = {
"\xaa\xaa\xaa\xaa\xaa\xaa",
"\xbb\xbb\xbb\xbb\xbb\xbb",
"\xcc\xcc\xcc\xcc\xcc\xcc",
"\xdd\xdd\xdd\xdd\xdd\xdd",
"\xee\xee\xee\xee\xee\xee",
"\xff\xff\xff\xff\xff\xff",
};
lfsr_data_t data;
uint8_t buffer[6];
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4))) => 0;
// note uattrs have a smaller size to help debugging
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(u+1), 0,
names[perm[j] % 6], 2))) => 0;
}
}
assert(rbyd.weight == N);
// copy block so we can reset after each delete
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try deleting each rid
for (unsigned j = 0; j < N; j++) {
// print what we are deleting to help debugging
printf("--- delete: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == N-1);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N-1);
for (unsigned k = 0; k < N-1; k++) {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_DATA,
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
if (k >= j) {
assert(memcmp(buffer, names[(k+1) % 6], 4) == 0);
} else {
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_ATTR(u+1),
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
if (k >= j) {
assert(memcmp(buffer, names[(k+1) % 6], 2) == 0);
} else {
assert(memcmp(buffer, names[k % 6], 2) == 0);
}
}
}
lfsr_rbyd_lookup(&lfs, &rbyd, N-1, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, N-1, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// try recreating the rid to make sure things still work
printf("--- create: %d ---\n", j);
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[j % 6], 6))) => 0;
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(u+1), 0,
names[j % 6], 3))) => 0;
}
assert(rbyd.weight == N);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N);
for (unsigned k = 0; k < N; k++) {
if (k == j) {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_DATA,
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 6;
assert(memcmp(buffer, names[k % 6], 6) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_ATTR(u+1),
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 3;
assert(memcmp(buffer, names[k % 6], 3) == 0);
}
} else {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_DATA,
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_ATTR(u+1),
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 2;
assert(memcmp(buffer, names[k % 6], 2) == 0);
}
}
}
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// cleanup
free(backup_block);
}
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N+N*M + 1 + 1+M;
printf("--- summary ---\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
# 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_traverse_permutations]
defines.N = 'range(1, 7)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4))) => 0;
}
assert(rbyd.weight == N);
// copy block so we can reset after each delete
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try deleting each rid
for (unsigned j = 0; j < N; j++) {
// print what we are deleting to help debugging
printf("--- delete: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == N-1);
// try traversing over the tags
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N-1);
tag_ = 0;
rid_ = -1;
for (unsigned k = 0; k < N-1; k++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
if (k >= j) {
assert(memcmp(buffer, names[(k+1) % 6], 4) == 0);
} else {
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
}
// cleanup
free(backup_block);
}
'''
# 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_traverse_range_permutations]
defines.N = 'range(1, 7)'
defines.M = 'range(1, 4)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4))) => 0;
// note uattrs have a smaller size to help debugging
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(u+1), 0,
names[perm[j] % 6], 2))) => 0;
}
}
assert(rbyd.weight == N);
// copy block so we can reset after each delete
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try deleting each rid
for (unsigned j = 0; j < N; j++) {
// print what we are deleting to help debugging
printf("--- delete: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == N-1);
// try traversing over the tags
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N-1);
tag_ = 0;
rid_ = -1;
for (unsigned k = 0; k < N-1; k++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
if (k >= j) {
assert(memcmp(buffer, names[(k+1) % 6], 4) == 0);
} else {
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(u+1));
assert(rid_ == k);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 2;
if (k >= j) {
assert(memcmp(buffer, names[(k+1) % 6], 2) == 0);
} else {
assert(memcmp(buffer, names[k % 6], 2) == 0);
}
}
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, NULL, &data_) => LFS_ERR_NOENT;
}
// cleanup
free(backup_block);
}
'''
# Note, "delete_all" is a weird state for rbyd trees to be in, since they
# don't really have a trunk at this point
[cases.test_rbyd_delete_all]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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;
// create and delete one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
// create and delete two ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1),
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
// create and delete two ids in the other order
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
// create and delete three ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1),
LFSR_RATTR(LFSR_TAG_RM, -1),
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
// create and delete three ids in the other order
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_delete_all_range]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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;
// create and delete one rid
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
// create and delete two ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1),
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
// create and delete two ids in the other order
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
// create and delete three ids
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 2, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1),
LFSR_RATTR(LFSR_TAG_RM, -1),
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
// create and delete three ids in the other order
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &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_all_permutations]
defines.N = 'range(1, 7)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_data_t data;
uint8_t buffer[6];
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// create one consistent block
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[j % 6], 4))) => 0;
}
assert(rbyd.weight == N);
// copy block so we can reset after each delete
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// restore backup
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
// delete each rid in permutation order
for (unsigned j = 0; j < N; j++) {
// adjust rid based on previous deletions
uint16_t rid = perm[j];
for (unsigned k = 0; k < j; k++) {
if (perm[k] < perm[j]) {
rid -= 1;
}
}
lfs_size_t rbyd_weight_before = rbyd.weight;
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == rbyd_weight_before-1);
}
// check that all tags are now removed
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, LFSR_TAG_DATA, 0,
NULL, &data) => LFS_ERR_NOENT;
// try resuming from all tags being removed
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa\xaa\xaa", 6))) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 6;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa\xaa\xaa", 6) == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// cleanup
free(backup_block);
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + 2*N + 1;
printf("--- summary ---\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
# 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_all_range_permutations]
defines.N = 'range(1, 7)'
defines.M = 'range(1, 4)'
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_data_t data;
uint8_t buffer[6];
// keep track of the worst case log size
lfs_size_t worst_size = 0;
size_t worst_perm_i = 0;
// create one consistent block
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[j % 6], 4))) => 0;
// note uattrs have a smaller size to help debugging
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(u+1), 0,
names[j % 6], 2))) => 0;
}
}
assert(rbyd.weight == N);
// copy block so we can reset after each delete
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// restore backup
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
// delete each rid in permutation order
for (unsigned j = 0; j < N; j++) {
// adjust rid based on previous deletions
uint16_t rid = perm[j];
for (unsigned k = 0; k < j; k++) {
if (perm[k] < perm[j]) {
rid -= 1;
}
}
lfs_size_t rbyd_weight_before = rbyd.weight;
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == rbyd_weight_before-1);
}
// check that all tags are now removed
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 0);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
// try resuming from all tags being removed
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa\xaa\xaa", 6))) => 0;
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(u+1), 0,
"\xaa\xaa\xaa", 3))) => 0;
}
assert(rbyd.weight == 1);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == 1);
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 6;
assert(memcmp(buffer, "\xaa\xaa\xaa\xaa\xaa\xaa", 6) == 0);
for (unsigned u = 0; u < M; u++) {
lfsr_rbyd_lookup(&lfs, &rbyd, 0, LFSR_TAG_ATTR(u+1),
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 3;
assert(memcmp(buffer, "\xaa\xaa\xaa", 3) == 0);
}
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_DATA,
NULL, &data) => LFS_ERR_NOENT;
lfsr_rbyd_lookup(&lfs, &rbyd, 1, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
// keep track of the worst size
if (lfsr_rbyd_eoff(&rbyd) > worst_size) {
worst_size = lfsr_rbyd_eoff(&rbyd);
worst_perm_i = perm_i;
}
}
// cleanup
free(backup_block);
// test that tree is self-balancing, we should be strictly bounded
// by height <= 2*log(n)+1, assume tags are strictly <=12 bytes
lfs_size_t n = 1 + N+N*M + N + 1+M;
printf("--- summary ---\n");
printf("worst permutation: %zd\n", worst_perm_i);
printf("worst size: %u B (N=%u, estimate=%u)\n",
worst_size, n, 12*n*(2*lfs_nlog2(n)+1)+4);
printf("worst avg height: %u B (N=%u, estimate=%u)\n",
worst_size / n, n, 12*(2*lfs_nlog2(n)+1)+4);
// note this only holds true with byte-level progs
if (PROG_SIZE == 1) {
assert(worst_size / n <= 12*(2*lfs_nlog2(n)+1)+4);
}
'''
# the main purpose of this test is to try to fuzz for failures in the
# balancing algorithm
[cases.test_rbyd_fuzz_create_deletes]
defines.N = 'range(1, 33)'
defines.SEED = 'range(1000)'
fuzz = 'SEED'
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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];
printf("perm: [");
uint32_t prng = SEED;
lfs_size_t count = 0;
for (unsigned i = 0; i < N; i++) {
// choose an rid
lfs_ssize_t rid = TEST_PRNG(&prng) % (count+1);
// choose create or delete
if (rid == (lfs_ssize_t)count || (TEST_PRNG(&prng) & 1)) {
printf("c%d=%c", rid, 'a'+(i % 26));
count += 1;
} else {
printf("d%d", rid);
count -= 1;
}
if (i < N-1) {
printf(", ");
}
}
printf("]\n");
// set up a simulation to compare against, fun fact this performs
// worst than our actual rbyd block!
char *sim = malloc(N);
memset(sim, 0, N);
// set up rbyd block
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
prng = SEED;
count = 0;
for (unsigned i = 0; i < N; i++) {
// choose an rid
lfs_ssize_t rid = TEST_PRNG(&prng) % (count+1);
// choose create or delete
if (rid == (lfs_ssize_t)count || (TEST_PRNG(&prng) & 1)) {
// update our sim
memmove(sim+rid+1, sim+rid, count-rid);
sim[rid] = 'a'+(i % 26);
count += 1;
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
&(uint8_t){'a'+(i % 26)}, 1))) => 0;
} else {
// update our sim
memmove(sim+rid, sim+rid+1, count-rid-1);
count -= 1;
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
}
}
// compare rbyd vs simulation
printf("expd: [");
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)count; rid++) {
printf("%c", sim[rid]);
if (rid < (lfs_ssize_t)count-1) {
printf(", ");
}
}
printf("]\n");
printf("rbyd: [");
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)rbyd.weight; rid++) {
int err = lfsr_rbyd_lookup(&lfs, &rbyd, rid, LFSR_TAG_DATA,
NULL, &data);
if (!err) {
lfs_ssize_t size = lfsr_data_read(&lfs, &data, buffer, 4);
printf("%.*s", size, buffer);
} else {
printf("?");
}
if (rid < (lfs_ssize_t)count-1) {
printf(", ");
}
}
printf("]\n");
assert(count == rbyd.weight);
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)count; rid++) {
lfsr_rbyd_lookup(&lfs, &rbyd, rid, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 1;
assert(memcmp(&sim[rid], buffer, 1) == 0);
}
// cleanup
free(sim);
'''
# Test rbyd weights
[cases.test_rbyd_sparse]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
// make id0 with weight w1
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
// make id2 with weight w2
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +2,
"\xbb\xbb\xbb\xbb", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
// make id5 with weight w3
lfsr_rbyd_commit(&lfs, &rbyd, 3, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +3,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
// make id9 with weight w4
lfsr_rbyd_commit(&lfs, &rbyd, 6, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +4,
"\xdd\xdd\xdd\xdd", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 9);
assert(weight_ == 4);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 9);
assert(weight_ == 4);
assert(lfsr_data_size(data_) == 4);
// make id14 with weight w5
lfsr_rbyd_commit(&lfs, &rbyd, 10, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +5,
"\xee\xee\xee\xee", 4))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 9);
assert(weight_ == 4);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 14);
assert(weight_ == 5);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 9);
assert(weight_ == 4);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 14);
assert(weight_ == 5);
assert(lfsr_data_size(data_) == 4);
'''
[cases.test_rbyd_sparse_traverse]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
// make id0 with weight w1
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
// make id2 with weight w2
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +2,
"\xbb\xbb\xbb\xbb", 4),
// make id5 with weight w3
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +3,
"\xcc\xcc\xcc\xcc", 4),
// make id9 with weight w4
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +4,
"\xdd\xdd\xdd\xdd", 4),
// make id14 with weight w5
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +5,
"\xee\xee\xee\xee", 4))) => 0;
// traverse, finding tags and weights
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 9);
assert(weight_ == 4);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 14);
assert(weight_ == 5);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 9);
assert(weight_ == 4);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 14);
assert(weight_ == 5);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_sparse_permutations]
defines.N = 'range(1, 8)'
defines.W = 5
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// test the given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid*W, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +W,
names[perm[j] % 6], 4))) => 0;
}
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == N*W);
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, j*W+W-1, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == j*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, j*W+W-1, LFSR_TAG_DATA,
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
}
}
'''
[cases.test_rbyd_sparse_traverse_permutations]
defines.N = 'range(1, 8)'
defines.W = 5
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// test the given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid*W, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +W,
names[perm[j] % 6], 4))) => 0;
}
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == N*W);
// try traversing all tags
tag_ = 0;
rid_ = -1;
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == j*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
}
'''
# Weights mixed with attributes
[cases.test_rbyd_sparse_mixed]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
// make id0 with weight w1
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"unrelated", 9),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xaa\xaa", 2))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 9);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 9);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
// make id2 with weight w2
lfsr_rbyd_commit(&lfs, &rbyd, 1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2),
LFSR_RATTR(
LFSR_TAG_GROW, +1),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb", 2))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 9);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 9);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
// make id5 with weight w3
lfsr_rbyd_commit(&lfs, &rbyd, 3, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2),
LFSR_RATTR(
LFSR_TAG_GROW, +2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xcc\xcc", 2))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 9);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 9);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
// make id9 with weight w4
lfsr_rbyd_commit(&lfs, &rbyd, 6, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xdd\xdd", 2),
LFSR_RATTR(
LFSR_TAG_GROW, +3),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xdd\xdd", 2))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 9);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 9);
assert(weight_ == 4);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 9);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 9);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 9);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 9);
assert(weight_ == 4);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 9);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 9);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
// make id14 with weight w5
lfsr_rbyd_commit(&lfs, &rbyd, 10, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xee\xee\xee\xee", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xee\xee", 2),
LFSR_RATTR(
LFSR_TAG_GROW, +4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xee\xee", 2))) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 9);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 9);
assert(weight_ == 4);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 9);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 9);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 14);
assert(weight_ == 5);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 14);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 14);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 9);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 2, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 5, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 9);
assert(weight_ == 4);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 9);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 9, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 9);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 14);
assert(weight_ == 5);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 14);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 14, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 14);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
'''
[cases.test_rbyd_sparse_mixed_traverse]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"unrelated", 9),
// make id0 with weight w1
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xaa\xaa", 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xaa\xaa", 2),
// make id2 with weight w2
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb", 2),
LFSR_RATTR(
LFSR_TAG_GROW, +1),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xbb\xbb", 2),
// make id5 with weight w3
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xcc\xcc", 2),
LFSR_RATTR(
LFSR_TAG_GROW, +2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xcc\xcc", 2),
// make id9 with weight w4
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xdd\xdd", 2),
LFSR_RATTR(
LFSR_TAG_GROW, +3),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xdd\xdd", 2),
// make id14 with weight w5
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xee\xee\xee\xee", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xee\xee", 2),
LFSR_RATTR(
LFSR_TAG_GROW, +4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xee\xee", 2))) => 0;
// traverse, finding tags and weights
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 9);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 9);
assert(weight_ == 4);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 9);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 9);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 14);
assert(weight_ == 5);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 14);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 14);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 9);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 0);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 0);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 2);
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 2);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 5);
assert(weight_ == 3);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 5);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 9);
assert(weight_ == 4);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 9);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 9);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == 14);
assert(weight_ == 5);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == 14);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == 14);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_sparse_mixed_permutations]
defines.N = 'range(1, 8)'
defines.W = 5
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// test the given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"unrelated", 9))) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid*W, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
names[perm[j] % 6], 2),
LFSR_RATTR(
LFSR_TAG_GROW, +W-1),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
names[perm[j] % 6], 2))) => 0;
}
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == N*W);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(3),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 9);
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, j*W+W-1, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == j*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, j*W+W-1, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == j*W+W-1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, j*W+W-1, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == j*W+W-1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookup(&lfs, &rbyd, j*W+W-1, LFSR_TAG_DATA,
NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
}
}
'''
[cases.test_rbyd_sparse_mixed_traverse_permutations]
defines.N = 'range(1, 8)'
defines.W = 5
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// test the given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(3), 0,
"unrelated", 9))) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid*W, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
names[perm[j] % 6], 2),
LFSR_RATTR(
LFSR_TAG_GROW, +W-1),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
names[perm[j] % 6], 2))) => 0;
}
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == N*W);
// try traversing all tags
tag_ = 0;
rid_ = -1;
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(3));
assert(rid_ == -1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 9);
for (unsigned j = 0; j < N; j++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == j*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[j % 6], 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == j*W+W-1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == j*W+W-1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
}
'''
# other sparse testing, various grow/shrink corner cases
[cases.test_rbyd_sparse_grow_permutations]
defines.N = 'range(1, 7)'
defines.W = 5
defines.D = [1, 2]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid*W, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +W,
names[perm[j] % 6], 4))) => 0;
}
assert(rbyd.weight == N*W);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try growing each rid
for (unsigned j = 0; j < N; j++) {
// print what we are growing to help debugging
printf("--- growing: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_GROW, +D))) => 0;
assert(rbyd.weight == N*W+D);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N*W+D);
for (unsigned k = 0; k < N; k++) {
if (k == j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1+D, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1+D);
assert(weight_ == W+D);
assert(lfsr_data_size(data_) == 4);
} else if (k > j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1+D, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1+D);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
} else {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
}
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
}
}
'''
[cases.test_rbyd_sparse_grupdate_permutations]
defines.N = 'range(1, 7)'
defines.W = 5
defines.D = [1, 2]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
const uint8_t names[6][6] = {
"\xaa\xaa\xaa\xaa\xaa\xaa",
"\xbb\xbb\xbb\xbb\xbb\xbb",
"\xcc\xcc\xcc\xcc\xcc\xcc",
"\xdd\xdd\xdd\xdd\xdd\xdd",
"\xee\xee\xee\xee\xee\xee",
"\xff\xff\xff\xff\xff\xff",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[6];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid*W, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +W,
names[perm[j] % 6], 4))) => 0;
}
assert(rbyd.weight == N*W);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try growing each rid
for (unsigned j = 0; j < N; j++) {
// print what we are growing to help debugging
printf("--- growing: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_GROW | LFSR_TAG_DATA, +D,
names[j % 6], 6))) => 0;
assert(rbyd.weight == N*W+D);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N*W+D);
for (unsigned k = 0; k < N; k++) {
if (k == j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1+D, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1+D);
assert(weight_ == W+D);
assert(lfsr_data_size(data_) == 6);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 6;
assert(memcmp(buffer, names[k % 6], 6) == 0);
} else if (k > j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1+D, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1+D);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
} else {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
}
}
}
'''
# I don't know if this actually happens in littlefs, but this tests a specific
# code path in lfsr_rbyd_append (split altgt + shrinking)
[cases.test_rbyd_sparse_grappend_permutations]
defines.N = 'range(1, 7)'
defines.W = 5
defines.D = [1, 2]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
const uint8_t names[6][6] = {
"\xaa\xaa\xaa\xaa\xaa\xaa",
"\xbb\xbb\xbb\xbb\xbb\xbb",
"\xcc\xcc\xcc\xcc\xcc\xcc",
"\xdd\xdd\xdd\xdd\xdd\xdd",
"\xee\xee\xee\xee\xee\xee",
"\xff\xff\xff\xff\xff\xff",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[6];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid*W, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), +W,
names[perm[j] % 6], 4))) => 0;
}
assert(rbyd.weight == N*W);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try growing each rid
for (unsigned j = 0; j < N; j++) {
// print what we are growing to help debugging
printf("--- growing: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_GROW | LFSR_TAG_ATTR(1), +D,
names[j % 6], 6))) => 0;
assert(rbyd.weight == N*W+D);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N*W+D);
for (unsigned k = 0; k < N; k++) {
if (k == j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd,
k*W+W-1+D, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == k*W+W-1+D);
assert(weight_ == W+D);
assert(lfsr_data_size(data_) == 6);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 6;
assert(memcmp(buffer, names[k % 6], 6) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd,
k*W+W-1+D, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == k*W+W-1+D);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
} else if (k > j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd,
k*W+W-1+D, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == k*W+W-1+D);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
} else {
lfsr_rbyd_lookupnext(&lfs, &rbyd,
k*W+W-1, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == k*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
}
}
}
'''
[cases.test_rbyd_sparse_shrink_permutations]
defines.N = 'range(1, 7)'
defines.W = 5
defines.D = [1, 2]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid*W, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +W,
names[perm[j] % 6], 4))) => 0;
}
assert(rbyd.weight == N*W);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try shrinking each rid
for (unsigned j = 0; j < N; j++) {
// print what we are shrinking to help debugging
printf("--- shrinking: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_GROW, -D))) => 0;
assert(rbyd.weight == N*W-D);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N*W-D);
for (unsigned k = 0; k < N; k++) {
if (k == j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1-D, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1-D);
assert(weight_ == W-D);
assert(lfsr_data_size(data_) == 4);
} else if (k > j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1-D, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1-D);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
} else {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
}
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
}
}
'''
[cases.test_rbyd_sparse_shrupdate_permutations]
defines.N = 'range(1, 7)'
defines.W = 5
defines.D = [1, 2]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
const uint8_t names[6][6] = {
"\xaa\xaa\xaa\xaa\xaa\xaa",
"\xbb\xbb\xbb\xbb\xbb\xbb",
"\xcc\xcc\xcc\xcc\xcc\xcc",
"\xdd\xdd\xdd\xdd\xdd\xdd",
"\xee\xee\xee\xee\xee\xee",
"\xff\xff\xff\xff\xff\xff",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[6];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid*W, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +W,
names[perm[j] % 6], 4))) => 0;
}
assert(rbyd.weight == N*W);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try shrinking each rid
for (unsigned j = 0; j < N; j++) {
// print what we are shrinking to help debugging
printf("--- shrinking: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_GROW | LFSR_TAG_DATA, -D,
names[j % 6], 6))) => 0;
assert(rbyd.weight == N*W-D);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N*W-D);
for (unsigned k = 0; k < N; k++) {
if (k == j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1-D, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1-D);
assert(weight_ == W-D);
assert(lfsr_data_size(data_) == 6);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 6;
assert(memcmp(buffer, names[k % 6], 6) == 0);
} else if (k > j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1-D, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1-D);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
} else {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
}
}
}
'''
# I don't know if this actually happens in littlefs, but this tests a specific
# code path in lfsr_rbyd_append (split altgt + shrinking)
[cases.test_rbyd_sparse_shrappend_permutations]
defines.N = 'range(1, 7)'
defines.W = 5
defines.D = [1, 2]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
const uint8_t names[6][6] = {
"\xaa\xaa\xaa\xaa\xaa\xaa",
"\xbb\xbb\xbb\xbb\xbb\xbb",
"\xcc\xcc\xcc\xcc\xcc\xcc",
"\xdd\xdd\xdd\xdd\xdd\xdd",
"\xee\xee\xee\xee\xee\xee",
"\xff\xff\xff\xff\xff\xff",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[6];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid*W, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), +W,
names[perm[j] % 6], 4))) => 0;
}
assert(rbyd.weight == N*W);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try shrinking each rid
for (unsigned j = 0; j < N; j++) {
// print what we are shrinking to help debugging
printf("--- shrinking: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_GROW | LFSR_TAG_ATTR(1), -D,
names[j % 6], 6))) => 0;
assert(rbyd.weight == N*W-D);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N*W-D);
for (unsigned k = 0; k < N; k++) {
if (k == j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd,
k*W+W-1-D, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == k*W+W-1-D);
assert(weight_ == W-D);
assert(lfsr_data_size(data_) == 6);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 6;
assert(memcmp(buffer, names[k % 6], 6) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd,
k*W+W-1-D, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == k*W+W-1-D);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
} else if (k > j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd,
k*W+W-1-D, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == k*W+W-1-D);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
} else {
lfsr_rbyd_lookupnext(&lfs, &rbyd,
k*W+W-1, LFSR_TAG_ATTR(2),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(2));
assert(rid_ == k*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
}
}
}
'''
[cases.test_rbyd_sparse_delete_permutations]
defines.N = 'range(1, 7)'
defines.W = 5
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
const uint8_t names[6][6] = {
"\xaa\xaa\xaa\xaa\xaa\xaa",
"\xbb\xbb\xbb\xbb\xbb\xbb",
"\xcc\xcc\xcc\xcc\xcc\xcc",
"\xdd\xdd\xdd\xdd\xdd\xdd",
"\xee\xee\xee\xee\xee\xee",
"\xff\xff\xff\xff\xff\xff",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[6];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid*W, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +W,
names[perm[j] % 6], 4))) => 0;
}
assert(rbyd.weight == N*W);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try deleting each rid
for (unsigned j = 0; j < N; j++) {
// print what we are deleting to help debugging
printf("--- deleting: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -W))) => 0;
assert(rbyd.weight == (N-1)*W);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == (N-1)*W);
for (unsigned k = 0; k < N-1; k++) {
if (k >= j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[(k+1) % 6], 4) == 0);
} else {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
}
// try recreating the rid to make sure things still work
printf("--- create: %d ---\n", j);
lfsr_rbyd_commit(&lfs, &rbyd, j*W, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +W,
names[j % 6], 6))) => 0;
assert(rbyd.weight == N*W);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N*W);
for (unsigned k = 0; k < N; k++) {
if (k == j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 6);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 6;
assert(memcmp(buffer, names[k % 6], 6) == 0);
} else {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 6) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
}
}
}
}
'''
[cases.test_rbyd_sparse_rattr_permutations]
defines.N = 'range(1, 7)'
defines.W = 5
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
lfsr_rbyd_commit(&lfs, &rbyd, rid*W, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +W,
names[perm[j] % 6], 4))) => 0;
}
assert(rbyd.weight == N*W);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try appending an rattr to each rid, this should not affect
// weights at all!
for (unsigned j = 0; j < N; j++) {
// print what we are appending to help debugging
printf("--- appending: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
names[j % 6], 2))) => 0;
assert(rbyd.weight == N*W);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N*W);
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
if (k == j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd,
k*W+W-1, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == k*W+W-1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
}
}
// now try removing the rattr
printf("--- removing: %d ---\n", j);
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0))) => 0;
assert(rbyd.weight == N*W);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N*W);
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
if (k == j) {
lfsr_rbyd_lookup(&lfs, &rbyd, k*W+W-1, LFSR_TAG_ATTR(1),
NULL, &data) => LFS_ERR_NOENT;
}
}
// and try putting the rattr back just for good measure
printf("--- appending: %d ---\n", j);
lfsr_rbyd_commit(&lfs, &rbyd, j*W+W-1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
names[j % 6], 2))) => 0;
assert(rbyd.weight == N*W);
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
assert(rbyd.weight == N*W);
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, k*W+W-1, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(rid_ == k*W+W-1);
assert(weight_ == W);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 4;
assert(memcmp(buffer, names[k % 6], 4) == 0);
if (k == j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd,
k*W+W-1, LFSR_TAG_ATTR(1),
&rid_, &tag_, &weight_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(1));
assert(rid_ == k*W+W-1);
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
}
}
}
}
'''
# Some more fuzzish testing
[cases.test_rbyd_fuzz_mixed]
defines.N = 'range(1, 33)'
defines.M = 3
defines.SEED = 'range(1000)'
fuzz = 'SEED'
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, 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];
printf("perm: [");
uint32_t prng = SEED;
lfs_size_t count = 0;
for (unsigned i = 0; i < N; i++) {
// choose create/delete or rattr append/remove
uint8_t op = TEST_PRNG(&prng) % 4;
// choose an rid
lfs_ssize_t rid = TEST_PRNG(&prng) % (count+1);
// choose an rattr
uint8_t u = TEST_PRNG(&prng) % M;
if (rid == (lfs_ssize_t)count || op == 0) {
printf("c%d=%c", rid, 'a'+(i % 26));
count += 1;
} else if (op == 1) {
printf("d%d", rid);
count -= 1;
} else if (op == 2) {
printf("a%d,%d=%c", rid, u, 'a'+(i % 26));
} else if (op == 3) {
printf("r%d,%d", rid, u);
}
if (i < N-1) {
printf(", ");
}
}
printf("]\n");
// set up a simulation to compare against, fun fact this performs
// worst than our actual rbyd block!
char *sim = malloc(N*(M+1));
memset(sim, 0, N*(M+1));
// set up rbyd block
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
prng = SEED;
count = 0;
for (unsigned i = 0; i < N; i++) {
// choose create/delete or rattr append/remove
uint8_t op = TEST_PRNG(&prng) % 4;
// choose an rid
lfs_ssize_t rid = TEST_PRNG(&prng) % (count+1);
// choose an rattr
uint8_t u = TEST_PRNG(&prng) % M;
if (rid == (lfs_ssize_t)count || op == 0) {
// update our sim
memmove(sim+(rid+1)*(M+1), sim+rid*(M+1), (count-rid)*(M+1));
memset(&sim[rid*(M+1)], 0, M+1);
sim[rid*(M+1)] = 'a'+(i % 26);
count += 1;
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
&(uint8_t){'a'+(i % 26)}, 1))) => 0;
} else if (op == 1) {
// update our sim
memmove(sim+rid*(M+1), sim+(rid+1)*(M+1), (count-rid-1)*(M+1));
count -= 1;
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
} else if (op == 2) {
// update our sim
sim[rid*(M+1) + u+1] = 'a'+(i % 26);
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(u), 0,
&(uint8_t){'a'+(i % 26)}, 1))) => 0;
} else if (op == 3) {
// update our sim
sim[rid*(M+1) + u+1] = '\0';
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(u), 0))) => 0;
}
}
// compare rbyd vs simulation
printf("expd: [");
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)count; rid++) {
printf("%c", sim[rid*(M+1)]);
for (uint8_t u = 0; u < M; u++) {
if (sim[rid*(M+1) + u+1]) {
printf("%c", sim[rid*(M+1) + u+1]);
} else {
printf("_");
}
}
if (rid < (lfs_ssize_t)count-1) {
printf(", ");
}
}
printf("]\n");
printf("rbyd: [");
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)rbyd.weight; rid++) {
int err = lfsr_rbyd_lookup(&lfs, &rbyd, rid, LFSR_TAG_DATA,
NULL, &data);
if (!err) {
lfs_ssize_t size = lfsr_data_read(&lfs, &data, buffer, 4);
printf("%.*s", size, buffer);
} else {
printf("?");
}
for (uint8_t u = 0; u < M; u++) {
err = lfsr_rbyd_lookup(&lfs, &rbyd, rid, LFSR_TAG_ATTR(u),
NULL, &data);
if (!err) {
lfs_ssize_t size = lfsr_data_read(&lfs, &data, buffer, 4);
printf("%.*s", size, buffer);
} else {
printf("_");
}
}
if (rid < (lfs_ssize_t)count-1) {
printf(", ");
}
}
printf("]\n");
assert(count == rbyd.weight);
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)count; rid++) {
lfsr_rbyd_lookup(&lfs, &rbyd, rid, LFSR_TAG_DATA, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 1;
assert(memcmp(&sim[rid*(M+1)], buffer, 1) == 0);
}
// cleanup
free(sim);
'''
[cases.test_rbyd_fuzz_sparse]
defines.N = 'range(1, 33)'
defines.W = 5
defines.SEED = 'range(1000)'
fuzz = 'SEED'
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
lfsr_tag_t tag_;
lfs_ssize_t rid_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_data_t data;
uint8_t buffer[4];
printf("perm: [");
uint32_t prng = SEED;
lfs_size_t count = 0;
for (unsigned i = 0; i < N; i++) {
// choose create/delete/grow/shrink
uint8_t op = TEST_PRNG(&prng) % 4;
// choose an rid
lfs_ssize_t rid = TEST_PRNG(&prng) % (count+1);
// choose a weight
lfs_size_t weight = 1 + (TEST_PRNG(&prng) % W);
if (rid == (lfs_ssize_t)count || op == 0) {
printf("c%dw%d=%c", rid, weight, 'a'+(i % 26));
count += 1;
} else if (op == 1) {
printf("d%d", rid);
count -= 1;
} else if (op == 2) {
printf("g%dw%d", rid, weight);
} else if (op == 3) {
printf("s%dw%d", rid, weight);
}
if (i < N-1) {
printf(", ");
}
}
printf("]\n");
// set up a simulation to compare against, fun fact this performs
// worst than our actual rbyd block!
char *sim = malloc(N);
lfs_size_t *sim_weights = malloc(N*sizeof(lfs_size_t));
memset(sim, 0, N);
memset(sim_weights, 0, N*sizeof(lfs_size_t));
// set up rbyd block
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
prng = SEED;
count = 0;
for (unsigned i = 0; i < N; i++) {
// choose create/delete/grow/shrink
uint8_t op = TEST_PRNG(&prng) % 4;
// choose an rid
lfs_ssize_t rid = TEST_PRNG(&prng) % (count+1);
// choose a weight
lfs_size_t weight = 1 + (TEST_PRNG(&prng) % W);
// calculate actual rid in rbyd space
lfs_ssize_t weighted_rid = 0;
for (lfs_ssize_t j = 0; j < rid; j++) {
weighted_rid += sim_weights[j];
}
if (rid == (lfs_ssize_t)count || op == 0) {
// update our sim
memmove(sim+rid+1, sim+rid, count-rid);
memmove(sim_weights+rid+1, sim_weights+rid,
(count-rid)*sizeof(lfs_size_t));
sim[rid] = 'a'+(i % 26);
sim_weights[rid] = weight;
count += 1;
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, weighted_rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +weight,
&(uint8_t){'a'+(i % 26)}, 1))) => 0;
} else if (op == 1) {
// get the correct weight from the sim
weight_ = sim_weights[rid];
// update our sim
memmove(sim+rid, sim+rid+1, count-rid-1);
memmove(sim_weights+rid, sim_weights+rid+1,
(count-rid-1)*sizeof(lfs_size_t));
count -= 1;
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, weighted_rid+weight_-1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -weight_))) => 0;
} else if (op == 2) {
// get the correct weight from the sim
weight_ = sim_weights[rid];
// update our sim
sim_weights[rid] += weight;
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, weighted_rid+weight_-1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_GROW, +weight))) => 0;
} else if (op == 3) {
// get the correct weight from the sim
weight_ = sim_weights[rid];
// don't let shrink go to zero here! this is already hard enough
// to simulate
weight = lfs_min(weight, weight_-1);
// update our sim
sim_weights[rid] -= weight;
// update our rbyd
lfsr_rbyd_commit(&lfs, &rbyd, weighted_rid+weight_-1, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_GROW, -weight))) => 0;
}
}
// compare rbyd vs simulation
printf("expd: [");
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)count; rid++) {
printf("%cw%d", sim[rid], sim_weights[rid]);
if (rid < (lfs_ssize_t)count-1) {
printf(", ");
}
}
printf("]\n");
printf("rbyd: [");
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)count; rid++) {
// calculate actual rid in rbyd space
lfs_ssize_t weighted_rid = 0;
for (lfs_ssize_t j = 0; j < rid; j++) {
weighted_rid += sim_weights[j];
}
int err = lfsr_rbyd_lookupnext(&lfs, &rbyd,
weighted_rid, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_);
if (!err) {
lfs_ssize_t size = lfsr_data_read(&lfs, &data_, buffer, 4);
if (size >= 0) {
printf("%.*sw%d", size, buffer, weight_);
} else {
printf("?");
}
} else {
printf("?");
}
if (rid < (lfs_ssize_t)count-1) {
printf(", ");
}
}
printf("]\n");
// calculate total weight
lfs_size_t total_weight = 0;
for (lfs_ssize_t j = 0; j < (lfs_ssize_t)count; j++) {
total_weight += sim_weights[j];
}
assert(total_weight == rbyd.weight);
for (lfs_ssize_t rid = 0; rid < (lfs_ssize_t)count; rid++) {
// calculate actual rid in rbyd space
lfs_ssize_t weighted_rid = 0;
for (lfs_ssize_t j = 0; j < rid; j++) {
weighted_rid += sim_weights[j];
}
lfsr_rbyd_lookupnext(&lfs, &rbyd,
weighted_rid, LFSR_TAG_DATA,
&rid_, &tag_, &weight_, &data_) => 0;
lfsr_rbyd_lookup(&lfs, &rbyd, rid_, tag_, NULL, &data) => 0;
lfsr_data_read(&lfs, &data, buffer, 4) => 1;
assert(memcmp(&sim[rid], buffer, 1) == 0);
}
// cleanup
free(sim);
free(sim_weights);
'''
### Supertype/subtype-wide things ###
# subtype-wide
[cases.test_rbyd_subwide_lookup_permutations]
defines.N = 'range(1, 7)'
defines.SHIFT = [0, 3, -3]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// build the attribute list for the current permutation
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
// give each rattr a subtype based on its rid + SHIFT
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR((perm[j] + SHIFT) & 0x7f), 0,
names[perm[j] % 6], 2))) => 0;
}
assert(rbyd.weight == N);
// test that we can lookup each rattr with a wide lookup
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == N);
for (unsigned j = 0; j < N; j++) {
lfsr_tag_t tag_;
lfsr_data_t data_;
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR((j + SHIFT) & 0x7f));
assert(lfsr_data_size(data_) == 2);
}
}
'''
# 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_subwide_remove_permutations]
defines.N = 'range(1, 7)'
defines.SHIFT = [0, 3, -3]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
// give each rattr a subtype based on its rid + SHIFT
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR((perm[j] + SHIFT) & 0x7f), 0,
names[perm[j] % 6], 2))) => 0;
}
assert(rbyd.weight == N);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 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);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
// remove with a wide tag
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_MASK8 | LFSR_TAG_ATTR, 0))) => 0;
// try traversing over the tags
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
lfsr_tag_t tag_ = 0;
lfs_ssize_t rid_ = -1;
lfs_size_t weight_;
lfsr_data_t data_;
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == k);
assert(tag_ == LFSR_TAG_DATA);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
if (k != j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == k);
assert(tag_ == LFSR_TAG_ATTR((k + SHIFT) & 0x7f));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
}
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
// also test that we can lookup each tag with a wide lookup
for (unsigned k = 0; k < N; k++) {
if (k == j) {
lfsr_rbyd_lookup(&lfs, &rbyd, k,
LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => LFS_ERR_NOENT;
} else {
lfsr_rbyd_lookup(&lfs, &rbyd, k,
LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR((k + SHIFT) & 0x7f));
assert(lfsr_data_size(data_) == 2);
}
}
}
// cleanup
free(backup_block);
}
'''
# 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_subwide_replace_permutations]
defines.N = 'range(1, 7)'
defines.SHIFT = [0, 3, -3]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
const uint8_t names[6][6] = {
"\xaa\xaa\xaa\xaa\xaa\xaa",
"\xbb\xbb\xbb\xbb\xbb\xbb",
"\xcc\xcc\xcc\xcc\xcc\xcc",
"\xdd\xdd\xdd\xdd\xdd\xdd",
"\xee\xee\xee\xee\xee\xee",
"\xff\xff\xff\xff\xff\xff",
};
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
// give each rattr a subtype based on its rid + SHIFT
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR((perm[j] + SHIFT) & 0x7f), 0,
names[perm[j] % 6], 2))) => 0;
}
assert(rbyd.weight == N);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try replacing each tag
for (unsigned j = 0; j < N; j++) {
// print what we are replacing to help debugging
printf("--- replace: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
// replace with bitwise inverse
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_MASK8 | LFSR_TAG_ATTR(~(j + SHIFT) & 0x7f),
0,
names[j % 6], 3))) => 0;
// try traversing over the tags
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
lfsr_tag_t tag_ = 0;
lfs_ssize_t rid_ = -1;
lfs_size_t weight_;
lfsr_data_t data_;
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == k);
assert(tag_ == LFSR_TAG_DATA);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
if (k == j) {
assert(rid_ == k);
assert(tag_ == LFSR_TAG_ATTR(~(k + SHIFT) & 0x7f));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 3);
} else {
assert(rid_ == k);
assert(tag_ == LFSR_TAG_ATTR((k + SHIFT) & 0x7f));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
}
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
// also test that we can lookup each tag with a wide lookup
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => 0;
if (k == j) {
assert(tag_ == LFSR_TAG_ATTR(~(k + SHIFT) & 0x7f));
assert(lfsr_data_size(data_) == 3);
} else {
assert(tag_ == LFSR_TAG_ATTR((k + SHIFT) & 0x7f));
assert(lfsr_data_size(data_) == 2);
}
}
}
// cleanup
free(backup_block);
}
'''
[cases.test_rbyd_subwide_mixed_lookup_permutations]
defines.N = 'range(1, 7)'
defines.SHIFT = [0, 3, -3]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// build the attribute list for the current permutation
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
// give each rattr a subtype based on its rid + SHIFT
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(0x7f & (perm[j] + SHIFT)), 0,
names[perm[j] % 6], 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(0x80), 0,
names[perm[j] % 6], 1))) => 0;
}
assert(rbyd.weight == N);
// test that we can lookup each rattr with a wide lookup
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == N);
for (unsigned j = 0; j < N; j++) {
lfsr_tag_t tag_;
lfsr_data_t data_;
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR(0x7f & (j + SHIFT)));
assert(lfsr_data_size(data_) == 2);
}
}
'''
# 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_subwide_mixed_remove_permutations]
defines.N = 'range(1, 7)'
defines.SHIFT = [0, 3, -3]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
// give each rattr a subtype based on its rid + SHIFT
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(0x7f & (perm[j] + SHIFT)), 0,
names[perm[j] % 6], 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(0x80), 0,
names[perm[j] % 6], 1))) => 0;
}
assert(rbyd.weight == N);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 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);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
// remove with a wide tag
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_MASK8 | LFSR_TAG_ATTR, 0))) => 0;
// try traversing over the tags
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
lfsr_tag_t tag_ = 0;
lfs_ssize_t rid_ = -1;
lfs_size_t weight_;
lfsr_data_t data_;
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == k);
assert(tag_ == LFSR_TAG_DATA);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
if (k != j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == k);
assert(tag_ == LFSR_TAG_ATTR(0x7f & (k + SHIFT)));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == k);
assert(tag_ == LFSR_TAG_ATTR(0x80));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 1);
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
// also test that we can lookup each tag with a wide lookup
for (unsigned k = 0; k < N; k++) {
if (k == j) {
lfsr_rbyd_lookup(&lfs, &rbyd, k,
LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => LFS_ERR_NOENT;
} else {
lfsr_rbyd_lookup(&lfs, &rbyd, k,
LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR((k + SHIFT) & 0x7f));
assert(lfsr_data_size(data_) == 2);
}
}
}
// cleanup
free(backup_block);
}
'''
# 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_subwide_mixed_replace_permutations]
defines.N = 'range(1, 7)'
defines.SHIFT = [0, 3, -3]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
const uint8_t names[6][6] = {
"\xaa\xaa\xaa\xaa\xaa\xaa",
"\xbb\xbb\xbb\xbb\xbb\xbb",
"\xcc\xcc\xcc\xcc\xcc\xcc",
"\xdd\xdd\xdd\xdd\xdd\xdd",
"\xee\xee\xee\xee\xee\xee",
"\xff\xff\xff\xff\xff\xff",
};
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
// give each rattr a subtype based on its rid + SHIFT
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(0x7f & (perm[j] + SHIFT)), 0,
names[perm[j] % 6], 2),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(0x80), 0,
names[perm[j] % 6], 1))) => 0;
}
assert(rbyd.weight == N);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try replacing each tag
for (unsigned j = 0; j < N; j++) {
// print what we are replacing to help debugging
printf("--- replace: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
// replace with bitwise inverse
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_MASK8 | LFSR_TAG_ATTR(~(j + SHIFT) & 0x7f),
0,
names[j % 6], 3))) => 0;
// try traversing over the tags
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
lfsr_tag_t tag_ = 0;
lfs_ssize_t rid_ = -1;
lfs_size_t weight_;
lfsr_data_t data_;
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == k);
assert(tag_ == LFSR_TAG_DATA);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
if (k == j) {
assert(rid_ == k);
assert(tag_ == LFSR_TAG_ATTR(0x7f & ~(k + SHIFT)));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 3);
} else {
assert(rid_ == k);
assert(tag_ == LFSR_TAG_ATTR(0x7f & (k + SHIFT)));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == k);
assert(tag_ == LFSR_TAG_ATTR(0x80));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 1);
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
// also test that we can lookup each tag with a wide lookup
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => 0;
if (k == j) {
assert(tag_ == LFSR_TAG_ATTR(~(k + SHIFT) & 0x7f));
assert(lfsr_data_size(data_) == 3);
} else {
assert(tag_ == LFSR_TAG_ATTR((k + SHIFT) & 0x7f));
assert(lfsr_data_size(data_) == 2);
}
}
}
// cleanup
free(backup_block);
}
'''
[cases.test_rbyd_subwide_weighted_lookup_permutations]
defines.N = 'range(1, 7)'
defines.SHIFT = [0, 3, -3]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// build the attribute list for the current permutation
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
// give each rattr a subtype based on its rid + SHIFT
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR((perm[j] + SHIFT) & 0x7f), +1,
names[perm[j] % 6], 4))) => 0;
}
assert(rbyd.weight == N);
// test that we can lookup each rattr with a wide lookup
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == N);
for (unsigned j = 0; j < N; j++) {
lfsr_tag_t tag_;
lfsr_data_t data_;
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR((j + SHIFT) & 0x7f));
assert(lfsr_data_size(data_) == 4);
}
}
'''
# 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_subwide_weighted_remove_permutations]
defines.N = 'range(1, 7)'
defines.SHIFT = [0, 3, -3]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
// give each rattr a subtype based on its rid + SHIFT
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR((perm[j] + SHIFT) & 0x7f), +1,
names[perm[j] % 6], 4))) => 0;
}
assert(rbyd.weight == N);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 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);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
// remove with a wide tag
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_MASK8 | LFSR_TAG_ATTR, 0))) => 0;
// try traversing over the tags
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
lfsr_tag_t tag_ = 0;
lfs_ssize_t rid_ = -1;
lfs_size_t weight_;
lfsr_data_t data_;
for (unsigned k = 0; k < N-1; k++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
if (k == j) {
assert(rid_ == k+1);
assert(tag_ == LFSR_TAG_ATTR((k+1 + SHIFT) & 0x7f));
assert(weight_ == 2);
assert(lfsr_data_size(data_) == 4);
} else if (k > j) {
assert(rid_ == k+1);
assert(tag_ == LFSR_TAG_ATTR((k+1 + SHIFT) & 0x7f));
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
} else {
assert(rid_ == k);
assert(tag_ == LFSR_TAG_ATTR((k + SHIFT) & 0x7f));
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
}
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
// also test that we can lookup each tag with a wide lookup
for (unsigned k = 0; k < N; k++) {
if (k == j) {
lfsr_rbyd_lookup(&lfs, &rbyd, k,
LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => LFS_ERR_NOENT;
} else {
lfsr_rbyd_lookup(&lfs, &rbyd, k,
LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR((k + SHIFT) & 0x7f));
assert(lfsr_data_size(data_) == 4);
}
}
}
// cleanup
free(backup_block);
}
'''
# 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_subwide_weighted_replace_permutations]
defines.N = 'range(1, 7)'
defines.SHIFT = [0, 3, -3]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
const uint8_t names[6][6] = {
"\xaa\xaa\xaa\xaa\xaa\xaa",
"\xbb\xbb\xbb\xbb\xbb\xbb",
"\xcc\xcc\xcc\xcc\xcc\xcc",
"\xdd\xdd\xdd\xdd\xdd\xdd",
"\xee\xee\xee\xee\xee\xee",
"\xff\xff\xff\xff\xff\xff",
};
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
// give each rattr a subtype based on its rid + SHIFT
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR((perm[j] + SHIFT) & 0x7f), +1,
names[perm[j] % 6], 4))) => 0;
}
assert(rbyd.weight == N);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try replacing each tag
for (unsigned j = 0; j < N; j++) {
// print what we are replacing to help debugging
printf("--- replace: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
// replace with bitwise inverse
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_MASK8 | LFSR_TAG_ATTR(~(j + SHIFT) & 0x7f),
0,
names[j % 6], 6))) => 0;
// try traversing over the tags
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
lfsr_tag_t tag_ = 0;
lfs_ssize_t rid_ = -1;
lfs_size_t weight_;
lfsr_data_t data_;
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
if (k == j) {
assert(rid_ == k);
assert(tag_ == LFSR_TAG_ATTR(~(k + SHIFT) & 0x7f));
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 6);
} else {
assert(rid_ == k);
assert(tag_ == LFSR_TAG_ATTR((k + SHIFT) & 0x7f));
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
}
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
// also test that we can lookup each tag with a wide lookup
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => 0;
if (k == j) {
assert(tag_ == LFSR_TAG_ATTR(~(k + SHIFT) & 0x7f));
assert(lfsr_data_size(data_) == 6);
} else {
assert(tag_ == LFSR_TAG_ATTR((k + SHIFT) & 0x7f));
assert(lfsr_data_size(data_) == 4);
}
}
}
// cleanup
free(backup_block);
}
'''
# supertype-wide
[cases.test_rbyd_supwide_lookup_permutations]
defines.N = 'range(1, 7)'
defines.SHIFT = [0, 3, -3]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// build the attribute list for the current permutation
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
// give each rattr a subtype based on its rid + SHIFT
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR((perm[j] + SHIFT) & 0x7f), 0,
names[perm[j] % 6], 2))) => 0;
}
assert(rbyd.weight == N);
// a supwide rattr lookup only gets the file type
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], 0) => 0;
assert(rbyd.weight == N);
for (unsigned j = 0; j < N; j++) {
lfsr_tag_t tag_;
lfsr_data_t data_;
lfsr_rbyd_lookup(&lfs, &rbyd, j, LFSR_TAG_MASK12,
&tag_, &data_) => 0;
assert(tag_ == LFSR_TAG_DATA);
assert(lfsr_data_size(data_) == 4);
}
}
'''
# 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_supwide_remove_permutations]
defines.N = 'range(1, 7)'
defines.SHIFT = [0, 3, -3]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_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",
};
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
// give each rattr a subtype based on its rid + SHIFT
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR((perm[j] + SHIFT) & 0x7f), 0,
names[perm[j] % 6], 2))) => 0;
}
assert(rbyd.weight == N);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 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);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
// remove with a wide tag
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_MASK12 | LFSR_TAG_ATTR,
0))) => 0;
// try traversing over the tags
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
lfsr_tag_t tag_ = 0;
lfs_ssize_t rid_ = -1;
lfs_size_t weight_;
lfsr_data_t data_;
for (unsigned k = 0; k < N; k++) {
if (k != j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == k);
assert(tag_ == LFSR_TAG_DATA);
assert(weight_ == ((k == j+1) ? 2 : 1));
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == k);
assert(tag_ == LFSR_TAG_ATTR((k + SHIFT) & 0x7f));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
}
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
// also test that we can lookup each tag with a wide lookup
for (unsigned k = 0; k < N; k++) {
if (k == j) {
lfsr_rbyd_lookup(&lfs, &rbyd, k,
LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => LFS_ERR_NOENT;
} else {
lfsr_rbyd_lookup(&lfs, &rbyd, k,
LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => 0;
assert(tag_ == LFSR_TAG_ATTR((k + SHIFT) & 0x7f));
assert(lfsr_data_size(data_) == 2);
}
}
}
// cleanup
free(backup_block);
}
'''
# 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_supwide_replace_permutations]
defines.N = 'range(1, 7)'
defines.SHIFT = [0, 3, -3]
# PERMUTATION=-1 => exhaust all permutations
# PERMUTATION=n => reproduce a specific permutation
defines.PERMUTATION = -1
# large progs take too long for now
if = 'PROG_SIZE < 512'
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
const uint8_t names[6][6] = {
"\xaa\xaa\xaa\xaa\xaa\xaa",
"\xbb\xbb\xbb\xbb\xbb\xbb",
"\xcc\xcc\xcc\xcc\xcc\xcc",
"\xdd\xdd\xdd\xdd\xdd\xdd",
"\xee\xee\xee\xee\xee\xee",
"\xff\xff\xff\xff\xff\xff",
};
// test all permutations of a given size
size_t perm_count = TEST_FACTORIAL(N);
for (size_t i = 0;
i < ((PERMUTATION == -1) ? perm_count : 1);
i++) {
uint32_t perm[N];
size_t perm_i = (PERMUTATION == -1) ? i : (size_t)PERMUTATION;
TEST_PERMUTATION(perm_i, perm, N);
// print permutation to help debugging
printf("--- permutation: %zd [", perm_i);
for (unsigned j = 0; j < N; j++) {
if (j > 0) {
printf(", ");
}
printf("%d", perm[j]);
}
printf("] ---\n");
// create given permutation with multiple commits
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
for (unsigned j = 0; j < N; j++) {
// adjust rid based on future insertions
uint16_t rid = perm[j];
for (unsigned k = j+1; k < N; k++) {
if (perm[j] > perm[k]) {
rid -= 1;
}
}
// give each rattr a subtype based on its rid + SHIFT
lfsr_rbyd_commit(&lfs, &rbyd, rid, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
names[perm[j] % 6], 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR((perm[j] + SHIFT) & 0x7f), 0,
names[perm[j] % 6], 2))) => 0;
}
assert(rbyd.weight == N);
// copy block so we can reset after each remove
lfsr_rbyd_t backup_rbyd = rbyd;
uint8_t *backup_block = malloc(lfsr_rbyd_eoff(&rbyd));
CFG->read(CFG, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd)) => 0;
// try replacing each tag
for (unsigned j = 0; j < N; j++) {
// print what we are replacing to help debugging
printf("--- replace: %d ---\n", j);
rbyd = backup_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_bd_prog(&lfs, rbyd.blocks[0], 0,
backup_block, lfsr_rbyd_eoff(&rbyd),
NULL, false) => 0;
lfsr_bd_flush(&lfs,
NULL, false) => 0;
// replace with bitwise inverse
lfsr_rbyd_commit(&lfs, &rbyd, j, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_MASK12 | LFSR_TAG_ATTR(~(j + SHIFT) & 0x7f),
0,
names[j % 6], 3))) => 0;
// try traversing over the tags
lfsr_rbyd_fetch(&lfs, &rbyd, rbyd.blocks[0], CFG->block_size) => 0;
lfsr_tag_t tag_ = 0;
lfs_ssize_t rid_ = -1;
lfs_size_t weight_;
lfsr_data_t data_;
for (unsigned k = 0; k < N; k++) {
if (k == j) {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == k);
assert(tag_ == LFSR_TAG_ATTR(~(k + SHIFT) & 0x7f));
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 3);
} else {
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == k);
assert(tag_ == LFSR_TAG_DATA);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == k);
assert(tag_ == LFSR_TAG_ATTR((k + SHIFT) & 0x7f));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 2);
}
}
lfsr_rbyd_lookupnext(&lfs, &rbyd, rid_, tag_+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
// also test that we can lookup each tag with a wide lookup
for (unsigned k = 0; k < N; k++) {
lfsr_rbyd_lookup(&lfs, &rbyd, k, LFSR_TAG_MASK8 | LFSR_TAG_ATTR,
&tag_, &data_) => 0;
if (k == j) {
assert(tag_ == LFSR_TAG_ATTR(~(k + SHIFT) & 0x7f));
assert(lfsr_data_size(data_) == 3);
} else {
assert(tag_ == LFSR_TAG_ATTR((k + SHIFT) & 0x7f));
assert(lfsr_data_size(data_) == 2);
}
}
}
// cleanup
free(backup_block);
}
'''
# Some very specific cases we want to cover
# One downside of having only altgt tags (not altge) is that we can end
# up with an awkward null tag in our rbyd. Need to test we handle this
# correctly.
[cases.test_rbyd_unreachable_hole]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
// create a null tag hole
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(0), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(0), 0))) => 0;
assert(rbyd.weight == 0);
// can we still access things?
lfs_ssize_t rid_;
lfsr_tag_t tag_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == -1);
assert(tag_ == LFSR_TAG_ATTR(1));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 4);
uint8_t rbuf[32];
lfsr_data_read(&lfs, &data_, rbuf, 32) => 4;
assert(memcmp(rbuf, "\xbb\xbb\xbb\xbb", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(1)+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_unreachable_hole_rm]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
// create a null tag hole
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(0), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(2), 0,
"\xcc\xcc\xcc\xcc", 4),
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(0), 0))) => 0;
assert(rbyd.weight == 0);
// remove a neighbor to the hole
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(1), 0))) => 0;
assert(rbyd.weight == 0);
// can we still access things?
lfs_ssize_t rid_;
lfsr_tag_t tag_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == -1);
assert(tag_ == LFSR_TAG_ATTR(2));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 4);
uint8_t rbuf[32];
lfsr_data_read(&lfs, &data_, rbuf, 32) => 4;
assert(memcmp(rbuf, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2)+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_unreachable_hole_delete]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
// create a null tag hole
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(0), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xcc\xcc\xcc\xcc", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(0), 0))) => 0;
assert(rbyd.weight == 2);
// delete a neighbor to the hole
lfsr_rbyd_commit(&lfs, &rbyd, 0, LFSR_RATTRS(
LFSR_RATTR(LFSR_TAG_RM, -1))) => 0;
assert(rbyd.weight == 1);
// can we still access things?
lfs_ssize_t rid_;
lfsr_tag_t tag_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == 0);
assert(tag_ == LFSR_TAG_DATA);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
uint8_t rbuf[32];
lfsr_data_read(&lfs, &data_, rbuf, 32) => 4;
assert(memcmp(rbuf, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_unreachable_hole_subwide]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
// create a null tag hole
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(0x00), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(0x01), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(0x80), 0,
"\xdd\xdd\xdd\xdd", 4),
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(0), 0))) => 0;
assert(rbyd.weight == 0);
// subwide replace a neighbor to the hole
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_MASK8 | LFSR_TAG_ATTR(0x02), 0,
"\xcc\xcc\xcc\xcc", 4))) => 0;
assert(rbyd.weight == 0);
// can we still access things?
lfs_ssize_t rid_;
lfsr_tag_t tag_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == -1);
assert(tag_ == LFSR_TAG_ATTR(0x02));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 4);
uint8_t rbuf[32];
lfsr_data_read(&lfs, &data_, rbuf, 32) => 4;
assert(memcmp(rbuf, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2)+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == -1);
assert(tag_ == LFSR_TAG_ATTR(0x80));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 4);
lfsr_data_read(&lfs, &data_, rbuf, 32) => 4;
assert(memcmp(rbuf, "\xdd\xdd\xdd\xdd", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(0x80)+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
'''
[cases.test_rbyd_unreachable_hole_supwide]
in = 'lfs.c'
code = '''
lfs_t lfs;
lfs_init(&lfs, LFS_M_RDWR, CFG) => 0;
lfsr_rbyd_t init_rbyd = {
.blocks[0] = 0,
.eoff = 0,
.cksum = 0,
.trunk = 0,
.weight = 0,
};
lfsr_rbyd_t rbyd;
// create a null tag hole
rbyd = init_rbyd;
lfsr_bd_erase(&lfs, rbyd.blocks[0]) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(0), 0,
"\xaa\xaa\xaa\xaa", 4),
LFSR_RATTR_BUF(
LFSR_TAG_ATTR(1), 0,
"\xbb\xbb\xbb\xbb", 4),
LFSR_RATTR_BUF(
LFSR_TAG_DATA, +1,
"\xdd\xdd\xdd\xdd", 4))) => 0;
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR(
LFSR_TAG_RM | LFSR_TAG_ATTR(0), 0))) => 0;
assert(rbyd.weight == 1);
// supwide replace a neighbor to the hole
lfsr_rbyd_commit(&lfs, &rbyd, -1, LFSR_RATTRS(
LFSR_RATTR_BUF(
LFSR_TAG_MASK12 | LFSR_TAG_ATTR(2), 0,
"\xcc\xcc\xcc\xcc", 4))) => 0;
assert(rbyd.weight == 1);
// can we still access things?
lfs_ssize_t rid_;
lfsr_tag_t tag_;
lfs_size_t weight_;
lfsr_data_t data_;
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, 0,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == -1);
assert(tag_ == LFSR_TAG_ATTR(2));
assert(weight_ == 0);
assert(lfsr_data_size(data_) == 4);
uint8_t rbuf[32];
lfsr_data_read(&lfs, &data_, rbuf, 32) => 4;
assert(memcmp(rbuf, "\xcc\xcc\xcc\xcc", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, -1, LFSR_TAG_ATTR(2)+1,
&rid_, &tag_, &weight_, &data_) => 0;
assert(rid_ == 0);
assert(tag_ == LFSR_TAG_DATA);
assert(weight_ == 1);
assert(lfsr_data_size(data_) == 4);
lfsr_data_read(&lfs, &data_, rbuf, 32) => 4;
assert(memcmp(rbuf, "\xdd\xdd\xdd\xdd", 4) == 0);
lfsr_rbyd_lookupnext(&lfs, &rbyd, 0, LFSR_TAG_DATA+1,
&rid_, &tag_, &weight_, &data_) => LFS_ERR_NOENT;
'''