//! Iter 20a snapshot tests. //! //! For each `examples/.ail.json`, the renderer's output is //! compared against the committed `examples/.prose.txt`. The //! snapshot files are part of the repo: changing the renderer requires //! a deliberate snapshot update, which is the point of this test. //! //! Update protocol (manual): regenerate the file by running //! `cargo run -p ail -- prose .ail.json > .prose.txt` //! once the renderer change is agreed; commit alongside the change. //! There is no `UPDATE_SNAPSHOTS=1` environment short-cut here on //! purpose — Iter 20a is the seeding round, and we want every change //! after this to be visible in a diff. use std::path::PathBuf; fn examples_dir() -> PathBuf { // tests/ runs with CARGO_MANIFEST_DIR == crates/ailang-prose. let mut p = PathBuf::from(env!("CARGO_MANIFEST_DIR")); p.pop(); p.pop(); p.push("examples"); p } fn check_snapshot(stem: &str) { let dir = examples_dir(); let json_path = dir.join(format!("{stem}.ail.json")); let prose_path = dir.join(format!("{stem}.prose.txt")); let module = ailang_core::load_module(&json_path) .unwrap_or_else(|e| panic!("failed to load {json_path:?}: {e}")); let actual = ailang_prose::module_to_prose(&module); let expected = std::fs::read_to_string(&prose_path) .unwrap_or_else(|e| panic!("failed to read snapshot {prose_path:?}: {e}")); if actual != expected { // Write `.actual` for inspection, then fail. let actual_path = dir.join(format!("{stem}.prose.txt.actual")); std::fs::write(&actual_path, &actual).expect("write .actual"); panic!( "prose snapshot mismatch for {stem}.\n\ Expected: {prose_path:?}\n\ Actual: {actual_path:?}\n\ To accept the new output, replace the expected file with the .actual file." ); } } #[test] fn snapshot_rc_own_param_drop() { check_snapshot("rc_own_param_drop"); } #[test] fn snapshot_rc_match_arm_partial_drop_leak() { check_snapshot("rc_match_arm_partial_drop_leak"); } #[test] fn snapshot_rc_app_let_partial_drop_leak() { check_snapshot("rc_app_let_partial_drop_leak"); } /// Iter 20b: this fixture exercises the infix renderer + paren elision. /// Pre-20b, the body had `if ==(n, 0) { ... }` and `tail sum_acc(-(n, /// 1), ICons(-(n, 1), acc))`; after 20b those collapse to `if n == 0` /// and `n - 1`. If this regresses, the renderer is broken. #[test] fn snapshot_bench_list_sum() { check_snapshot("bench_list_sum"); }