Files
cleveragents-core/features/skill_cli_coverage_r2.feature
freemo 3a2b134f3c
CI / lint (pull_request) Successful in 14s
CI / benchmark-publish (pull_request) Has been skipped
CI / quality (pull_request) Successful in 27s
CI / typecheck (pull_request) Successful in 37s
CI / security (pull_request) Successful in 39s
CI / build (pull_request) Successful in 29s
CI / integration_tests (pull_request) Successful in 5m51s
CI / benchmark-regression (pull_request) Successful in 22m39s
CI / unit_tests (pull_request) Successful in 29m35s
CI / docker (pull_request) Successful in 13s
CI / coverage (pull_request) Successful in 2h3m1s
CI / lint (push) Successful in 21s
CI / typecheck (push) Successful in 57s
CI / security (push) Successful in 51s
CI / quality (push) Successful in 27s
CI / integration_tests (push) Successful in 4m59s
CI / build (push) Successful in 23s
CI / benchmark-publish (push) Successful in 14m39s
CI / benchmark-regression (push) Has been skipped
CI / unit_tests (push) Successful in 29m48s
CI / docker (push) Successful in 15s
CI / coverage (push) Successful in 1h45m42s
test(coverage): add Behave scenarios for remaining under-tested modules
Added Behave BDD feature files and step definitions targeting coverage
gaps in six modules:

- container.py: exercise get_database_url env-var fallback, AI provider
  None path, cached container singleton, override_providers edge cases
  (lines 66-69, 125-130; branches at 51, 57, 82, 87, 256, 284-288)
- correction_service.py: exercise exception-handling paths in
  execute_revert and execute_append via monkeypatched analyze_impact
  and ULID failures (lines 254-262, 320-328)
- plan_lifecycle_service.py: exercise _persisted UoW commit paths,
  InvalidPhaseTransitionError custom message branch, non-reusable
  action archive, and error_details merge logic (branches at 100,
  216, 237, 327, 461, 570, 576, 607)
- plan.py (CLI): exercise spec-dict optional field branches,
  _print_lifecycle_plan conditional rendering, use_action argument
  parsing, auto-resolve paths, legacy wrappers, and validation
  error branches across 66 scenarios
- skill.py (CLI): exercise singleton cache, timestamp-absent show,
  no-tools MCP, add/remove/list/show format and error branches
  across 26 scenarios
- models.py (DB): exercise to_domain/from_domain None-field branches
  in SkillModel, SessionModel, ToolModel, LifecycleActionModel,
  LifecyclePlanModel, NamespacedProjectModel, and SessionMessageModel
  across 41 scenarios

All 302 features, 6503 scenarios, 28271 steps pass (nox -e unit_tests).

ISSUES CLOSED: #446
2026-02-25 19:38:43 -05:00

273 lines
14 KiB
Gherkin

