Repository navigation
test: close coverage gaps in MCP glue and remaining tool handlers - #23
Merged
Merged
Conversation
Measured with pytest-cov: 92% overall (1856 stmts, 140 miss). The
weakest spots were the MCP dispatch path every one of the 99 tools
goes through, plus two handlers that only had a registration-existence
test and no invocation test.
- tests/test_mcp_client.py (new): HexStrikeClient had 0% coverage.
check_health() and execute_tool() are now covered for the success
path, an HTTP error status, and a request exception -> 100%.
- tests/test_mcp.py: added a test that calls mcp.call_tool("nmap_scan",
...) with client.execute_tool mocked, asserting tool_func's
sig.bind(...).apply_defaults() actually fills in every handler
parameter before dispatch - this closure is what turns a ToolSpec
into a working MCP tool for all 99 registered tools, and previously
only its metadata (name/description) was exercised, never a real
call through it.
- tests/test_api.py: added a GET-request variant (exercises the
request.args.to_dict() branch), a missing-required-argument case
(exercises the TypeError -> 400 branch), and a handler-raises case
(exercises the generic Exception -> 500 branch) of create_tool_view.
api/app.py -> 100%.
- tests/test_password_tools.py: hydra_attack had no invocation test
(only hashcat_scan/john_scan did). Added two, covering both branches
of each optional flag. password.py -> 100%.
- tests/test_osint_tools.py: same gap for amass_enum (only
hakrawler_crawl was tested). Added two. osint.py -> 100%.
Deliberately left uncovered: hexstrike/core/visual.py (a banner/color
constants module, no branching logic to test) and mcp/server.py's
main()/`if __name__` block (argparse + a blocking mcp.run() call -
mocking it out mainly re-tests argparse plumbing for little value).
Result: 94% overall, 241/241 tests passing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UCXzPVYGQRPh8iwyajTsRt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Measured coverage with
pytest-cov: 92% overall (1856 stmts, 140 miss). The weakest spots were the MCP dispatch path every one of the 99 tools goes through, plus two handlers that only had a registration-existence test and no invocation test.tests/test_mcp_client.py(new):HexStrikeClienthad 0% coverage — the HTTP client used by every single MCP tool call to reach the Flask API. Now coverscheck_health()andexecute_tool()for the success path, an HTTP error status, and a request exception. → 100%.tests/test_mcp.py: added a test that callsmcp.call_tool("nmap_scan", ...)withclient.execute_toolmocked, assertingtool_func'ssig.bind(...).apply_defaults()actually fills in every handler parameter before dispatch. This closure is what turns aToolSpecinto a working MCP tool for all 99 registered tools — previously only its metadata (name/description) was exercised, never an actual call through it.tests/test_api.py: added a GET-request variant (exercises therequest.args.to_dict()branch), a missing-required-argument case (exercises theTypeError→ 400 branch), and a handler-raises case (exercises the genericException→ 500 branch) ofcreate_tool_view.api/app.py→ 100%.tests/test_password_tools.py:hydra_attackhad no invocation test (onlyhashcat_scan/john_scandid). Added two, covering both branches of each optional flag.password.py→ 100%.tests/test_osint_tools.py: same gap foramass_enum(onlyhakrawler_crawlwas tested). Added two.osint.py→ 100%.Deliberately left uncovered:
hexstrike/core/visual.py(banner/color constants, no branching logic) andmcp/server.py'smain()/if __name__block (argparse + a blockingmcp.run()call — mocking it out mainly re-tests argparse plumbing for little value).Result: 94% overall, 241/241 tests passing (up from 92%/228).
Test plan
pytest tests/ -q --cov=hexstrike --cov-report=term-missinglocally → 241 passed, 94% coverageapi/app.py,mcp/client.py,password.py,osint.py) hits 100%🤖 Generated with Claude Code
https://claude.ai/code/session_01UCXzPVYGQRPh8iwyajTsRt