use vyre_conform::templates::{render, TemplateContext, TemplateError};
fn preamble_assertions(output: &str) {
assert!(
output.contains("ONE test"),
"preamble inclusion failed: missing 'ONE test'"
);
assert!(
output.contains("mutation-tested"),
"preamble inclusion failed: missing 'mutation-tested'"
);
}
#[test]
fn preamble_renders_standalone() {
let src = include_str!("../src/generate/templates/preamble.tmpl");
let ctx = TemplateContext::new();
let out = render(src, &ctx).expect("preamble should render without fields");
assert!(out.contains("ONE test"));
assert!(out.contains("unlimited time"));
}
#[test]
fn op_correctness_renders() {
let src = include_str!("../src/generate/templates/op_correctness.tmpl");
let ctx = TemplateContext::new()
.with_scalar("op_name", "add")
.with_scalar("file", "add")
.with_scalar("expected", "5")
.with_scalar("inputs", "[2, 3]")
.with_scalar("spec_path", "src/spec/tables/add.rs")
.with_scalar("line", "42")
.with_scalar("category", "A")
.with_scalar("op", "add")
.with_scalar("input_desc", "2_3");
let out = render(src, &ctx).expect("op_correctness should render");
preamble_assertions(&out);
assert!(out.contains("REQUIRED:"), "missing REQUIRED section");
assert!(out.contains("FORBIDDEN:"), "missing FORBIDDEN section");
assert!(out.contains("add from vyre/src/ops/primitive/add.rs"));
assert!(out.contains("test_add_2_3_spec_table"));
}
#[test]
fn law_renders() {
let src = include_str!("../src/generate/templates/law.tmpl");
let ctx = TemplateContext::new()
.with_scalar("op_name", "add")
.with_scalar("law_name", "Commutativity")
.with_scalar("law_description", "a + b == b + a")
.with_scalar("input_class", "u32")
.with_scalar("law_formula", "a + b == b + a")
.with_scalar("specific_inputs", "[0, 1]")
.with_scalar("op", "add")
.with_scalar("law", "Commutativity");
let out = render(src, &ctx).expect("law should render");
preamble_assertions(&out);
assert!(out.contains("REQUIRED:"), "missing REQUIRED section");
assert!(out.contains("FORBIDDEN:"), "missing FORBIDDEN section");
assert!(out.contains("Commutativity (a + b == b + a)"));
}
#[test]
fn validation_renders() {
let src = include_str!("../src/generate/templates/validation.tmpl");
let ctx = TemplateContext::new()
.with_scalar("V_NNN", "V001")
.with_scalar("description", "empty program body")
.with_scalar("NNN", "001");
let out = render(src, &ctx).expect("validation should render");
preamble_assertions(&out);
assert!(out.contains("REQUIRED:"), "missing REQUIRED section");
assert!(out.contains("FORBIDDEN:"), "missing FORBIDDEN section");
assert!(out.contains("Validation rule V001"));
}
#[test]
fn backend_equiv_renders() {
let src = include_str!("../src/generate/templates/backend_equiv.tmpl");
let ctx = TemplateContext::new()
.with_scalar("op_name", "add")
.with_scalar("op", "add")
.with_scalar("input_class", "u32");
let out = render(src, &ctx).expect("backend_equiv should render");
preamble_assertions(&out);
assert!(out.contains("REQUIRED:"), "missing REQUIRED section");
assert!(out.contains("FORBIDDEN:"), "missing FORBIDDEN section");
assert!(out.contains("I3 (backend equivalence)"));
}
#[test]
fn archetype_renders() {
let src = include_str!("../src/generate/templates/archetype.tmpl");
let ctx = TemplateContext::new()
.with_scalar("op_name", "add")
.with_scalar("archetype_id", "A1")
.with_scalar("archetype_name", "IdentityPair")
.with_scalar("property", "identity element holds")
.with_scalar("oracle_chosen_from_hierarchy", "ReferenceInterpreter")
.with_scalar(
"archetype_description",
"pair of values where one is the identity",
)
.with_scalar("op", "add");
let out = render(src, &ctx).expect("archetype should render");
preamble_assertions(&out);
assert!(out.contains("REQUIRED:"), "missing REQUIRED section");
assert!(out.contains("FORBIDDEN:"), "missing FORBIDDEN section");
assert!(out.contains("A1 (IdentityPair)"));
}
#[test]
fn mutation_kill_renders() {
let src = include_str!("../src/generate/templates/mutation_kill.tmpl");
let ctx = TemplateContext::new()
.with_scalar("op_name", "add")
.with_scalar("mutation_description", "ArithOpSwap Add->Sub")
.with_scalar("oracle_chosen_from_hierarchy", "ReferenceInterpreter")
.with_scalar(
"mutation_details",
"Swap BinOp::Add to BinOp::Sub in primitive add.rs",
)
.with_scalar("op", "add");
let out = render(src, &ctx).expect("mutation_kill should render");
preamble_assertions(&out);
assert!(out.contains("REQUIRED:"), "missing REQUIRED section");
assert!(out.contains("FORBIDDEN:"), "missing FORBIDDEN section");
assert!(out.contains("ArithOpSwap Add->Sub"));
}
#[test]
fn list_directive_expands() {
let src = "Items: {list:items}- {name}\n{/list}";
let item1 = TemplateContext::new().with_scalar("name", "foo");
let item2 = TemplateContext::new().with_scalar("name", "bar");
let ctx = TemplateContext::new().with_list("items", vec![item1, item2]);
let out = render(src, &ctx).expect("list should render");
assert_eq!(out, "Items: - foo\n- bar\n");
}
#[test]
fn missing_list_directive_errors() {
let src = "{list:ops}OP:{name}{/list}";
let ctx = TemplateContext::new();
let err = render(src, &ctx).expect_err("missing list must not render as empty output");
assert!(
matches!(err, TemplateError::UnknownField(ref s) if s == "ops"),
"Fix: missing list field must report UnknownField(\"ops\"), got {err:?}"
);
}
#[test]
fn if_directive_conditional() {
let src = "{if:show}visible{/if}{if:hide}hidden{/if}";
let ctx = TemplateContext::new()
.with_conditional("show", true)
.with_conditional("hide", false);
let out = render(src, &ctx).expect("if should render");
assert_eq!(out, "visible");
}
#[test]
fn nested_list_and_if() {
let src = "{list:outer}{if:ok}[{name}]{/if}\n{/list}";
let item1 = TemplateContext::new()
.with_scalar("name", "a")
.with_conditional("ok", true);
let item2 = TemplateContext::new()
.with_scalar("name", "b")
.with_conditional("ok", false);
let ctx = TemplateContext::new().with_list("outer", vec![item1, item2]);
let out = render(src, &ctx).expect("nested directives should render");
assert_eq!(out, "[a]\n\n");
}
#[test]
fn unknown_field_errors() {
let src = "{missing}";
let ctx = TemplateContext::new();
let err = render(src, &ctx).expect_err("should error on unknown field");
assert!(matches!(err, TemplateError::UnknownField(ref s) if s == "missing"));
}
#[test]
fn malformed_unclosed_brace_errors() {
let src = "{unclosed";
let ctx = TemplateContext::new();
let err = render(src, &ctx).expect_err("should error on unclosed brace");
assert!(matches!(err, TemplateError::MalformedDirective));
}
#[test]
fn unclosed_list_block_errors() {
let src = "{list:items}no close";
let ctx = TemplateContext::new();
let err = render(src, &ctx).expect_err("should error on unclosed list");
assert!(matches!(err, TemplateError::MalformedDirective));
}
#[test]
fn include_not_found_errors() {
let src = "{include:no_such_template}";
let ctx = TemplateContext::new();
let err = render(src, &ctx).expect_err("should error on missing include");
assert!(matches!(err, TemplateError::IncludeNotFound(ref s) if s == "no_such_template"));
}