Feature: Skill CLI branch coverage round 2
Cover partial branches in src/cleveragents/cli/commands/skill.py
Lines 74, 109, 112, 121, 155, 164, 169, and related conditionals.
All lines are hit but many conditional branches are only tested in one direction.
Background:
Given r2skill- a reset skill CLI service
# -------------------------------------------------------------------
# _get_skill_service singleton (line 74 false branch)
# -------------------------------------------------------------------
Scenario: Service singleton returns existing instance on second call
When r2skill- I call _get_skill_service twice without resetting
Then r2skill- both calls return the same SkillService object
# -------------------------------------------------------------------
# _skill_spec_dict — missing timestamps (lines 109, 112 false)
# -------------------------------------------------------------------
Scenario: Show skill with JSON format when timestamps are absent
Given r2skill- a registered skill "local/no-timestamps" with tool_refs
And r2skill- the timestamps for "local/no-timestamps" are removed
When r2skill- I invoke show "local/no-timestamps" with format "json"
Then r2skill- the output should be valid JSON
And r2skill- the JSON output should not contain key "created"
And r2skill- the JSON output should not contain key "updated"
# -------------------------------------------------------------------
# _tool_count — MCP with no tools (line 121-122 false branch)
# -------------------------------------------------------------------
Scenario: Tool count for skill with MCP server having no tools
Given r2skill- a registered skill "local/mcp-no-tools" with MCP server but no tool list
When r2skill- I invoke show "local/mcp-no-tools" with format "rich"
Then r2skill- the CLI exit code should be 0
And r2skill- the output should contain "OK"
# -------------------------------------------------------------------
# _print_skill_registered — no includes (line 155 false)
# -------------------------------------------------------------------
Scenario: Add skill with no includes shows no Includes panel
Given r2skill- a temp YAML config for "local/no-includes" with only tool_refs
When r2skill- I invoke add with the temp config in rich format
Then r2skill- the CLI exit code should be 0
And r2skill- the output should contain "Skill Registered"
And r2skill- the output should not contain "Includes"
# -------------------------------------------------------------------
# _print_skill_registered — empty sources (line 164 false)
# -------------------------------------------------------------------
Scenario: Add skill with no tool sources shows no Tool Sources panel
Given r2skill- a temp YAML config for "local/empty-skill" with no tools
When r2skill- I invoke add with the temp config in rich format
Then r2skill- the CLI exit code should be 0
And r2skill- the output should contain "Skill Registered"
And r2skill- the output should not contain "Tool Sources"
# -------------------------------------------------------------------
# _print_skill_registered — source type branches (lines 169, 173, 177, 181)
# -------------------------------------------------------------------
Scenario: Add skill with only MCP sources excludes builtin from sources
Given r2skill- a temp YAML config for "local/mcp-only" with MCP and tools
When r2skill- I invoke add with the temp config in rich format
Then r2skill- the CLI exit code should be 0
And r2skill- the output should contain "mcp"
Scenario: Add skill with only custom inline tools
Given r2skill- a temp YAML config for "local/custom-only" with inline tools
When r2skill- I invoke add with the temp config in rich format
Then r2skill- the CLI exit code should be 0
And r2skill- the output should contain "custom"
# -------------------------------------------------------------------
# add command — non-rich format (line 483 true branch)
# -------------------------------------------------------------------
Scenario: Add skill with JSON format returns JSON output
Given r2skill- a temp YAML config for "local/json-add" with only tool_refs
When r2skill- I invoke add with the temp config in format "json"
Then r2skill- the CLI exit code should be 0
And r2skill- the output should be valid JSON
And r2skill- the JSON output should contain key "name"
# -------------------------------------------------------------------
# add command — update existing skill (lines 474, 491)
# -------------------------------------------------------------------
Scenario: Update existing skill via add --update shows Changes panel
Given r2skill- a temp YAML config for "local/updatable" with only tool_refs
And r2skill- the skill "local/updatable" is already registered via add
And r2skill- a second temp YAML config for "local/updatable" with different tools
When r2skill- I invoke add with the second config and --update in rich format
Then r2skill- the CLI exit code should be 0
And r2skill- the output should contain "Skill Updated"
And r2skill- the output should contain "Changes"
# -------------------------------------------------------------------
# add command — duplicate without --update (line 500-510)
# -------------------------------------------------------------------
Scenario: Add duplicate skill without update raises already-registered error
Given r2skill- a temp YAML config for "local/duplicate" with only tool_refs
And r2skill- the skill "local/duplicate" is already registered via add
And r2skill- a duplicate temp YAML config for "local/duplicate"
When r2skill- I invoke add with the duplicate config without update
Then r2skill- the CLI exit code should not be 0
And r2skill- the output should contain "already registered"
And r2skill- the output should contain "--update"
# -------------------------------------------------------------------
# list — empty registry (line 646 true)
# -------------------------------------------------------------------
Scenario: List skills when registry is empty shows message
When r2skill- I invoke list in rich format
Then r2skill- the output should contain "No skills found"
# -------------------------------------------------------------------
# list — non-rich format (line 651 true)
# -------------------------------------------------------------------
Scenario: List skills with JSON format
Given r2skill- a registered skill "local/for-json-list" with tool_refs
When r2skill- I invoke list in format "json"
Then r2skill- the CLI exit code should be 0
And r2skill- the output should be valid JSON
# -------------------------------------------------------------------
# list — non-local namespace (line 671 else branch)
# -------------------------------------------------------------------
Scenario: List skills with non-local namespace counts server skills
Given r2skill- a registered skill "server/remote-skill" with tool_refs
When r2skill- I invoke list in rich format
Then r2skill- the CLI exit code should be 0
And r2skill- the output should contain "server/remote-skill"
# -------------------------------------------------------------------
# show — non-rich format (line 724 true)
# -------------------------------------------------------------------
Scenario: Show skill with JSON format returns structured data
Given r2skill- a registered skill "local/for-json-show" with tool_refs
When r2skill- I invoke show "local/for-json-show" with format "json"
Then r2skill- the CLI exit code should be 0
And r2skill- the output should be valid JSON
And r2skill- the JSON output should contain key "name"
# -------------------------------------------------------------------
# show — KeyError path (line 731-733)
# -------------------------------------------------------------------
Scenario: Show nonexistent skill raises not-found error
When r2skill- I invoke show "local/nonexistent" with format "rich"
Then r2skill- the CLI exit code should not be 0
And r2skill- the output should contain "Skill not found"
# -------------------------------------------------------------------
# remove — rich format output (line 564 false, full rich path)
# -------------------------------------------------------------------
Scenario: Remove skill with rich format shows removal panel
Given r2skill- a registered skill "local/to-remove" with tool_refs
When r2skill- I invoke remove "local/to-remove" with --yes in rich format
Then r2skill- the CLI exit code should be 0
And r2skill- the output should contain "Skill Removed"
And r2skill- the output should contain "OK"
# -------------------------------------------------------------------
# remove — non-rich format (line 564 true)
# -------------------------------------------------------------------
Scenario: Remove skill with JSON format returns structured output
Given r2skill- a registered skill "local/to-remove-json" with tool_refs
When r2skill- I invoke remove "local/to-remove-json" with --yes in format "json"
Then r2skill- the CLI exit code should be 0
And r2skill- the output should be valid JSON
# -------------------------------------------------------------------
# remove — dependent skills (lines 577-587)
# -------------------------------------------------------------------
Scenario: Remove skill that is included by another skill shows dependency warning
Given r2skill- a registered skill "local/base-dep" with tool_refs
And r2skill- a registered skill "local/parent-dep" that includes "local/base-dep"
When r2skill- I invoke remove "local/base-dep" with --yes in rich format
Then r2skill- the CLI exit code should be 0
And r2skill- the output should contain "skill(s) include this skill"
# -------------------------------------------------------------------
# remove — KeyError path (line 601-603)
# -------------------------------------------------------------------
Scenario: Remove nonexistent skill raises not-found error
When r2skill- I invoke remove "local/nonexistent" with --yes in rich format
Then r2skill- the CLI exit code should not be 0
And r2skill- the output should contain "Skill not found"
# -------------------------------------------------------------------
# tools — non-rich format (line 801 true)
# -------------------------------------------------------------------
Scenario: Tools command with JSON format returns structured tool data
Given r2skill- a registered skill "local/for-json-tools" with tool_refs
When r2skill- I invoke tools "local/for-json-tools" with format "json"
Then r2skill- the CLI exit code should be 0
And r2skill- the output should be valid JSON
# -------------------------------------------------------------------
# tools — inline entries in non-rich output (lines 806-811)
# -------------------------------------------------------------------
Scenario: Tools command with inline tools in JSON format shows custom source
Given r2skill- a registered skill "local/inline-tools" with anonymous inline tools
When r2skill- I invoke tools "local/inline-tools" with format "json"
Then r2skill- the CLI exit code should be 0
And r2skill- the output should be valid JSON
And r2skill- the JSON tool list should contain source "custom"
# -------------------------------------------------------------------
# tools — KeyError path (line 827-829)
# -------------------------------------------------------------------
Scenario: Tools for nonexistent skill raises not-found error
When r2skill- I invoke tools "local/nonexistent" with format "rich"
Then r2skill- the CLI exit code should not be 0
And r2skill- the output should contain "Skill not found"
# -------------------------------------------------------------------
# _print_skill_registered — MCP servers panel (line 189)
# -------------------------------------------------------------------
Scenario: Add skill with MCP servers shows MCP Servers panel
Given r2skill- a temp YAML config for "local/with-mcp-panel" with MCP servers
When r2skill- I invoke add with the temp config in rich format
Then r2skill- the CLI exit code should be 0
And r2skill- the output should contain "MCP Servers"
# -------------------------------------------------------------------
# _print_skill_detail — no direct tools (line 302 false)
# -------------------------------------------------------------------
Scenario: Show skill with no direct tools omits direct tools table
Given r2skill- a registered skill "local/no-direct-tools" with no tools at all
When r2skill- I invoke show "local/no-direct-tools" with format "rich"
Then r2skill- the CLI exit code should be 0
And r2skill- the output should not contain "Direct Tools"
# -------------------------------------------------------------------
# _print_skill_detail — MCP tools in show (line 287 true/false)
# -------------------------------------------------------------------
Scenario: Show skill with MCP servers displays MCP panel
Given r2skill- a registered skill "local/show-mcp" with MCP server and explicit tools
When r2skill- I invoke show "local/show-mcp" with format "rich"
Then r2skill- the CLI exit code should be 0
And r2skill- the output should contain "MCP Servers"
# -------------------------------------------------------------------
# tools — MCP entry in non-rich format (line 806 true)
# -------------------------------------------------------------------
Scenario: Tools command with MCP entries in JSON format
Given r2skill- a registered skill "local/mcp-tools-json" with MCP server and explicit tools
When r2skill- I invoke tools "local/mcp-tools-json" with format "json"
Then r2skill- the CLI exit code should be 0
And r2skill- the output should be valid JSON
And r2skill- the JSON tool list should contain source "mcp"