simplecov-mcp 1.0.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +98 -50
- data/docs/{ARCHITECTURE.md → dev/ARCHITECTURE.md} +11 -10
- data/docs/dev/BRANCH_ONLY_COVERAGE.md +158 -0
- data/docs/{DEVELOPMENT.md → dev/DEVELOPMENT.md} +2 -1
- data/docs/dev/README.md +10 -0
- data/docs/dev/RELEASING.md +146 -0
- data/docs/{arch-decisions → dev/arch-decisions}/001-x-arch-decision.md +3 -1
- data/docs/{arch-decisions → dev/arch-decisions}/002-x-arch-decision.md +7 -5
- data/docs/{arch-decisions → dev/arch-decisions}/003-x-arch-decision.md +2 -0
- data/docs/{arch-decisions → dev/arch-decisions}/004-x-arch-decision.md +6 -2
- data/docs/{arch-decisions → dev/arch-decisions}/005-x-arch-decision.md +4 -2
- data/docs/{arch-decisions → dev/arch-decisions}/README.md +3 -3
- data/docs/{presentations → dev/presentations}/simplecov-mcp-presentation.md +28 -22
- data/docs/fixtures/demo_project/README.md +9 -0
- data/docs/{ADVANCED_USAGE.md → user/ADVANCED_USAGE.md} +129 -319
- data/docs/user/CLI_FALLBACK_FOR_LLMS.md +34 -0
- data/docs/user/CLI_USAGE.md +750 -0
- data/docs/{ERROR_HANDLING.md → user/ERROR_HANDLING.md} +12 -12
- data/docs/user/EXAMPLES.md +588 -0
- data/docs/user/INSTALLATION.md +130 -0
- data/docs/{LIBRARY_API.md → user/LIBRARY_API.md} +90 -32
- data/docs/{MCP_INTEGRATION.md → user/MCP_INTEGRATION.md} +36 -34
- data/docs/user/README.md +14 -0
- data/docs/{TROUBLESHOOTING.md → user/TROUBLESHOOTING.md} +21 -100
- data/docs/user/V2-BREAKING-CHANGES.md +472 -0
- data/exe/simplecov-mcp +1 -1
- data/lib/simplecov_mcp/{cli_config.rb → app_config.rb} +12 -12
- data/lib/simplecov_mcp/app_context.rb +1 -1
- data/lib/simplecov_mcp/base_tool.rb +66 -38
- data/lib/simplecov_mcp/cli.rb +67 -123
- data/lib/simplecov_mcp/commands/base_command.rb +16 -27
- data/lib/simplecov_mcp/commands/command_factory.rb +8 -2
- data/lib/simplecov_mcp/commands/detailed_command.rb +16 -2
- data/lib/simplecov_mcp/commands/list_command.rb +1 -1
- data/lib/simplecov_mcp/commands/raw_command.rb +18 -2
- data/lib/simplecov_mcp/commands/summary_command.rb +20 -3
- data/lib/simplecov_mcp/commands/totals_command.rb +53 -0
- data/lib/simplecov_mcp/commands/uncovered_command.rb +24 -5
- data/lib/simplecov_mcp/commands/validate_command.rb +60 -0
- data/lib/simplecov_mcp/commands/version_command.rb +19 -4
- data/lib/simplecov_mcp/config_parser.rb +32 -0
- data/lib/simplecov_mcp/constants.rb +3 -3
- data/lib/simplecov_mcp/coverage_reporter.rb +31 -0
- data/lib/simplecov_mcp/error_handler.rb +81 -40
- data/lib/simplecov_mcp/error_handler_factory.rb +2 -2
- data/lib/simplecov_mcp/errors.rb +32 -20
- data/lib/simplecov_mcp/formatters/source_formatter.rb +23 -19
- data/lib/simplecov_mcp/formatters.rb +51 -0
- data/lib/simplecov_mcp/mcp_server.rb +9 -7
- data/lib/simplecov_mcp/mode_detector.rb +6 -5
- data/lib/simplecov_mcp/model.rb +122 -83
- data/lib/simplecov_mcp/option_normalizers.rb +39 -18
- data/lib/simplecov_mcp/option_parser_builder.rb +82 -65
- data/lib/simplecov_mcp/option_parsers/env_options_parser.rb +3 -5
- data/lib/simplecov_mcp/option_parsers/error_helper.rb +18 -17
- data/lib/simplecov_mcp/path_relativizer.rb +17 -14
- data/lib/simplecov_mcp/predicate_evaluator.rb +72 -0
- data/lib/simplecov_mcp/presenters/base_coverage_presenter.rb +1 -3
- data/lib/simplecov_mcp/presenters/coverage_detailed_presenter.rb +1 -3
- data/lib/simplecov_mcp/presenters/coverage_raw_presenter.rb +1 -3
- data/lib/simplecov_mcp/presenters/coverage_summary_presenter.rb +1 -3
- data/lib/simplecov_mcp/presenters/coverage_uncovered_presenter.rb +1 -3
- data/lib/simplecov_mcp/presenters/project_coverage_presenter.rb +1 -3
- data/lib/simplecov_mcp/presenters/project_totals_presenter.rb +27 -0
- data/lib/simplecov_mcp/resolvers/coverage_line_resolver.rb +14 -18
- data/lib/simplecov_mcp/resolvers/resultset_path_resolver.rb +7 -9
- data/lib/simplecov_mcp/resultset_loader.rb +20 -25
- data/lib/simplecov_mcp/staleness_checker.rb +50 -46
- data/lib/simplecov_mcp/table_formatter.rb +64 -0
- data/lib/simplecov_mcp/tools/all_files_coverage_tool.rb +20 -50
- data/lib/simplecov_mcp/tools/coverage_detailed_tool.rb +13 -7
- data/lib/simplecov_mcp/tools/coverage_raw_tool.rb +12 -7
- data/lib/simplecov_mcp/tools/coverage_summary_tool.rb +13 -8
- data/lib/simplecov_mcp/tools/coverage_table_tool.rb +20 -60
- data/lib/simplecov_mcp/tools/coverage_totals_tool.rb +44 -0
- data/lib/simplecov_mcp/tools/help_tool.rb +38 -66
- data/lib/simplecov_mcp/tools/uncovered_lines_tool.rb +13 -8
- data/lib/simplecov_mcp/tools/validate_tool.rb +72 -0
- data/lib/simplecov_mcp/tools/version_tool.rb +7 -14
- data/lib/simplecov_mcp/util.rb +18 -12
- data/lib/simplecov_mcp/version.rb +1 -1
- data/lib/simplecov_mcp.rb +23 -29
- data/spec/all_files_coverage_tool_spec.rb +4 -3
- data/spec/{cli_config_spec.rb → app_config_spec.rb} +31 -26
- data/spec/base_tool_spec.rb +17 -14
- data/spec/cli/show_default_report_spec.rb +2 -2
- data/spec/cli_enumerated_options_spec.rb +31 -9
- data/spec/cli_error_spec.rb +46 -23
- data/spec/cli_format_spec.rb +123 -0
- data/spec/cli_json_options_spec.rb +50 -0
- data/spec/cli_source_spec.rb +11 -63
- data/spec/cli_spec.rb +82 -97
- data/spec/cli_usage_spec.rb +15 -15
- data/spec/commands/base_command_spec.rb +12 -92
- data/spec/commands/command_factory_spec.rb +7 -3
- data/spec/commands/detailed_command_spec.rb +10 -24
- data/spec/commands/list_command_spec.rb +28 -0
- data/spec/commands/raw_command_spec.rb +43 -20
- data/spec/commands/summary_command_spec.rb +10 -23
- data/spec/commands/totals_command_spec.rb +34 -0
- data/spec/commands/uncovered_command_spec.rb +29 -23
- data/spec/commands/validate_command_spec.rb +213 -0
- data/spec/commands/version_command_spec.rb +38 -0
- data/spec/constants_spec.rb +3 -3
- data/spec/coverage_reporter_spec.rb +102 -0
- data/spec/coverage_table_tool_spec.rb +21 -10
- data/spec/coverage_totals_tool_spec.rb +37 -0
- data/spec/error_handler_spec.rb +120 -4
- data/spec/error_mode_spec.rb +18 -22
- data/spec/errors_edge_cases_spec.rb +101 -28
- data/spec/errors_stale_spec.rb +34 -0
- data/spec/file_based_mcp_tools_spec.rb +6 -6
- data/spec/fixtures/project1/lib/bar.rb +2 -0
- data/spec/fixtures/project1/lib/foo.rb +2 -0
- data/spec/help_tool_spec.rb +2 -18
- data/spec/integration_spec.rb +114 -170
- data/spec/logging_fallback_spec.rb +3 -3
- data/spec/mcp_server_integration_spec.rb +1 -1
- data/spec/mcp_server_spec.rb +70 -53
- data/spec/mode_detector_spec.rb +46 -41
- data/spec/model_error_handling_spec.rb +141 -82
- data/spec/model_staleness_spec.rb +13 -13
- data/spec/option_normalizers_spec.rb +111 -112
- data/spec/option_parsers/env_options_parser_spec.rb +25 -37
- data/spec/option_parsers/error_helper_spec.rb +56 -56
- data/spec/path_relativizer_spec.rb +15 -0
- data/spec/presenters/coverage_detailed_presenter_spec.rb +1 -1
- data/spec/presenters/coverage_summary_presenter_spec.rb +1 -1
- data/spec/presenters/coverage_uncovered_presenter_spec.rb +1 -1
- data/spec/presenters/project_coverage_presenter_spec.rb +9 -8
- data/spec/presenters/project_totals_presenter_spec.rb +144 -0
- data/spec/resolvers/coverage_line_resolver_spec.rb +261 -36
- data/spec/resolvers/resultset_path_resolver_spec.rb +13 -8
- data/spec/shared_examples/file_based_mcp_tools.rb +23 -18
- data/spec/shared_examples/formatted_command_examples.rb +64 -0
- data/spec/simple_cov_mcp_module_spec.rb +24 -3
- data/spec/simplecov_mcp/formatters/source_formatter_spec.rb +267 -0
- data/spec/simplecov_mcp/formatters_spec.rb +76 -0
- data/spec/simplecov_mcp/presenters/base_coverage_presenter_spec.rb +79 -0
- data/spec/simplecov_mcp_model_spec.rb +99 -49
- data/spec/simplecov_mcp_opts_spec.rb +42 -39
- data/spec/spec_helper.rb +27 -92
- data/spec/staleness_checker_spec.rb +10 -9
- data/spec/staleness_more_spec.rb +4 -4
- data/spec/support/cli_helpers.rb +22 -0
- data/spec/support/control_flow_helpers.rb +20 -0
- data/spec/support/fake_mcp.rb +40 -0
- data/spec/support/io_helpers.rb +29 -0
- data/spec/support/mcp_helpers.rb +35 -0
- data/spec/support/mcp_runner.rb +10 -8
- data/spec/support/mocking_helpers.rb +30 -0
- data/spec/table_format_spec.rb +70 -0
- data/spec/tools/validate_tool_spec.rb +132 -0
- data/spec/tools_error_handling_spec.rb +34 -48
- data/spec/util_spec.rb +5 -4
- data/spec/version_spec.rb +7 -7
- data/spec/version_tool_spec.rb +20 -22
- metadata +90 -23
- data/docs/BRANCH_ONLY_COVERAGE.md +0 -81
- data/docs/CLI_USAGE.md +0 -637
- data/docs/EXAMPLES.md +0 -430
- data/docs/INSTALLATION.md +0 -352
- data/spec/cli_success_predicate_spec.rb +0 -141
data/spec/error_mode_spec.rb
CHANGED
|
@@ -7,8 +7,8 @@ RSpec.describe 'Error Mode System' do
|
|
|
7
7
|
Class.new do
|
|
8
8
|
attr_reader :messages
|
|
9
9
|
|
|
10
|
-
def initialize
|
|
11
|
-
def error(msg)
|
|
10
|
+
def initialize = @messages = []
|
|
11
|
+
def error(msg) = @messages << msg
|
|
12
12
|
end.new
|
|
13
13
|
end
|
|
14
14
|
|
|
@@ -27,8 +27,8 @@ RSpec.describe 'Error Mode System' do
|
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
-
context 'with error_mode: :
|
|
31
|
-
subject(:handler) { SimpleCovMcp::ErrorHandler.new(error_mode: :
|
|
30
|
+
context 'with error_mode: :log' do
|
|
31
|
+
subject(:handler) { SimpleCovMcp::ErrorHandler.new(error_mode: :log, logger: test_logger) }
|
|
32
32
|
|
|
33
33
|
it 'logs errors but not stack traces' do
|
|
34
34
|
expect(handler.log_errors?).to be true
|
|
@@ -41,8 +41,8 @@ RSpec.describe 'Error Mode System' do
|
|
|
41
41
|
end
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
context 'with error_mode: :
|
|
45
|
-
subject(:handler) { SimpleCovMcp::ErrorHandler.new(error_mode: :
|
|
44
|
+
context 'with error_mode: :debug' do
|
|
45
|
+
subject(:handler) { SimpleCovMcp::ErrorHandler.new(error_mode: :debug, logger: test_logger) }
|
|
46
46
|
|
|
47
47
|
it 'logs errors with stack traces' do
|
|
48
48
|
expect(handler.log_errors?).to be true
|
|
@@ -51,7 +51,7 @@ RSpec.describe 'Error Mode System' do
|
|
|
51
51
|
# Create an error with a proper backtrace
|
|
52
52
|
begin
|
|
53
53
|
raise StandardError, 'Test error message'
|
|
54
|
-
rescue
|
|
54
|
+
rescue => e
|
|
55
55
|
handler.handle_error(e, context: 'test', reraise: false)
|
|
56
56
|
end
|
|
57
57
|
|
|
@@ -64,14 +64,14 @@ RSpec.describe 'Error Mode System' do
|
|
|
64
64
|
|
|
65
65
|
describe 'ErrorHandlerFactory' do
|
|
66
66
|
it 'creates handlers with correct modes' do
|
|
67
|
-
cli_handler = SimpleCovMcp::ErrorHandlerFactory.for_cli(error_mode: :
|
|
68
|
-
expect(cli_handler.error_mode).to eq(:
|
|
67
|
+
cli_handler = SimpleCovMcp::ErrorHandlerFactory.for_cli(error_mode: :debug)
|
|
68
|
+
expect(cli_handler.error_mode).to eq(:debug)
|
|
69
69
|
|
|
70
70
|
lib_handler = SimpleCovMcp::ErrorHandlerFactory.for_library(error_mode: :off)
|
|
71
71
|
expect(lib_handler.error_mode).to eq(:off)
|
|
72
72
|
|
|
73
|
-
mcp_handler = SimpleCovMcp::ErrorHandlerFactory.for_mcp_server(error_mode: :
|
|
74
|
-
expect(mcp_handler.error_mode).to eq(:
|
|
73
|
+
mcp_handler = SimpleCovMcp::ErrorHandlerFactory.for_mcp_server(error_mode: :log)
|
|
74
|
+
expect(mcp_handler.error_mode).to eq(:log)
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
77
|
|
|
@@ -82,13 +82,13 @@ RSpec.describe 'Error Mode System' do
|
|
|
82
82
|
test_error = StandardError.new('Test MCP error')
|
|
83
83
|
|
|
84
84
|
# Test different error modes
|
|
85
|
-
[:off, :
|
|
85
|
+
[:off, :log, :debug].each do |mode|
|
|
86
86
|
expect(SimpleCovMcp::ErrorHandlerFactory)
|
|
87
87
|
.to receive(:for_mcp_server).with(error_mode: mode).and_call_original
|
|
88
88
|
|
|
89
89
|
response = SimpleCovMcp::BaseTool.handle_mcp_error(test_error, 'TestTool', error_mode: mode)
|
|
90
90
|
expect(response).to be_a(MCP::Tool::Response)
|
|
91
|
-
expect(response.payload.first[
|
|
91
|
+
expect(response.payload.first['text']).to include('Error:')
|
|
92
92
|
end
|
|
93
93
|
end
|
|
94
94
|
end
|
|
@@ -101,21 +101,17 @@ RSpec.describe 'Error Mode System' do
|
|
|
101
101
|
|
|
102
102
|
# Test that the option parser accepts the flag
|
|
103
103
|
expect do
|
|
104
|
-
cli.send(:parse_options!, ['--error-mode', '
|
|
104
|
+
cli.send(:parse_options!, ['--error-mode', 'debug', 'summary', 'lib/foo.rb'])
|
|
105
105
|
end.not_to raise_error
|
|
106
106
|
|
|
107
|
-
expect(cli.config.error_mode).to eq(:
|
|
107
|
+
expect(cli.config.error_mode).to eq(:debug)
|
|
108
108
|
end
|
|
109
109
|
|
|
110
110
|
it 'creates error handler with specified mode' do
|
|
111
111
|
cli = SimpleCovMcp::CoverageCLI.new
|
|
112
112
|
cli.send(:parse_options!, ['--error-mode', 'off', 'summary', 'lib/foo.rb'])
|
|
113
113
|
|
|
114
|
-
|
|
115
|
-
cli.send(:ensure_error_handler)
|
|
116
|
-
|
|
117
|
-
error_handler = cli.instance_variable_get(:@error_handler)
|
|
118
|
-
expect(error_handler.error_mode).to eq(:off)
|
|
114
|
+
expect(cli.send(:error_handler).error_mode).to eq(:off)
|
|
119
115
|
end
|
|
120
116
|
|
|
121
117
|
it 'validates error mode values' do
|
|
@@ -136,8 +132,8 @@ RSpec.describe 'Error Mode System' do
|
|
|
136
132
|
|
|
137
133
|
it 'accepts all valid error modes' do
|
|
138
134
|
expect { SimpleCovMcp::ErrorHandler.new(error_mode: :off) }.not_to raise_error
|
|
139
|
-
expect { SimpleCovMcp::ErrorHandler.new(error_mode: :
|
|
140
|
-
expect { SimpleCovMcp::ErrorHandler.new(error_mode: :
|
|
135
|
+
expect { SimpleCovMcp::ErrorHandler.new(error_mode: :log) }.not_to raise_error
|
|
136
|
+
expect { SimpleCovMcp::ErrorHandler.new(error_mode: :debug) }.not_to raise_error
|
|
141
137
|
end
|
|
142
138
|
end
|
|
143
139
|
end
|
|
@@ -2,7 +2,66 @@
|
|
|
2
2
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
|
-
RSpec.describe
|
|
5
|
+
RSpec.describe SimpleCovMcp do
|
|
6
|
+
describe SimpleCovMcp::ConfigurationError do
|
|
7
|
+
describe '#user_friendly_message' do
|
|
8
|
+
it 'prefixes message with "Configuration error:"' do
|
|
9
|
+
error = described_class.new('Invalid option value')
|
|
10
|
+
|
|
11
|
+
expect(error.user_friendly_message).to eq('Configuration error: Invalid option value')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'handles empty message' do
|
|
15
|
+
error = described_class.new('')
|
|
16
|
+
|
|
17
|
+
expect(error.user_friendly_message).to eq('Configuration error: ')
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it 'handles nil message' do
|
|
21
|
+
# When nil is passed to StandardError, it uses the class name as the message
|
|
22
|
+
error = described_class.new(nil)
|
|
23
|
+
|
|
24
|
+
expect(error.user_friendly_message).to eq('Configuration error: SimpleCovMcp::ConfigurationError')
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
describe SimpleCovMcp::ResultsetNotFoundError do
|
|
31
|
+
describe '#user_friendly_message' do
|
|
32
|
+
it 'includes helpful tips in CLI mode' do
|
|
33
|
+
# Create a CLI context (not MCP mode)
|
|
34
|
+
error_handler = SimpleCovMcp::ErrorHandlerFactory.for_cli
|
|
35
|
+
context = SimpleCovMcp.create_context(error_handler: error_handler, mode: :cli)
|
|
36
|
+
SimpleCovMcp.with_context(context) do
|
|
37
|
+
error = described_class.new('Coverage data not found')
|
|
38
|
+
message = error.user_friendly_message
|
|
39
|
+
|
|
40
|
+
expect(message).to include(
|
|
41
|
+
'File error: Coverage data not found',
|
|
42
|
+
'Try one of the following:',
|
|
43
|
+
'cd to a directory containing coverage/.resultset.json',
|
|
44
|
+
'Specify a resultset: simplecov-mcp -r PATH',
|
|
45
|
+
'Use -h for help: simplecov-mcp -h'
|
|
46
|
+
)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'does not include helpful tips in MCP mode' do
|
|
51
|
+
# Create an MCP context
|
|
52
|
+
error_handler = SimpleCovMcp::ErrorHandlerFactory.for_mcp_server
|
|
53
|
+
context = SimpleCovMcp.create_context(error_handler: error_handler, mode: :mcp)
|
|
54
|
+
SimpleCovMcp.with_context(context) do
|
|
55
|
+
error = described_class.new('Coverage data not found')
|
|
56
|
+
message = error.user_friendly_message
|
|
57
|
+
|
|
58
|
+
expect(message).to eq('File error: Coverage data not found')
|
|
59
|
+
expect(message).not_to include('Try one of the following:')
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
6
65
|
describe SimpleCovMcp::CoverageDataStaleError do
|
|
7
66
|
describe 'time formatting edge cases' do
|
|
8
67
|
it 'handles invalid epoch seconds gracefully in rescue path' do
|
|
@@ -12,7 +71,7 @@ RSpec.describe 'SimpleCovMcp error edge cases' do
|
|
|
12
71
|
raise ArgumentError, "Can't convert"
|
|
13
72
|
end
|
|
14
73
|
|
|
15
|
-
error =
|
|
74
|
+
error = described_class.new(
|
|
16
75
|
'Test error',
|
|
17
76
|
nil,
|
|
18
77
|
file_path: 'test.rb',
|
|
@@ -34,7 +93,7 @@ RSpec.describe 'SimpleCovMcp error edge cases' do
|
|
|
34
93
|
'unparseable_time_string'
|
|
35
94
|
end
|
|
36
95
|
|
|
37
|
-
error =
|
|
96
|
+
error = described_class.new(
|
|
38
97
|
'Test error',
|
|
39
98
|
nil,
|
|
40
99
|
file_path: 'test.rb',
|
|
@@ -63,7 +122,7 @@ RSpec.describe 'SimpleCovMcp error edge cases' do
|
|
|
63
122
|
raise ArgumentError, "Can't convert"
|
|
64
123
|
end
|
|
65
124
|
|
|
66
|
-
error =
|
|
125
|
+
error = described_class.new(
|
|
67
126
|
'Test error',
|
|
68
127
|
nil,
|
|
69
128
|
file_path: 'test.rb',
|
|
@@ -81,9 +140,9 @@ RSpec.describe 'SimpleCovMcp error edge cases' do
|
|
|
81
140
|
end
|
|
82
141
|
|
|
83
142
|
describe 'default message generation' do
|
|
84
|
-
it 'uses default message when message is nil' do
|
|
85
|
-
error =
|
|
86
|
-
nil, # No message provided
|
|
143
|
+
it 'uses default message when message is nil with file_path' do
|
|
144
|
+
error = described_class.new(
|
|
145
|
+
nil, # No message provided - triggers default_message
|
|
87
146
|
nil,
|
|
88
147
|
file_path: 'test.rb',
|
|
89
148
|
file_mtime: Time.at(2000),
|
|
@@ -91,52 +150,66 @@ RSpec.describe 'SimpleCovMcp error edge cases' do
|
|
|
91
150
|
)
|
|
92
151
|
|
|
93
152
|
message = error.user_friendly_message
|
|
94
|
-
#
|
|
95
|
-
|
|
96
|
-
expect(message).to include('Coverage data')
|
|
97
|
-
expect(message).to include('stale')
|
|
153
|
+
# default_message returns "Coverage data appears stale for test.rb"
|
|
154
|
+
expect(message).to include('Coverage data appears stale for test.rb')
|
|
98
155
|
# File path should appear in the details section
|
|
99
156
|
expect(message).to match(/File\s+-/)
|
|
100
157
|
end
|
|
101
158
|
|
|
102
159
|
it 'uses generic default message when file_path is nil' do
|
|
103
|
-
|
|
104
|
-
|
|
160
|
+
# This tests the fallback path when file_path is nil: fp = file_path || 'file'
|
|
161
|
+
error = described_class.new(
|
|
162
|
+
nil, # No message - triggers default_message
|
|
105
163
|
nil,
|
|
106
|
-
file_path: nil, # No file path
|
|
164
|
+
file_path: nil, # No file path - triggers 'file' fallback
|
|
107
165
|
file_mtime: Time.at(2000),
|
|
108
166
|
cov_timestamp: 1000
|
|
109
167
|
)
|
|
110
168
|
|
|
111
169
|
message = error.user_friendly_message
|
|
112
|
-
# When file_path is nil,
|
|
113
|
-
expect(message).to include('Coverage data')
|
|
114
|
-
expect(message).to include('file')
|
|
170
|
+
# When file_path is nil, default_message returns "Coverage data appears stale for file"
|
|
171
|
+
expect(message).to include('Coverage data appears stale for file')
|
|
115
172
|
end
|
|
116
173
|
end
|
|
117
174
|
end
|
|
118
175
|
|
|
119
176
|
describe SimpleCovMcp::CoverageDataProjectStaleError do
|
|
120
177
|
describe 'default message generation' do
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
178
|
+
# These tests exercise the private default_message method
|
|
179
|
+
it 'includes project stale info when message is nil' do
|
|
180
|
+
error = described_class.new(
|
|
181
|
+
nil, # StandardError sets message to class name when nil
|
|
124
182
|
nil,
|
|
125
183
|
cov_timestamp: 1000,
|
|
126
184
|
newer_files: ['file1.rb', 'file2.rb']
|
|
127
185
|
)
|
|
128
186
|
|
|
129
187
|
message = error.user_friendly_message
|
|
130
|
-
#
|
|
131
|
-
expect(message).to include('Coverage data')
|
|
132
|
-
expect(message).to include('
|
|
188
|
+
# user_friendly_message prefixes with "Coverage data stale (project):"
|
|
189
|
+
expect(message).to include('Coverage data stale (project)')
|
|
190
|
+
expect(message).to include('Newer files')
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
it 'exercises default_message directly via send' do
|
|
194
|
+
# Directly test the private default_message method for coverage
|
|
195
|
+
# This is necessary because user_friendly_message uses `message || default_message`
|
|
196
|
+
# and StandardError sets message to class name when initialized with nil
|
|
197
|
+
error = described_class.new(
|
|
198
|
+
'explicit message',
|
|
199
|
+
nil,
|
|
200
|
+
cov_timestamp: 1000
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
# Call the private default_message method directly
|
|
204
|
+
result = error.send(:default_message)
|
|
205
|
+
expect(result).to eq('Coverage data appears stale for project')
|
|
133
206
|
end
|
|
134
207
|
end
|
|
135
208
|
|
|
136
209
|
describe 'large file list truncation' do
|
|
137
210
|
it 'shows all files when there are 10 or fewer deleted files' do
|
|
138
211
|
deleted_files = (1..10).map { |i| "deleted_file_#{i}.rb" }
|
|
139
|
-
error =
|
|
212
|
+
error = described_class.new(
|
|
140
213
|
'Test error',
|
|
141
214
|
nil,
|
|
142
215
|
cov_timestamp: 1000,
|
|
@@ -153,7 +226,7 @@ RSpec.describe 'SimpleCovMcp error edge cases' do
|
|
|
153
226
|
|
|
154
227
|
it 'truncates and shows ellipsis when there are more than 10 deleted files' do
|
|
155
228
|
deleted_files = (1..15).map { |i| "deleted_file_#{i}.rb" }
|
|
156
|
-
error =
|
|
229
|
+
error = described_class.new(
|
|
157
230
|
'Test error',
|
|
158
231
|
nil,
|
|
159
232
|
cov_timestamp: 1000,
|
|
@@ -176,7 +249,7 @@ RSpec.describe 'SimpleCovMcp error edge cases' do
|
|
|
176
249
|
|
|
177
250
|
it 'shows all files when there are 10 or fewer missing files' do
|
|
178
251
|
missing_files = (1..10).map { |i| "missing_file_#{i}.rb" }
|
|
179
|
-
error =
|
|
252
|
+
error = described_class.new(
|
|
180
253
|
'Test error',
|
|
181
254
|
nil,
|
|
182
255
|
cov_timestamp: 1000,
|
|
@@ -193,7 +266,7 @@ RSpec.describe 'SimpleCovMcp error edge cases' do
|
|
|
193
266
|
|
|
194
267
|
it 'truncates and shows ellipsis when there are more than 10 missing files' do
|
|
195
268
|
missing_files = (1..12).map { |i| "missing_file_#{i}.rb" }
|
|
196
|
-
error =
|
|
269
|
+
error = described_class.new(
|
|
197
270
|
'Test error',
|
|
198
271
|
nil,
|
|
199
272
|
cov_timestamp: 1000,
|
|
@@ -214,7 +287,7 @@ RSpec.describe 'SimpleCovMcp error edge cases' do
|
|
|
214
287
|
|
|
215
288
|
it 'truncates and shows ellipsis when there are more than 10 newer files' do
|
|
216
289
|
newer_files = (1..20).map { |i| "newer_file_#{i}.rb" }
|
|
217
|
-
error =
|
|
290
|
+
error = described_class.new(
|
|
218
291
|
'Test error',
|
|
219
292
|
nil,
|
|
220
293
|
cov_timestamp: 1000,
|
data/spec/errors_stale_spec.rb
CHANGED
|
@@ -46,4 +46,38 @@ RSpec.describe SimpleCovMcp::CoverageDataStaleError do
|
|
|
46
46
|
expect(msg).to match(/Coverage\s*-\s*time:\s*not found.*lines: 0/m)
|
|
47
47
|
expect(msg).not_to include('Delta')
|
|
48
48
|
end
|
|
49
|
+
|
|
50
|
+
it 'uses default message when message is nil' do
|
|
51
|
+
err = described_class.new(
|
|
52
|
+
nil,
|
|
53
|
+
nil,
|
|
54
|
+
file_path: 'lib/example.rb',
|
|
55
|
+
file_mtime: Time.now,
|
|
56
|
+
cov_timestamp: Time.now.to_i - 1000,
|
|
57
|
+
src_len: 10,
|
|
58
|
+
cov_len: 8,
|
|
59
|
+
resultset_path: '/coverage/.resultset.json'
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
msg = err.user_friendly_message
|
|
63
|
+
expect(msg).to include('Coverage data stale:')
|
|
64
|
+
expect(msg).to include('Coverage data appears stale for lib/example.rb')
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'uses "file" in default message when file_path is also nil' do
|
|
68
|
+
err = described_class.new(
|
|
69
|
+
nil,
|
|
70
|
+
nil,
|
|
71
|
+
file_path: nil,
|
|
72
|
+
file_mtime: nil,
|
|
73
|
+
cov_timestamp: nil,
|
|
74
|
+
src_len: 0,
|
|
75
|
+
cov_len: 0,
|
|
76
|
+
resultset_path: nil
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
msg = err.user_friendly_message
|
|
80
|
+
expect(msg).to include('Coverage data stale:')
|
|
81
|
+
expect(msg).to include('Coverage data appears stale for file')
|
|
82
|
+
end
|
|
49
83
|
end
|
|
@@ -11,7 +11,7 @@ require 'simplecov_mcp/tools/coverage_detailed_tool'
|
|
|
11
11
|
|
|
12
12
|
RSpec.describe 'File-based MCP Tools' do
|
|
13
13
|
# Test each file-based tool using the shared example with its specific configuration
|
|
14
|
-
FILE_BASED_TOOL_CONFIGS.
|
|
14
|
+
FILE_BASED_TOOL_CONFIGS.each_value do |config|
|
|
15
15
|
describe config[:tool_class] do
|
|
16
16
|
it_behaves_like 'a file-based MCP tool', config
|
|
17
17
|
end
|
|
@@ -27,7 +27,7 @@ RSpec.describe 'File-based MCP Tools' do
|
|
|
27
27
|
|
|
28
28
|
it 'all file-based tools accept the same basic parameters' do
|
|
29
29
|
# Test that all tools can be called with the same parameter signature
|
|
30
|
-
FILE_BASED_TOOL_CONFIGS.
|
|
30
|
+
FILE_BASED_TOOL_CONFIGS.each_value do |config|
|
|
31
31
|
model = instance_double(SimpleCovMcp::CoverageModel)
|
|
32
32
|
allow(SimpleCovMcp::CoverageModel).to receive(:new).and_return(model)
|
|
33
33
|
allow(model).to receive(config[:model_method]).and_return(config[:mock_data])
|
|
@@ -46,7 +46,7 @@ RSpec.describe 'File-based MCP Tools' do
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
it 'all file-based tools return JSON resources with consistent structure' do
|
|
49
|
-
FILE_BASED_TOOL_CONFIGS.
|
|
49
|
+
FILE_BASED_TOOL_CONFIGS.each_value do |config|
|
|
50
50
|
model = instance_double(SimpleCovMcp::CoverageModel)
|
|
51
51
|
allow(SimpleCovMcp::CoverageModel).to receive(:new).and_return(model)
|
|
52
52
|
allow(model).to receive(config[:model_method]).and_return(config[:mock_data])
|
|
@@ -79,7 +79,7 @@ RSpec.describe 'File-based MCP Tools' do
|
|
|
79
79
|
config[:expected_keys].include?('summary')
|
|
80
80
|
end
|
|
81
81
|
|
|
82
|
-
summary_tools.
|
|
82
|
+
summary_tools.each_value do |config|
|
|
83
83
|
model = instance_double(SimpleCovMcp::CoverageModel)
|
|
84
84
|
allow(SimpleCovMcp::CoverageModel).to receive(:new).and_return(model)
|
|
85
85
|
allow(model).to receive(config[:model_method]).and_return(config[:mock_data])
|
|
@@ -90,8 +90,8 @@ RSpec.describe 'File-based MCP Tools' do
|
|
|
90
90
|
data = JSON.parse(response.payload.first['text'])
|
|
91
91
|
|
|
92
92
|
if data.key?('summary')
|
|
93
|
-
expect(data['summary']).to include('covered', 'total', '
|
|
94
|
-
expect(data['summary']['
|
|
93
|
+
expect(data['summary']).to include('covered', 'total', 'percentage')
|
|
94
|
+
expect(data['summary']['percentage']).to be_a(Numeric)
|
|
95
95
|
end
|
|
96
96
|
end
|
|
97
97
|
end
|
data/spec/help_tool_spec.rb
CHANGED
|
@@ -20,23 +20,7 @@ RSpec.describe SimpleCovMcp::Tools::HelpTool do
|
|
|
20
20
|
tool_names = data['tools'].map { |entry| entry['tool'] }
|
|
21
21
|
|
|
22
22
|
expect(tool_names).to include('coverage_summary_tool', 'uncovered_lines_tool',
|
|
23
|
-
'all_files_coverage_tool', 'coverage_table_tool', 'version_tool')
|
|
24
|
-
expect(data['tools']).to all(include('use_when', 'avoid_when', 'inputs'
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
it 'filters entries when a query is provided' do
|
|
28
|
-
response = described_class.call(query: 'uncovered', server_context: server_context)
|
|
29
|
-
payload = response.payload.first
|
|
30
|
-
expect(payload['type']).to eq('text')
|
|
31
|
-
data = JSON.parse(payload['text'])
|
|
32
|
-
|
|
33
|
-
expect(data['tools']).not_to be_empty
|
|
34
|
-
expect(data['tools']).to all(satisfy do |entry|
|
|
35
|
-
combined =
|
|
36
|
-
[entry['tool'], entry['label'], entry['use_when'], entry['avoid_when']]
|
|
37
|
-
.compact.join(' ').downcase
|
|
38
|
-
combined.include?('uncovered')
|
|
39
|
-
end)
|
|
40
|
-
expect(data['tools'].map { |entry| entry['tool'] }).to include('uncovered_lines_tool')
|
|
23
|
+
'all_files_coverage_tool', 'coverage_totals_tool', 'coverage_table_tool', 'version_tool')
|
|
24
|
+
expect(data['tools']).to all(include('use_when', 'avoid_when', 'inputs'))
|
|
41
25
|
end
|
|
42
26
|
end
|