Skip to content

[Test Improver] test: add unit tests for compile command logic (38% -> ~50%)#859

Closed
danielmeppiel wants to merge 2 commits intomainfrom
test-assist/compile-command-logic-24811162489-b389af219034a9b1
Closed

[Test Improver] test: add unit tests for compile command logic (38% -> ~50%)#859
danielmeppiel wants to merge 2 commits intomainfrom
test-assist/compile-command-logic-24811162489-b389af219034a9b1

Conversation

@danielmeppiel
Copy link
Copy Markdown
Collaborator

🤖 Test Improver - automated AI assistant for improving test coverage.

Goal and Rationale

src/apm_cli/commands/compile/cli.py (622 lines) was at ~38% coverage. This PR adds focused unit tests for:

  1. _resolve_compile_target - A pure function mapping CLI target inputs to compiler-understood strings. This function handles the logic for multi-target lists (["claude", "copilot"]"all") and is called on every apm compile invocation.

  2. _get_validation_suggestion - A pure helper providing actionable error messages during --validate mode.

  3. compile CLI early-exit paths - Validates the guard rails that prevent compilation on invalid project states (no apm.yml, no content, empty .apm/).

  4. --validate mode - Tests the validation-only code path including success, validation errors, and exception handling.

  5. --dry-run suppression of the no-content early exit (enabling preview in empty projects).

These paths were completely untested despite being exercised on every apm compile call.

Approach

  • Pure functions (_resolve_compile_target, _get_validation_suggestion) tested directly with no mocking needed.
  • CLI tests use Click's CliRunner with isolated_filesystem() to avoid filesystem side effects.
  • AgentsCompiler and discover_primitives are mocked to isolate the CLI dispatch logic from compilation internals.

Coverage Impact

Module Before After (estimated)
commands/compile/cli.py ~38% ~50%+
Total tests 5155 5173 (+18)

Test Status

All 18 new tests pass. Full unit suite (5173 tests) passes:

python3 -m uv run pytest tests/unit tests/test_console.py -q --ignore=tests/unit/commands/test_policy_status.py
5173 passed, 1 warning, 26 subtests passed in 18.35s

Note: test_policy_status.py has one pre-existing failure (unrelated to this PR — the _ascii_only check conflicts with ANSI codes in Rich's table output) and is ignored for baseline comparison.

Trade-offs

  • Tests for --validate mock discover_primitives and AgentsCompiler to stay fast and deterministic.
  • The --dry-run test exercises the path broadly rather than asserting specific output since the distributed/single-file fork has many state combinations.

Reproducibility

uv run pytest tests/unit/test_compile_command_logic.py -v

Generated by Daily Test Improver ·

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/daily-test-improver.md@b87234850bf9664d198f28a02df0f937d0447295

…ate mode, early exits)

- Tests for _resolve_compile_target: all target resolution paths (None, single
  string passthrough, list with claude-only, agents-family, mixed -> all)
- Tests for _get_validation_suggestion: covers Missing description, applyTo,
  empty content, and unknown-error fallback cases
- CLI integration tests for early-exit paths: no apm.yml, no content, empty .apm/
- CLI integration tests for --validate mode: success, failure, and exception paths
- CLI integration test for --dry-run suppressing the no-content early exit

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@danielmeppiel danielmeppiel added automation Deprecated: use type/automation. Kept for issue history; will be removed in milestone 0.10.0. testing Deprecated: use area/testing. Kept for issue history; will be removed in milestone 0.10.0. labels Apr 23, 2026
@github-actions
Copy link
Copy Markdown

🔒 Supply Chain Security Review — PASS

Reviewed tests/unit/test_compile_command_logic.py (243 lines, test-only) against five security criteria. No issues found.

Check Status Detail
CodeQL URL rule ✅ OK All in assertions check plain English words or filenames ("apm.yml", "validated", "description:", "applyTo", etc.). None are URL-shaped — no py/incomplete-url-substring-sanitization trigger.
Path safety ✅ OK All filesystem ops use runner.isolated_filesystem(temp_dir=tmp_path) with relative paths. No .. components, no absolute paths, no user-controlled segments.
Mock scope ✅ OK Patches target only apm_cli.commands.compile.cli.{discover_primitives, AgentsCompiler}. No mocks on path_security, AuthResolver, cleanup, or any security-critical module.
Test isolation ✅ OK All writes contained within pytest tmp_path. No os.environ mutation, no global os.chdir.
No network calls ✅ OK No HTTP client imports. The two paths that could reach the network (discover_primitives, AgentsCompiler) are mocked wherever they could be reached.

No required fixes, no suggestions. Clean from a supply-chain security perspective.

