//! Workspace-level tests for the polymorphic prelude free fns
//! `ne` / `lt` / `le` / `gt` / `ge` shipped in milestone 23.
//!
//! Property protected: each free fn is monomorphised on demand at the
//! call site's concrete type, producing a mono symbol named
//! `<fn>__<TypeName>`. If the unified mono pass (iter 23.4) stops
//! emitting the free-fn mono arm, or the prelude entry for the fn
//! gets renamed / dropped, these tests fail.
//!
//! See `crates/ail/tests/mono_unification.rs` (iter 23.4) for the
//! end-to-end runtime correctness checks; this file checks only that
//! the mono symbols are produced.

use ailang_check::{check_workspace, monomorphise_workspace};
use ailang_surface::load_workspace;
use std::path::PathBuf;

fn fixture(name: &str) -> PathBuf {
    PathBuf::from(env!("CARGO_MANIFEST_DIR"))
        .join("../../examples")
        .join(name)
}

fn mono_symbol_names(workspace_name: &str) -> Vec<String> {
    let ws = load_workspace(&fixture(workspace_name)).expect("load");
    let diags = check_workspace(&ws);
    assert!(diags.is_empty(), "typecheck failed: {:#?}", diags);
    let mono = monomorphise_workspace(&ws).expect("mono");
    mono.modules
        .values()
        .flat_map(|m| m.defs.iter())
        .filter_map(|d| match d {
            ailang_core::ast::Def::Fn(f) => Some(f.name.clone()),
            _ => None,
        })
        .collect()
}

#[test]
fn ne_at_int_produces_mono_symbol() {
    let names = mono_symbol_names("ne_at_int_smoke.ail");
    assert!(
        names.iter().any(|n| n == "ne__Int"),
        "expected ne__Int in workspace, found: {names:#?}"
    );
}

#[test]
fn lt_at_int_produces_mono_symbol() {
    let names = mono_symbol_names("lt_at_int_smoke.ail");
    assert!(
        names.iter().any(|n| n == "lt__Int"),
        "expected lt__Int in workspace, found: {names:#?}"
    );
}

#[test]
fn le_at_str_produces_mono_symbol() {
    let names = mono_symbol_names("le_at_str_smoke.ail");
    assert!(
        names.iter().any(|n| n == "le__Str"),
        "expected le__Str in workspace, found: {names:#?}"
    );
}

#[test]
fn gt_at_bool_produces_mono_symbol() {
    let names = mono_symbol_names("gt_at_bool_smoke.ail");
    assert!(
        names.iter().any(|n| n == "gt__Bool"),
        "expected gt__Bool in workspace, found: {names:#?}"
    );
}

#[test]
fn ge_at_int_produces_mono_symbol() {
    let names = mono_symbol_names("ge_at_int_smoke.ail");
    assert!(
        names.iter().any(|n| n == "ge__Int"),
        "expected ge__Int in workspace, found: {names:#?}"
    );
}
