simplecov-mcp 1.0.1 → 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 +12 -19
- 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 -88
- 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 +103 -161
- 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 +139 -78
- 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 +97 -47
- 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
|
@@ -3,15 +3,17 @@
|
|
|
3
3
|
require 'spec_helper'
|
|
4
4
|
|
|
5
5
|
RSpec.describe SimpleCovMcp::CoverageModel do
|
|
6
|
-
let(:root) { (FIXTURES_DIR / 'project1').to_s }
|
|
7
6
|
subject(:model) { described_class.new(root: root) }
|
|
8
7
|
|
|
8
|
+
let(:root) { (FIXTURES_DIR / 'project1').to_s }
|
|
9
|
+
|
|
10
|
+
|
|
9
11
|
describe 'initialization error handling' do
|
|
10
12
|
it 'raises FileError when File.read raises Errno::ENOENT directly' do
|
|
11
13
|
# Stub find_resultset to return a path, but File.read to raise ENOENT
|
|
12
14
|
allow(SimpleCovMcp::CovUtil).to receive(:find_resultset)
|
|
13
15
|
.and_return('/some/path/.resultset.json')
|
|
14
|
-
allow(
|
|
16
|
+
allow(JSON).to receive(:load_file).with('/some/path/.resultset.json')
|
|
15
17
|
.and_raise(Errno::ENOENT, 'No such file')
|
|
16
18
|
|
|
17
19
|
expect do
|
|
@@ -35,11 +37,11 @@ RSpec.describe SimpleCovMcp::CoverageModel do
|
|
|
35
37
|
end
|
|
36
38
|
|
|
37
39
|
describe 'summary_for' do
|
|
38
|
-
it 'computes covered/total/
|
|
40
|
+
it 'computes covered/total/percentage' do
|
|
39
41
|
data = model.summary_for('lib/foo.rb')
|
|
40
42
|
expect(data['summary']['total']).to eq(3)
|
|
41
43
|
expect(data['summary']['covered']).to eq(2)
|
|
42
|
-
expect(data['summary']['
|
|
44
|
+
expect(data['summary']['percentage']).to be_within(0.01).of(66.67)
|
|
43
45
|
end
|
|
44
46
|
end
|
|
45
47
|
|
|
@@ -75,35 +77,46 @@ RSpec.describe SimpleCovMcp::CoverageModel do
|
|
|
75
77
|
|
|
76
78
|
describe 'staleness_for' do
|
|
77
79
|
it 'returns the staleness character for a file' do
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
80
|
+
checker = instance_double(SimpleCovMcp::StalenessChecker, off?: false)
|
|
81
|
+
allow(SimpleCovMcp::StalenessChecker).to receive(:new).and_return(checker)
|
|
82
|
+
allow(checker).to receive(:stale_for_file?) do |file_abs, _|
|
|
83
|
+
if file_abs == File.expand_path('lib/foo.rb', root)
|
|
84
|
+
'T'
|
|
85
|
+
else
|
|
86
|
+
false
|
|
85
87
|
end
|
|
88
|
+
end
|
|
86
89
|
|
|
87
90
|
expect(model.staleness_for('lib/foo.rb')).to eq('T')
|
|
88
|
-
expect(model.staleness_for('lib/bar.rb')).to
|
|
91
|
+
expect(model.staleness_for('lib/bar.rb')).to be(false)
|
|
89
92
|
end
|
|
90
93
|
|
|
91
94
|
it 'returns false when an exception occurs during staleness check' do
|
|
92
95
|
# Stub the checker to raise an error
|
|
93
|
-
|
|
96
|
+
checker = instance_double(SimpleCovMcp::StalenessChecker, off?: false)
|
|
97
|
+
allow(SimpleCovMcp::StalenessChecker).to receive(:new).and_return(checker)
|
|
98
|
+
allow(checker).to receive(:stale_for_file?)
|
|
94
99
|
.and_raise(StandardError, 'Something went wrong')
|
|
95
100
|
|
|
96
101
|
# The rescue clause should catch the error and return false
|
|
97
|
-
expect(model.staleness_for('lib/foo.rb')).to
|
|
102
|
+
expect(model.staleness_for('lib/foo.rb')).to be(false)
|
|
98
103
|
end
|
|
99
104
|
|
|
100
105
|
it 'returns false when coverage data is not found for the file' do
|
|
101
106
|
# Try to get staleness for a file that doesn't exist in coverage
|
|
102
|
-
expect(model.staleness_for('lib/nonexistent.rb')).to
|
|
107
|
+
expect(model.staleness_for('lib/nonexistent.rb')).to be(false)
|
|
103
108
|
end
|
|
104
109
|
end
|
|
105
110
|
|
|
106
111
|
describe 'all_files' do
|
|
112
|
+
it 'sorts descending (default) by percentage then by file path' do
|
|
113
|
+
files = model.all_files
|
|
114
|
+
# lib/foo.rb has 66.67%, lib/bar.rb has 33.33%
|
|
115
|
+
expect(files.first['file']).to eq(File.expand_path('lib/foo.rb', root))
|
|
116
|
+
expect(files.first['percentage']).to be_within(0.01).of(66.67)
|
|
117
|
+
expect(files.last['file']).to eq(File.expand_path('lib/bar.rb', root))
|
|
118
|
+
end
|
|
119
|
+
|
|
107
120
|
it 'sorts ascending by percentage then by file path' do
|
|
108
121
|
files = model.all_files(sort_order: :ascending)
|
|
109
122
|
expect(files.first['file']).to eq(File.expand_path('lib/bar.rb', root))
|
|
@@ -151,6 +164,24 @@ RSpec.describe SimpleCovMcp::CoverageModel do
|
|
|
151
164
|
end
|
|
152
165
|
end
|
|
153
166
|
|
|
167
|
+
describe '#project_totals' do
|
|
168
|
+
it 'aggregates coverage totals across all files' do
|
|
169
|
+
totals = model.project_totals
|
|
170
|
+
|
|
171
|
+
expect(totals['lines']).to include('total' => 6, 'covered' => 3, 'uncovered' => 3)
|
|
172
|
+
expect(totals['percentage']).to be_within(0.01).of(50.0)
|
|
173
|
+
expect(totals['files']).to include('total' => 2)
|
|
174
|
+
expect(totals['files']['ok'] + totals['files']['stale']).to eq(totals['files']['total'])
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it 'respects tracked_globs filtering' do
|
|
178
|
+
totals = model.project_totals(tracked_globs: ['lib/foo.rb'])
|
|
179
|
+
|
|
180
|
+
expect(totals['lines']).to include('total' => 3, 'covered' => 2, 'uncovered' => 1)
|
|
181
|
+
expect(totals['files']).to include('total' => 1)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
154
185
|
describe 'resolve method error handling' do
|
|
155
186
|
it 'raises FileError when coverage_lines is nil after lookup' do
|
|
156
187
|
# Stub lookup_lines to return nil without raising
|
|
@@ -164,16 +195,27 @@ RSpec.describe SimpleCovMcp::CoverageModel do
|
|
|
164
195
|
it 'converts Errno::ENOENT to FileNotFoundError during resolve' do
|
|
165
196
|
# We need to trigger Errno::ENOENT inside the resolve method
|
|
166
197
|
# Stub the checker's check_file! method to raise Errno::ENOENT
|
|
167
|
-
|
|
198
|
+
checker = instance_double(SimpleCovMcp::StalenessChecker, off?: false)
|
|
199
|
+
allow(SimpleCovMcp::StalenessChecker).to receive(:new).and_return(checker)
|
|
200
|
+
allow(checker).to receive(:check_file!)
|
|
168
201
|
.and_raise(Errno::ENOENT, 'No such file or directory')
|
|
169
202
|
|
|
170
203
|
# Create a model with staleness checking enabled to trigger the check_file! call
|
|
171
|
-
stale_model = described_class.new(root: root, staleness:
|
|
204
|
+
stale_model = described_class.new(root: root, staleness: :error)
|
|
172
205
|
|
|
173
206
|
expect do
|
|
174
207
|
stale_model.summary_for('lib/foo.rb')
|
|
175
208
|
end.to raise_error(SimpleCovMcp::FileNotFoundError, /File not found/)
|
|
176
209
|
end
|
|
210
|
+
|
|
211
|
+
it 'raises FileError when lookup_lines raises RuntimeError' do
|
|
212
|
+
allow(SimpleCovMcp::CovUtil).to receive(:lookup_lines)
|
|
213
|
+
.and_raise(RuntimeError, 'Could not find coverage data')
|
|
214
|
+
|
|
215
|
+
expect do
|
|
216
|
+
model.summary_for('lib/some_file.rb')
|
|
217
|
+
end.to raise_error(SimpleCovMcp::FileError, /No coverage data found for file/)
|
|
218
|
+
end
|
|
177
219
|
end
|
|
178
220
|
|
|
179
221
|
describe 'resultset directory handling' do
|
|
@@ -194,7 +236,7 @@ RSpec.describe SimpleCovMcp::CoverageModel do
|
|
|
194
236
|
|
|
195
237
|
expect(data['summary']['total']).to eq(5)
|
|
196
238
|
expect(data['summary']['covered']).to eq(3)
|
|
197
|
-
expect(data['summary']['
|
|
239
|
+
expect(data['summary']['percentage']).to be_within(0.01).of(60.0)
|
|
198
240
|
end
|
|
199
241
|
|
|
200
242
|
it 'returns detailed data using branch-derived hits' do
|
|
@@ -234,6 +276,40 @@ RSpec.describe SimpleCovMcp::CoverageModel do
|
|
|
234
276
|
|
|
235
277
|
describe 'multiple suites in resultset' do
|
|
236
278
|
let(:resultset_path) { '/tmp/multi_suite_resultset.json' }
|
|
279
|
+
let(:suite_a_cov) do
|
|
280
|
+
{
|
|
281
|
+
File.join(root, 'lib', 'foo.rb') => { 'lines' => [1, 0, nil, 2] }
|
|
282
|
+
}
|
|
283
|
+
end
|
|
284
|
+
let(:suite_b_cov) do
|
|
285
|
+
{
|
|
286
|
+
File.join(root, 'lib', 'bar.rb') => { 'lines' => [0, 1, 1] }
|
|
287
|
+
}
|
|
288
|
+
end
|
|
289
|
+
let(:resultset) do
|
|
290
|
+
{
|
|
291
|
+
'RSpec' => { 'timestamp' => 100, 'coverage' => suite_a_cov },
|
|
292
|
+
'Cucumber' => { 'timestamp' => 200, 'coverage' => suite_b_cov }
|
|
293
|
+
}
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
let(:shared_file) { File.join(root, 'lib', 'foo.rb') }
|
|
297
|
+
let(:suite_a_cov_combined) do
|
|
298
|
+
{
|
|
299
|
+
shared_file => { 'lines' => [1, 0, nil, 0] }
|
|
300
|
+
}
|
|
301
|
+
end
|
|
302
|
+
let(:suite_b_cov_combined) do
|
|
303
|
+
{
|
|
304
|
+
shared_file => { 'lines' => [0, 3, nil, 1] }
|
|
305
|
+
}
|
|
306
|
+
end
|
|
307
|
+
let(:resultset_combined) do
|
|
308
|
+
{
|
|
309
|
+
'RSpec' => { 'timestamp' => 100, 'coverage' => suite_a_cov_combined },
|
|
310
|
+
'Cucumber' => { 'timestamp' => 150, 'coverage' => suite_b_cov_combined }
|
|
311
|
+
}
|
|
312
|
+
end
|
|
237
313
|
|
|
238
314
|
before do
|
|
239
315
|
allow(SimpleCovMcp::CovUtil).to receive(:find_resultset).and_wrap_original do
|
|
@@ -246,23 +322,11 @@ RSpec.describe SimpleCovMcp::CoverageModel do
|
|
|
246
322
|
original.call(search_root, resultset: resultset)
|
|
247
323
|
end
|
|
248
324
|
end
|
|
249
|
-
|
|
325
|
+
# This line might need to be removed as we now mock JSON.load_file directly
|
|
250
326
|
end
|
|
251
327
|
|
|
252
328
|
it 'merges coverage data from multiple suites while keeping latest timestamp' do
|
|
253
|
-
|
|
254
|
-
File.join(root, 'lib', 'foo.rb') => { 'lines' => [1, 0, nil, 2] }
|
|
255
|
-
}
|
|
256
|
-
suite_b_cov = {
|
|
257
|
-
File.join(root, 'lib', 'bar.rb') => { 'lines' => [0, 1, 1] }
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
resultset = {
|
|
261
|
-
'RSpec' => { 'timestamp' => 100, 'coverage' => suite_a_cov },
|
|
262
|
-
'Cucumber' => { 'timestamp' => 200, 'coverage' => suite_b_cov }
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
allow(File).to receive(:read).with(resultset_path).and_return(resultset.to_json)
|
|
329
|
+
allow(JSON).to receive(:load_file).with(resultset_path).and_return(resultset)
|
|
266
330
|
|
|
267
331
|
model = described_class.new(root: root)
|
|
268
332
|
files = model.all_files(sort_order: :ascending)
|
|
@@ -274,20 +338,7 @@ RSpec.describe SimpleCovMcp::CoverageModel do
|
|
|
274
338
|
end
|
|
275
339
|
|
|
276
340
|
it 'combines coverage arrays when the same file appears in multiple suites' do
|
|
277
|
-
|
|
278
|
-
suite_a_cov = {
|
|
279
|
-
shared_file => { 'lines' => [1, 0, nil, 0] }
|
|
280
|
-
}
|
|
281
|
-
suite_b_cov = {
|
|
282
|
-
shared_file => { 'lines' => [0, 3, nil, 1] }
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
resultset = {
|
|
286
|
-
'RSpec' => { 'timestamp' => 100, 'coverage' => suite_a_cov },
|
|
287
|
-
'Cucumber' => { 'timestamp' => 150, 'coverage' => suite_b_cov }
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
allow(File).to receive(:read).with(resultset_path).and_return(resultset.to_json)
|
|
341
|
+
allow(JSON).to receive(:load_file).with(resultset_path).and_return(resultset_combined)
|
|
291
342
|
|
|
292
343
|
model = described_class.new(root: root)
|
|
293
344
|
detailed = model.detailed_for('lib/foo.rb')
|
|
@@ -367,7 +418,6 @@ RSpec.describe SimpleCovMcp::CoverageModel do
|
|
|
367
418
|
|
|
368
419
|
it 'accepts sort_order parameter' do
|
|
369
420
|
# Test that sort_order parameter is passed through correctly
|
|
370
|
-
rows_desc = model.all_files(sort_order: :descending)
|
|
371
421
|
output_asc = model.format_table(sort_order: :ascending)
|
|
372
422
|
output_desc = model.format_table(sort_order: :descending)
|
|
373
423
|
|
|
@@ -14,42 +14,45 @@ RSpec.describe 'SIMPLECOV_MCP_OPTS Environment Variable' do
|
|
|
14
14
|
|
|
15
15
|
describe 'CLI option parsing from environment' do
|
|
16
16
|
it 'parses simple options from SIMPLECOV_MCP_OPTS' do
|
|
17
|
-
ENV['SIMPLECOV_MCP_OPTS'] = '--error-mode off --json'
|
|
17
|
+
ENV['SIMPLECOV_MCP_OPTS'] = '--error-mode off --format json'
|
|
18
|
+
env_opts = SimpleCovMcp.send(:extract_env_opts)
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
silence_output
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
puts "DEBUG: Caught exception: #{e.class}: #{e.message}" if ENV['DEBUG']
|
|
20
|
+
swallow_system_exit do
|
|
21
|
+
silence_output do
|
|
22
|
+
cli.send(:run, env_opts + ['summary', 'lib/foo.rb'])
|
|
23
|
+
end
|
|
24
24
|
end
|
|
25
|
-
|
|
25
|
+
rescue SimpleCovMcp::Error => e
|
|
26
|
+
# Expected to fail due to missing file, but options should be parsed
|
|
27
|
+
puts "DEBUG: Caught exception: #{e.class}: #{e.message}" if ENV['DEBUG']
|
|
28
|
+
ensure
|
|
26
29
|
expect(cli.config.error_mode).to eq(:off)
|
|
27
|
-
expect(cli.config.
|
|
30
|
+
expect(cli.config.format).to eq(:json)
|
|
28
31
|
end
|
|
29
32
|
|
|
30
33
|
it 'handles quoted options with spaces' do
|
|
31
34
|
test_path = File.join(Dir.tmpdir, 'test path with spaces', '.resultset.json')
|
|
32
35
|
ENV['SIMPLECOV_MCP_OPTS'] = "--resultset \"#{test_path}\""
|
|
36
|
+
env_opts = SimpleCovMcp.send(:extract_env_opts)
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
# load the (non-existent) resultset, preventing it from leaking to the console.
|
|
39
|
-
silence_output do
|
|
40
|
-
cli.send(:run, ['--help'])
|
|
38
|
+
exit_status = swallow_system_exit do
|
|
39
|
+
silence_output do
|
|
40
|
+
cli.send(:run, env_opts + ['--help'])
|
|
41
|
+
end
|
|
41
42
|
end
|
|
42
43
|
|
|
44
|
+
expect(exit_status).to eq(0) # --help exits cleanly
|
|
43
45
|
expect(cli.config.resultset).to eq(test_path)
|
|
44
46
|
end
|
|
45
47
|
|
|
46
48
|
it 'supports setting log-file to stdout from environment' do
|
|
47
49
|
ENV['SIMPLECOV_MCP_OPTS'] = '--log-file stdout'
|
|
50
|
+
env_opts = SimpleCovMcp.send(:extract_env_opts)
|
|
48
51
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
52
|
+
swallow_system_exit do
|
|
53
|
+
silence_output do
|
|
54
|
+
cli.send(:run, env_opts + ['--help'])
|
|
55
|
+
end
|
|
53
56
|
end
|
|
54
57
|
|
|
55
58
|
expect(cli.config.log_file).to eq('stdout')
|
|
@@ -57,15 +60,17 @@ RSpec.describe 'SIMPLECOV_MCP_OPTS Environment Variable' do
|
|
|
57
60
|
|
|
58
61
|
it 'command line arguments override environment options' do
|
|
59
62
|
ENV['SIMPLECOV_MCP_OPTS'] = '--error-mode off'
|
|
63
|
+
env_opts = SimpleCovMcp.send(:extract_env_opts)
|
|
60
64
|
|
|
61
65
|
begin
|
|
62
|
-
|
|
66
|
+
args = env_opts + ['--error-mode', 'debug', 'summary', 'lib/foo.rb']
|
|
67
|
+
silence_output { cli.send(:run, args) }
|
|
63
68
|
rescue SystemExit, SimpleCovMcp::Error
|
|
64
69
|
# Expected to fail, but options should be parsed
|
|
65
70
|
end
|
|
66
71
|
|
|
67
72
|
# Command line should override environment
|
|
68
|
-
expect(cli.config.error_mode).to eq(:
|
|
73
|
+
expect(cli.config.error_mode).to eq(:debug)
|
|
69
74
|
end
|
|
70
75
|
|
|
71
76
|
it 'handles malformed SIMPLECOV_MCP_OPTS gracefully' do
|
|
@@ -78,13 +83,13 @@ RSpec.describe 'SIMPLECOV_MCP_OPTS Environment Variable' do
|
|
|
78
83
|
|
|
79
84
|
it 'returns empty array when SIMPLECOV_MCP_OPTS is not set' do
|
|
80
85
|
# ENV is already cleared by around block
|
|
81
|
-
opts =
|
|
86
|
+
opts = SimpleCovMcp.send(:extract_env_opts)
|
|
82
87
|
expect(opts).to eq([])
|
|
83
88
|
end
|
|
84
89
|
|
|
85
90
|
it 'returns empty array when SIMPLECOV_MCP_OPTS is empty' do
|
|
86
91
|
ENV['SIMPLECOV_MCP_OPTS'] = ''
|
|
87
|
-
opts =
|
|
92
|
+
opts = SimpleCovMcp.send(:extract_env_opts)
|
|
88
93
|
expect(opts).to eq([])
|
|
89
94
|
end
|
|
90
95
|
end
|
|
@@ -96,7 +101,7 @@ RSpec.describe 'SIMPLECOV_MCP_OPTS Environment Variable' do
|
|
|
96
101
|
# This would normally be MCP mode (no TTY, no subcommand)
|
|
97
102
|
stdin = double('stdin', tty?: false)
|
|
98
103
|
|
|
99
|
-
env_opts = SimpleCovMcp.send(:
|
|
104
|
+
env_opts = SimpleCovMcp.send(:extract_env_opts)
|
|
100
105
|
full_argv = env_opts + []
|
|
101
106
|
|
|
102
107
|
expect(SimpleCovMcp::ModeDetector.cli_mode?(full_argv, stdin: stdin)).to be true
|
|
@@ -106,7 +111,7 @@ RSpec.describe 'SIMPLECOV_MCP_OPTS Environment Variable' do
|
|
|
106
111
|
ENV['SIMPLECOV_MCP_OPTS'] = '--option "unclosed quote'
|
|
107
112
|
|
|
108
113
|
# Should return empty array and not crash
|
|
109
|
-
opts = SimpleCovMcp.send(:
|
|
114
|
+
opts = SimpleCovMcp.send(:extract_env_opts)
|
|
110
115
|
expect(opts).to eq([])
|
|
111
116
|
end
|
|
112
117
|
|
|
@@ -114,15 +119,14 @@ RSpec.describe 'SIMPLECOV_MCP_OPTS Environment Variable' do
|
|
|
114
119
|
ENV['SIMPLECOV_MCP_OPTS'] = '--force-cli'
|
|
115
120
|
|
|
116
121
|
# Mock STDIN to not be a TTY (would normally trigger MCP server mode)
|
|
117
|
-
allow(
|
|
118
|
-
|
|
119
|
-
# Stub exit to prevent process termination
|
|
120
|
-
allow_any_instance_of(Object).to receive(:exit)
|
|
122
|
+
allow($stdin).to receive(:tty?).and_return(false)
|
|
121
123
|
|
|
122
124
|
# Run with --help which should produce help output
|
|
123
125
|
output = nil
|
|
124
126
|
silence_output do |out, err|
|
|
125
|
-
|
|
127
|
+
swallow_system_exit do
|
|
128
|
+
SimpleCovMcp.run(['--help'])
|
|
129
|
+
end
|
|
126
130
|
output = out.string + err.string
|
|
127
131
|
end
|
|
128
132
|
|
|
@@ -135,7 +139,7 @@ RSpec.describe 'SIMPLECOV_MCP_OPTS Environment Variable' do
|
|
|
135
139
|
ENV['SIMPLECOV_MCP_OPTS'] = ''
|
|
136
140
|
|
|
137
141
|
# Mock STDIN to not be a TTY and to provide valid JSON-RPC
|
|
138
|
-
allow(
|
|
142
|
+
allow($stdin).to receive(:tty?).and_return(false)
|
|
139
143
|
|
|
140
144
|
# Provide a minimal JSON-RPC request that the server can handle
|
|
141
145
|
json_request = JSON.generate({
|
|
@@ -149,7 +153,7 @@ RSpec.describe 'SIMPLECOV_MCP_OPTS Environment Variable' do
|
|
|
149
153
|
}
|
|
150
154
|
})
|
|
151
155
|
|
|
152
|
-
allow(
|
|
156
|
+
allow($stdin).to receive(:gets).and_return(json_request, nil)
|
|
153
157
|
|
|
154
158
|
# Capture output to verify MCP server response
|
|
155
159
|
output = nil
|
|
@@ -167,16 +171,15 @@ RSpec.describe 'SIMPLECOV_MCP_OPTS Environment Variable' do
|
|
|
167
171
|
describe 'integration with actual CLI usage' do
|
|
168
172
|
it 'works end-to-end with --resultset option' do
|
|
169
173
|
test_resultset = File.join(Dir.tmpdir, 'test_coverage', '.resultset.json')
|
|
170
|
-
ENV['SIMPLECOV_MCP_OPTS'] = "--resultset #{test_resultset} --json"
|
|
171
|
-
|
|
172
|
-
allow_any_instance_of(Object).to receive(:exit)
|
|
174
|
+
ENV['SIMPLECOV_MCP_OPTS'] = "--resultset #{test_resultset} --format json"
|
|
175
|
+
env_opts = SimpleCovMcp.send(:extract_env_opts)
|
|
173
176
|
|
|
174
|
-
|
|
175
|
-
silence_output { cli.send(:run, ['--help']) }
|
|
176
|
-
end
|
|
177
|
+
swallow_system_exit do
|
|
178
|
+
silence_output { cli.send(:run, env_opts + ['--help']) }
|
|
179
|
+
end
|
|
177
180
|
|
|
178
181
|
expect(cli.config.resultset).to eq(test_resultset)
|
|
179
|
-
expect(cli.config.
|
|
182
|
+
expect(cli.config.format).to eq(:json)
|
|
180
183
|
end
|
|
181
184
|
end
|
|
182
185
|
end
|
data/spec/spec_helper.rb
CHANGED
|
@@ -5,9 +5,17 @@ begin
|
|
|
5
5
|
require 'simplecov'
|
|
6
6
|
SimpleCov.start do
|
|
7
7
|
enable_coverage :branch if SimpleCov.respond_to?(:enable_coverage)
|
|
8
|
-
add_filter
|
|
8
|
+
add_filter(/^\/spec\//)
|
|
9
9
|
track_files 'lib/**/*.rb'
|
|
10
10
|
end
|
|
11
|
+
|
|
12
|
+
# Report lowest coverage files at the end of the test run
|
|
13
|
+
SimpleCov.at_exit do
|
|
14
|
+
SimpleCov.result.format!
|
|
15
|
+
require 'simplecov_mcp'
|
|
16
|
+
report = SimpleCovMcp::CoverageReporter.report(threshold: 80, count: 5)
|
|
17
|
+
puts report if report
|
|
18
|
+
end
|
|
11
19
|
rescue LoadError
|
|
12
20
|
warn 'SimpleCov not available; skipping coverage'
|
|
13
21
|
end
|
|
@@ -57,14 +65,16 @@ def mock_resultset_with_metadata(root, metadata, coverage: nil)
|
|
|
57
65
|
File.join(root, 'lib', 'bar.rb') => { 'lines' => [0, 0, 1] }
|
|
58
66
|
}
|
|
59
67
|
|
|
60
|
-
|
|
68
|
+
fake_resultset_hash = {
|
|
61
69
|
'RSpec' => {
|
|
62
70
|
'coverage' => coverage || default_coverage
|
|
63
71
|
}.merge(metadata)
|
|
64
72
|
}
|
|
65
73
|
|
|
66
|
-
allow(
|
|
67
|
-
|
|
74
|
+
allow(JSON).to receive(:load_file).and_call_original # Allow real JSON.load_file for other calls
|
|
75
|
+
|
|
76
|
+
allow(JSON).to receive(:load_file).with(end_with('.resultset.json'))
|
|
77
|
+
.and_return(fake_resultset_hash)
|
|
68
78
|
allow(SimpleCovMcp::CovUtil).to receive(:find_resultset)
|
|
69
79
|
.and_wrap_original do |method, search_root, resultset: nil|
|
|
70
80
|
if File.absolute_path(search_root) == abs_root && (resultset.nil? || resultset.to_s.empty?)
|
|
@@ -76,8 +86,8 @@ def mock_resultset_with_metadata(root, metadata, coverage: nil)
|
|
|
76
86
|
end
|
|
77
87
|
|
|
78
88
|
# Automatically require all files in spec/support and spec/shared_examples
|
|
79
|
-
Dir[File.join(__dir__, 'support', '**', '*.rb')].
|
|
80
|
-
Dir[File.join(__dir__, 'shared_examples', '**', '*.rb')].
|
|
89
|
+
Dir[File.join(__dir__, 'support', '**', '*.rb')].each { |f| require f }
|
|
90
|
+
Dir[File.join(__dir__, 'shared_examples', '**', '*.rb')].each { |f| require f }
|
|
81
91
|
|
|
82
92
|
RSpec.configure do |config|
|
|
83
93
|
config.example_status_persistence_file_path = '.rspec_status'
|
|
@@ -85,107 +95,32 @@ RSpec.configure do |config|
|
|
|
85
95
|
config.order = :defined
|
|
86
96
|
Kernel.srand config.seed
|
|
87
97
|
|
|
88
|
-
# Suppress logging during tests by redirecting to
|
|
89
|
-
|
|
90
|
-
SimpleCovMcp.
|
|
91
|
-
|
|
98
|
+
# Suppress logging during tests by redirecting to /dev/null
|
|
99
|
+
# This is cheap and doesn't break tests that verify logging behavior
|
|
100
|
+
SimpleCovMcp.default_log_file = 'stderr'
|
|
101
|
+
SimpleCovMcp.active_log_file = 'stderr'
|
|
92
102
|
|
|
93
|
-
#
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
def silence_output
|
|
97
|
-
original_stdout = $stdout
|
|
98
|
-
original_stderr = $stderr
|
|
99
|
-
$stdout = StringIO.new
|
|
100
|
-
$stderr = StringIO.new
|
|
101
|
-
yield $stdout, $stderr
|
|
102
|
-
ensure
|
|
103
|
-
$stdout = original_stdout
|
|
104
|
-
$stderr = original_stderr
|
|
103
|
+
# Reset log file after each test to ensure tests that change it don't pollute others
|
|
104
|
+
config.after do
|
|
105
|
+
SimpleCovMcp.active_log_file = File::NULL
|
|
105
106
|
end
|
|
106
107
|
|
|
107
|
-
# Stub staleness checking to return a specific value
|
|
108
|
-
# @param value [String, false] The staleness value to return ('L', 'T', 'M', or false)
|
|
109
|
-
def stub_staleness_check(value)
|
|
110
|
-
checker_double = instance_double(SimpleCovMcp::StalenessChecker)
|
|
111
|
-
allow(checker_double).to receive_messages(stale_for_file?: value, off?: false)
|
|
112
|
-
allow(checker_double).to receive(:check_file!)
|
|
113
|
-
allow(SimpleCovMcp::StalenessChecker).to receive(:new).and_return(checker_double)
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
# CLI test helpers
|
|
118
|
-
module CLITestHelpers
|
|
119
|
-
# Run CLI with the given arguments and return [stdout, stderr, exit_status]
|
|
120
|
-
def run_cli_with_status(*argv)
|
|
121
|
-
cli = SimpleCovMcp::CoverageCLI.new
|
|
122
|
-
status = nil
|
|
123
|
-
out_str = err_str = nil
|
|
124
|
-
silence_output do |out, err|
|
|
125
|
-
begin
|
|
126
|
-
cli.run(argv.flatten)
|
|
127
|
-
status = 0
|
|
128
|
-
rescue SystemExit => e
|
|
129
|
-
status = e.status
|
|
130
|
-
end
|
|
131
|
-
out_str = out.string
|
|
132
|
-
err_str = err.string
|
|
133
|
-
end
|
|
134
|
-
[out_str, err_str, status]
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
# MCP Tool shared examples and helpers
|
|
139
|
-
module MCPToolTestHelpers
|
|
140
|
-
def setup_mcp_response_stub
|
|
141
|
-
# Standardized MCP::Tool::Response stub that works for all tools
|
|
142
|
-
response_class = Class.new do
|
|
143
|
-
attr_reader :payload, :meta
|
|
144
|
-
|
|
145
|
-
def initialize(payload, meta: nil)
|
|
146
|
-
@payload = payload
|
|
147
|
-
@meta = meta
|
|
148
|
-
end
|
|
149
|
-
end
|
|
150
|
-
stub_const('MCP::Tool::Response', response_class)
|
|
151
|
-
end
|
|
152
|
-
|
|
153
|
-
def expect_mcp_text_json(response, expected_keys: [])
|
|
154
|
-
item = response.payload.first
|
|
155
|
-
|
|
156
|
-
# Check for a 'text' part
|
|
157
|
-
expect(item['type']).to eq('text')
|
|
158
|
-
expect(item).to have_key('text')
|
|
159
|
-
|
|
160
|
-
# Parse and validate JSON content
|
|
161
|
-
data = JSON.parse(item['text'])
|
|
162
|
-
|
|
163
|
-
# Check for expected keys
|
|
164
|
-
expected_keys.each do |key|
|
|
165
|
-
expect(data).to have_key(key)
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
[data, item] # Return for additional custom assertions
|
|
169
|
-
end
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
RSpec.configure do |config|
|
|
175
108
|
config.include TestIOHelpers
|
|
176
109
|
config.include CLITestHelpers
|
|
177
110
|
config.include MCPToolTestHelpers
|
|
111
|
+
config.include MockingHelpers
|
|
112
|
+
config.include ControlFlowHelpers
|
|
178
113
|
end
|
|
179
114
|
|
|
180
115
|
# Custom matchers
|
|
181
116
|
RSpec::Matchers.define :show_source_table_or_fallback do
|
|
182
117
|
match do |output|
|
|
183
|
-
has_table_header = output.match?(/(^|\n)\s*Line\s
|
|
118
|
+
has_table_header = output.match?(/(^|\n)\s*Line\s*\|\s+Source/)
|
|
184
119
|
has_fallback = output.include?('[source not available]')
|
|
185
120
|
has_table_header || has_fallback
|
|
186
121
|
end
|
|
187
122
|
|
|
188
|
-
failure_message do |
|
|
123
|
+
failure_message do |_output|
|
|
189
124
|
"expected output to include a source table header (e.g., 'Line | Source') " \
|
|
190
125
|
"or the fallback '[source not available]'"
|
|
191
126
|
end
|
|
@@ -5,6 +5,7 @@ require 'fileutils'
|
|
|
5
5
|
|
|
6
6
|
RSpec.describe SimpleCovMcp::StalenessChecker do
|
|
7
7
|
let(:tmpdir) { Dir.mktmpdir('scmcp-stale') }
|
|
8
|
+
|
|
8
9
|
after { FileUtils.remove_entry(tmpdir) if tmpdir && File.directory?(tmpdir) }
|
|
9
10
|
|
|
10
11
|
def write_file(path, lines)
|
|
@@ -57,8 +58,8 @@ RSpec.describe SimpleCovMcp::StalenessChecker do
|
|
|
57
58
|
end
|
|
58
59
|
end
|
|
59
60
|
|
|
60
|
-
context '
|
|
61
|
-
|
|
61
|
+
context 'when computing file staleness details' do
|
|
62
|
+
it_behaves_like 'a staleness check',
|
|
62
63
|
description: 'detects newer file vs coverage timestamp',
|
|
63
64
|
file_lines: ['a', 'b'],
|
|
64
65
|
coverage_lines: [1, 1],
|
|
@@ -75,7 +76,7 @@ RSpec.describe SimpleCovMcp::StalenessChecker do
|
|
|
75
76
|
expected_stale_char: 'T',
|
|
76
77
|
expected_error: SimpleCovMcp::CoverageDataStaleError
|
|
77
78
|
|
|
78
|
-
|
|
79
|
+
it_behaves_like 'a staleness check',
|
|
79
80
|
description: 'detects length mismatch between source and coverage',
|
|
80
81
|
file_lines: ['a', 'b', 'c', 'd'],
|
|
81
82
|
coverage_lines: [1, 1],
|
|
@@ -92,7 +93,7 @@ RSpec.describe SimpleCovMcp::StalenessChecker do
|
|
|
92
93
|
expected_stale_char: 'L',
|
|
93
94
|
expected_error: SimpleCovMcp::CoverageDataStaleError
|
|
94
95
|
|
|
95
|
-
|
|
96
|
+
it_behaves_like 'a staleness check',
|
|
96
97
|
description: 'treats missing file as stale',
|
|
97
98
|
file_lines: nil,
|
|
98
99
|
coverage_lines: [1, 1, 1],
|
|
@@ -107,7 +108,7 @@ RSpec.describe SimpleCovMcp::StalenessChecker do
|
|
|
107
108
|
expected_stale_char: 'M',
|
|
108
109
|
expected_error: SimpleCovMcp::CoverageDataStaleError
|
|
109
110
|
|
|
110
|
-
|
|
111
|
+
it_behaves_like 'a staleness check',
|
|
111
112
|
description: 'is not stale when timestamps and lengths match',
|
|
112
113
|
file_lines: ['a', 'b', 'c'],
|
|
113
114
|
coverage_lines: [1, 0, nil],
|
|
@@ -123,7 +124,7 @@ RSpec.describe SimpleCovMcp::StalenessChecker do
|
|
|
123
124
|
expected_error: nil
|
|
124
125
|
end
|
|
125
126
|
|
|
126
|
-
context 'missing_trailing_newline? edge cases' do
|
|
127
|
+
context 'when handling missing_trailing_newline? edge cases' do
|
|
127
128
|
let(:checker) do
|
|
128
129
|
described_class.new(root: tmpdir, resultset: nil, mode: 'off', timestamp: Time.now)
|
|
129
130
|
end
|
|
@@ -192,7 +193,7 @@ RSpec.describe SimpleCovMcp::StalenessChecker do
|
|
|
192
193
|
end
|
|
193
194
|
end
|
|
194
195
|
|
|
195
|
-
context 'line count
|
|
196
|
+
context 'when adjusting line count with missing trailing newline' do
|
|
196
197
|
let(:checker) do
|
|
197
198
|
described_class.new(root: tmpdir, resultset: nil, mode: 'off', timestamp: Time.now)
|
|
198
199
|
end
|
|
@@ -246,7 +247,7 @@ RSpec.describe SimpleCovMcp::StalenessChecker do
|
|
|
246
247
|
end
|
|
247
248
|
end
|
|
248
249
|
|
|
249
|
-
context 'safe_count_lines edge cases' do
|
|
250
|
+
context 'when handling safe_count_lines edge cases' do
|
|
250
251
|
let(:checker) do
|
|
251
252
|
described_class.new(root: tmpdir, resultset: nil, mode: 'off', timestamp: Time.now)
|
|
252
253
|
end
|
|
@@ -287,7 +288,7 @@ RSpec.describe SimpleCovMcp::StalenessChecker do
|
|
|
287
288
|
end
|
|
288
289
|
end
|
|
289
290
|
|
|
290
|
-
context 'rel
|
|
291
|
+
context 'when rel has path prefix mismatches' do
|
|
291
292
|
let(:checker) do
|
|
292
293
|
described_class.new(root: tmpdir, resultset: nil, mode: 'off', timestamp: Time.now)
|
|
293
294
|
end
|