simplecov-mcp 0.3.0 → 1.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/LICENSE +21 -0
- data/README.md +173 -356
- data/docs/ADVANCED_USAGE.md +967 -0
- data/docs/ARCHITECTURE.md +79 -0
- data/docs/BRANCH_ONLY_COVERAGE.md +81 -0
- data/docs/CLI_USAGE.md +637 -0
- data/docs/DEVELOPMENT.md +82 -0
- data/docs/ERROR_HANDLING.md +93 -0
- data/docs/EXAMPLES.md +430 -0
- data/docs/INSTALLATION.md +352 -0
- data/docs/LIBRARY_API.md +635 -0
- data/docs/MCP_INTEGRATION.md +488 -0
- data/docs/TROUBLESHOOTING.md +276 -0
- data/docs/arch-decisions/001-x-arch-decision.md +93 -0
- data/docs/arch-decisions/002-x-arch-decision.md +157 -0
- data/docs/arch-decisions/003-x-arch-decision.md +163 -0
- data/docs/arch-decisions/004-x-arch-decision.md +199 -0
- data/docs/arch-decisions/005-x-arch-decision.md +187 -0
- data/docs/arch-decisions/README.md +60 -0
- data/docs/presentations/simplecov-mcp-presentation.md +249 -0
- data/exe/simplecov-mcp +4 -4
- data/lib/simplecov_mcp/app_context.rb +26 -0
- data/lib/simplecov_mcp/base_tool.rb +74 -0
- data/lib/simplecov_mcp/cli.rb +234 -0
- data/lib/simplecov_mcp/cli_config.rb +56 -0
- data/lib/simplecov_mcp/commands/base_command.rb +78 -0
- data/lib/simplecov_mcp/commands/command_factory.rb +39 -0
- data/lib/simplecov_mcp/commands/detailed_command.rb +24 -0
- data/lib/simplecov_mcp/commands/list_command.rb +13 -0
- data/lib/simplecov_mcp/commands/raw_command.rb +22 -0
- data/lib/simplecov_mcp/commands/summary_command.rb +24 -0
- data/lib/simplecov_mcp/commands/uncovered_command.rb +26 -0
- data/lib/simplecov_mcp/commands/version_command.rb +18 -0
- data/lib/simplecov_mcp/constants.rb +22 -0
- data/lib/simplecov_mcp/error_handler.rb +124 -0
- data/lib/simplecov_mcp/error_handler_factory.rb +31 -0
- data/lib/simplecov_mcp/errors.rb +179 -0
- data/lib/simplecov_mcp/formatters/source_formatter.rb +148 -0
- data/lib/simplecov_mcp/mcp_server.rb +40 -0
- data/lib/simplecov_mcp/mode_detector.rb +55 -0
- data/lib/simplecov_mcp/model.rb +300 -0
- data/lib/simplecov_mcp/option_normalizers.rb +92 -0
- data/lib/simplecov_mcp/option_parser_builder.rb +134 -0
- data/lib/simplecov_mcp/option_parsers/env_options_parser.rb +50 -0
- data/lib/simplecov_mcp/option_parsers/error_helper.rb +109 -0
- data/lib/simplecov_mcp/path_relativizer.rb +61 -0
- data/lib/simplecov_mcp/presenters/base_coverage_presenter.rb +44 -0
- data/lib/simplecov_mcp/presenters/coverage_detailed_presenter.rb +16 -0
- data/lib/simplecov_mcp/presenters/coverage_raw_presenter.rb +16 -0
- data/lib/simplecov_mcp/presenters/coverage_summary_presenter.rb +16 -0
- data/lib/simplecov_mcp/presenters/coverage_uncovered_presenter.rb +16 -0
- data/lib/simplecov_mcp/presenters/project_coverage_presenter.rb +52 -0
- data/lib/simplecov_mcp/resolvers/coverage_line_resolver.rb +126 -0
- data/lib/simplecov_mcp/resolvers/resolver_factory.rb +28 -0
- data/lib/simplecov_mcp/resolvers/resultset_path_resolver.rb +78 -0
- data/lib/simplecov_mcp/resultset_loader.rb +136 -0
- data/lib/simplecov_mcp/staleness_checker.rb +243 -0
- data/lib/{simple_cov_mcp → simplecov_mcp}/tools/all_files_coverage_tool.rb +31 -13
- data/lib/{simple_cov_mcp → simplecov_mcp}/tools/coverage_detailed_tool.rb +7 -7
- data/lib/{simple_cov_mcp → simplecov_mcp}/tools/coverage_raw_tool.rb +7 -7
- data/lib/{simple_cov_mcp → simplecov_mcp}/tools/coverage_summary_tool.rb +7 -7
- data/lib/simplecov_mcp/tools/coverage_table_tool.rb +90 -0
- data/lib/{simple_cov_mcp → simplecov_mcp}/tools/help_tool.rb +13 -4
- data/lib/{simple_cov_mcp → simplecov_mcp}/tools/uncovered_lines_tool.rb +7 -7
- data/lib/{simple_cov_mcp → simplecov_mcp}/tools/version_tool.rb +11 -3
- data/lib/simplecov_mcp/util.rb +82 -0
- data/lib/{simple_cov_mcp → simplecov_mcp}/version.rb +1 -1
- data/lib/simplecov_mcp.rb +144 -2
- data/spec/MCP_INTEGRATION_TESTS_README.md +111 -0
- data/spec/TIMESTAMPS.md +48 -0
- data/spec/all_files_coverage_tool_spec.rb +29 -25
- data/spec/base_tool_spec.rb +11 -10
- data/spec/cli/show_default_report_spec.rb +33 -0
- data/spec/cli_config_spec.rb +137 -0
- data/spec/cli_enumerated_options_spec.rb +68 -0
- data/spec/cli_error_spec.rb +105 -47
- data/spec/cli_source_spec.rb +82 -23
- data/spec/cli_spec.rb +140 -5
- data/spec/cli_success_predicate_spec.rb +141 -0
- data/spec/cli_table_spec.rb +1 -1
- data/spec/cli_usage_spec.rb +10 -26
- data/spec/commands/base_command_spec.rb +187 -0
- data/spec/commands/command_factory_spec.rb +72 -0
- data/spec/commands/detailed_command_spec.rb +48 -0
- data/spec/commands/raw_command_spec.rb +46 -0
- data/spec/commands/summary_command_spec.rb +47 -0
- data/spec/commands/uncovered_command_spec.rb +49 -0
- data/spec/constants_spec.rb +61 -0
- data/spec/coverage_table_tool_spec.rb +17 -33
- data/spec/error_handler_spec.rb +22 -13
- data/spec/error_mode_spec.rb +143 -0
- data/spec/errors_edge_cases_spec.rb +239 -0
- data/spec/errors_stale_spec.rb +2 -2
- data/spec/file_based_mcp_tools_spec.rb +99 -0
- data/spec/fixtures/project1/lib/bar.rb +0 -1
- data/spec/fixtures/project1/lib/foo.rb +0 -1
- data/spec/help_tool_spec.rb +11 -17
- data/spec/integration_spec.rb +845 -0
- data/spec/logging_fallback_spec.rb +128 -0
- data/spec/mcp_logging_spec.rb +44 -0
- data/spec/mcp_server_integration_spec.rb +23 -0
- data/spec/mcp_server_spec.rb +15 -4
- data/spec/mode_detector_spec.rb +148 -0
- data/spec/model_error_handling_spec.rb +210 -0
- data/spec/model_staleness_spec.rb +40 -10
- data/spec/option_normalizers_spec.rb +204 -0
- data/spec/option_parsers/env_options_parser_spec.rb +233 -0
- data/spec/option_parsers/error_helper_spec.rb +222 -0
- data/spec/path_relativizer_spec.rb +83 -0
- data/spec/presenters/coverage_detailed_presenter_spec.rb +19 -0
- data/spec/presenters/coverage_raw_presenter_spec.rb +15 -0
- data/spec/presenters/coverage_summary_presenter_spec.rb +15 -0
- data/spec/presenters/coverage_uncovered_presenter_spec.rb +16 -0
- data/spec/presenters/project_coverage_presenter_spec.rb +86 -0
- data/spec/resolvers/coverage_line_resolver_spec.rb +57 -0
- data/spec/resolvers/resolver_factory_spec.rb +61 -0
- data/spec/resolvers/resultset_path_resolver_spec.rb +55 -0
- data/spec/resultset_loader_spec.rb +167 -0
- data/spec/shared_examples/README.md +115 -0
- data/spec/shared_examples/coverage_presenter_examples.rb +66 -0
- data/spec/shared_examples/file_based_mcp_tools.rb +174 -0
- data/spec/shared_examples/mcp_tool_text_json_response.rb +16 -0
- data/spec/simple_cov_mcp_module_spec.rb +16 -0
- data/spec/simplecov_mcp_model_spec.rb +340 -9
- data/spec/simplecov_mcp_opts_spec.rb +182 -0
- data/spec/spec_helper.rb +147 -4
- data/spec/staleness_checker_spec.rb +373 -0
- data/spec/staleness_more_spec.rb +16 -13
- data/spec/support/mcp_runner.rb +64 -0
- data/spec/tools_error_handling_spec.rb +144 -0
- data/spec/util_spec.rb +109 -34
- data/spec/version_spec.rb +117 -9
- data/spec/version_tool_spec.rb +131 -10
- metadata +120 -63
- data/lib/simple_cov/mcp.rb +0 -9
- data/lib/simple_cov_mcp/base_tool.rb +0 -70
- data/lib/simple_cov_mcp/cli.rb +0 -390
- data/lib/simple_cov_mcp/error_handler.rb +0 -131
- data/lib/simple_cov_mcp/error_handler_factory.rb +0 -38
- data/lib/simple_cov_mcp/errors.rb +0 -176
- data/lib/simple_cov_mcp/mcp_server.rb +0 -30
- data/lib/simple_cov_mcp/model.rb +0 -104
- data/lib/simple_cov_mcp/staleness_checker.rb +0 -125
- data/lib/simple_cov_mcp/tools/coverage_table_tool.rb +0 -61
- data/lib/simple_cov_mcp/util.rb +0 -122
- data/lib/simple_cov_mcp.rb +0 -102
- data/spec/coverage_detailed_tool_spec.rb +0 -36
- data/spec/coverage_raw_tool_spec.rb +0 -32
- data/spec/coverage_summary_tool_spec.rb +0 -39
- data/spec/legacy_shim_spec.rb +0 -13
- data/spec/uncovered_lines_tool_spec.rb +0 -33
data/lib/simple_cov_mcp.rb
DELETED
@@ -1,102 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'json'
|
4
|
-
require 'time'
|
5
|
-
require 'pathname'
|
6
|
-
require 'mcp'
|
7
|
-
require 'mcp/server/transports/stdio_transport'
|
8
|
-
require 'awesome_print'
|
9
|
-
|
10
|
-
require_relative 'simple_cov_mcp/version'
|
11
|
-
require_relative 'simple_cov_mcp/util'
|
12
|
-
require_relative 'simple_cov_mcp/errors'
|
13
|
-
require_relative 'simple_cov_mcp/error_handler'
|
14
|
-
require_relative 'simple_cov_mcp/error_handler_factory'
|
15
|
-
require_relative 'simple_cov_mcp/model'
|
16
|
-
require_relative 'simple_cov_mcp/base_tool'
|
17
|
-
require_relative 'simple_cov_mcp/tools/coverage_raw_tool'
|
18
|
-
require_relative 'simple_cov_mcp/tools/coverage_summary_tool'
|
19
|
-
require_relative 'simple_cov_mcp/tools/uncovered_lines_tool'
|
20
|
-
require_relative 'simple_cov_mcp/tools/coverage_detailed_tool'
|
21
|
-
require_relative 'simple_cov_mcp/tools/all_files_coverage_tool'
|
22
|
-
require_relative 'simple_cov_mcp/tools/coverage_table_tool'
|
23
|
-
require_relative 'simple_cov_mcp/tools/version_tool'
|
24
|
-
require_relative 'simple_cov_mcp/tools/help_tool'
|
25
|
-
require_relative 'simple_cov_mcp/mcp_server'
|
26
|
-
require_relative 'simple_cov_mcp/cli'
|
27
|
-
|
28
|
-
module SimpleCovMcp
|
29
|
-
def self.run(argv)
|
30
|
-
# Determine whether to run CLI or MCP server based on arguments and environment
|
31
|
-
if should_run_cli?(argv)
|
32
|
-
CoverageCLI.new(error_handler: ErrorHandlerFactory.for_cli).run(argv)
|
33
|
-
else
|
34
|
-
MCPServer.new.run
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
# For library usage, allow configuration of error handling.
|
39
|
-
# This method is intended for applications that want to embed simplecov-mcp
|
40
|
-
# functionality without the CLI behavior of showing friendly error messages
|
41
|
-
# and exiting. Instead, it raises custom exceptions that can be caught.
|
42
|
-
#
|
43
|
-
# Usage:
|
44
|
-
# # Basic usage - raises custom exceptions on errors
|
45
|
-
# SimpleCov::Mcp.run_as_library(['summary', 'lib/foo.rb'])
|
46
|
-
#
|
47
|
-
# # With custom error handler (e.g., disable logging)
|
48
|
-
# handler = SimpleCov::Mcp::ErrorHandler.new(log_errors: false)
|
49
|
-
# SimpleCov::Mcp.run_as_library(['summary', 'lib/foo.rb'], error_handler: handler)
|
50
|
-
#
|
51
|
-
# # Exception handling
|
52
|
-
# begin
|
53
|
-
# SimpleCov::Mcp.run_as_library(['summary', 'missing.rb'])
|
54
|
-
# rescue SimpleCov::Mcp::FileError => e
|
55
|
-
# puts "File not found: #{e.user_friendly_message}"
|
56
|
-
# rescue SimpleCov::Mcp::CoverageDataError => e
|
57
|
-
# puts "Coverage issue: #{e.user_friendly_message}"
|
58
|
-
# end
|
59
|
-
def self.run_as_library(argv, error_handler: nil)
|
60
|
-
# Set global error handler for library usage (affects shared components like MCP tools)
|
61
|
-
SimpleCovMcp.error_handler = error_handler || ErrorHandlerFactory.for_library
|
62
|
-
|
63
|
-
model = CoverageModel.new
|
64
|
-
execute_library_command(model, argv)
|
65
|
-
rescue SimpleCovMcp::Error => e
|
66
|
-
raise e # Re-raise custom errors for library users to catch
|
67
|
-
rescue => e
|
68
|
-
SimpleCovMcp.error_handler.handle_error(e, context: 'library execution')
|
69
|
-
raise e # Re-raise for library users to handle
|
70
|
-
end
|
71
|
-
|
72
|
-
private
|
73
|
-
|
74
|
-
def self.execute_library_command(model, argv)
|
75
|
-
return model.all_files if argv.empty?
|
76
|
-
|
77
|
-
unless argv.length >= 2
|
78
|
-
raise UsageError.new("Invalid arguments. Use: [] for all files, or [command, path] for specific file")
|
79
|
-
end
|
80
|
-
|
81
|
-
command, path = argv[0], argv[1]
|
82
|
-
case command
|
83
|
-
when 'summary' then model.summary_for(path)
|
84
|
-
when 'raw' then model.raw_for(path)
|
85
|
-
when 'uncovered' then model.uncovered_for(path)
|
86
|
-
when 'detailed' then model.detailed_for(path)
|
87
|
-
else
|
88
|
-
raise UsageError.new("Unknown command: #{command}. Use: summary, raw, uncovered, or detailed")
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
def self.should_run_cli?(argv)
|
93
|
-
# Force CLI mode if environment variable is set
|
94
|
-
return true if ENV['SIMPLECOV_MCP_CLI'] == '1'
|
95
|
-
|
96
|
-
# If a subcommand is provided, run CLI
|
97
|
-
return true if CoverageCLI::SUBCOMMANDS.include?(argv[0])
|
98
|
-
|
99
|
-
# If interactive TTY, prefer CLI; else (e.g., pipes), run MCP server
|
100
|
-
STDIN.tty?
|
101
|
-
end
|
102
|
-
end
|
@@ -1,36 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
require 'simple_cov_mcp/tools/coverage_detailed_tool'
|
5
|
-
|
6
|
-
RSpec.describe SimpleCovMcp::Tools::CoverageDetailedTool do
|
7
|
-
let(:server_context) { instance_double('ServerContext').as_null_object }
|
8
|
-
|
9
|
-
before do
|
10
|
-
stub_const('MCP::Tool::Response', Struct.new(:payload))
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'returns JSON as an application/json resource' do
|
14
|
-
model = instance_double(SimpleCovMcp::CoverageModel)
|
15
|
-
allow(SimpleCovMcp::CoverageModel).to receive(:new).and_return(model)
|
16
|
-
allow(model).to receive(:detailed_for).with('lib/foo.rb').and_return(
|
17
|
-
{
|
18
|
-
'file' => '/abs/path/lib/foo.rb',
|
19
|
-
'lines' => [
|
20
|
-
{ 'line' => 1, 'hits' => 1, 'covered' => true },
|
21
|
-
{ 'line' => 2, 'hits' => 0, 'covered' => false }
|
22
|
-
],
|
23
|
-
'summary' => { 'covered' => 1, 'total' => 2, 'pct' => 50.0 }
|
24
|
-
}
|
25
|
-
)
|
26
|
-
|
27
|
-
response = described_class.call(path: 'lib/foo.rb', server_context: server_context)
|
28
|
-
item = response.payload.first
|
29
|
-
expect(item['type']).to eq('resource')
|
30
|
-
expect(item['resource']).to include('mimeType' => 'application/json', 'name' => 'coverage_detailed.json')
|
31
|
-
data = JSON.parse(item['resource']['text'])
|
32
|
-
expect(data).to include('file', 'lines', 'summary')
|
33
|
-
expect(data['lines']).to be_an(Array)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
@@ -1,32 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
require 'simple_cov_mcp/tools/coverage_raw_tool'
|
5
|
-
|
6
|
-
RSpec.describe SimpleCovMcp::Tools::CoverageRawTool do
|
7
|
-
let(:server_context) { instance_double('ServerContext').as_null_object }
|
8
|
-
|
9
|
-
before do
|
10
|
-
stub_const('MCP::Tool::Response', Struct.new(:payload))
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'returns JSON as an application/json resource' do
|
14
|
-
model = instance_double(SimpleCovMcp::CoverageModel)
|
15
|
-
allow(SimpleCovMcp::CoverageModel).to receive(:new).and_return(model)
|
16
|
-
allow(model).to receive(:raw_for).with('lib/foo.rb').and_return(
|
17
|
-
{
|
18
|
-
'file' => '/abs/path/lib/foo.rb',
|
19
|
-
'lines' => [nil, 1, 0]
|
20
|
-
}
|
21
|
-
)
|
22
|
-
|
23
|
-
response = described_class.call(path: 'lib/foo.rb', server_context: server_context)
|
24
|
-
item = response.payload.first
|
25
|
-
expect(item['type']).to eq('resource')
|
26
|
-
expect(item['resource']).to include('mimeType' => 'application/json', 'name' => 'coverage_raw.json')
|
27
|
-
data = JSON.parse(item['resource']['text'])
|
28
|
-
expect(data).to include('file', 'lines')
|
29
|
-
expect(data['lines']).to be_an(Array)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
@@ -1,39 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
require 'simple_cov_mcp/tools/coverage_summary_tool'
|
5
|
-
|
6
|
-
RSpec.describe SimpleCovMcp::Tools::CoverageSummaryTool do
|
7
|
-
let(:server_context) { instance_double('ServerContext').as_null_object }
|
8
|
-
|
9
|
-
before do
|
10
|
-
response_class = Class.new do
|
11
|
-
attr_reader :payload, :meta
|
12
|
-
def initialize(payload, meta: nil)
|
13
|
-
@payload = payload
|
14
|
-
@meta = meta
|
15
|
-
end
|
16
|
-
end
|
17
|
-
stub_const('MCP::Tool::Response', response_class)
|
18
|
-
end
|
19
|
-
|
20
|
-
it 'returns JSON as an application/json resource' do
|
21
|
-
model = instance_double(SimpleCovMcp::CoverageModel)
|
22
|
-
allow(SimpleCovMcp::CoverageModel).to receive(:new).and_return(model)
|
23
|
-
allow(model).to receive(:summary_for).with('lib/foo.rb').and_return(
|
24
|
-
{
|
25
|
-
'file' => '/abs/path/lib/foo.rb',
|
26
|
-
'summary' => { 'covered' => 10, 'total' => 12, 'pct' => 83.33 }
|
27
|
-
}
|
28
|
-
)
|
29
|
-
|
30
|
-
response = described_class.call(path: 'lib/foo.rb', server_context: server_context)
|
31
|
-
item = response.payload.first
|
32
|
-
expect(item['type']).to eq('resource')
|
33
|
-
expect(item['resource']).to include('mimeType' => 'application/json', 'name' => 'coverage_summary.json')
|
34
|
-
data = JSON.parse(item['resource']['text'])
|
35
|
-
expect(data).to include('file', 'summary')
|
36
|
-
expect(data['summary']).to include('covered', 'total', 'pct')
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
data/spec/legacy_shim_spec.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
RSpec.describe 'Legacy require shim' do
|
6
|
-
it "defines SimpleCov::Mcp aliasing SimpleCovMcp" do
|
7
|
-
# Ensure the legacy file itself is executed for coverage and behavior
|
8
|
-
load File.expand_path('../../lib/simple_cov/mcp.rb', __FILE__)
|
9
|
-
expect(defined?(SimpleCov::Mcp)).to be_truthy
|
10
|
-
expect(SimpleCov::Mcp).to eq(SimpleCovMcp)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
@@ -1,33 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
require 'simple_cov_mcp/tools/uncovered_lines_tool'
|
5
|
-
|
6
|
-
RSpec.describe SimpleCovMcp::Tools::UncoveredLinesTool do
|
7
|
-
let(:server_context) { instance_double('ServerContext').as_null_object }
|
8
|
-
|
9
|
-
before do
|
10
|
-
stub_const('MCP::Tool::Response', Struct.new(:payload))
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'returns JSON as an application/json resource' do
|
14
|
-
model = instance_double(SimpleCovMcp::CoverageModel)
|
15
|
-
allow(SimpleCovMcp::CoverageModel).to receive(:new).and_return(model)
|
16
|
-
allow(model).to receive(:uncovered_for).with('lib/foo.rb').and_return(
|
17
|
-
{
|
18
|
-
'file' => '/abs/path/lib/foo.rb',
|
19
|
-
'uncovered' => [5, 9, 12],
|
20
|
-
'summary' => { 'covered' => 10, 'total' => 12, 'pct' => 83.33 }
|
21
|
-
}
|
22
|
-
)
|
23
|
-
|
24
|
-
response = described_class.call(path: 'lib/foo.rb', server_context: server_context)
|
25
|
-
item = response.payload.first
|
26
|
-
expect(item['type']).to eq('resource')
|
27
|
-
expect(item['resource']).to include('mimeType' => 'application/json', 'name' => 'uncovered_lines.json')
|
28
|
-
data = JSON.parse(item['resource']['text'])
|
29
|
-
expect(data).to include('file', 'uncovered', 'summary')
|
30
|
-
expect(data['uncovered']).to eq([5, 9, 12])
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|