use super::*;
#[test]
fn reused_summary_counts_its_entire_height_at_the_current_stack_depth() {
let mut ar = Arena::try_new_boxed().unwrap();
let object = atom(&mut ar, 0);
let q = quote(&mut ar, 7);
let child = binary(&mut ar, 3, q, q);
let right = binary(&mut ar, 3, child, q);
let formula = binary(&mut ar, 3, child, right);
let mut records = Vec::new();
derive(&mut ar, object, formula, &mut records);
let result = records[2].candidate.result;
for max_frames in [3, 4] {
let mut stream = SemanticStream::new(
key(&ar, object, formula),
Limits {
max_frames,
..limits()
},
)
.unwrap();
enter(&mut stream, &ar, object, formula, &mut 0).unwrap();
enter(&mut stream, &ar, object, child, &mut 0).unwrap();
emit(&mut stream, &ar, &records, 0, &mut 0);
emit(&mut stream, &ar, &records, 1, &mut 0);
let handle = finish(&mut stream, &ar, result, Some(0), &mut 0)
.unwrap()
.unwrap();
enter(&mut stream, &ar, object, right, &mut 0).unwrap();
assert_eq!(stream.active_frames(), 2);
let reused = stream.reuse(handle);
if max_frames == 3 {
assert_eq!(reused, Err(Error::Limit));
assert!(stream.is_poisoned());
} else {
reused.unwrap();
emit(&mut stream, &ar, &records, 6, &mut 0);
finish(&mut stream, &ar, records[7].candidate.result, None, &mut 0).unwrap();
finish(&mut stream, &ar, records[8].candidate.result, None, &mut 0).unwrap();
let done = stream.bind_terminal(claim(&ar, records[8])).unwrap();
assert_eq!(
(done.summary().occurrences(), done.summary().peak_frames()),
(9, 4)
);
}
}
}
#[test]
fn hash_outputs_require_all_limbs_and_exact_pair_of_pairs_topology() {
for tag in [0, 15] {
let mut ar = Arena::try_new_boxed().unwrap();
let object = atom(&mut ar, 123);
let body = if tag == 0 {
atom(&mut ar, 0)
} else {
op(&mut ar, 1, object)
};
let formula = op(&mut ar, tag, body);
let mut records = Vec::new();
derive(&mut ar, object, formula, &mut records);
let c = records.last().unwrap().candidate;
let (left, right) = pair(&ar, c.result);
let (h0, h1) = pair(&ar, left);
let (h2, h3) = pair(&ar, right);
let original = [h0, h1, h2, h3];
let mut wrongs = vec![
ar.pair(left, h2).unwrap(),
ar.pair(h0, right).unwrap(),
ar.pair(right, left).unwrap(),
];
for limb in 0..4 {
let mut changed = original;
let changed_value = ar.atom_value(original[limb]).unwrap().as_u64() ^ 1;
changed[limb] = atom(&mut ar, changed_value);
let left = ar.pair(changed[0], changed[1]).unwrap();
let right = ar.pair(changed[2], changed[3]).unwrap();
wrongs.push(ar.pair(left, right).unwrap());
}
for wrong in wrongs {
let mut stream = SemanticStream::new(key(&ar, object, formula), limits()).unwrap();
enter(&mut stream, &ar, object, formula, &mut 0).unwrap();
for &child in c.premises.as_slice() {
emit(&mut stream, &ar, &records, child, &mut 0);
}
assert_eq!(
finish(&mut stream, &ar, wrong, None, &mut 0),
Err(Error::Output)
);
}
}
}
#[test]
fn pair_arguments_and_wide_words_reject_at_the_primitive_boundary() {
for tag in [4, 5, 6, 7, 8, 10, 11, 12, 13, 14] {
for wide in [false, true] {
if wide && ![11, 12, 13, 14].contains(&tag) {
continue;
}
let mut ar = Arena::try_new_boxed().unwrap();
let object = atom(&mut ar, 0);
let value = if wide {
atom(&mut ar, 1 << 32)
} else {
ar.pair(object, object).unwrap()
};
let bad = op(&mut ar, 1, value);
let good = quote(&mut ar, 1);
let formula = match tag {
4 => branch(&mut ar, bad, good, good),
8 | 13 => op(&mut ar, tag, bad),
_ => binary(&mut ar, tag, good, bad),
};
let mut stream = SemanticStream::new(key(&ar, object, formula), limits()).unwrap();
enter(&mut stream, &ar, object, formula, &mut 0).unwrap();
if ![4, 8, 13].contains(&tag) {
let (_, result) = pair(&ar, good);
enter(&mut stream, &ar, object, good, &mut 0).unwrap();
finish(&mut stream, &ar, result, None, &mut 0).unwrap();
}
enter(&mut stream, &ar, object, bad, &mut 0).unwrap();
assert_eq!(
finish(&mut stream, &ar, value, None, &mut 0),
Err(Error::Type)
);
assert!(stream.is_poisoned());
}
}
}
#[test]
fn malformed_enter_noun_indices_and_noncanonical_root_reject() {
let mut ar = Arena::try_new_boxed().unwrap();
let object = atom(&mut ar, 0);
let one = atom(&mut ar, 1);
let pair_tag = ar.pair(object, one).unwrap();
let address = atom(&mut ar, 2);
for (formula, error) in [
(object, Error::Shape),
(op(&mut ar, 0, address), Error::Shape),
(ar.pair(pair_tag, object).unwrap(), Error::Type),
(op(&mut ar, 3, object), Error::Shape),
] {
let mut stream = SemanticStream::new(key(&ar, object, formula), limits()).unwrap();
assert_eq!(enter(&mut stream, &ar, object, formula, &mut 0), Err(error));
}
let q = quote(&mut ar, 7);
let root = key(&ar, object, q);
for field in 0..2 {
for limb in 0..4 {
let mut changed = root;
if field == 0 {
changed.object[limb] = nebu::field::P;
} else {
changed.formula[limb] = nebu::field::P;
}
assert!(matches!(
SemanticStream::new(changed, limits()),
Err(Error::Key)
));
}
}
let (memory, ids) = snapshot(&ar, &[object, q], 0);
let view = memory.view(memory.len()).unwrap();
let mut stream = SemanticStream::new(root, limits()).unwrap();
assert_eq!(stream.enter(&view, ids[0], memory.len()), Err(Error::Noun));
let mut stream = SemanticStream::new(root, limits()).unwrap();
stream.enter(&view, ids[0], ids[1]).unwrap();
assert_eq!(stream.finish(&view, memory.len(), None), Err(Error::Noun));
}