agentdir 0.1.6

Virtual file tree infrastructure for agent-ready file layouts using CoW reflinks
Documentation
from __future__ import annotations

import json
import re
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[3]


def read(path: str) -> str:
    return (ROOT / path).read_text(encoding="utf-8")


def test_ci_runs_rust_workspace_tests_on_linux_macos_windows() -> None:
    workflow = read(".github/workflows/ci.yml")
    assert "branches: [main]" in workflow
    assert "branches: [master]" not in workflow
    assert "os: [ubuntu-latest, macos-latest, windows-latest]" in workflow
    assert re.search(r"runs-on:\s*\$\{\{\s*matrix\.os\s*\}\}", workflow)
    assert "cargo test --workspace" in workflow
    assert "CLI smoke (${{ matrix.os }})" in workflow
    assert "Strategy smoke (${{ matrix.os }})" in workflow


def test_ci_enforces_release_qa_artifact_checks() -> None:
    workflow = read(".github/workflows/ci.yml")
    assert "Release QA artifact checks" in workflow
    assert "python3 crates/agentdir/tests/issue_18_release_qa.py" in workflow


def test_cli_smoke_script_exercises_required_commands_and_readonly_check() -> None:
    script = read("scripts/ci/cli_smoke.py")
    for command in ("init", "map", "stat", "cat", "refresh", "export-mapping"):
        assert f'"{command}"' in script
    assert "assert_materialized_readonly" in script
    assert "CLI smoke passed" in script
    assert "agentdir binary not found" in script
    assert "scripts/ci/cli_smoke.py --agentdir" in read(".github/workflows/ci.yml")


def test_strategy_smoke_script_covers_reflink_virtual_and_symlink_contracts() -> None:
    script = read("scripts/ci/strategy_smoke.py")
    for strategy in ("reflink", "virtual", "symlink"):
        assert f'"{strategy}"' in script
    assert "symlink source mutation observed" in script
    assert "passthrough" in script
    assert "Strategy smoke passed" in script
    assert "scripts/ci/strategy_smoke.py --agentdir" in read(".github/workflows/ci.yml")


def test_release_preflight_checks_versions_and_packaging_commands() -> None:
    script = read("scripts/ci/release_preflight.py")
    for path in (
        "crates/agentdir/Cargo.toml",
        "crates/agentdir-cli/Cargo.toml",
        "bindings/python/pyproject.toml",
        "bindings/node/package.json",
        "bindings/node/package-lock.json",
        "bindings/node/index.js",
        "bindings/python/uv.lock",
    ):
        assert path in script
    for command in (
        "cargo publish -p agentdir --dry-run",
        "cargo publish -p agentdir-cli --dry-run",
        "npm pack --dry-run",
        "maturin sdist",
    ):
        assert command in script
    assert "Release metadata preflight passed" in script
    assert "scripts/ci/release_preflight.py --metadata-only" in read(
        ".github/workflows/release-rust.yml"
    )
    assert "../../scripts/ci/release_preflight.py --metadata-only" in read(
        ".github/workflows/release-node.yml"
    )
    assert "../../scripts/ci/release_preflight.py --metadata-only" in read(
        ".github/workflows/release-python.yml"
    )


def test_python_release_workflow_import_smokes_built_wheels_per_os() -> None:
    workflow = read(".github/workflows/release-python.yml")
    assert "smoke:" in workflow
    assert "needs: build" in workflow
    assert "runs-on: ${{ matrix.os }}" in workflow
    assert "python -m pip install --no-index --find-links dist agentdir" in workflow
    assert "python scripts/ci/python_wheel_smoke.py" in workflow
    assert "target: aarch64" in workflow


def test_python_wheel_smoke_script_exercises_binding_surface() -> None:
    script = read("scripts/ci/python_wheel_smoke.py")
    for snippet in (
        "agentdir import failed",
        "Workspace.init",
        ".map(",
        ".read_bytes(",
        ".export_mapping(",
        ".refresh()",
        "Python wheel smoke passed",
    ):
        assert snippet in script
    assert "raise SystemExit(main())" in script


def test_smoke_scripts_support_keep_temp_for_manual_qa_artifacts() -> None:
    cli_script = read("scripts/ci/cli_smoke.py")
    strategy_script = read("scripts/ci/strategy_smoke.py")
    assert "--keep-temp" in cli_script
    assert "--keep-temp" in strategy_script
    assert "keeping temp directory" in cli_script
    assert "keeping temp directory" in strategy_script


def test_release_preflight_has_expected_version_negative_path() -> None:
    script = read("scripts/ci/release_preflight.py")
    assert "GITHUB_REF_TYPE" in script
    assert "GITHUB_REF_NAME" in script
    assert "release tag does not contain a semver version" in script
    assert "--expected-version" in script
    assert "version mismatch" in script


def test_node_package_lock_root_version_matches_package_json() -> None:
    package = json.loads(read("bindings/node/package.json"))
    lock = json.loads(read("bindings/node/package-lock.json"))
    assert lock["version"] == package["version"]
    assert lock["packages"][""]["version"] == package["version"]


def test_release_rust_workflow_dry_runs_cli_before_publish() -> None:
    workflow = read(".github/workflows/release-rust.yml")
    assert "cargo publish -p agentdir-cli --dry-run" in workflow
    dry_run_at = workflow.index("cargo publish -p agentdir-cli --dry-run")
    publish_at = workflow.index("Publish agentdir-cli")
    index_at = workflow.index("Wait for crates.io sparse index")
    assert index_at < dry_run_at < publish_at


def test_release_node_workflow_packs_before_publish() -> None:
    workflow = read(".github/workflows/release-node.yml")
    assert "npm pack --dry-run" in workflow
    assert workflow.index("npm pack --dry-run") < workflow.index("npm publish --access public")


def main() -> int:
    failures = 0
    for name, check in sorted(globals().items()):
        if not name.startswith("test_") or not callable(check):
            continue
        try:
            check()
        except (AssertionError, OSError, KeyError) as error:
            failures += 1
            print(f"FAIL {name}: {error}", file=sys.stderr)
        else:
            print(f"PASS {name}")
    if failures:
        return 1
    return 0


if __name__ == "__main__":
    raise SystemExit(main())