//! Pins the canonical type-scoped resolution path of `ail describe`.
//!
//! Property protected: `ail describe` resolves the CANONICAL
//! `<Type>.<op>` form for a type-associated operation (model 0007 §1
//! declares `<Type>.<op>` the canonical form; the op lives in the
//! type's home module). For `series_sma`, `Series` is a known TYPE
//! (its `TypeDef` is defined in module `series`), not a module — so
//! `Series.push` must resolve to the SAME `push` fn that the
//! module-scoped `series.push` and the bare `push` already resolve to.
//!
//! Scope: this pins ONLY `Type.op` resolution (issue #64 part 1). It
//! does NOT pin "describe Type lists the type's ops" (part 2).
//!
//! Pure reader: spawns the committed `ail` binary against the
//! committed `examples/series_sma.ail` fixture; mutates nothing.

use ailang_test_support::examples_dir;
use std::path::PathBuf;
use std::process::Command;

fn ail_bin() -> PathBuf {
    // CARGO_BIN_EXE_<name> is set by cargo when building integration tests.
    PathBuf::from(env!("CARGO_BIN_EXE_ail"))
}

/// `ail describe --workspace examples/series_sma.ail Series.push`
/// exits 0 and prints the `series.push` function definition — the
/// same def the module-scoped `series.push` resolves to. `Series` is
/// a type defined in module `series`, so the canonical `<Type>.<op>`
/// form must resolve through the type's home module.
#[test]
fn describe_resolves_type_scoped_op() {
    let fixture = examples_dir().join("series_sma.ail");
    let output = Command::new(ail_bin())
        .args([
            "describe",
            "--workspace",
            fixture.to_str().unwrap(),
            "Series.push",
        ])
        .output()
        .expect("ail binary must launch");

    let stdout = String::from_utf8_lossy(&output.stdout);
    let stderr = String::from_utf8_lossy(&output.stderr);

    assert!(
        output.status.success(),
        "describe Series.push must exit 0 (resolve the canonical \
         type-scoped form); exit={:?}\nstdout: {stdout}\nstderr: {stderr}",
        output.status.code(),
    );
    // Same def the module-scoped `series.push` prints: the home
    // module line and the `push` fn header (Form-A projection).
    assert!(
        stdout.contains("module: series"),
        "expected the home-module line `module: series`; got:\n{stdout}"
    );
    assert!(
        stdout.contains("(fn push"),
        "expected the `push` fn definition in the output; got:\n{stdout}"
    );
}
