use std::sync::Arc;
use crate::dsl::compile::compile_gk;
use crate::node::PortType;
use super::builder::SubcontextBuilder;
use super::error::{ContractViolation, SourceContext};
use super::kernel::{wrap_root_kernel, RootMarker, ScopeKernel};
use super::module::{BodyFragment, ScopeModule};
use super::name::ChildName;
use super::pull::{NamedPullConsumer, PullConsumer};
use super::spec::{ExportSpec, ImportSpec};
use crate::node::Value;
fn parent_kernel() -> Arc<ScopeKernel<RootMarker>> {
let kernel = compile_gk(
"input cycle: u64\n\
const dataset := \"sift1m\"\n\
seed := hash(cycle)\n",
)
.expect("parent kernel compile");
wrap_root_kernel(kernel, "test-root")
}
#[test]
fn subcontext_builder_yields_typed_builder() {
let parent = parent_kernel();
let _b: SubcontextBuilder<RootMarker> = parent.subcontext_builder();
}
#[test]
fn finalize_compiles_simple_gk_source_block() {
let parent = parent_kernel();
let mut b = parent.subcontext_builder();
b.context(SourceContext::new("simple-gk-source"));
b.body(BodyFragment::GkSource(
"input cycle: u64\nx := 5\n".to_string(),
));
let module = b.finalize().expect("finalize should succeed");
assert!(module.program().output_names().iter().any(|n| *n == "x"));
assert_eq!(module.context().label, "simple-gk-source");
}
#[test]
fn finalize_rejects_unbound_import() {
let parent = parent_kernel();
let mut b = parent.subcontext_builder();
b.context(SourceContext::new("unbound-import"));
b.body(BodyFragment::GkSource(
"input cycle: u64\nout := mul(cycle, foo)\n".to_string(),
));
let err = b.finalize().expect_err("should fail to compile");
match err {
ContractViolation::Compile(msg) => {
assert!(!msg.is_empty(), "compile error message should not be empty");
}
other => panic!("expected Compile, got {other:?}"),
}
}
#[test]
fn finalize_rejects_import_with_no_matching_parent_name() {
let parent = parent_kernel();
let mut b = parent.subcontext_builder();
b.context(SourceContext::new("rule1-direct"));
b.import(ImportSpec::extern_("nonexistent", PortType::U64));
b.body(BodyFragment::GkSource("input cycle: u64\nx := 5\n".to_string()));
let err = b.finalize().expect_err("should reject");
match err {
ContractViolation::UnboundImport { import, .. } => {
assert_eq!(import, "nonexistent");
}
other => panic!("expected UnboundImport, got {other:?}"),
}
}
#[test]
fn spawn_records_named_child() {
let parent = parent_kernel();
let mut b = parent.clone().subcontext_builder();
b.context(SourceContext::for_phase("p1"));
b.body(BodyFragment::GkSource(
"input cycle: u64\ny := mul(cycle, 2)\n".to_string(),
));
let module: ScopeModule<_> = b.finalize().expect("finalize");
let name = ChildName::phase("p1");
let _child = parent
.spawn(name.clone(), module)
.expect("spawn should succeed");
assert!(parent.has_child(&name), "parent registry should record `p1`");
}
#[test]
fn duplicate_spawn_errors() {
let parent = parent_kernel();
let module1 = {
let mut b = parent.clone().subcontext_builder();
b.context(SourceContext::for_phase("dup"));
b.body(BodyFragment::GkSource("input cycle: u64\na := 1\n".to_string()));
b.finalize().expect("first finalize")
};
let module2 = {
let mut b = parent.clone().subcontext_builder();
b.context(SourceContext::for_phase("dup-again"));
b.body(BodyFragment::GkSource("input cycle: u64\nb := 2\n".to_string()));
b.finalize().expect("second finalize")
};
let name = ChildName::phase("dup");
parent.spawn(name.clone(), module1).expect("first spawn");
let err = parent
.spawn(name.clone(), module2)
.expect_err("second spawn should fail");
match err {
ContractViolation::DuplicateChild {
name: collided,
prior_site,
this_site,
} => {
assert_eq!(collided, name);
assert_eq!(prior_site.label, "phase:dup");
assert_eq!(this_site.label, "phase:dup-again");
}
other => panic!("expected DuplicateChild, got {other:?}"),
}
}
#[test]
fn release_child_allows_respawn() {
let parent = parent_kernel();
let module1 = {
let mut b = parent.clone().subcontext_builder();
b.context(SourceContext::for_phase("rel"));
b.body(BodyFragment::GkSource("input cycle: u64\na := 1\n".to_string()));
b.finalize().expect("first finalize")
};
let module2 = {
let mut b = parent.clone().subcontext_builder();
b.context(SourceContext::for_phase("rel-again"));
b.body(BodyFragment::GkSource("input cycle: u64\na := 1\n".to_string()));
b.finalize().expect("second finalize")
};
let name = ChildName::phase("rel");
parent.spawn(name.clone(), module1).expect("first spawn");
parent.release_child(&name);
assert!(!parent.has_child(&name));
parent
.spawn(name.clone(), module2)
.expect("respawn after release should succeed");
assert!(parent.has_child(&name));
}
#[test]
fn register_pull_persists_into_artifact() {
let parent = parent_kernel();
let mut b = parent.clone().subcontext_builder();
b.context(SourceContext::for_phase("with-pulls"));
let consumer: Arc<dyn PullConsumer> = Arc::new(NamedPullConsumer::new(
"validation",
["seed".to_string(), "dataset".to_string()],
));
b.register_pull(consumer);
b.body(BodyFragment::GkSource(
"input cycle: u64\nz := mul(cycle, 3)\n".to_string(),
));
let module = b.finalize().expect("finalize");
assert_eq!(module.consumers().len(), 1);
assert_eq!(module.consumers()[0].label(), "validation");
assert_eq!(
module.consumers()[0].names(),
&["seed".to_string(), "dataset".to_string()]
);
let name = ChildName::phase("with-pulls");
let child = parent.spawn(name, module).expect("spawn");
let consumers = child.consumers();
assert_eq!(consumers.len(), 1);
assert_eq!(
consumers[0].names(),
&["seed".to_string(), "dataset".to_string()]
);
}
#[test]
fn body_fragment_statements_compile_to_program() {
use crate::dsl::lexer;
use crate::dsl::parser;
let parent = parent_kernel();
let src = "input cycle: u64\nq := add(cycle, 7)\n";
let tokens = lexer::lex(src).expect("lex");
let file = parser::parse(tokens).expect("parse");
let mut b = parent.subcontext_builder();
b.context(SourceContext::new("statements-fragment"));
b.body(BodyFragment::Statements(file.statements));
let module = b.finalize().expect("finalize");
assert!(module.program().output_names().iter().any(|n| *n == "q"));
}
fn parent_with_shared_u64(name: &str, init: u64) -> Arc<ScopeKernel<RootMarker>> {
let src = format!(
"input cycle: u64\n\
shared {name} := {init}\n",
);
let kernel = compile_gk(&src).expect("parent kernel compile");
wrap_root_kernel(kernel, "test-root-shared")
}
#[test]
fn parent_shared_export_collision_rewrites_to_cell_write() {
let parent = parent_with_shared_u64("X", 0);
let mut b = parent.clone().subcontext_builder();
b.context(SourceContext::for_phase("rule2-rewrite"));
b.export(ExportSpec::shared("X", crate::node::PortType::U64));
b.body(BodyFragment::GkSource(
"input cycle: u64\nX := 42\n".to_string(),
));
let module = b.finalize().expect("finalize should succeed under Rule 2");
let wts = module.write_throughs();
assert_eq!(wts.len(), 1, "expected one write-through binding");
assert_eq!(wts[0].export_name, "X");
assert_eq!(wts[0].source_output, "__write_X");
assert!(module
.program()
.output_names()
.iter()
.any(|n| *n == "__write_X"));
assert!(module.program().find_input("X").is_some());
let name = ChildName::phase("rule2-rewrite");
let child = parent.spawn(name, module).expect("spawn");
assert_eq!(child.write_throughs().len(), 1);
assert_eq!(parent.lock_inner().lookup("X"), Some(Value::U64(0)));
child.commit_write_throughs();
assert_eq!(parent.lock_inner().lookup("X"), Some(Value::U64(42)));
}
#[test]
fn parent_shared_export_collision_propagates_through_siblings() {
let parent = parent_with_shared_u64("flag", 0);
let writer_module = {
let mut b = parent.clone().subcontext_builder();
b.context(SourceContext::for_phase("writer"));
b.export(ExportSpec::shared("flag", crate::node::PortType::U64));
b.body(BodyFragment::GkSource(
"input cycle: u64\nflag := 7\n".to_string(),
));
b.finalize().expect("writer finalize")
};
let reader_module = {
let mut b = parent.clone().subcontext_builder();
b.context(SourceContext::for_phase("reader"));
b.import(ImportSpec::shared("flag", crate::node::PortType::U64));
b.body(BodyFragment::GkSource(
"input cycle: u64\nextern flag: u64\nseen := flag\n".to_string(),
));
b.finalize().expect("reader finalize")
};
let writer = parent
.spawn(ChildName::phase("writer"), writer_module)
.expect("writer spawn");
let reader = parent
.spawn(ChildName::phase("reader"), reader_module)
.expect("reader spawn");
writer.commit_write_throughs();
let seen = {
let mut inner = reader.lock_inner();
inner.pull("seen").clone()
};
assert_eq!(
seen,
Value::U64(7),
"reader should observe writer's write through the shared cell"
);
}
#[test]
fn workload_regex_does_not_match_actual_describe_keyspace_output() {
use regex::Regex;
let workload_pattern = r"(?im)^\s*(VIRTUAL\s+)?TABLE\s+system_views\.sai_column_indexes\s*\(";
let re = Regex::new(workload_pattern).expect("regex compiles");
let realistic_describe = "\
CREATE KEYSPACE system_views WITH replication = {'class': 'LocalStrategy'};
CREATE TABLE system_views.sai_column_indexes (
keyspace_name text,
table_name text,
index_name text,
column_name text,
PRIMARY KEY ((keyspace_name), table_name, index_name)
);
CREATE VIRTUAL TABLE system_views.indexes (
keyspace_name text,
table_name text,
index_name text,
PRIMARY KEY ((keyspace_name), table_name, index_name)
);
";
assert!(
!re.is_match(realistic_describe),
"the workload regex was expected to MISS this realistic CQL describe \
output (because it lacks the `CREATE\\s+` prefix); if this assertion \
starts failing, the regex was fixed and this test should be inverted"
);
let fixed_pattern = r"(?im)^\s*(?:CREATE\s+)?(?:VIRTUAL\s+)?TABLE\s+system_views\.sai_column_indexes\s*\(";
let fixed = Regex::new(fixed_pattern).expect("fixed regex compiles");
assert!(
fixed.is_match(realistic_describe),
"the corrected regex (allowing optional `CREATE\\s+`) should match"
);
}
#[test]
fn describe_keyspace_body_is_multirow_not_unary() {
use crate::nodes::exactly_one::ExactlyOneValue;
use crate::node::GkNode;
let multi_row_body = Value::Json(std::sync::Arc::new(serde_json::json!([
{"keyspace_name": "system_views", "type": "keyspace", "name": "system_views",
"create_statement": "CREATE KEYSPACE system_views WITH ..."},
{"keyspace_name": "system_views", "type": "table", "name": "sai_column_indexes",
"create_statement": "CREATE TABLE system_views.sai_column_indexes (..."},
{"keyspace_name": "system_views", "type": "table", "name": "indexes",
"create_statement": "CREATE VIRTUAL TABLE system_views.indexes (..."},
])));
let node = ExactlyOneValue::new();
let mut out = [Value::None];
let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
node.eval(&[multi_row_body], &mut out);
}));
assert!(
result.is_err(),
"exactly_one_value must reject a 3-row describe-keyspace body — \
the workload would never see a meaningful schema_text from this shape"
);
}
#[test]
fn workload_emulation_shared_cell_through_op_template_chain() {
let workload_canonical = compile_gk(
"input cycle: u64\nshared has_match := false\n"
).expect("workload-root compile");
let detect_matter = super::GkMatter::builder()
.label("detect_op")
.source("input cycle: u64\n".to_string())
.result_bindings(
"has_match := log_info(regex_match(\
exactly_one_value(body), \"hello\"))\n"
)
.build()
.expect("detect matter");
let detect_canonical = workload_canonical
.build_subscope(detect_matter)
.expect("detect-canonical subscope");
let fiber_main_matter = super::GkMatter::builder()
.program(workload_canonical.program().clone())
.build()
.expect("fiber main matter");
let fiber_main = workload_canonical
.build_subscope(fiber_main_matter)
.expect("fiber main subscope");
let detect_fiber_matter = super::GkMatter::builder()
.program(detect_canonical.program().clone())
.build()
.expect("detect fiber matter");
let mut detect_fiber = fiber_main
.build_subscope(detect_fiber_matter)
.expect("detect-fiber subscope");
let body_idx = detect_fiber.program().find_input("body").expect("body slot");
detect_fiber.state().set_input(
body_idx,
Value::Json(std::sync::Arc::new(serde_json::json!([{"col": "hello world"}]))),
);
detect_fiber.commit_write_throughs();
let root_value = workload_canonical.get_input("has_match");
match root_value {
Some(Value::U64(1)) | Some(Value::Bool(true)) => {} other => panic!(
"workload-root should observe the detect fiber's write through \
the shared cell; got {other:?}",
),
}
let consumer_matter = super::GkMatter::builder()
.label("consumer_op")
.source(
"input cycle: u64\nextern has_match: bool\nseen := has_match\n".to_string()
)
.build()
.expect("consumer matter");
let consumer_canonical = workload_canonical
.build_subscope(consumer_matter)
.expect("consumer-canonical subscope");
let consumer_fiber_matter = super::GkMatter::builder()
.program(consumer_canonical.program().clone())
.build()
.expect("consumer fiber matter");
let mut consumer_fiber = fiber_main
.build_subscope(consumer_fiber_matter)
.expect("consumer-fiber subscope");
let seen = consumer_fiber.pull("seen").clone();
match seen {
Value::U64(1) | Value::Bool(true) => {} other => panic!(
"consumer fiber should see the detect fiber's cell write \
(workload-emulation pattern); got {other:?}",
),
}
}
#[test]
fn shared_bool_literal_init_does_not_leak_false_as_named_input() {
for src in [
"input cycle: u64\n\
shared has_sai_column_indexes := false\n\
shared has_indexes := false\n",
"shared has_sai_column_indexes := false\n\
shared has_indexes := true\n",
] {
let kernel = compile_gk(src).expect("compile");
let inputs = kernel.program().input_names();
assert!(
!inputs.iter().any(|n| n == "false" || n == "true"),
"boolean literal leaked as a named input slot; got inputs {inputs:?}"
);
assert!(inputs.iter().any(|n| n == "has_sai_column_indexes"));
assert!(inputs.iter().any(|n| n == "has_indexes"));
}
}
#[test]
fn log_info_preserves_bool_type_through_result_binding_cell() {
use super::CompileOptions;
let root = compile_gk(
"input cycle: u64\nshared has_match := false\n"
).expect("root compile");
let phase_program = compile_gk(
"input cycle: u64\nlocal := cycle\n"
).expect("phase compile").program().clone();
let phase_kernel = root.materialize_subscope(phase_program, &[]);
let opts = CompileOptions {
workload_dir: None,
gk_lib_paths: Vec::new(),
strict: false,
required_outputs: Vec::new(),
context_label: Some("op-template".to_string()),
cursor_limit: None,
..Default::default()
};
let body = "input cycle: u64\n".to_string();
let result_bindings = "schema_text := exactly_one_value(body)\nhas_match := log_info(regex_match(schema_text, \"hello\"))\n";
let matter = super::GkMatter::builder()
.label("op-template")
.source(body)
.result_bindings(result_bindings)
.options(opts)
.build()
.expect("matter build");
let kernel = phase_kernel.build_subscope(matter).expect("op-template build");
let mut kernel = kernel;
let body_idx = kernel.program().find_input("body").expect("body slot");
kernel.state().set_input(
body_idx,
Value::Json(std::sync::Arc::new(serde_json::json!([{"col": "hello world"}]))),
);
kernel.commit_write_throughs();
match root.lookup("has_match") {
Some(Value::Bool(true)) => {} other => panic!(
"expected Bool(true) in cell after regex_match wrapped in log_info, got {other:?}"
),
}
}
#[test]
fn build_kernel_under_parent_full_sees_live_parents_cells() {
use super::CompileOptions;
let root = compile_gk(
"input cycle: u64\nshared has_sai_column_indexes := false\n"
).expect("root compile");
let phase_program = compile_gk(
"input cycle: u64\nlocal := cycle\n"
).expect("phase compile").program().clone();
let phase_kernel = root.materialize_subscope(phase_program, &[]);
let opts = CompileOptions {
workload_dir: None,
gk_lib_paths: Vec::new(),
strict: false,
required_outputs: Vec::new(),
context_label: Some("op-template".to_string()),
cursor_limit: None,
..Default::default()
};
let body = "input cycle: u64\n".to_string();
let result_bindings = "has_sai_column_indexes := cycle == cycle\n";
let matter = super::GkMatter::builder()
.label("op-template")
.source(body)
.result_bindings(result_bindings)
.options(opts)
.build()
.expect("matter build");
let mut kernel = phase_kernel.build_subscope(matter).expect("op-template build");
kernel.commit_write_throughs();
let observed = root.lookup("has_sai_column_indexes")
.expect("root cell should be set");
assert!(
!matches!(observed, Value::Bool(false)),
"root should observe a write-through (cell still at init): {observed:?}",
);
}
#[test]
fn shared_cell_cascade_survives_for_iteration_through_silent_intermediates() {
use crate::kernel::GkKernel;
use std::sync::Arc;
let root_kernel = compile_gk(
"input cycle: u64\nshared flag := 0\n"
).expect("root compile");
let scenario_canon = compile_gk(
"input cycle: u64\nlocal := cycle\n"
).expect("scenario compile");
let scenario = GkKernel::for_iteration(
&Arc::new(scenario_canon),
&Arc::new(root_kernel),
&[],
);
let foreach_program = compile_gk(
"input cycle: u64\nextern profile: String\n"
).expect("for_each compile").program().clone();
let mut foreach = scenario.materialize_subscope(foreach_program, &[]);
let pidx = foreach.program().find_input("profile").expect("profile slot");
foreach.state().set_input(pidx, Value::Str("p0".into()));
let leaf_program = compile_gk(
"input cycle: u64\n\
extern flag: u64\n\
__write_flag := 7\n"
).expect("leaf compile").program().clone();
let mut leaf = foreach.materialize_subscope(leaf_program, &[]);
leaf.set_write_throughs(vec![crate::kernel::KernelWriteThrough {
export_name: "flag".to_string(),
source_output: "__write_flag".to_string(),
}]);
leaf.commit_write_throughs();
assert_eq!(
leaf.get_input("flag"),
Some(Value::U64(7)),
"leaf's cell-bound input should reflect its own write through the cell",
);
let reader_program = compile_gk(
"input cycle: u64\nextern flag: u64\nseen := flag\n"
).expect("reader compile").program().clone();
let mut reader = foreach.materialize_subscope(reader_program, &[]);
let seen = reader.pull("seen").clone();
assert_eq!(seen, Value::U64(7), "sibling reader should observe write through cell");
}
#[test]
fn shared_cell_cascade_survives_legacy_bind_program_under_parent_chain() {
let root_kernel = compile_gk(
"input cycle: u64\nshared counter := 0\n"
).expect("root compile");
let mid_program = compile_gk("input cycle: u64\nlocal := cycle\n")
.expect("mid compile")
.program()
.clone();
let mid = root_kernel.materialize_subscope(mid_program, &[]);
let leaf_program = compile_gk(
"input cycle: u64\n\
extern counter: u64\n\
__write_counter := 42\n"
).expect("leaf compile").program().clone();
let mut leaf = mid.materialize_subscope(leaf_program, &[]);
leaf.set_write_throughs(vec![crate::kernel::KernelWriteThrough {
export_name: "counter".to_string(),
source_output: "__write_counter".to_string(),
}]);
leaf.commit_write_throughs();
assert_eq!(
root_kernel.lookup("counter"),
Some(Value::U64(42)),
"root should observe leaf's write through the transit-cell cascade",
);
}
#[test]
fn parent_shared_cell_cascades_to_grandchild_through_silent_intermediate() {
let root = parent_with_shared_u64("flag", 0);
let mid_module = {
let mut b = root.clone().subcontext_builder();
b.context(SourceContext::for_phase("mid"));
b.body(BodyFragment::GkSource(
"input cycle: u64\nlocal := cycle\n".to_string(),
));
b.finalize().expect("mid finalize")
};
let mid = Arc::new(
root.spawn(ChildName::phase("mid"), mid_module)
.expect("mid spawn"),
);
let leaf_module = {
let mut b = mid.clone().subcontext_builder();
b.context(SourceContext::for_phase("leaf"));
b.export(ExportSpec::shared("flag", crate::node::PortType::U64));
b.body(BodyFragment::GkSource(
"input cycle: u64\nflag := 9\n".to_string(),
));
b.finalize().expect("leaf finalize — Rule 2 must see root's cell through mid")
};
let leaf = mid
.spawn(ChildName::phase("leaf"), leaf_module)
.expect("leaf spawn");
assert_eq!(
leaf.write_throughs().len(),
1,
"leaf should carry the Rule 2 write-through bound to root's transitive cell"
);
assert_eq!(root.lock_inner().lookup("flag"), Some(Value::U64(0)));
leaf.commit_write_throughs();
assert_eq!(
root.lock_inner().lookup("flag"),
Some(Value::U64(9)),
"root should observe leaf's write through the transitive shared cell"
);
}
#[test]
fn bind_program_under_parent_rebinds_compiled_program() {
let parent_kernel = compile_gk(
"input cycle: u64\n\
const n := 7\n",
)
.expect("parent compile");
let child_kernel = compile_gk(
"input cycle: u64\n\
extern n: u64\n\
passthrough := mul(n, 1)\n",
)
.expect("child compile");
let program = child_kernel.program().clone();
let mut bound = parent_kernel.materialize_subscope(program, &[]);
let v = bound.pull("passthrough").clone();
assert_eq!(v.as_u64(), 7);
}
#[test]
fn build_kernel_under_parent_threads_compile_options() {
let parent_kernel = compile_gk("input cycle: u64\nconst n := 5\n")
.expect("parent compile");
let opts = super::builder::CompileOptions {
workload_dir: None,
gk_lib_paths: Vec::new(),
strict: false,
required_outputs: Vec::new(),
context_label: Some("phase-3-options-test".to_string()),
cursor_limit: None,
..Default::default()
};
let matter = super::GkMatter::builder()
.label("phase-3-options-test")
.source("extern n: u64\ndoubled := mul(n, 2)\n")
.options(opts)
.build()
.expect("matter build");
let mut kernel = parent_kernel
.build_subscope(matter)
.expect("bridge with options");
let v = kernel.pull("doubled").clone();
assert_eq!(v.as_u64(), 10);
}
#[test]
fn parent_final_export_collision_still_errors() {
let kernel = compile_gk(
"input cycle: u64\n\
const fixed := 42\n",
)
.expect("parent kernel compile");
let parent = wrap_root_kernel(kernel, "test-root-final");
let mut b = parent.clone().subcontext_builder();
b.context(SourceContext::for_phase("final-shadow"));
b.export(ExportSpec::local("fixed", crate::node::PortType::U64));
b.body(BodyFragment::GkSource(
"input cycle: u64\nfixed := 99\n".to_string(),
));
let err = b.finalize().expect_err("final-shadow must error");
match err {
ContractViolation::FinalShadow { export, .. } => {
assert_eq!(export, "fixed");
}
other => panic!("expected FinalShadow, got {other:?}"),
}
}
#[test]
fn add_result_bindings_injects_only_referenced_magic_externs() {
let parent = parent_kernel();
let mut b = parent.subcontext_builder();
b.context(SourceContext::new("rb-closure"));
b.body(BodyFragment::GkSource("input cycle: u64\n".to_string()));
b.add_result_bindings("started_with_x := regex_match(body, \"^x\")\n")
.expect("add_result_bindings");
let module = b.finalize().expect("finalize");
assert!(module.program().find_input("body").is_some(),
"body input slot should be present");
assert!(module.program().find_input("count").is_none(),
"count slot should be absent (not referenced)");
assert!(module.program().find_input("ok").is_none(),
"ok slot should be absent (not referenced)");
assert!(module.program().output_names().iter().any(|n| *n == "started_with_x"),
"result LHS should surface as an output");
}
#[test]
fn add_result_bindings_diagnostic_force_allocates_unreferenced_magic_externs() {
let parent = parent_kernel();
let mut b = parent.subcontext_builder();
b.context(SourceContext::new("rb-diagnostic"));
b.with_compile_options(super::CompileOptions {
kernel_opt: crate::kernel::KernelOptLevel::Diagnostic,
..Default::default()
});
b.body(BodyFragment::GkSource("input cycle: u64\n".to_string()));
b.add_result_bindings("started_with_x := regex_match(body, \"^x\")\n")
.expect("add_result_bindings");
let module = b.finalize().expect("finalize");
assert!(module.program().find_input("body").is_some(),
"body slot present (referenced)");
assert!(module.program().find_input("count").is_some(),
"count slot present under Diagnostic (force-allocated)");
assert!(module.program().find_input("ok").is_some(),
"ok slot present under Diagnostic (force-allocated)");
}
#[test]
fn add_result_bindings_rule2_writethrough_to_parent_shared() {
let parent_src = "\
input cycle: u64\n\
shared count_seen := 0\n\
";
let parent_kernel = compile_gk(parent_src).expect("parent compile");
let parent = wrap_root_kernel(parent_kernel, "rb-rule2-root");
let mut b = parent.clone().subcontext_builder();
b.context(SourceContext::new("rb-rule2"));
b.body(BodyFragment::GkSource("input cycle: u64\n".to_string()));
b.add_result_bindings("count_seen := count\n")
.expect("add_result_bindings");
let module = b.finalize().expect("finalize");
let wts = module.write_throughs();
assert_eq!(wts.len(), 1, "expected one write-through binding");
assert_eq!(wts[0].export_name, "count_seen");
assert_eq!(wts[0].source_output, "__write_count_seen");
assert!(module.program().find_input("count_seen").is_some(),
"count_seen input slot should be present (cell-bound)");
assert!(module.program().find_input("count").is_some(),
"count magic-extern slot should be present (referenced)");
}
#[test]
fn add_result_bindings_rejects_reassignment_of_magic_wire() {
let parent = parent_kernel();
let mut b = parent.subcontext_builder();
b.context(SourceContext::new("rb-reassign"));
b.body(BodyFragment::GkSource("input cycle: u64\n".to_string()));
let err = match b.add_result_bindings("body := \"oops\"\n") {
Ok(_) => panic!("reassigning body must error"),
Err(e) => e,
};
match err {
ContractViolation::Compile(msg) => {
assert!(
msg.contains("body") && msg.contains("runtime-injected"),
"diagnostic should name the wire and the cause: {msg}"
);
}
other => panic!("expected Compile, got {other:?}"),
}
}
#[test]
fn add_result_bindings_empty_source_is_noop() {
let parent = parent_kernel();
let mut b = parent.subcontext_builder();
b.context(SourceContext::new("rb-empty"));
b.body(BodyFragment::GkSource("input cycle: u64\n".to_string()));
b.add_result_bindings("").expect("empty source is a no-op");
b.add_result_bindings(" \n \n").expect("whitespace-only source is a no-op");
let module = b.finalize().expect("finalize");
assert!(module.program().find_input("body").is_none());
}