use std::path::{Path, PathBuf};
use crate::Compiler;
use workshop_rs::catalog::{Catalog, Locale};
use workshop_rs::roundtrip::equivalent;
fn fixture_dir(name: &str) -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../../compatibility/fixtures/synthetic")
.join(name)
}
fn compile_fixture(name: &str) -> crate::CompilationArtifact {
let dir = fixture_dir(name);
let source = std::fs::read_to_string(dir.join("source.opy")).expect("source must be readable");
let hir = crate::compile(&source, "source.opy", &dir).expect("fixture must resolve");
Compiler::new()
.expect("released workshop contract must load")
.compile_hir(&hir)
.expect("fixture must lower to canonical WIR")
}
fn assert_fixture_matches_oracle(name: &str) {
let dir = fixture_dir(name);
let artifact = compile_fixture(name);
let oracle: serde_json::Value = serde_json::from_str(
&std::fs::read_to_string(dir.join("oracle.json")).expect("oracle must be readable"),
)
.expect("oracle must parse");
let workshop = oracle["compile"]["workshop"]
.as_str()
.expect("oracle must contain Workshop output");
let catalog = Catalog::builtin().expect("catalog must load");
let oracle = workshop_rs::parser::parse(workshop, &catalog, &Locale::new("en-US"))
.expect("oracle Workshop output must reparse");
assert!(
equivalent(&artifact.wir, &oracle),
"issue #145 native WIR diverged for {name}\n--- native ---\n{}\n--- oracle ---\n{}",
artifact.emitted,
workshop
);
}
#[test]
fn contextual_chase_lowering_matches_the_pinned_oracle() {
let source = r#"
globalvar value
rule "chase":
@Event global
chase(value, 10, rate=2, ChaseReeval.NONE)
chase(value, 10, duration=3, ChaseReeval.NONE)
"#;
let hir =
crate::compile(source, "issue-145-chase.opy", Path::new(".")).expect("source resolves");
let artifact = Compiler::new()
.expect("released workshop contract must load")
.compile_hir(&hir)
.expect("contextual chase must lower");
assert!(
artifact
.emitted
.contains("Chase Global Variable At Rate(Global.value, 10, 2, None);")
);
assert!(
artifact
.emitted
.contains("Chase Global Variable Over Time(Global.value, 10, 3, None);")
);
}
#[test]
fn string_modifier_lowering_matches_the_pinned_oracle() {
assert_fixture_matches_oracle("issue-28-string-modifiers");
}
#[test]
fn broad_supported_syntax_lowering_reaches_canonical_wir() {
let artifact = compile_fixture("issue-28-syntax");
assert!(artifact.emitted.contains("Loop If(Not(Array Contains"));
assert!(artifact.emitted.contains("Mapped Array"));
assert!(artifact.emitted.contains("Custom String(\"wide\")"));
assert!(artifact.emitted.contains("Set Global Variable(value, 1);"));
}
#[test]
fn literal_dict_lookup_hit_and_miss_match_the_pinned_oracle() {
assert_fixture_matches_oracle("issue-46-unsupported");
}
#[test]
fn nested_indexed_assignments_match_the_pinned_oracle() {
assert_fixture_matches_oracle("issue-60-nested-index");
}
#[test]
fn four_dimensional_indexed_assignment_is_rejected_at_the_pinned_boundary() {
let dir = fixture_dir("issue-60-4d-negative");
let source = std::fs::read_to_string(dir.join("source.opy")).expect("source must be readable");
let hir = crate::compile(&source, "source.opy", &dir).expect("fixture must resolve");
let error = match Compiler::new()
.expect("released workshop contract must load")
.compile_hir(&hir)
{
Ok(_) => panic!("four-dimensional assignment must remain rejected"),
Err(error) => error,
};
let oracle: serde_json::Value = serde_json::from_str(
&std::fs::read_to_string(dir.join("oracle.json")).expect("oracle must be readable"),
)
.expect("oracle must parse");
assert_eq!(oracle["compile"]["status"], "failure");
assert_eq!(error.diagnostic.code, "unsupported-integration-surface");
assert_eq!(error.diagnostic.span.as_ref().unwrap().start.line, 5);
}
#[test]
fn translated_implicit_subroutine_fixture_matches_the_pinned_oracle() {
assert_fixture_matches_oracle("issue-31-positive");
}
#[test]
fn null_initializers_are_dropped_but_float_zero_is_preserved() {
let source = r#"
globalvar null_value = null
globalvar integer_zero = 0
globalvar float_zero = 0.0
rule "initializer contract":
@Event global
pass
"#;
let hir = crate::compile(source, "issue-145.opy", Path::new(".")).expect("source resolves");
let artifact = Compiler::new()
.expect("released workshop contract must load")
.compile_hir(&hir)
.expect("initializers must lower");
assert!(!artifact.emitted.contains("Set Global Variable(null_value,"));
assert!(
!artifact
.emitted
.contains("Set Global Variable(integer_zero,")
);
assert!(artifact.emitted.contains("Set Global Variable(float_zero,"));
}