mutant 0.5.12 → 0.5.13
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog.md +10 -0
- data/circle.yml +1 -1
- data/config/flay.yml +1 -1
- data/config/flog.yml +1 -1
- data/config/mutant.yml +1 -2
- data/config/reek.yml +12 -3
- data/config/rubocop.yml +4 -0
- data/lib/mutant.rb +45 -16
- data/lib/mutant/constants.rb +11 -11
- data/lib/mutant/delegator.rb +50 -0
- data/lib/mutant/{differ.rb → diff.rb} +5 -5
- data/lib/mutant/killer.rb +29 -106
- data/lib/mutant/matcher/method.rb +2 -11
- data/lib/mutant/mutation.rb +17 -3
- data/lib/mutant/mutation/evil.rb +2 -10
- data/lib/mutant/mutation/neutral.rb +4 -30
- data/lib/mutant/mutator/node/literal/fixnum.rb +0 -1
- data/lib/mutant/mutator/node/literal/float.rb +0 -1
- data/lib/mutant/mutator/node/literal/string.rb +0 -1
- data/lib/mutant/mutator/node/literal/symbol.rb +6 -2
- data/lib/mutant/mutator/node/named_value/variable_assignment.rb +8 -3
- data/lib/mutant/mutator/util/symbol.rb +3 -1
- data/lib/mutant/node_helpers.rb +1 -3
- data/lib/mutant/reporter.rb +10 -0
- data/lib/mutant/reporter/cli.rb +15 -2
- data/lib/mutant/reporter/cli/printer.rb +12 -105
- data/lib/mutant/reporter/cli/progress.rb +12 -0
- data/lib/mutant/reporter/cli/progress/config.rb +32 -0
- data/lib/mutant/reporter/cli/{printer/killer.rb → progress/mutation.rb} +9 -16
- data/lib/mutant/reporter/cli/progress/noop.rb +22 -0
- data/lib/mutant/reporter/cli/progress/subject.rb +118 -0
- data/lib/mutant/reporter/cli/registry.rb +77 -0
- data/lib/mutant/reporter/cli/report.rb +12 -0
- data/lib/mutant/reporter/cli/report/config.rb +118 -0
- data/lib/mutant/reporter/cli/report/mutation.rb +112 -0
- data/lib/mutant/reporter/cli/report/subject.rb +33 -0
- data/lib/mutant/reporter/null.rb +13 -0
- data/lib/mutant/reporter/trace.rb +41 -0
- data/lib/mutant/runner.rb +22 -20
- data/lib/mutant/runner/config.rb +6 -5
- data/lib/mutant/runner/killer.rb +59 -0
- data/lib/mutant/runner/mutation.rb +17 -10
- data/lib/mutant/runner/subject.rb +14 -4
- data/lib/mutant/strategy.rb +30 -16
- data/lib/mutant/subject/method/instance.rb +1 -1
- data/lib/mutant/test.rb +86 -0
- data/lib/mutant/version.rb +1 -1
- data/spec/integration/mutant/null_spec.rb +18 -0
- data/spec/integration/mutant/rspec_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -2
- data/spec/unit/mutant/diff_spec.rb +162 -0
- data/spec/unit/mutant/mutation_spec.rb +8 -5
- data/spec/unit/mutant/mutator/node/and_asgn_spec.rb +1 -9
- data/spec/unit/mutant/mutator/node/block_spec.rb +6 -18
- data/spec/unit/mutant/mutator/node/case_spec.rb +10 -16
- data/spec/unit/mutant/mutator/node/define_spec.rb +5 -17
- data/spec/unit/mutant/mutator/node/dstr_spec.rb +0 -6
- data/spec/unit/mutant/mutator/node/dsym_spec.rb +0 -5
- data/spec/unit/mutant/mutator/node/if_spec.rb +13 -17
- data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +1 -7
- data/spec/unit/mutant/mutator/node/literal/float_spec.rb +0 -9
- data/spec/unit/mutant/mutator/node/literal/range_spec.rb +0 -10
- data/spec/unit/mutant/mutator/node/literal/string_spec.rb +1 -5
- data/spec/unit/mutant/mutator/node/literal/symbol_spec.rb +1 -5
- data/spec/unit/mutant/mutator/node/named_value/access_spec.rb +4 -7
- data/spec/unit/mutant/mutator/node/named_value/constant_assignment_spec.rb +1 -5
- data/spec/unit/mutant/mutator/node/named_value/variable_assignment_spec.rb +4 -8
- data/spec/unit/mutant/mutator/node/op_assgn_spec.rb +0 -7
- data/spec/unit/mutant/mutator/node/or_asgn_spec.rb +1 -9
- data/spec/unit/mutant/mutator/node/rescue_spec.rb +0 -4
- data/spec/unit/mutant/reporter/null_spec.rb +11 -0
- data/spec/unit/mutant/runner/config_spec.rb +6 -7
- data/spec/unit/mutant/runner/mutation_spec.rb +101 -0
- data/spec/unit/mutant/runner/subject_spec.rb +10 -7
- data/spec/unit/mutant_spec.rb +53 -0
- metadata +65 -62
- data/lib/mutant/killer/forked.rb +0 -46
- data/lib/mutant/killer/forking.rb +0 -46
- data/lib/mutant/killer/static.rb +0 -34
- data/lib/mutant/mutator/node/literal/dynamic.rb +0 -27
- data/lib/mutant/random.rb +0 -38
- data/lib/mutant/reporter/cli/printer/config.rb +0 -154
- data/lib/mutant/reporter/cli/printer/mutation.rb +0 -103
- data/lib/mutant/reporter/cli/printer/subject.rb +0 -150
- data/spec/unit/mutant/differ/diff_spec.rb +0 -123
- data/spec/unit/mutant/differ_spec.rb +0 -42
- data/spec/unit/mutant/killer/success_predicate_spec.rb +0 -30
- data/spec/unit/mutant/rspec/killer_spec.rb +0 -57
- data/spec/unit/mutant/runner/mutation/killer_spec.rb +0 -44
@@ -0,0 +1,112 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Reporter
|
5
|
+
class CLI
|
6
|
+
class Report
|
7
|
+
|
8
|
+
# Reporter for mutations
|
9
|
+
class Mutation < self
|
10
|
+
|
11
|
+
# Run report printer
|
12
|
+
#
|
13
|
+
# @return [self]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
#
|
17
|
+
def run
|
18
|
+
puts(object.identification)
|
19
|
+
puts(details)
|
20
|
+
self
|
21
|
+
end
|
22
|
+
|
23
|
+
# Reporter for noop mutations
|
24
|
+
class Noop < self
|
25
|
+
handle(Mutant::Mutation::Neutral::Noop)
|
26
|
+
|
27
|
+
MESSAGE = [
|
28
|
+
'Parsed subject AST:',
|
29
|
+
'%s',
|
30
|
+
'Unparsed source:',
|
31
|
+
'%s'
|
32
|
+
].join("\n").freeze
|
33
|
+
|
34
|
+
delegate :killers
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# Return details
|
39
|
+
#
|
40
|
+
# @return [self]
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
#
|
44
|
+
def details
|
45
|
+
info(MESSAGE, object.subject.node.inspect, object.original_source)
|
46
|
+
end
|
47
|
+
|
48
|
+
end # Noop
|
49
|
+
|
50
|
+
# Reporter for mutations producing a diff
|
51
|
+
class Diff < self
|
52
|
+
handle(Mutant::Mutation::Evil)
|
53
|
+
handle(Mutant::Mutation::Neutral)
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
# Run report printer
|
58
|
+
#
|
59
|
+
# @return [self]
|
60
|
+
#
|
61
|
+
# @api private
|
62
|
+
#
|
63
|
+
def details
|
64
|
+
original, current = object.original_source, object.source
|
65
|
+
diff = Mutant::Diff.build(original, current)
|
66
|
+
color? ? diff.colorized_diff : diff.diff
|
67
|
+
end
|
68
|
+
|
69
|
+
end # Diff
|
70
|
+
end # Mutation
|
71
|
+
|
72
|
+
# Subject report printer
|
73
|
+
class MutationRunner < self
|
74
|
+
handle(Mutant::Runner::Mutation)
|
75
|
+
|
76
|
+
# Run report printer
|
77
|
+
#
|
78
|
+
# @return [self]
|
79
|
+
#
|
80
|
+
# @api private
|
81
|
+
#
|
82
|
+
def run
|
83
|
+
visit(object.mutation)
|
84
|
+
if object.mutation.kind_of?(Mutant::Mutation::Neutral::Noop)
|
85
|
+
report_noop
|
86
|
+
end
|
87
|
+
self
|
88
|
+
end
|
89
|
+
|
90
|
+
delegate :killers
|
91
|
+
|
92
|
+
private
|
93
|
+
|
94
|
+
# Report noop output
|
95
|
+
#
|
96
|
+
# @return [undefined]
|
97
|
+
#
|
98
|
+
# @api private
|
99
|
+
#
|
100
|
+
def report_noop
|
101
|
+
info('NOOP MUTATION TESTS FAILED!')
|
102
|
+
killers.reject(&:success?).map(&:report).map(&:test_report).each do |report|
|
103
|
+
puts(report.test.identification)
|
104
|
+
puts(report.output)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end # Mutation
|
109
|
+
end # Report
|
110
|
+
end # CLI
|
111
|
+
end # Reporter
|
112
|
+
end # Mutant
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Reporter
|
5
|
+
class CLI
|
6
|
+
class Report
|
7
|
+
|
8
|
+
# Subject report printer
|
9
|
+
class Subject < self
|
10
|
+
handle(Mutant::Runner::Subject)
|
11
|
+
|
12
|
+
delegate :subject, :failed_mutations
|
13
|
+
|
14
|
+
# Run report printer
|
15
|
+
#
|
16
|
+
# @return [self]
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
#
|
20
|
+
def run
|
21
|
+
status(subject.identification)
|
22
|
+
object.tests.each do |test|
|
23
|
+
puts("- #{test.identification}")
|
24
|
+
end
|
25
|
+
object.failed_mutations.each(&method(:visit))
|
26
|
+
self
|
27
|
+
end
|
28
|
+
|
29
|
+
end # Subject
|
30
|
+
end # Report
|
31
|
+
end # CLI
|
32
|
+
end # Reporter
|
33
|
+
end # Mutant
|
data/lib/mutant/reporter/null.rb
CHANGED
@@ -5,6 +5,7 @@ module Mutant
|
|
5
5
|
|
6
6
|
# Null reporter
|
7
7
|
class Null < self
|
8
|
+
include Equalizer.new
|
8
9
|
|
9
10
|
# Report object
|
10
11
|
#
|
@@ -18,6 +19,18 @@ module Mutant
|
|
18
19
|
self
|
19
20
|
end
|
20
21
|
|
22
|
+
# Report progress on object
|
23
|
+
#
|
24
|
+
# @param [Object] _object
|
25
|
+
#
|
26
|
+
# @return [self]
|
27
|
+
#
|
28
|
+
# @api private
|
29
|
+
#
|
30
|
+
def progress(_object)
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
21
34
|
end # Null
|
22
35
|
end # Reporter
|
23
36
|
end # Mutant
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Reporter
|
3
|
+
# Reporter to trace report calls, used as a spec adapter
|
4
|
+
class Trace
|
5
|
+
include Concord::Public.new(:progress_calls, :report_calls)
|
6
|
+
|
7
|
+
# Return new trace reporter
|
8
|
+
#
|
9
|
+
# @return [Tracer]
|
10
|
+
#
|
11
|
+
# @api private
|
12
|
+
#
|
13
|
+
def self.new
|
14
|
+
super([], [])
|
15
|
+
end
|
16
|
+
|
17
|
+
# Report object
|
18
|
+
#
|
19
|
+
# @param [Object] object
|
20
|
+
#
|
21
|
+
# @return [self]
|
22
|
+
#
|
23
|
+
def report(object)
|
24
|
+
report_calls << object
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
# Report new progress on object
|
29
|
+
#
|
30
|
+
# @param [Object] object
|
31
|
+
#
|
32
|
+
# @return [self]
|
33
|
+
#
|
34
|
+
def progress(object)
|
35
|
+
progress_calls << object
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
end # Tracker
|
40
|
+
end # reporter
|
41
|
+
end # Mutant
|
data/lib/mutant/runner.rb
CHANGED
@@ -48,9 +48,9 @@ module Mutant
|
|
48
48
|
#
|
49
49
|
# @api private
|
50
50
|
#
|
51
|
-
def self.run(config, object)
|
51
|
+
def self.run(config, object, *arguments)
|
52
52
|
handler = lookup(object.class)
|
53
|
-
handler.new(config, object)
|
53
|
+
handler.new(config, object, *arguments)
|
54
54
|
end
|
55
55
|
|
56
56
|
# Return config
|
@@ -101,16 +101,6 @@ module Mutant
|
|
101
101
|
(@end || Time.now) - @start
|
102
102
|
end
|
103
103
|
|
104
|
-
# Return reporter
|
105
|
-
#
|
106
|
-
# @return [Reporter]
|
107
|
-
#
|
108
|
-
# @api private
|
109
|
-
#
|
110
|
-
def reporter
|
111
|
-
config.reporter
|
112
|
-
end
|
113
|
-
|
114
104
|
# Test if runner is successful
|
115
105
|
#
|
116
106
|
# @return [true]
|
@@ -133,7 +123,7 @@ module Mutant
|
|
133
123
|
#
|
134
124
|
abstract_method :run
|
135
125
|
|
136
|
-
#
|
126
|
+
# Run reporter on object
|
137
127
|
#
|
138
128
|
# @param [Object] object
|
139
129
|
#
|
@@ -141,20 +131,32 @@ module Mutant
|
|
141
131
|
#
|
142
132
|
# @api private
|
143
133
|
#
|
144
|
-
def
|
145
|
-
reporter.
|
134
|
+
def progress(object)
|
135
|
+
reporter.progress(object)
|
146
136
|
end
|
147
137
|
|
148
|
-
#
|
138
|
+
# Return reporter
|
139
|
+
#
|
140
|
+
# @return [Reporter]
|
141
|
+
#
|
142
|
+
# @api private
|
143
|
+
#
|
144
|
+
def reporter
|
145
|
+
config.reporter
|
146
|
+
end
|
147
|
+
|
148
|
+
# Perform dispatch on multiple inputs
|
149
|
+
#
|
150
|
+
# @param [Enumerable<Object>] input
|
149
151
|
#
|
150
152
|
# @return [Enumerable<Runner>]
|
151
153
|
#
|
152
154
|
# @api private
|
153
155
|
#
|
154
|
-
def
|
156
|
+
def visit_collection(input, *arguments)
|
155
157
|
collection = []
|
156
158
|
input.each do |object|
|
157
|
-
runner = visit(object)
|
159
|
+
runner = visit(object, *arguments)
|
158
160
|
collection << runner
|
159
161
|
@stop = runner.stop?
|
160
162
|
break if @stop
|
@@ -170,8 +172,8 @@ module Mutant
|
|
170
172
|
#
|
171
173
|
# @api private
|
172
174
|
#
|
173
|
-
def visit(object)
|
174
|
-
Runner.run(config, object)
|
175
|
+
def visit(object, *arguments)
|
176
|
+
Runner.run(config, object, *arguments)
|
175
177
|
end
|
176
178
|
|
177
179
|
end # Runner
|
data/lib/mutant/runner/config.rb
CHANGED
@@ -5,6 +5,9 @@ module Mutant
|
|
5
5
|
# Runner for object config
|
6
6
|
class Config < self
|
7
7
|
|
8
|
+
# The expected coverage precision
|
9
|
+
COVERAGE_PRECISION = 1
|
10
|
+
|
8
11
|
register Mutant::Config
|
9
12
|
|
10
13
|
# Run runner for object
|
@@ -40,8 +43,6 @@ module Mutant
|
|
40
43
|
end
|
41
44
|
memoize :failed_subjects
|
42
45
|
|
43
|
-
COVERAGE_PRECISION = 1
|
44
|
-
|
45
46
|
# Test if run was successful
|
46
47
|
#
|
47
48
|
# @return [true]
|
@@ -122,7 +123,7 @@ module Mutant
|
|
122
123
|
def run_subjects
|
123
124
|
strategy = self.strategy
|
124
125
|
strategy.setup
|
125
|
-
@subjects =
|
126
|
+
@subjects = visit_collection(config.subjects)
|
126
127
|
strategy.teardown
|
127
128
|
end
|
128
129
|
|
@@ -133,10 +134,10 @@ module Mutant
|
|
133
134
|
# @api private
|
134
135
|
#
|
135
136
|
def run
|
136
|
-
|
137
|
+
progress(config)
|
137
138
|
run_subjects
|
138
139
|
@end = Time.now
|
139
|
-
report(self)
|
140
|
+
reporter.report(self)
|
140
141
|
end
|
141
142
|
|
142
143
|
end # Config
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Runner
|
3
|
+
# Killer runner
|
4
|
+
class Killer < self
|
5
|
+
include Equalizer.new(:config, :killer)
|
6
|
+
|
7
|
+
register Mutant::Killer
|
8
|
+
|
9
|
+
# Return killer
|
10
|
+
#
|
11
|
+
# @return [Killer]
|
12
|
+
#
|
13
|
+
# @api private
|
14
|
+
#
|
15
|
+
attr_reader :killer
|
16
|
+
protected :killer
|
17
|
+
|
18
|
+
# Return kill report
|
19
|
+
#
|
20
|
+
# @return [Killer::Report]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
#
|
24
|
+
attr_reader :report
|
25
|
+
|
26
|
+
# Test if killer ran successfully
|
27
|
+
#
|
28
|
+
# @return [Boolean]
|
29
|
+
#
|
30
|
+
# @api private
|
31
|
+
def success?
|
32
|
+
@report.success?
|
33
|
+
end
|
34
|
+
|
35
|
+
# Initialize object
|
36
|
+
#
|
37
|
+
# @param [Config] config
|
38
|
+
# @param [Mutation] mutation
|
39
|
+
#
|
40
|
+
# @return [undefined]
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
#
|
44
|
+
def initialize(config, killer)
|
45
|
+
@killer = killer
|
46
|
+
super(config)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Run killer
|
50
|
+
#
|
51
|
+
# @api private
|
52
|
+
#
|
53
|
+
def run
|
54
|
+
@report = killer.run
|
55
|
+
end
|
56
|
+
|
57
|
+
end # Killer
|
58
|
+
end # Runner
|
59
|
+
end # Mutant
|
@@ -4,7 +4,7 @@ module Mutant
|
|
4
4
|
class Runner
|
5
5
|
# Mutation runner
|
6
6
|
class Mutation < self
|
7
|
-
include Equalizer.new(:config, :mutation)
|
7
|
+
include Equalizer.new(:config, :mutation, :tests)
|
8
8
|
|
9
9
|
register Mutant::Mutation
|
10
10
|
|
@@ -16,26 +16,28 @@ module Mutant
|
|
16
16
|
#
|
17
17
|
attr_reader :mutation
|
18
18
|
|
19
|
-
# Return
|
19
|
+
# Return killers
|
20
20
|
#
|
21
|
-
# @return [Killer]
|
21
|
+
# @return [Enumerable<Runner::Killer>]
|
22
22
|
#
|
23
23
|
# @api private
|
24
24
|
#
|
25
|
-
attr_reader :
|
25
|
+
attr_reader :killers
|
26
26
|
|
27
27
|
# Initialize object
|
28
28
|
#
|
29
29
|
# @param [Config] config
|
30
30
|
# @param [Mutation] mutation
|
31
|
+
# @param [Enumerable<Test>] tests
|
31
32
|
#
|
32
33
|
# @return [undefined]
|
33
34
|
#
|
34
35
|
# @api private
|
35
36
|
#
|
36
|
-
def initialize(config, mutation)
|
37
|
-
@mutation = mutation
|
37
|
+
def initialize(config, mutation, tests)
|
38
|
+
@mutation, @tests = mutation, tests
|
38
39
|
super(config)
|
40
|
+
@stop = config.fail_fast && !success?
|
39
41
|
end
|
40
42
|
|
41
43
|
# Test if mutation was handeled successfully
|
@@ -49,7 +51,7 @@ module Mutant
|
|
49
51
|
# @api private
|
50
52
|
#
|
51
53
|
def success?
|
52
|
-
|
54
|
+
killers.any?(&:success?)
|
53
55
|
end
|
54
56
|
|
55
57
|
private
|
@@ -61,9 +63,14 @@ module Mutant
|
|
61
63
|
# @api private
|
62
64
|
#
|
63
65
|
def run
|
64
|
-
|
65
|
-
|
66
|
-
|
66
|
+
progress(mutation)
|
67
|
+
@killers = @tests.map do |test|
|
68
|
+
Mutant::Killer.new(
|
69
|
+
mutation: mutation,
|
70
|
+
test: test
|
71
|
+
)
|
72
|
+
end.map(&method(:visit))
|
73
|
+
progress(self)
|
67
74
|
end
|
68
75
|
|
69
76
|
end # Mutation
|