@@ -7,7 +7,7 @@ use std::process::Command;
77
88use crate :: common:: tracedecay_command_with_home;
99use tempfile:: TempDir ;
10- use tracedecay:: mcp:: tools:: get_tool_definitions;
10+ use tracedecay:: mcp:: tools:: { get_tool_definitions, render_tool_cli_help } ;
1111
1212/// MCP tools intentionally exempt from bundled-skill coverage.
1313/// Keep empty unless a tool is truly internal.
@@ -47,28 +47,46 @@ fn every_mcp_tool_is_listed_by_the_cli_discovery_command() {
4747}
4848
4949#[ test]
50- fn every_mcp_tool_is_invocable_via_the_cli ( ) {
51- let home = TempDir :: new ( ) . expect ( "create isolated TraceDecay home" ) ;
50+ fn every_mcp_tool_renders_its_own_cli_help ( ) {
5251 for def in get_tool_definitions ( ) {
5352 let short = short_name ( & def. name ) ;
54- let output = isolated_tracedecay_command ( & home)
55- . args ( [ "tool" , short, "--help" ] )
56- . output ( )
57- . unwrap_or_else ( |e| panic ! ( "run `tracedecay tool {short} --help`: {e}" ) ) ;
58- let stdout = String :: from_utf8_lossy ( & output. stdout ) ;
59- assert ! (
60- output. status. success( ) ,
61- "`tracedecay tool {short} --help` must succeed so the tool stays \
62- invocable without an MCP client:\n {}",
63- String :: from_utf8_lossy( & output. stderr)
64- ) ;
53+ let stdout = render_tool_cli_help ( & def) ;
6554 assert ! (
6655 stdout. contains( & format!( "tracedecay tool {short}" ) ) ,
6756 "`tracedecay tool {short} --help` should print the tool's own help, got:\n {stdout}"
6857 ) ;
6958 }
7059}
7160
61+ /// One real `tracedecay tool <name> --help` invocation, asserting the binary
62+ /// prints exactly what `render_tool_cli_help` renders. Tool-name resolution
63+ /// and help dispatch are shared across tools, so a single spawn keeps the CLI
64+ /// wiring covered end-to-end without paying one process per tool.
65+ #[ test]
66+ fn tool_cli_help_matches_rendered_help_end_to_end ( ) {
67+ let home = TempDir :: new ( ) . expect ( "create isolated TraceDecay home" ) ;
68+ let def = get_tool_definitions ( )
69+ . into_iter ( )
70+ . next ( )
71+ . expect ( "at least one MCP tool definition" ) ;
72+ let short = short_name ( & def. name ) ;
73+ let output = isolated_tracedecay_command ( & home)
74+ . args ( [ "tool" , short, "--help" ] )
75+ . output ( )
76+ . unwrap_or_else ( |e| panic ! ( "run `tracedecay tool {short} --help`: {e}" ) ) ;
77+ assert ! (
78+ output. status. success( ) ,
79+ "`tracedecay tool {short} --help` must succeed so tools stay invocable \
80+ without an MCP client:\n {}",
81+ String :: from_utf8_lossy( & output. stderr)
82+ ) ;
83+ assert_eq ! (
84+ String :: from_utf8_lossy( & output. stdout) ,
85+ render_tool_cli_help( & def) ,
86+ "CLI help output should be exactly the rendered help"
87+ ) ;
88+ }
89+
7290/// True when `haystack` mentions `tool_name` as a standalone identifier
7391/// (not as a prefix of a longer tool name such as `tracedecay_lcm_expand`
7492/// inside `tracedecay_lcm_expand_query`).
0 commit comments