17e125a90a
Second slice: the resolved-tap carrier. FlatTap { name, node, field } is the
output-side twin of SourceSpec — its name survives compile, load-bearing for
by-name binding (#275). FlatGraph gains a taps field, threaded (empty) through
every construction site the compiler enumerates. Bootstrap ignores it (taps
materialize as real recorder nodes/edges before bootstrap in a later slice).
Purely additive: the inert-producer pin and full suite stay green.
refs #282
71 lines
3.7 KiB
Rust
71 lines
3.7 KiB
Rust
//! End-to-end coverage for the `FlatTap` / `FlatGraph.taps` plumbing (#282,
|
|
//! "thread all literal sites"): a `Composite` can declare a `Tap` (via
|
|
//! `with_taps`), but this slice adds only the flat-graph *carrier* — no
|
|
//! resolution step exists yet. These tests pin the two halves of that
|
|
//! contract at the public `aura_engine` boundary: `compile()` never surfaces
|
|
//! a declared `Tap` into the flat graph it hands to `Harness::bootstrap`
|
|
//! (`compile_never_resolves_declared_taps_yet`), and the field's presence is
|
|
//! otherwise perfectly transparent to compilation of the rest of the graph
|
|
//! (`tapped_composite_compiles_identically_to_untapped_besides_the_taps_list`)
|
|
//! — a future resolving slice (`bind_tap`) is expected to flip the first of
|
|
//! these; until it does, a regression that started eagerly resolving taps,
|
|
//! or one that let a `Tap` perturb node/edge flattening, would be caught
|
|
//! here.
|
|
|
|
use aura_core::ScalarKind;
|
|
use aura_engine::{Composite, OutField, Role, Tap, TapWire, Target};
|
|
use aura_std::Sub;
|
|
|
|
/// A trivial one-node composite with a single declared output (`Sub`'s
|
|
/// difference), matching the `taps` argument requested by each test. Both of
|
|
/// `Sub`'s input slots are fed by one root-bound (source) role — enough to
|
|
/// satisfy `compile()`'s port-connectivity + root-binding checks.
|
|
fn leaf(taps: Vec<Tap>) -> Composite {
|
|
Composite::new(
|
|
"leaf",
|
|
vec![Sub::builder().into()],
|
|
vec![],
|
|
vec![Role {
|
|
name: "price".into(),
|
|
targets: vec![Target { node: 0, slot: 0 }, Target { node: 0, slot: 1 }],
|
|
source: Some(ScalarKind::F64),
|
|
}],
|
|
vec![OutField { node: 0, field: 0, name: "o".into() }],
|
|
)
|
|
.with_taps(taps)
|
|
}
|
|
|
|
/// Property: **`compile()` resolves no `Tap`s in this slice.** A composite
|
|
/// declaring a valid `Tap` (naming a real interior producer, `node: 0, field:
|
|
/// 0`) still compiles to a `FlatGraph` whose `taps` list is empty — the
|
|
/// declaration is carried on the `Composite` only; nothing yet lowers it into
|
|
/// the flat `FlatTap` the run loop could someday read. If a later change
|
|
/// started eagerly resolving `Tap`s into `FlatGraph.taps` inside `compile()`
|
|
/// without an explicit opt-in (`bind_tap`), this test would flip green->red,
|
|
/// flagging the design-changing move for the ledger instead of it happening
|
|
/// silently.
|
|
#[test]
|
|
fn compile_never_resolves_declared_taps_yet() {
|
|
let tapped = leaf(vec![Tap { name: "spread".into(), from: TapWire { node: 0, field: 0 } }]);
|
|
let flat = tapped.compile().expect("a tap-bearing composite still compiles");
|
|
assert!(flat.taps.is_empty(), "compile() must not resolve declared Taps in this slice: {:?}", flat.taps);
|
|
}
|
|
|
|
/// Property: **a declared `Tap` is otherwise inert at compile time** — it
|
|
/// changes nothing about the flattened node/edge structure. Compiling the
|
|
/// same composite with and without a `Tap` declaration must produce
|
|
/// structurally identical flat graphs (same node count, same edges); the
|
|
/// only difference tap-bearing scaffolding is *allowed* to make is the (here,
|
|
/// still-empty) `taps` list itself.
|
|
#[test]
|
|
fn tapped_composite_compiles_identically_to_untapped_besides_the_taps_list() {
|
|
let untapped = leaf(vec![]).compile().expect("untapped compiles");
|
|
let tapped = leaf(vec![Tap { name: "spread".into(), from: TapWire { node: 0, field: 0 } }])
|
|
.compile()
|
|
.expect("tapped compiles");
|
|
|
|
assert_eq!(untapped.nodes.len(), tapped.nodes.len(), "tap declaration must not add/remove flat nodes");
|
|
assert_eq!(untapped.edges, tapped.edges, "tap declaration must not perturb flat edges");
|
|
assert_eq!(untapped.taps, tapped.taps, "both compile to the same (empty) taps list in this slice");
|
|
}
|