Files
k-os/crates/domain/src/capability/tree_tests.rs

121 lines
3.5 KiB
Rust

use super::derivation::descendants;
use super::tree::CapTree;
const N: usize = 12;
/// The tree as a plain parent array, updated by the rules the tree must
/// follow; `descendants` from derivation.rs answers subtree questions.
struct Model {
live: [bool; N],
parents: [Option<u16>; N],
}
impl Model {
fn detach(&mut self, i: usize) {
let grandparent = self.parents[i];
for p in self.parents.iter_mut() {
if *p == Some(i as u16) {
*p = grandparent;
}
}
self.live[i] = false;
self.parents[i] = None;
}
fn below(&self, root: usize) -> [bool; N] {
let mut d = descendants(&self.parents, root);
d[root] = false;
d
}
}
struct Rng(u64);
impl Rng {
fn below(&mut self, n: usize) -> usize {
self.0 ^= self.0 << 13;
self.0 ^= self.0 >> 7;
self.0 ^= self.0 << 17;
(self.0 % n as u64) as usize
}
}
fn check(t: &CapTree<N>, m: &Model) {
for i in 0..N {
assert_eq!(t.is_live(i), m.live[i], "liveness of {i}");
assert_eq!(t.parent(i), m.parents[i].map(usize::from), "parent of {i}");
if !m.live[i] {
continue;
}
let mut out = [0u16; N];
let n = t.descendants(i, &mut out);
let mut got = [false; N];
for d in &out[..n] {
assert!(!got[*d as usize], "{d} listed twice under {i}");
got[*d as usize] = true;
}
assert_eq!(got, m.below(i), "subtree of {i}");
}
}
#[test]
fn matches_the_parent_array_model_under_random_operations() {
for seed in 1..200u64 {
let mut rng = Rng(seed.wrapping_mul(0x9E37_79B9_7F4A_7C15));
let mut t = CapTree::<N>::new();
let mut m = Model {
live: [false; N],
parents: [None; N],
};
for _ in 0..300 {
let i = rng.below(N);
match rng.below(4) {
0 | 1 => {
let parent = match rng.below(3) {
0 => None,
_ => Some(rng.below(N)),
};
let ok = !m.live[i] && parent.is_none_or(|p| p != i && m.live[p]);
assert_eq!(t.attach(i, parent), ok, "attach {i} under {parent:?}");
if ok {
m.live[i] = true;
m.parents[i] = parent.map(|p| p as u16);
}
}
2 => {
t.detach(i);
if m.live[i] {
m.detach(i);
}
}
_ => {
t.remove_descendants(i);
if m.live[i] {
let below = m.below(i);
for (j, b) in below.iter().enumerate() {
if *b {
m.live[j] = false;
m.parents[j] = None;
}
}
}
}
}
check(&t, &m);
}
}
}
#[test]
fn detaching_a_middle_node_hands_its_children_up() {
let mut t = CapTree::<4>::new();
assert!(t.attach(0, None));
assert!(t.attach(1, Some(0)));
assert!(t.attach(2, Some(1)));
assert!(t.attach(3, Some(1)));
t.detach(1);
assert_eq!(t.parent(2), Some(0));
assert_eq!(t.parent(3), Some(0));
let mut out = [0u16; 4];
assert_eq!(t.descendants(0, &mut out), 2);
}