diff --git a/crates/thing-contract/tests/goldens.rs b/crates/thing-contract/tests/goldens.rs index cf6928c..41b8a7f 100644 --- a/crates/thing-contract/tests/goldens.rs +++ b/crates/thing-contract/tests/goldens.rs @@ -565,12 +565,12 @@ fn refusal_cases() { let payloads: std::collections::BTreeMap<_, _> = refusal_payloads().into_iter().collect(); let committed = |name: &str| golden_bytes(&format!("{name}.bin"), &payloads[name]); - let cases: [(&str, &str, &str, &str); 3] = [ - ("result-thing1-flat", "gamecult.thing.command_result", "thing:result:inv-1.1", "CommandResult"), - ("node-unknown-arm", "gamecult.thing.surface", "thing:surface:provider.a.main", "Node"), - ("outcome-unknown-arm", "gamecult.thing.command_result", "thing:result:inv-1.1", "Outcome"), + let cases: [(&str, &str, &str); 3] = [ + ("result-thing1-flat", "gamecult.thing.command_result", "thing:result:inv-1.1"), + ("node-unknown-arm", "gamecult.thing.surface", "thing:surface:provider.a.main"), + ("outcome-unknown-arm", "gamecult.thing.command_result", "thing:result:inv-1.1"), ]; - for (name, kind, key, union) in cases { + for (name, kind, key) in cases { let mut cache = CultCache::new(); ThingContract.register_entries(&mut cache).unwrap(); let bytes = committed(name); @@ -582,25 +582,45 @@ fn refusal_cases() { let message = format!("{error:#}"); assert!(message.contains(kind), "{name}: the error names the kind: {message}"); assert!(message.contains(key), "{name}: the error names the record key: {message}"); - assert!(message.contains(union) || name == "result-thing1-flat", "{name}: {message}"); assert!(!message.contains(CANARY), "{name}: the error echoed a value: {message}"); } - // The unknown arm key is named; the payload never is. + // Decoded directly, the refusal names the union and the arm key, and never the payload. + for (name, union, key) in [("node-unknown-arm", "Node", "13"), ("outcome-unknown-arm", "Outcome", "4")] { + let bytes = committed(name); + let message = if union == "Node" { + rmp_serde::from_slice::(&bytes).unwrap_err().to_string() + } else { + rmp_serde::from_slice::(&bytes).unwrap_err().to_string() + }; + assert!(message.contains(union) && message.contains(key), "{name}: {message}"); + assert!(!message.contains(CANARY), "{name}: {message}"); + } + + // An extra trailing slot is read (CultLib's extra-trailing-slots ruling); a missing slot is not. + let mut answered = invocation(); + answered.invocation_id = "inv-1".into(); + let extra: CommandResult = rmp_serde::from_slice(&committed("result-extra-slot")).unwrap(); + assert_eq!(extra, CommandResult::pending(&answered, 1, "working")); + let missing = rmp_serde::from_slice::(&committed("result-missing-slot")).unwrap_err(); + println!("missing slot: {missing}"); let mut cache = CultCache::new(); ThingContract.register_entries(&mut cache).unwrap(); - let node = cache - .put_envelope::(envelope::("k", committed("node-unknown-arm"))) + let missing = cache + .put_envelope::(envelope::("thing:result:inv-1.1", committed("result-missing-slot"))) .unwrap_err(); - assert!(format!("{node:#}").contains("13"), "{node:#}"); - let outcome = cache - .put_envelope::(envelope::("k", committed("outcome-unknown-arm"))) - .unwrap_err(); - assert!(format!("{outcome:#}").contains('4'), "{outcome:#}"); + let message = format!("{missing:#}"); + assert!(message.contains("gamecult.thing.command_result") && message.contains("thing:result:inv-1.1"), "{message}"); } #[test] fn deep_tree() { + // Decoding a Node costs tens of KiB of debug stack per nesting level, so the chain runs on a + // thread that has the room; the 2 MiB default does not. + std::thread::Builder::new().stack_size(16 * 1024 * 1024).spawn(deep_tree_body).unwrap().join().unwrap(); +} + +fn deep_tree_body() { // A 64-deep Box chain. let mut chain = text("leaf", "bottom"); for depth in (0..64).rev() { diff --git a/crates/thing-contract/tests/goldens/asset-catalog.bin b/crates/thing-contract/tests/goldens/asset-catalog.bin new file mode 100644 index 0000000..9794336 Binary files /dev/null and b/crates/thing-contract/tests/goldens/asset-catalog.bin differ diff --git a/crates/thing-contract/tests/goldens/composition-all-params.bin b/crates/thing-contract/tests/goldens/composition-all-params.bin new file mode 100644 index 0000000..a93e57a Binary files /dev/null and b/crates/thing-contract/tests/goldens/composition-all-params.bin differ diff --git a/crates/thing-contract/tests/goldens/invocation-all-inputs.bin b/crates/thing-contract/tests/goldens/invocation-all-inputs.bin new file mode 100644 index 0000000..52c0590 Binary files /dev/null and b/crates/thing-contract/tests/goldens/invocation-all-inputs.bin differ diff --git a/crates/thing-contract/tests/goldens/node-unknown-arm.bin b/crates/thing-contract/tests/goldens/node-unknown-arm.bin new file mode 100644 index 0000000..a36baf9 --- /dev/null +++ b/crates/thing-contract/tests/goldens/node-unknown-arm.bin @@ -0,0 +1 @@ +–ªprovider.a¤main¯CANARY-7f3a91c2’ ‘¯CANARY-7f3a91c2� \ No newline at end of file diff --git a/crates/thing-contract/tests/goldens/outcome-unknown-arm.bin b/crates/thing-contract/tests/goldens/outcome-unknown-arm.bin new file mode 100644 index 0000000..aa5b9f6 --- /dev/null +++ b/crates/thing-contract/tests/goldens/outcome-unknown-arm.bin @@ -0,0 +1 @@ +“¥inv-1’‘¯CANARY-7f3a91c2 \ No newline at end of file diff --git a/crates/thing-contract/tests/goldens/result-completed-open-external.bin b/crates/thing-contract/tests/goldens/result-completed-open-external.bin new file mode 100644 index 0000000..04a1e7a Binary files /dev/null and b/crates/thing-contract/tests/goldens/result-completed-open-external.bin differ diff --git a/crates/thing-contract/tests/goldens/result-completed-open-surface.bin b/crates/thing-contract/tests/goldens/result-completed-open-surface.bin new file mode 100644 index 0000000..ff1963e Binary files /dev/null and b/crates/thing-contract/tests/goldens/result-completed-open-surface.bin differ diff --git a/crates/thing-contract/tests/goldens/result-completed.bin b/crates/thing-contract/tests/goldens/result-completed.bin new file mode 100644 index 0000000..1f92a8f --- /dev/null +++ b/crates/thing-contract/tests/goldens/result-completed.bin @@ -0,0 +1 @@ +“Ù$3f2b8c1e-5d44-4a6b-9a07-1c2d3e4f5a6b’“ÃÀ \ No newline at end of file diff --git a/crates/thing-contract/tests/goldens/result-denied-no-node.bin b/crates/thing-contract/tests/goldens/result-denied-no-node.bin new file mode 100644 index 0000000..64425b4 --- /dev/null +++ b/crates/thing-contract/tests/goldens/result-denied-no-node.bin @@ -0,0 +1 @@ +“Ù$3f2b8c1e-5d44-4a6b-9a07-1c2d3e4f5a6b’’«not allowedÀ \ No newline at end of file diff --git a/crates/thing-contract/tests/goldens/result-denied.bin b/crates/thing-contract/tests/goldens/result-denied.bin new file mode 100644 index 0000000..8d03fc3 --- /dev/null +++ b/crates/thing-contract/tests/goldens/result-denied.bin @@ -0,0 +1 @@ +“Ù$3f2b8c1e-5d44-4a6b-9a07-1c2d3e4f5a6b’’©not yours¢go \ No newline at end of file diff --git a/crates/thing-contract/tests/goldens/result-extra-slot.bin b/crates/thing-contract/tests/goldens/result-extra-slot.bin new file mode 100644 index 0000000..29a7ef8 Binary files /dev/null and b/crates/thing-contract/tests/goldens/result-extra-slot.bin differ diff --git a/crates/thing-contract/tests/goldens/result-failed.bin b/crates/thing-contract/tests/goldens/result-failed.bin new file mode 100644 index 0000000..387cae8 --- /dev/null +++ b/crates/thing-contract/tests/goldens/result-failed.bin @@ -0,0 +1 @@ +“Ù$3f2b8c1e-5d44-4a6b-9a07-1c2d3e4f5a6b’‘¥broke \ No newline at end of file diff --git a/crates/thing-contract/tests/goldens/result-missing-slot.bin b/crates/thing-contract/tests/goldens/result-missing-slot.bin new file mode 100644 index 0000000..60a1739 --- /dev/null +++ b/crates/thing-contract/tests/goldens/result-missing-slot.bin @@ -0,0 +1 @@ +’¥inv-1 \ No newline at end of file diff --git a/crates/thing-contract/tests/goldens/result-pending.bin b/crates/thing-contract/tests/goldens/result-pending.bin new file mode 100644 index 0000000..21a9198 Binary files /dev/null and b/crates/thing-contract/tests/goldens/result-pending.bin differ diff --git a/crates/thing-contract/tests/goldens/result-thing1-flat.bin b/crates/thing-contract/tests/goldens/result-thing1-flat.bin new file mode 100644 index 0000000..18bf70e --- /dev/null +++ b/crates/thing-contract/tests/goldens/result-thing1-flat.bin @@ -0,0 +1 @@ +�§receipt†©commandId¥inv-1§command¢go¥state©completed§message¯CANARY-7f3a91c2­sourceVersion«issuedAtUtc´2026-01-01T00:00:00Z \ No newline at end of file diff --git a/crates/thing-contract/tests/goldens/surface-all-arms.bin b/crates/thing-contract/tests/goldens/surface-all-arms.bin new file mode 100644 index 0000000..8c3b084 Binary files /dev/null and b/crates/thing-contract/tests/goldens/surface-all-arms.bin differ diff --git a/crates/thing-contract/tests/goldens/surface.cc b/crates/thing-contract/tests/goldens/surface.cc new file mode 100644 index 0000000..6eaa439 Binary files /dev/null and b/crates/thing-contract/tests/goldens/surface.cc differ