use agent_frame::{
AdmitError, Check, Life, Op, Packet, PacketAdmitError, PacketBody, RawPacket, RawUnit,
RootEvent, RootKind, Span, Unit,
};
use content_addressable::{ContentId, RawContentId};
const SRC: &[u8] = b"the quick brown fox jumps over the lazy dog";
fn root() -> ContentId {
RootEvent::new(RootKind::OperatorPrompt, b"do the thing", 0)
.id()
.unwrap()
}
fn admissible() -> RawUnit {
Unit::seal(Op::Elide, SRC, Span::new(4, 9), root())
.expect("the baseline must be admissible, or these tests prove nothing")
.to_raw()
}
#[test]
fn the_baseline_is_actually_admitted() {
let u = Unit::try_from(admissible()).expect("baseline admits");
assert_eq!(u.op(), Op::Elide);
assert_eq!(u.depth(), 0);
}
#[test]
fn a_decoded_generate_is_refused() {
let mut raw = admissible();
raw.op = Op::Generate;
raw.depth = 1; let err = Unit::try_from(raw).expect_err("generate must not cross the boundary");
assert_eq!(
err,
AdmitError::NotMintableInV0 {
op: Op::Generate,
check: Check::GroundAttest,
}
);
assert!(
err.to_string().contains("has no implementation"),
"the refusal must say WHY, not just no: {err}"
);
}
#[test]
fn a_decoded_concise_is_refused() {
let mut raw = admissible();
raw.op = Op::Concise;
let err = Unit::try_from(raw).expect_err("concise must not cross the boundary");
assert_eq!(
err,
AdmitError::NotMintableInV0 {
op: Op::Concise,
check: Check::Ground,
}
);
}
#[test]
fn a_decoded_depth_two_is_refused() {
for declared in [1_u32, 2, 7, u32::MAX] {
let mut raw = admissible();
raw.depth = declared;
let err = Unit::try_from(raw)
.unwrap_err_or_panic(&format!("depth {declared} must not cross the boundary"));
assert_eq!(
err,
AdmitError::DepthMismatch {
op: Op::Elide,
declared,
implied: 0,
},
"elision does not raise depth, so any declared depth but 0 is a lie"
);
}
}
#[test]
fn a_decoded_unaddressed_span_is_refused() {
for (start, end) in [(0_u64, 0_u64), (9, 9), (9, 4)] {
let mut raw = admissible();
raw.span = Span::new(start, end);
let err = Unit::try_from(raw).expect_err("a span covering no bytes addresses nothing");
assert_eq!(err, AdmitError::UnaddressedSpan { start, end });
}
}
#[test]
fn lifecycle_is_admitted_as_data() {
for life in [Life::Live, Life::Superseded, Life::Withdrawn] {
let mut raw = admissible();
raw.life = life;
let u = Unit::try_from(raw).expect("lifecycle asserts nothing, so it admits");
assert_eq!(u.life(), life);
}
}
#[test]
fn admission_does_not_pretend_to_verify() {
let mut raw = admissible();
raw.elided = RawContentId::from_content(b"not what that span contains");
let u = Unit::try_from(raw).expect("admission checks the shape, not the world");
assert!(
agent_frame::verify_unit(&u, SRC).is_err(),
"the lie must be caught by verification, which is the half that holds the bytes"
);
}
#[test]
fn neither_admission_nor_verification_resolves_the_root() {
let real = admissible();
let mut forged = real;
forged.root = RootEvent::new(RootKind::HarnessEvent, b"never happened", u64::MAX)
.id()
.unwrap();
assert_ne!(forged.root, real.root, "the forged root must differ");
let u = Unit::try_from(forged)
.expect("admission proves the root is a well-formed id, not that anything answers to it");
assert_eq!(
u.root(),
forged.root,
"the unresolvable id is carried as-is"
);
let v = agent_frame::verify_unit(&u, SRC)
.expect("re-derivation settles source, span and elided — the root is not among them");
assert_eq!(v.source, RawContentId::from_content(SRC));
assert_eq!(v.span, Span::new(4, 9));
}
trait UnwrapErrOrPanic<E> {
fn unwrap_err_or_panic(self, msg: &str) -> E;
}
impl<T: std::fmt::Debug, E> UnwrapErrOrPanic<E> for Result<T, E> {
fn unwrap_err_or_panic(self, msg: &str) -> E {
match self {
Ok(v) => panic!("{msg}: admitted {v:?}"),
Err(e) => e,
}
}
}
fn packet_json(parents: &[String]) -> String {
let links = parents
.iter()
.map(|p| format!("\"{p}\""))
.collect::<Vec<_>>()
.join(",");
format!(r#"{{"payload":{{"units":[]}},"parents":[{links}]}}"#)
}
fn two_addresses() -> (String, String) {
let uid = Unit::try_from(admissible())
.expect("baseline admits")
.id()
.unwrap();
let a = Packet::genesis(vec![uid]).id().unwrap().to_string();
let b = Packet::genesis(vec![]).id().unwrap().to_string();
assert_ne!(
a, b,
"the two parents must differ, or the case is not multiparent"
);
(a, b)
}
#[test]
fn both_legitimate_chain_shapes_are_admitted() {
let (a, _) = two_addresses();
let genesis: RawPacket = serde_json::from_str(&packet_json(&[])).expect("genesis decodes");
let genesis = Packet::try_from(genesis).expect("zero parents is genesis, and admits");
assert!(genesis.is_genesis());
assert_eq!(genesis.prior(), None);
let one: RawPacket = serde_json::from_str(&packet_json(std::slice::from_ref(&a)))
.expect("a one-parent node decodes");
let one = Packet::try_from(one).expect("exactly one parent is a chain link, and admits");
assert!(!one.is_genesis());
assert_eq!(
one.prior().map(|p| p.to_string()),
Some(a),
"the admitted link must be the one the bytes named"
);
}
#[test]
fn a_decoded_two_parent_node_is_refused() {
let (a, b) = two_addresses();
let raw: RawPacket = serde_json::from_str(&packet_json(&[a, b]))
.expect("a two-parent DAG node is well-formed bytes; that is why admission must judge it");
assert_eq!(raw.parents().len(), 2, "the decode must really carry two");
let err = Packet::try_from(raw).expect_err("a DAG node must not become a v0 packet");
assert_eq!(err, PacketAdmitError::NotAChain { parents: 2 });
assert!(
err.to_string().contains("CHAIN"),
"the refusal must say WHY, not just no: {err}"
);
}
#[test]
fn no_admitted_packet_is_both_non_genesis_and_priorless() {
let (a, b) = two_addresses();
for n in 0..=3 {
let parents: Vec<String> = [a.clone(), b.clone()].into_iter().cycle().take(n).collect();
let raw: RawPacket = serde_json::from_str(&packet_json(&parents)).expect("decodes");
let seen = raw.parents().len();
match Packet::try_from(raw) {
Ok(p) => {
assert!(seen <= 1, "{seen} parents must not admit");
assert_eq!(
p.is_genesis(),
p.prior().is_none(),
"genesis and priorless must be the SAME fact"
);
}
Err(e) => assert_eq!(e, PacketAdmitError::NotAChain { parents: seen }),
}
}
}
#[test]
fn a_packets_own_bytes_still_round_trip_through_admission() {
let p = Packet::following(Packet::genesis(vec![]).id().unwrap(), vec![]);
let wire = serde_json::to_vec(&p).expect("a packet serialises");
let raw: RawPacket = serde_json::from_slice(&wire).expect("the wire form is a RawPacket");
assert_eq!(
Packet::try_from(raw).expect("its own bytes admit"),
p,
"what this process writes must be what another process admits"
);
let by_hand = RawPacket::genesis(PacketBody { units: vec![] });
assert!(Packet::try_from(by_hand)
.expect("a hand-built genesis node admits")
.is_genesis());
}