Module: SimpleCov::CLI::Tests
- Extended by:
- CommandHelpers, Tests
- Included in:
- Tests
- Defined in:
- lib/simplecov/cli/tests.rb,
lib/simplecov/cli/tests/redundancy.rb
Overview
simplecov tests [<path>[:<line>]]: list the recorded tests from a
coverage.json written under track_tests. Text output is one id per line
so the list can feed a test runner directly; empty answers keep stdout
empty and note the emptiness on stderr instead.
Defined Under Namespace
Modules: Redundancy
Constant Summary
CommandHelpers::STATS_ROW_FORMAT
Instance Method Summary
collapse
-
#context_table(entry, contexts, opts, stderr) ⇒ Object
-
#decode_table(raw, context_count) ⇒ Object
An absent key is an untouched file; anything malformed, a foreign index or a non-hex bitmap, poisons the whole answer, matching the all-or-nothing tolerance the resultset reader applies.
-
#emit(ids, opts, stdout, stderr) ⇒ Object
-
#empty_message(opts) ⇒ Object
-
#ids_from(table, contexts, line) ⇒ Object
-
#locate_entry(document, opts, stderr) ⇒ Object
-
#note_empty(opts, stderr) ⇒ Object
-
#parse(args) ⇒ Object
-
#resolve(document, opts, stderr) ⇒ Object
-
#run(args, stdout:, stderr:) ⇒ Object
-
#selected_ids(document, contexts, opts, stderr) ⇒ Object
-
#split_target(target) ⇒ Object
Only an all-digit tail after the last colon reads as a line number, so Windows drive colons and exotic filenames stay plain paths.
build_parser, command_name, common_options, error, error_nil, on_help, one?, parse_common, quiet_option, recorded_contexts, stats_row
Instance Method Details
#context_table(entry, contexts, opts, stderr) ⇒ Object
92
93
94
95
96
97
98
99
|
# File 'lib/simplecov/cli/tests.rb', line 92
def context_table(entry, contexts, opts, stderr)
raw = entry["contexts"] || {}
table = decode_table(raw, contexts.size) if raw.is_a?(Hash)
return table if table
CoverageFile.report_invalid(stderr, "tests", opts.fetch(:input),
"entry for #{opts.fetch(:path)} carries a malformed \"contexts\" table")
end
|
#decode_table(raw, context_count) ⇒ Object
An absent key is an untouched file; anything malformed, a foreign index or
a non-hex bitmap, poisons the whole answer, matching the all-or-nothing
tolerance the resultset reader applies.
104
105
106
107
108
109
110
111
112
113
114
115
116
|
# File 'lib/simplecov/cli/tests.rb', line 104
def decode_table(raw, context_count)
table = {} raw.each do |index, hex|
return nil unless index.is_a?(String) && index.match?(/\A\d+\z/)
return nil unless hex.is_a?(String) && hex.match?(/\A\h+\z/)
position = Integer(index, 10)
return nil unless position < context_count
table[position] = Integer(hex, 16)
end
table
end
|
#emit(ids, opts, stdout, stderr) ⇒ Object
123
124
125
126
127
128
|
# File 'lib/simplecov/cli/tests.rb', line 123
def emit(ids, opts, stdout, stderr)
return stdout.puts(JSON.pretty_generate(ids)) if opts.fetch(:json)
return note_empty(opts, stderr) if ids.empty?
ids.each { |id| stdout.puts(id) }
end
|
#empty_message(opts) ⇒ Object
134
135
136
137
138
139
140
141
142
143
144
145
|
# File 'lib/simplecov/cli/tests.rb', line 134
def empty_message(opts)
target = opts.fetch(:target)
if opts[:redundant] && !opts.fetch(:no_recording)
return "no redundant test covers #{target}" if target
"no redundant tests, every recorded test covers at least one line uniquely"
elsif target
"no recorded test covers #{target}"
else
"no tests recorded"
end
end
|
#ids_from(table, contexts, line) ⇒ Object
118
119
120
121
|
# File 'lib/simplecov/cli/tests.rb', line 118
def ids_from(table, contexts, line)
bit = line && (1 << (line - 1))
table.filter_map { |index, bitmap| contexts.fetch(index) if bit.nil? || bitmap.anybits?(bit) }.sort
end
|
#locate_entry(document, opts, stderr) ⇒ Object
77
78
79
80
81
82
83
84
85
86
87
88
89
90
|
# File 'lib/simplecov/cli/tests.rb', line 77
def locate_entry(document, opts, stderr)
coverage = document["coverage"]
input = opts.fetch(:input)
unless coverage.is_a?(Hash)
return CoverageFile.report_invalid(stderr, "tests", input, '"coverage" must be an object')
end
path = opts.fetch(:path)
match = CoverageFile.lookup(coverage, path)
return error_nil(stderr, CoverageFile.not_found_message(coverage, path, input)) unless match
return match.last if match.last.is_a?(Hash)
CoverageFile.report_invalid(stderr, "tests", input, "entry for #{path} must be an object")
end
|
#note_empty(opts, stderr) ⇒ Object
130
131
132
|
# File 'lib/simplecov/cli/tests.rb', line 130
def note_empty(opts, stderr)
stderr.puts("simplecov tests: #{empty_message(opts)}")
end
|
#parse(args) ⇒ Object
33
34
35
36
37
38
39
40
41
42
|
# File 'lib/simplecov/cli/tests.rb', line 33
def parse(args)
opts, rest = parse_common(args) do |parser, options|
parser.on("--redundant") { options[:redundant] = true }
end
opts[:target] = rest.first
split = split_target(rest.first)
opts[:path] = split.fetch(:path)
opts[:line] = split.fetch(:line)
opts
end
|
#resolve(document, opts, stderr) ⇒ Object
55
56
57
58
59
60
61
62
63
64
65
|
# File 'lib/simplecov/cli/tests.rb', line 55
def resolve(document, opts, stderr)
contexts = recorded_contexts(document, opts, stderr)
return unless contexts
opts[:no_recording] = contexts.empty?
ids = selected_ids(document, contexts, opts, stderr)
return ids unless ids && opts[:redundant]
redundant = Redundancy.redundant_ids(document, contexts, opts, stderr)
redundant && (ids & redundant)
end
|
#run(args, stdout:, stderr:) ⇒ Object
19
20
21
22
23
24
25
26
27
28
29
30
31
|
# File 'lib/simplecov/cli/tests.rb', line 19
def run(args, stdout:, stderr:)
opts = parse(args)
return error(stderr, "line number must be positive") if opts.fetch(:line)&.zero?
document = CoverageFile.load_document(opts.fetch(:input), command: "tests", stderr: stderr)
return 1 unless document
ids = resolve(document, opts, stderr)
return 1 unless ids
emit(ids, opts, stdout, stderr)
0
end
|
#selected_ids(document, contexts, opts, stderr) ⇒ Object
67
68
69
70
71
72
73
74
75
|
# File 'lib/simplecov/cli/tests.rb', line 67
def selected_ids(document, contexts, opts, stderr)
return contexts.sort unless opts.fetch(:path)
entry = locate_entry(document, opts, stderr)
return unless entry
table = context_table(entry, contexts, opts, stderr)
table && ids_from(table, contexts, opts.fetch(:line))
end
|
#split_target(target) ⇒ Object
Only an all-digit tail after the last colon reads as a line number, so
Windows drive colons and exotic filenames stay plain paths.
46
47
48
49
50
51
52
53
|
# File 'lib/simplecov/cli/tests.rb', line 46
def split_target(target)
return {path: nil, line: nil} unless target
path, sep, tail = target.rpartition(":")
return {path: target, line: nil} if sep.empty? || !tail.match?(/\A\d+\z/)
{path: path, line: Integer(tail, 10)}
end
|