simplecov-mcp 0.2.0 → 0.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 06e96d273c6549d1f0539baa88ec863009f263e6d9f214c66157ac5e708b51a5
4
- data.tar.gz: fc1503a39a31d19076f4e7827aad1d1996fd4760b381aafdf7e4b13f8891fb0c
3
+ metadata.gz: '08e9a29ca4d2e2daafd4620690021de136eaa2cfc2ba652340f73d8b69547d8d'
4
+ data.tar.gz: 784e8ef1f21e6ed4e37783a840935e909d8a6d1f6ae4c941da34d0e6635f9f95
5
5
  SHA512:
6
- metadata.gz: 41125a954fca4422327a821f18ad55b8de0d473ea3c3d67bc0bb9eb6105d81aa09efcab262a09f0cedeb809adb73a0e974b36d0dcf00ceff55af8e639a573afe
7
- data.tar.gz: 7ab8e6375e1645557a8dd30c72be8e37e9d4fd97de59e330db24c0f6ec92339db5488b43c5cc9dbc975edbf5184fdb3179d5425cb48d5791d2fb0650659ab439
6
+ metadata.gz: 52e2a95fda335f611f38cd0b97164a62e381532ceb71b330c32023be10eeb8d97e999bdc32f0dafac168f0470cac481151e78f223623e90a377fe79ef807705b
7
+ data.tar.gz: 42ce8d9f01b069f2e3dd0d0e817cd135298fa14d06553ef5b0771d37baf9f5bd4c194d9a9296a823966da21ec505e69b41fd489dfcfa1b0e0b74bb63949b7a21
data/README.md CHANGED
@@ -92,6 +92,12 @@ echo '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"all_files_
92
92
 
93
93
  Tip: In an MCP-capable editor/agent, configure `simplecov-mcp` as a stdio server and call the same tool names with the `arguments` shown above.
94
94
 
95
+ Response content types (MCP):
96
+
97
+ - JSON data returns as a single `type: "resource"` item with `resource.mimeType: "application/json"` and the JSON string in `resource.text` (e.g., `name: "coverage_summary.json"`).
98
+ - Human-readable strings (e.g., the table and version) return as `type: "text"`.
99
+ - Errors return as `type: "text"` with a friendly message.
100
+
95
101
  Resultset resolution:
96
102
 
97
103
  - If `resultset:` is provided, it may be:
@@ -120,7 +126,7 @@ Using simplecov-mcp, show me a table of all files and their coverages.
120
126
 
121
127
  ----
122
128
 
123
- Using simplecov-mcp, find the uncovered code lines and report to me:
129
+ Using simplecov-mcp, find the uncovered code lines and report to me, in a markdown file:
124
130
 
125
131
  * the most important coverage omissions to address
126
132
  * the simplest coverage omissions to address
@@ -348,6 +354,11 @@ Available tools:
348
354
  - Returns `{ files: [{"file","covered","total","percentage","stale"}, ...] }` where `stale` is a boolean.
349
355
  - `version_tool()` — returns version information
350
356
 
357
+ Response shape and content types:
358
+
359
+ - JSON tools above return a single content item `{ "type": "resource", "resource": { "mimeType": "application/json", "text": "{...}", "name": "<tool>.json" } }`.
360
+ - `coverage_table_tool` and `version_tool` return `{ "type": "text", "text": "..." }`.
361
+
351
362
  Notes:
352
363
 
353
364
  - `resultset` lets clients pass a nonstandard path to `.resultset.json` directly (absolute or relative to `root`). It may be:
@@ -44,6 +44,22 @@ module SimpleCovMcp
44
44
  ::MCP::Tool::Response.new([{ type: 'text', text: "Error: #{normalized.user_friendly_message}" }])
45
45
  end
46
46
 
47
+ # Respond with JSON as a resource to avoid clients mutating content types.
48
+ # The resource embeds the JSON string with a clear MIME type.
49
+ def self.respond_json(payload, name: 'data.json', pretty: false)
50
+ json = pretty ? JSON.pretty_generate(payload) : JSON.generate(payload)
51
+ ::MCP::Tool::Response.new([
52
+ {
53
+ 'type' => 'resource',
54
+ 'resource' => {
55
+ 'mimeType' => 'application/json',
56
+ 'text' => json,
57
+ 'name' => name
58
+ }
59
+ }
60
+ ])
61
+ end
62
+
47
63
  private
48
64
 
49
65
  def self.log_mcp_error(error, tool_name)
@@ -53,7 +53,7 @@ module SimpleCovMcp
53
53
  stale_count = files.count { |f| f['stale'] }
54
54
  ok_count = total - stale_count
