mutant 0.7.9 → 0.8.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/Changelog.md +11 -1
- data/README.md +5 -12
- data/bin/mutant +17 -1
- data/config/flay.yml +1 -1
- data/config/flog.yml +1 -1
- data/config/reek.yml +4 -4
- data/config/rubocop.yml +21 -3
- data/lib/mutant.rb +15 -61
- data/lib/mutant/cli.rb +1 -7
- data/lib/mutant/color.rb +2 -2
- data/lib/mutant/config.rb +1 -1
- data/lib/mutant/expression/method.rb +1 -1
- data/lib/mutant/expression/methods.rb +1 -1
- data/lib/mutant/expression/namespace.rb +1 -1
- data/lib/mutant/mutator/node/send.rb +18 -18
- data/lib/mutant/reporter/cli.rb +1 -6
- data/lib/mutant/reporter/cli/format.rb +2 -2
- data/lib/mutant/reporter/cli/printer.rb +5 -500
- data/lib/mutant/reporter/cli/printer/config.rb +32 -0
- data/lib/mutant/reporter/cli/printer/env_progress.rb +66 -0
- data/lib/mutant/reporter/cli/printer/env_result.rb +23 -0
- data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +37 -0
- data/lib/mutant/reporter/cli/printer/mutation_result.rb +151 -0
- data/lib/mutant/reporter/cli/printer/status.rb +60 -0
- data/lib/mutant/reporter/cli/printer/status_progressive.rb +52 -0
- data/lib/mutant/reporter/cli/printer/subject_progress.rb +90 -0
- data/lib/mutant/reporter/cli/printer/subject_result.rb +28 -0
- data/lib/mutant/reporter/cli/printer/test_result.rb +33 -0
- data/lib/mutant/require_highjack.rb +11 -50
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/zombifier.rb +79 -37
- data/meta/send.rb +1 -1
- data/mutant-rspec.gemspec +1 -1
- data/mutant.gemspec +3 -3
- data/spec/integration/mutant/corpus_spec.rb +2 -2
- data/spec/integration/mutant/rspec_spec.rb +5 -15
- data/spec/integrations.yml +3 -3
- data/spec/spec_helper.rb +1 -0
- data/spec/support/corpus.rb +233 -220
- data/spec/support/file_system.rb +60 -0
- data/spec/support/rb_bug.rb +1 -1
- data/spec/support/ruby_vm.rb +82 -0
- data/spec/support/shared_context.rb +19 -10
- data/spec/unit/mutant/ast_spec.rb +2 -2
- data/spec/unit/mutant/cache_spec.rb +22 -0
- data/spec/unit/mutant/cli_spec.rb +1 -30
- data/spec/unit/mutant/context_spec.rb +1 -0
- data/spec/unit/mutant/expression/method_spec.rb +6 -4
- data/spec/unit/mutant/parallel/master_spec.rb +1 -1
- data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +33 -0
- data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +76 -0
- data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +35 -0
- data/spec/unit/mutant/reporter/cli/printer/mutation_progress_result_spec.rb +23 -0
- data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +110 -0
- data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +51 -0
- data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +145 -0
- data/spec/unit/mutant/reporter/cli/printer/subject_progress_spec.rb +37 -0
- data/spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb +37 -0
- data/spec/unit/mutant/reporter/cli/printer/test_result_spec.rb +14 -0
- data/spec/unit/mutant/reporter/cli/printer_spec.rb +140 -0
- data/spec/unit/mutant/reporter/cli_spec.rb +69 -313
- data/spec/unit/mutant/reporter/trace_spec.rb +12 -0
- data/spec/unit/mutant/require_highjack_spec.rb +25 -28
- data/spec/unit/mutant/warning_filter_spec.rb +7 -0
- data/spec/unit/mutant/zombifier_spec.rb +120 -0
- data/spec/unit/mutant_spec.rb +0 -43
- data/test_app/Gemfile.rspec3.3 +6 -0
- metadata +46 -17
- data/.travis.yml +0 -20
- data/lib/mutant/zombifier/file.rb +0 -100
- data/spec/integration/mutant/zombie_spec.rb +0 -6
@@ -0,0 +1,32 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Reporter
|
3
|
+
class CLI
|
4
|
+
class Printer
|
5
|
+
# Printer for mutation config
|
6
|
+
class Config < self
|
7
|
+
|
8
|
+
# Report configuration
|
9
|
+
#
|
10
|
+
# @param [Mutant::Config] config
|
11
|
+
#
|
12
|
+
# @return [undefined]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
# rubocop:disable AbcSize
|
17
|
+
#
|
18
|
+
def run
|
19
|
+
info 'Mutant configuration:'
|
20
|
+
info 'Matcher: %s', object.matcher.inspect
|
21
|
+
info 'Integration: %s', object.integration.name
|
22
|
+
info 'Expect Coverage: %0.2f%%', (object.expected_coverage * 100)
|
23
|
+
info 'Jobs: %d', object.jobs
|
24
|
+
info 'Includes: %s', object.includes
|
25
|
+
info 'Requires: %s', object.requires
|
26
|
+
end
|
27
|
+
|
28
|
+
end # Config
|
29
|
+
end # Printer
|
30
|
+
end # CLI
|
31
|
+
end # Reporter
|
32
|
+
end # Mutant
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Reporter
|
3
|
+
class CLI
|
4
|
+
class Printer
|
5
|
+
# Env progress printer
|
6
|
+
class EnvProgress < self
|
7
|
+
delegate(
|
8
|
+
:coverage,
|
9
|
+
:amount_subjects,
|
10
|
+
:amount_mutations,
|
11
|
+
:amount_mutations_alive,
|
12
|
+
:amount_mutations_killed,
|
13
|
+
:runtime,
|
14
|
+
:killtime,
|
15
|
+
:overhead,
|
16
|
+
:env
|
17
|
+
)
|
18
|
+
|
19
|
+
# Run printer
|
20
|
+
#
|
21
|
+
# @return [undefined]
|
22
|
+
#
|
23
|
+
# @api private
|
24
|
+
#
|
25
|
+
# rubocop:disable MethodLength
|
26
|
+
# rubocop:disable AbcSize
|
27
|
+
#
|
28
|
+
def run
|
29
|
+
visit(Config, env.config)
|
30
|
+
info 'Subjects: %s', amount_subjects
|
31
|
+
info 'Mutations: %s', amount_mutations
|
32
|
+
info 'Kills: %s', amount_mutations_killed
|
33
|
+
info 'Alive: %s', amount_mutations_alive
|
34
|
+
info 'Runtime: %0.2fs', runtime
|
35
|
+
info 'Killtime: %0.2fs', killtime
|
36
|
+
info 'Overhead: %0.2f%%', overhead_percent
|
37
|
+
status 'Coverage: %0.2f%%', coverage_percent
|
38
|
+
status 'Expected: %0.2f%%', (env.config.expected_coverage * 100)
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Return coverage percent
|
44
|
+
#
|
45
|
+
# @return [Float]
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
#
|
49
|
+
def coverage_percent
|
50
|
+
coverage * 100
|
51
|
+
end
|
52
|
+
|
53
|
+
# Return overhead percent
|
54
|
+
#
|
55
|
+
# @return [Float]
|
56
|
+
#
|
57
|
+
# @api private
|
58
|
+
#
|
59
|
+
def overhead_percent
|
60
|
+
(overhead / killtime) * 100
|
61
|
+
end
|
62
|
+
end # EnvProgress
|
63
|
+
end # Printer
|
64
|
+
end # CLI
|
65
|
+
end # Reporter
|
66
|
+
end # Mutant
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Reporter
|
3
|
+
class CLI
|
4
|
+
class Printer
|
5
|
+
# Full env result reporter
|
6
|
+
class EnvResult < self
|
7
|
+
delegate(:failed_subject_results)
|
8
|
+
|
9
|
+
# Run printer
|
10
|
+
#
|
11
|
+
# @return [undefined]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
#
|
15
|
+
def run
|
16
|
+
visit_collection(SubjectResult, failed_subject_results)
|
17
|
+
visit(EnvProgress, object)
|
18
|
+
end
|
19
|
+
end # EnvResult
|
20
|
+
end # Printer
|
21
|
+
end # CLI
|
22
|
+
end # Reporter
|
23
|
+
end # Mutant
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Reporter
|
3
|
+
class CLI
|
4
|
+
class Printer
|
5
|
+
# Printer for mutation progress results
|
6
|
+
class MutationProgressResult < self
|
7
|
+
SUCCESS = '.'.freeze
|
8
|
+
FAILURE = 'F'.freeze
|
9
|
+
|
10
|
+
# Run printer
|
11
|
+
#
|
12
|
+
# @return [undefined]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
def run
|
17
|
+
char(success? ? SUCCESS : FAILURE)
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
# Write colorized char
|
23
|
+
#
|
24
|
+
# @param [String] char
|
25
|
+
#
|
26
|
+
# @return [undefined]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
#
|
30
|
+
def char(char)
|
31
|
+
output.write(colorize(status_color, char))
|
32
|
+
end
|
33
|
+
end # MutationProgressResult
|
34
|
+
end # Printer
|
35
|
+
end # CLI
|
36
|
+
end # Reporter
|
37
|
+
end # Mutant
|
@@ -0,0 +1,151 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Reporter
|
3
|
+
class CLI
|
4
|
+
class Printer
|
5
|
+
# Reporter for mutation results
|
6
|
+
class MutationResult < self
|
7
|
+
|
8
|
+
delegate :mutation, :test_result
|
9
|
+
|
10
|
+
DIFF_ERROR_MESSAGE =
|
11
|
+
'BUG: Mutation NOT resulted in exactly one diff hunk. Please report a reproduction!'.freeze
|
12
|
+
|
13
|
+
MAP = {
|
14
|
+
Mutant::Mutation::Evil => :evil_details,
|
15
|
+
Mutant::Mutation::Neutral => :neutral_details,
|
16
|
+
Mutant::Mutation::Noop => :noop_details
|
17
|
+
}.freeze
|
18
|
+
|
19
|
+
NEUTRAL_MESSAGE =
|
20
|
+
"--- Neutral failure ---\n" \
|
21
|
+
"Original code was inserted unmutated. And the test did NOT PASS.\n" \
|
22
|
+
"Your tests do not pass initially or you found a bug in mutant / unparser.\n" \
|
23
|
+
"Subject AST:\n" \
|
24
|
+
"%s\n" \
|
25
|
+
"Unparsed Source:\n" \
|
26
|
+
"%s\n" \
|
27
|
+
"Test Result:\n".freeze
|
28
|
+
|
29
|
+
NO_DIFF_MESSAGE =
|
30
|
+
"--- Internal failure ---\n" \
|
31
|
+
"BUG: Mutation NOT resulted in exactly one diff hunk. Please report a reproduction!\n" \
|
32
|
+
"Original unparsed source:\n" \
|
33
|
+
"%s\n" \
|
34
|
+
"Original AST:\n" \
|
35
|
+
"%s\n" \
|
36
|
+
"Mutated unparsed source:\n" \
|
37
|
+
"%s\n" \
|
38
|
+
"Mutated AST:\n" \
|
39
|
+
"%s\n".freeze
|
40
|
+
|
41
|
+
NOOP_MESSAGE =
|
42
|
+
"---- Noop failure -----\n" \
|
43
|
+
"No code was inserted. And the test did NOT PASS.\n" \
|
44
|
+
"This is typically a problem of your specs not passing unmutated.\n" \
|
45
|
+
"Test Result:\n".freeze
|
46
|
+
|
47
|
+
FOOTER = '-----------------------'.freeze
|
48
|
+
|
49
|
+
# Run report printer
|
50
|
+
#
|
51
|
+
# @return [undefined]
|
52
|
+
#
|
53
|
+
# @api private
|
54
|
+
#
|
55
|
+
def run
|
56
|
+
puts(mutation.identification)
|
57
|
+
print_details
|
58
|
+
puts(FOOTER)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# Return details
|
64
|
+
#
|
65
|
+
# @return [undefined]
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
#
|
69
|
+
def print_details
|
70
|
+
__send__(MAP.fetch(mutation.class))
|
71
|
+
end
|
72
|
+
|
73
|
+
# Return evil details
|
74
|
+
#
|
75
|
+
# @return [String]
|
76
|
+
#
|
77
|
+
# @api private
|
78
|
+
#
|
79
|
+
def evil_details
|
80
|
+
diff = Diff.build(mutation.original_source, mutation.source)
|
81
|
+
diff = color? ? diff.colorized_diff : diff.diff
|
82
|
+
if diff
|
83
|
+
output.write(diff)
|
84
|
+
else
|
85
|
+
print_no_diff_message
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Print no diff message
|
90
|
+
#
|
91
|
+
# @return [undefined]
|
92
|
+
#
|
93
|
+
# @api private
|
94
|
+
#
|
95
|
+
def print_no_diff_message
|
96
|
+
info(
|
97
|
+
NO_DIFF_MESSAGE,
|
98
|
+
mutation.original_source,
|
99
|
+
original_node.inspect,
|
100
|
+
mutation.source,
|
101
|
+
mutation.node.inspect
|
102
|
+
)
|
103
|
+
end
|
104
|
+
|
105
|
+
# Noop details
|
106
|
+
#
|
107
|
+
# @return [String]
|
108
|
+
#
|
109
|
+
# @api private
|
110
|
+
#
|
111
|
+
def noop_details
|
112
|
+
info(NOOP_MESSAGE)
|
113
|
+
visit_test_result
|
114
|
+
end
|
115
|
+
|
116
|
+
# Neutral details
|
117
|
+
#
|
118
|
+
# @return [String]
|
119
|
+
#
|
120
|
+
# @api private
|
121
|
+
#
|
122
|
+
def neutral_details
|
123
|
+
info(NEUTRAL_MESSAGE, original_node.inspect, mutation.source)
|
124
|
+
visit_test_result
|
125
|
+
end
|
126
|
+
|
127
|
+
# Visit failed test results
|
128
|
+
#
|
129
|
+
# @return [undefined]
|
130
|
+
#
|
131
|
+
# @api private
|
132
|
+
#
|
133
|
+
def visit_test_result
|
134
|
+
visit(TestResult, test_result)
|
135
|
+
end
|
136
|
+
|
137
|
+
# Return original node
|
138
|
+
#
|
139
|
+
# @return [Parser::AST::Node]
|
140
|
+
#
|
141
|
+
# @api private
|
142
|
+
#
|
143
|
+
def original_node
|
144
|
+
mutation.subject.node
|
145
|
+
end
|
146
|
+
|
147
|
+
end # MutationResult
|
148
|
+
end # Printer
|
149
|
+
end # CLI
|
150
|
+
end # Reporter
|
151
|
+
end # Mutant
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Reporter
|
3
|
+
class CLI
|
4
|
+
class Printer
|
5
|
+
# Printer for runner status
|
6
|
+
class Status < self
|
7
|
+
|
8
|
+
delegate(:active_jobs, :payload)
|
9
|
+
|
10
|
+
ACTIVE_JOB_HEADER = 'Active Jobs:'.freeze
|
11
|
+
ACTIVE_JOB_FORMAT = '%d: %s'.freeze
|
12
|
+
|
13
|
+
# Print progress for collector
|
14
|
+
#
|
15
|
+
# @return [undefined]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
def run
|
20
|
+
visit(EnvProgress, payload)
|
21
|
+
job_status
|
22
|
+
info('Active subjects: %d', active_subject_results.length)
|
23
|
+
visit_collection(SubjectProgress, active_subject_results)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
# Print worker status
|
29
|
+
#
|
30
|
+
# @return [undefined]
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
#
|
34
|
+
def job_status
|
35
|
+
return if active_jobs.empty?
|
36
|
+
info(ACTIVE_JOB_HEADER)
|
37
|
+
active_jobs.sort_by(&:index).each do |job|
|
38
|
+
info(ACTIVE_JOB_FORMAT, job.index, job.payload.identification)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Return active subject results
|
43
|
+
#
|
44
|
+
# @return [Array<Result::Subject>]
|
45
|
+
#
|
46
|
+
# @api private
|
47
|
+
#
|
48
|
+
def active_subject_results
|
49
|
+
active_subjects = active_jobs.map(&:payload).flat_map(&:subject)
|
50
|
+
|
51
|
+
payload.subject_results.select do |subject_result|
|
52
|
+
active_subjects.include?(subject_result.subject)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end # Status
|
57
|
+
end # Printer
|
58
|
+
end # CLI
|
59
|
+
end # Reporter
|
60
|
+
end # Mutant
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Reporter
|
3
|
+
class CLI
|
4
|
+
class Printer
|
5
|
+
# Reporter for progressive output format on scheduler Status objects
|
6
|
+
class StatusProgressive < self
|
7
|
+
FORMAT = '(%02d/%02d) %3d%% - killtime: %0.02fs runtime: %0.02fs overhead: %0.02fs'.freeze
|
8
|
+
|
9
|
+
delegate(
|
10
|
+
:coverage,
|
11
|
+
:runtime,
|
12
|
+
:amount_mutations_killed,
|
13
|
+
:amount_mutations,
|
14
|
+
:amount_mutation_results,
|
15
|
+
:killtime,
|
16
|
+
:overhead
|
17
|
+
)
|
18
|
+
|
19
|
+
# Run printer
|
20
|
+
#
|
21
|
+
# @return [undefined]
|
22
|
+
#
|
23
|
+
# @api private
|
24
|
+
#
|
25
|
+
def run
|
26
|
+
status(
|
27
|
+
FORMAT,
|
28
|
+
amount_mutations_killed,
|
29
|
+
amount_mutations,
|
30
|
+
coverage * 100,
|
31
|
+
killtime,
|
32
|
+
runtime,
|
33
|
+
overhead
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
# Return object being printed
|
40
|
+
#
|
41
|
+
# @return [Result::Env]
|
42
|
+
#
|
43
|
+
# @api private
|
44
|
+
#
|
45
|
+
def object
|
46
|
+
super.payload
|
47
|
+
end
|
48
|
+
end # StatusProgressive
|
49
|
+
end # Printer
|
50
|
+
end # CLI
|
51
|
+
end # Reporter
|
52
|
+
end # Mutant
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Reporter
|
3
|
+
class CLI
|
4
|
+
class Printer
|
5
|
+
# Reporter for subject progress
|
6
|
+
class SubjectProgress < self
|
7
|
+
FORMAT = '(%02d/%02d) %3d%% - killtime: %0.02fs runtime: %0.02fs overhead: %0.02fs'.freeze
|
8
|
+
|
9
|
+
delegate(
|
10
|
+
:tests,
|
11
|
+
:subject,
|
12
|
+
:coverage,
|
13
|
+
:runtime,
|
14
|
+
:amount_mutations_killed,
|
15
|
+
:amount_mutations,
|
16
|
+
:amount_mutation_results,
|
17
|
+
:killtime,
|
18
|
+
:overhead
|
19
|
+
)
|
20
|
+
|
21
|
+
# Run printer
|
22
|
+
#
|
23
|
+
# @return [undefined]
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
#
|
27
|
+
def run
|
28
|
+
puts("#{subject.identification} mutations: #{amount_mutations}")
|
29
|
+
print_mutation_results
|
30
|
+
print_progress_bar_finish
|
31
|
+
print_stats
|
32
|
+
print_tests
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
# Print stats
|
38
|
+
#
|
39
|
+
# @return [undefined]
|
40
|
+
#
|
41
|
+
# @api private
|
42
|
+
#
|
43
|
+
def print_stats
|
44
|
+
status(
|
45
|
+
FORMAT,
|
46
|
+
amount_mutations_killed,
|
47
|
+
amount_mutations,
|
48
|
+
coverage * 100,
|
49
|
+
killtime,
|
50
|
+
runtime,
|
51
|
+
overhead
|
52
|
+
)
|
53
|
+
end
|
54
|
+
|
55
|
+
# Print tests
|
56
|
+
#
|
57
|
+
# @return [undefined]
|
58
|
+
#
|
59
|
+
# @api private
|
60
|
+
#
|
61
|
+
def print_tests
|
62
|
+
tests.each do |test|
|
63
|
+
puts "- #{test.identification}"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# Print progress bar finish
|
68
|
+
#
|
69
|
+
# @return [undefined]
|
70
|
+
#
|
71
|
+
# @api private
|
72
|
+
#
|
73
|
+
def print_progress_bar_finish
|
74
|
+
puts(nil) unless amount_mutation_results.zero?
|
75
|
+
end
|
76
|
+
|
77
|
+
# Print mutation results
|
78
|
+
#
|
79
|
+
# @return [undefined]
|
80
|
+
#
|
81
|
+
# @api private
|
82
|
+
#
|
83
|
+
def print_mutation_results
|
84
|
+
visit_collection(MutationProgressResult, object.mutation_results)
|
85
|
+
end
|
86
|
+
end # SubjectProgress
|
87
|
+
end # Printer
|
88
|
+
end # CLI
|
89
|
+
end # Reporter
|
90
|
+
end # Mutant
|