//! Prose-projection snapshot tests. //! //! For each `examples/.ail`, 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 > .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 ailang_test_support::examples_dir; fn check_snapshot(stem: &str) { let dir = examples_dir(); let ail_path = dir.join(format!("{stem}.ail")); let prose_path = dir.join(format!("{stem}.prose.txt")); let module = ailang_surface::load_module(&ail_path) .unwrap_or_else(|e| panic!("failed to load {ail_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"); } /// 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"); } #[test] fn snapshot_test_22b3_default_e2e() { check_snapshot("test_22b3_default_e2e"); } #[test] fn snapshot_test_22b2_instance_present() { check_snapshot("test_22b2_instance_present"); } #[test] fn snapshot_test_22b2_constraint_declared_via_superclass() { check_snapshot("test_22b2_constraint_declared_via_superclass"); } /// Ct.4.3: snapshot for the canonical ordering-match fixture. /// `ordering_match.ail.json` is in the `ordering_match` module /// and references `prelude.Ordering` via a cross-module /// `Term::Ctor.type_name`. The prose printer drops Ctor /// `type_name`s entirely (recoverable from typecheck context), /// so the rendered prose carries `LT`/`EQ`/`GT` without any /// `prelude.` qualifier — the trim-on-print logic is exercised /// by the unit tests on `Type::Con`, which is the surface /// where the qualifier survives into the rendered text. #[test] fn snapshot_ordering_match() { check_snapshot("ordering_match"); } #[test] fn snapshot_loop_sum_to_run() { check_snapshot("loop_sum_to_run"); } #[test] fn snapshot_loop_forever_build() { check_snapshot("loop_forever_build"); }