55
55
  payload = { files: files, counts: { total: total, ok: ok_count, stale: stale_count } }
56
- ::MCP::Tool::Response.new([{ type: 'text', text: JSON.pretty_generate(payload) }])
56
+ respond_json(payload, name: 'all_files_coverage.json')
57
57
  rescue => e
58
58
  handle_mcp_error(e, 'AllFilesCoverageTool')
59
59
  end
@@ -19,7 +19,7 @@ module SimpleCovMcp
19
19
  mode = stale
20
20
  model = CoverageModel.new(root: root, resultset: resultset, staleness: mode)
21
21
  data = model.detailed_for(path)
22
- ::MCP::Tool::Response.new([{ type: 'text', text: JSON.pretty_generate(data) }])
22
+ respond_json(data, name: 'coverage_detailed.json', pretty: true)
23
23
  rescue => e
24
24
  handle_mcp_error(e, 'CoverageDetailedTool')
25
25
  end
@@ -19,7 +19,7 @@ module SimpleCovMcp
19
19
  mode = stale
20
20
  model = CoverageModel.new(root: root, resultset: resultset, staleness: mode)
21
21
  data = model.raw_for(path)
22
- ::MCP::Tool::Response.new([{ type: 'text', text: JSON.pretty_generate(data) }])
22
+ respond_json(data, name: 'coverage_raw.json', pretty: true)
23
23
  rescue => e
24
24
  handle_mcp_error(e, 'CoverageRawTool')
25
25
  end
@@ -19,7 +19,7 @@ module SimpleCovMcp
19
19
  mode = stale
20
20
  model = CoverageModel.new(root: root, resultset: resultset, staleness: mode)
21
21
  data = model.summary_for(path)
22
- ::MCP::Tool::Response.new([{ type: 'text', text: JSON.pretty_generate(data) }])
22
+ respond_json(data, name: 'coverage_summary.json', pretty: true)
23
23
  rescue => e
24
24
  handle_mcp_error(e, 'CoverageSummaryTool')
25
25
  end
@@ -88,7 +88,8 @@ module SimpleCovMcp
88
88
  entries = TOOL_GUIDE.map { |guide| format_entry(guide) }
89
89
  entries = filter_entries(entries, query) if query && !query.strip.empty?
90
90
 
91
- ::MCP::Tool::Response.new([{ type: 'text', text: JSON.pretty_generate({ query: query, tools: entries }) }])
91
+ data = { query: query, tools: entries }
92
+ respond_json(data, name: 'tools_help.json')
92
93
  rescue => e
93
94
  handle_mcp_error(e, 'HelpTool')
94
95
  end
@@ -19,7 +19,7 @@ module SimpleCovMcp
19
19
  mode = stale
20
20
  model = CoverageModel.new(root: root, resultset: resultset, staleness: mode)
21
21
  data = model.uncovered_for(path)
22
- ::MCP::Tool::Response.new([{ type: 'text', text: JSON.pretty_generate(data) }])
22
+ respond_json(data, name: 'uncovered_lines.json', pretty: true)
23
23
  rescue => e
24
24
  handle_mcp_error(e, 'UncoveredLinesTool')
25
25
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SimpleCovMcp
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
@@ -28,11 +28,13 @@ RSpec.describe SimpleCovMcp::Tools::AllFilesCoverageTool do
28
28
 
29
29
  response = described_class.call(root: root, server_context: server_context)
30
30
  entry = response.payload.first
31
- json = entry[:json] || entry['json']
31
+ expect(entry['type']).to eq('resource')
32
+ expect(entry['resource']).to include('mimeType' => 'application/json')
33
+ json = JSON.parse(entry['resource']['text'])
32
34
 
33
- expect(json).to have_key(:files).or have_key('files')
34
- files = json[:files] || json['files']
35
- counts = json[:counts] || json['counts']
35
+ expect(json).to have_key('files')
36
+ files = json['files']
37
+ counts = json['counts']
36
38
 
37
39
  expect(files.length).to eq(2)
38
40
  expect(counts).to include('total' => 2).or include(total: 2)
@@ -0,0 +1,36 @@
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
+
@@ -0,0 +1,32 @@
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
+
@@ -0,0 +1,39 @@
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
+
@@ -10,9 +10,9 @@ RSpec.describe SimpleCovMcp::Tools::HelpTool do
10
10
  response_class = Class.new do
11
11
  attr_reader :payload, :meta
12
12
 
13
- def initialize(payload, meta: nil)
13
+ def initialize(payload)
14
14
  @payload = payload
15
- @meta = meta
15
+ @meta = nil
16
16
  end
17
17
  end
18
18
  stub_const('MCP::Tool::Response', response_class)
@@ -20,28 +20,29 @@ RSpec.describe SimpleCovMcp::Tools::HelpTool do
20
20
 
21
21
  it 'returns guidance for each registered tool' do
22
22
  response = described_class.call(server_context: server_context)
23
- expect(response.meta[:mimeType]).to eq('application/json')
23
+ expect(response.meta).to be_nil
24
24
 
25
25
  payload = response.payload.first
26
- expect(payload[:type]).to eq('json')
27
-
28
- data = payload[:json]
29
- tool_names = data[:tools].map { |entry| entry['tool'] }
26
+ expect(payload['type']).to eq('resource')
27
+ expect(payload['resource']).to include('mimeType' => 'application/json')
28
+ data = JSON.parse(payload['resource']['text'])
29
+ tool_names = data['tools'].map { |entry| entry['tool'] }
30
30
 
31
31
  expect(tool_names).to include('coverage_summary_tool', 'uncovered_lines_tool', 'all_files_coverage_tool', 'coverage_table_tool', 'version_tool')
32
- expect(data[:tools]).to all(include('use_when', 'avoid_when', 'inputs', 'example'))
32
+ expect(data['tools']).to all(include('use_when', 'avoid_when', 'inputs', 'example'))
33
33
  end
34
34
 
35
35
  it 'filters entries when a query is provided' do
36
36
  response = described_class.call(query: 'uncovered', server_context: server_context)
37
37
  payload = response.payload.first
38
- data = payload[:json]
38
+ expect(payload['type']).to eq('resource')
39
+ data = JSON.parse(payload['resource']['text'])
39
40
 
40
- expect(data[:tools]).not_to be_empty
41
- expect(data[:tools]).to all(satisfy do |entry|
41
+ expect(data['tools']).not_to be_empty
42
+ expect(data['tools']).to all(satisfy do |entry|
42
43
  combined = [entry['tool'], entry['label'], entry['use_when'], entry['avoid_when']].compact.join(' ').downcase
43
44
  combined.include?('uncovered')
44
45
  end)
45
- expect(data[:tools].map { |entry| entry['tool'] }).to include('uncovered_lines_tool')
46
+ expect(data['tools'].map { |entry| entry['tool'] }).to include('uncovered_lines_tool')
46
47
  end
47
48
  end
@@ -0,0 +1,33 @@
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
+
data/spec/version_spec.rb CHANGED
@@ -5,6 +5,11 @@ require 'spec_helper'
5
5
  RSpec.describe 'Version constant' do
6
6
  it 'exposes a semver-like version string' do
7
7
  expect(SimpleCovMcp::VERSION).to be_a(String)
8
- expect(SimpleCovMcp::VERSION).to match(/\A\d+\.\d+\.\d+(?:[.-][0-9A-Za-z]+)?\z/)
8
+ # Named fragments for readability (simplified SemVer)
9
+ CORE = /\d+\.\d+\.\d+/
10
+ ID = /[[:alnum:].-]+/ # ASCII alnum plus dot/hyphen
11
+ SEMVER = /\A#{CORE.source}(?:-#{ID.source})?(?:\+#{ID.source})?\z/
12
+
13
+ expect(SimpleCovMcp::VERSION).to match(SEMVER)
9
14
  end
10
15
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'simple_cov_mcp/tools/version_tool'
5
+
6
+ RSpec.describe SimpleCovMcp::Tools::VersionTool 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 a text payload with the version string' do
14
+ response = described_class.call(server_context: server_context)
15
+ item = response.payload.first
16
+ expect(item[:type] || item['type']).to eq('text')
17
+ text = item[:text] || item['text']
18
+ expect(text).to include('SimpleCovMcp version:')
19
+ expect(text).to include(SimpleCovMcp::VERSION)
20
+ end
21
+ end
22
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: simplecov-mcp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Keith R. Bennett
@@ -13,16 +13,16 @@ dependencies:
13
13
  name: mcp
14
14
  requirement: !ruby/object:Gem::Requirement
15
15
  requirements:
16
- - - "~>"
16
+ - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: '0.2'
18
+ version: '0.3'
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
- - - "~>"
23
+ - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: '0.2'
25
+ version: '0.3'
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: awesome_print
28
28
  requirement: !ruby/object:Gem::Requirement
@@ -106,11 +106,13 @@ files:
106
106
  - spec/all_files_coverage_tool_spec.rb
107
107
  - spec/base_tool_spec.rb
108
108
  - spec/cli_error_spec.rb
109
- - spec/cli_json_source_spec.rb
110
109
  - spec/cli_source_spec.rb
111
110
  - spec/cli_spec.rb
112
111
  - spec/cli_table_spec.rb
113
112
  - spec/cli_usage_spec.rb
113
+ - spec/coverage_detailed_tool_spec.rb
114
+ - spec/coverage_raw_tool_spec.rb
115
+ - spec/coverage_summary_tool_spec.rb
114
116
  - spec/coverage_table_tool_spec.rb
115
117
  - spec/error_handler_spec.rb
116
118
  - spec/errors_stale_spec.rb
@@ -123,8 +125,10 @@ files:
123
125
  - spec/simplecov_mcp_model_spec.rb
124
126
  - spec/spec_helper.rb
125
127
  - spec/staleness_more_spec.rb
128
+ - spec/uncovered_lines_tool_spec.rb
126
129
  - spec/util_spec.rb
127
130
  - spec/version_spec.rb
131
+ - spec/version_tool_spec.rb
128
132
  homepage: https://github.com/keithrbennett/simplecov-mcp
129
133
  licenses:
130
134
  - MIT
@@ -1,92 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- RSpec.describe SimpleCovMcp::CoverageCLI do
6
- let(:root) { (FIXTURES / 'project1').to_s }
7
-
8
- def run_cli_json(*argv)
9
- cli = described_class.new
10
- out = nil
11
- silence_output do |stdout, _stderr|
12
- cli.run(argv.flatten)
13
- out = stdout.string
14
- end
15
- JSON.parse(out)
16
- end
17
-
18
- it 'includes source rows in JSON for summary --source=full' do
19
- data = run_cli_json('summary', 'lib/foo.rb', '--root', root, '--resultset', 'coverage', '--json', '--source=full')
20
- expect(data['file']).to eq('lib/foo.rb')
21
- expect(data['source']).to be_an(Array)
22
- expect(data['source'].first).to include('line', 'code', 'hits', 'covered')
23
- end
24
-
25
- it 'includes source rows in JSON for uncovered --source=uncovered' do
26
- data = run_cli_json('uncovered', 'lib/foo.rb', '--root', root, '--resultset', 'coverage', '--json', '--source=uncovered', '--source-context', '1')
27
- expect(data['file']).to eq('lib/foo.rb')
28
- expect(data['source']).to be_an(Array)
29
- # Only a subset of lines around uncovered should appear
30
- lines = data['source'].map { |h| h['line'] }
31
- expect(lines).to include(2) # the uncovered line
32
- end
33
-
34
- it 'includes source rows in JSON for detailed --source=full' do
35
- data = run_cli_json('detailed', 'lib/foo.rb', '--root', root, '--resultset', 'coverage', '--json', '--source=full')
36
- expect(data['file']).to eq('lib/foo.rb')
37
- expect(data['lines']).to be_an(Array)
38
- expect(data['source']).to be_an(Array)
39
- end
40
-
41
- it 'renders uncovered source with various context sizes without error' do
42
- [0, -5, 50].each do |ctx|
43
- out, err, status = begin
44
- cli = described_class.new
45
- s = nil
46
- o = e = nil
47
- silence_output do |stdout, stderr|
48
- begin
49
- cli.run(['uncovered', 'lib/foo.rb', '--root', root, '--resultset', 'coverage', '--source=uncovered', '--source-context', ctx.to_s, '--no-color'])
50
- s = 0
51
- rescue SystemExit => ex
52
- s = ex.status
53
- end
54
- o = stdout.string
55
- e = stderr.string
56
- end
57
- [o, e, s]
58
- end
59
- expect(status).to eq(0)
60
- expect(err).to eq("")
61
- expect(out).to include('File: lib/foo.rb')
62
- expect(out).to include('Uncovered lines: 2')
63
- end
64
- end
65
-
66
- it 'respects --color and --no-color for source rendering' do
67
- # Force color on
68
- out_color = begin
69
- cli = described_class.new
70
- silence_output do |stdout, _stderr|
71
- cli.run(['summary', 'lib/foo.rb', '--root', root, '--resultset', 'coverage', '--source', '--color'])
72
- stdout.string
73
- end
74
- end
75
- # If source table is rendered, it should contain ANSI escapes when color is on
76
- if out_color.include?('Line') && out_color.include?('|')
77
- expect(out_color).to match(/\e\[\d+m/)
78
- else
79
- expect(out_color).to include('[source not available]')
80
- end
81
-
82
- # Force color off: expect no ANSI sequences
83
- out_nocolor = begin
84
- cli = described_class.new
85
- silence_output do |stdout, _stderr|
86
- cli.run(['summary', 'lib/foo.rb', '--root', root, '--resultset', 'coverage', '--source', '--no-color'])
87
- stdout.string
88
- end
89
- end
90
- expect(out_nocolor).not_to match(/\e\[\d+m/)
91
- end
92
- end