Generated by PR Review Panel for issue #859 · ● 7.5M ·

@danielmeppiel danielmeppiel marked this pull request as ready for review May 2, 2026 21:29
Copilot AI review requested due to automatic review settings May 2, 2026 21:29
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new unit test module for apm compile command logic. It targets the CLI layer in src/apm_cli/commands/compile/cli.py, aiming to improve coverage around target resolution, validation helpers, and early-exit behavior.

Changes:

  • Adds direct unit tests for _resolve_compile_target and _get_validation_suggestion.
  • Adds CliRunner tests for missing apm.yml, empty-project handling, and --validate flows.
  • Adds a mocked --dry-run test intended to cover the no-content bypass path.
Show a summary per file
File Description
tests/unit/test_compile_command_logic.py New compile-command test module covering helper functions and selected CLI guard rails.

Copilot's findings

Comments suppressed due to low confidence (2)

tests/unit/test_compile_command_logic.py:54

  • The second assertion here regresses the routing fix from test_compile_target_flag.py: a cursor/opencode/codex list must stay AGENTS-only and must not collapse to "vscode", otherwise the compiler will think Copilot output is required. This expectation conflicts with the current resolver semantics and will fail the test suite.
    def test_list_agents_family_combined_returns_vscode(self):
        """Multiple agents-family members still resolve to 'vscode'."""
        assert _resolve_compile_target(["vscode", "copilot"]) == "vscode"
        assert _resolve_compile_target(["cursor", "opencode", "codex"]) == "vscode"

tests/unit/test_compile_command_logic.py:68

  • parse_target_field() normalizes any raw target: [all] input to the string "all" before compile() ever calls _resolve_compile_target(), so this list shape is unreachable in real CLI/apm.yml flows. Asserting the helper's current defensive fallback to "vscode" locks in accidental behavior on a non-user-visible code path and makes future cleanup harder.
    def test_list_with_all_returns_all(self):
        """'all' as a list element is treated like an agents-family name (no claude), so vscode."""
        # 'all' is not in the agents-family set AND not 'claude', so single passthrough when alone
        result = _resolve_compile_target(["all"])
        # 'all' is not in {"copilot", "vscode", "agents", "cursor", "opencode", "codex"} and != "claude"
        # so has_agents_family=False, has_claude=False -> returns "vscode"
        assert result == "vscode"
  • Files reviewed: 1/1 changed files
  • Comments generated: 3

Comment on lines +46 to +54
def test_list_agents_family_only_returns_vscode(self):
"""Lists from the agents family resolve to 'vscode'."""
for target in (["vscode"], ["copilot"], ["agents"], ["cursor"], ["opencode"], ["codex"]):
assert _resolve_compile_target(target) == "vscode", f"Failed for {target}"

def test_list_agents_family_combined_returns_vscode(self):
"""Multiple agents-family members still resolve to 'vscode'."""
assert _resolve_compile_target(["vscode", "copilot"]) == "vscode"
assert _resolve_compile_target(["cursor", "opencode", "codex"]) == "vscode"
Comment on lines +56 to +68
def test_list_claude_and_agents_family_returns_all(self):
"""When both claude and an agents-family target appear, resolve to 'all'."""
assert _resolve_compile_target(["claude", "vscode"]) == "all"
assert _resolve_compile_target(["copilot", "claude"]) == "all"
assert _resolve_compile_target(["claude", "cursor", "opencode"]) == "all"

def test_list_with_all_returns_all(self):
"""'all' as a list element is treated like an agents-family name (no claude), so vscode."""
# 'all' is not in the agents-family set AND not 'claude', so single passthrough when alone
result = _resolve_compile_target(["all"])
# 'all' is not in {"copilot", "vscode", "agents", "cursor", "opencode", "codex"} and != "claude"
# so has_agents_family=False, has_claude=False -> returns "vscode"
assert result == "vscode"
Comment on lines +233 to +243
mock_intermediate = MagicMock()
mock_intermediate.success = False # force single-file fallback to show errors

with patch("apm_cli.commands.compile.cli.AgentsCompiler") as MockCompiler:
mock_compiler = MockCompiler.return_value
mock_compiler.compile.return_value = mock_result
# With dry_run=True, early exit is suppressed; compilation still called
result = runner.invoke(compile, ["--dry-run", "--single-agents"])

# Either succeeds or hits a later error - just shouldn't have -1 from unhandled exception
assert result.exit_code in (0, 1)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

automation Deprecated: use type/automation. Kept for issue history; will be removed in milestone 0.10.0. testing Deprecated: use area/testing. Kept for issue history; will be removed in milestone 0.10.0.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants