mutant 0.5.12 → 0.5.13
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 +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
@@ -24,17 +24,8 @@ module Mutant
|
|
24
24
|
def each
|
25
25
|
return to_enum unless block_given?
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
yield subject
|
30
|
-
else
|
31
|
-
message = sprintf(
|
32
|
-
'Cannot find definition of: %s in %s',
|
33
|
-
identification,
|
34
|
-
source_location.join(':')
|
35
|
-
)
|
36
|
-
$stderr.puts(message)
|
37
|
-
end
|
27
|
+
if !skip? && subject
|
28
|
+
yield subject
|
38
29
|
end
|
39
30
|
|
40
31
|
self
|
data/lib/mutant/mutation.rb
CHANGED
@@ -6,6 +6,9 @@ module Mutant
|
|
6
6
|
include AbstractType, Adamantium::Flat
|
7
7
|
include Concord::Public.new(:subject, :node)
|
8
8
|
|
9
|
+
CODE_DELIMITER = "\0".freeze
|
10
|
+
CODE_RANGE = (0..4).freeze
|
11
|
+
|
9
12
|
# Return mutated root node
|
10
13
|
#
|
11
14
|
# @return [Parser::AST::Node]
|
@@ -54,8 +57,9 @@ module Mutant
|
|
54
57
|
# @api private
|
55
58
|
#
|
56
59
|
def identification
|
57
|
-
"#{subject.identification}:#{code}"
|
60
|
+
"#{self.class::SYMBOL}:#{subject.identification}:#{code}"
|
58
61
|
end
|
62
|
+
memoize :identification
|
59
63
|
|
60
64
|
# Return mutation code
|
61
65
|
#
|
@@ -64,7 +68,7 @@ module Mutant
|
|
64
68
|
# @api private
|
65
69
|
#
|
66
70
|
def code
|
67
|
-
sha1[
|
71
|
+
sha1[CODE_RANGE]
|
68
72
|
end
|
69
73
|
memoize :code
|
70
74
|
|
@@ -89,6 +93,16 @@ module Mutant
|
|
89
93
|
subject.source
|
90
94
|
end
|
91
95
|
|
96
|
+
# Test if test should fail under mutation
|
97
|
+
#
|
98
|
+
# @return [Boolean]
|
99
|
+
#
|
100
|
+
# @api private
|
101
|
+
#
|
102
|
+
def should_fail?
|
103
|
+
self.class::SHOULD_FAIL
|
104
|
+
end
|
105
|
+
|
92
106
|
private
|
93
107
|
|
94
108
|
# Return sha1 sum of source and subject identification
|
@@ -98,7 +112,7 @@ module Mutant
|
|
98
112
|
# @api private
|
99
113
|
#
|
100
114
|
def sha1
|
101
|
-
Digest::SHA1.hexdigest(subject.identification +
|
115
|
+
Digest::SHA1.hexdigest(subject.identification + CODE_DELIMITER + source)
|
102
116
|
end
|
103
117
|
memoize :sha1
|
104
118
|
|
data/lib/mutant/mutation/evil.rb
CHANGED
@@ -5,16 +5,8 @@ module Mutant
|
|
5
5
|
# Evul mutation
|
6
6
|
class Evil < self
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
# @return [String]
|
11
|
-
#
|
12
|
-
# @api private
|
13
|
-
#
|
14
|
-
def identification
|
15
|
-
"evil:#{super}"
|
16
|
-
end
|
17
|
-
memoize :identification
|
8
|
+
SHOULD_FAIL = true
|
9
|
+
SYMBOL = 'evil'.freeze
|
18
10
|
|
19
11
|
# Test if killer is successful
|
20
12
|
#
|
@@ -5,41 +5,15 @@ module Mutant
|
|
5
5
|
# Neutral mutation
|
6
6
|
class Neutral < self
|
7
7
|
|
8
|
-
SYMBOL
|
8
|
+
SYMBOL = 'neutral'.freeze
|
9
|
+
SHOULD_FAIL = false
|
9
10
|
|
10
11
|
# Noop mutation, special case of neutral
|
11
12
|
class Noop < self
|
12
13
|
|
13
|
-
SYMBOL = 'noop'
|
14
|
+
SYMBOL = 'noop'.freeze
|
14
15
|
|
15
|
-
end
|
16
|
-
|
17
|
-
# Return identification
|
18
|
-
#
|
19
|
-
# @return [String]
|
20
|
-
#
|
21
|
-
# @api private
|
22
|
-
#
|
23
|
-
def identification
|
24
|
-
"#{self.class::SYMBOL}:#{super}"
|
25
|
-
end
|
26
|
-
memoize :identification
|
27
|
-
|
28
|
-
# Test if killer is successful
|
29
|
-
#
|
30
|
-
# @param [Killer] killer
|
31
|
-
#
|
32
|
-
# @return [true]
|
33
|
-
# if killer did NOT killed mutation
|
34
|
-
#
|
35
|
-
# @return [false]
|
36
|
-
# otherwise
|
37
|
-
#
|
38
|
-
# @api private
|
39
|
-
#
|
40
|
-
def success?(killer)
|
41
|
-
!killer.killed?
|
42
|
-
end
|
16
|
+
end # Noop
|
43
17
|
|
44
18
|
end # Neutral
|
45
19
|
end # Mutation
|
@@ -9,7 +9,9 @@ module Mutant
|
|
9
9
|
|
10
10
|
handle(:sym)
|
11
11
|
|
12
|
-
|
12
|
+
children :value
|
13
|
+
|
14
|
+
PREFIX = '__mutant__'.freeze
|
13
15
|
|
14
16
|
private
|
15
17
|
|
@@ -21,7 +23,9 @@ module Mutant
|
|
21
23
|
#
|
22
24
|
def dispatch
|
23
25
|
emit_nil
|
24
|
-
|
26
|
+
Mutator::Util::Symbol.each(value, self) do |value|
|
27
|
+
emit_self(value)
|
28
|
+
end
|
25
29
|
end
|
26
30
|
|
27
31
|
end # Symbol
|
@@ -10,11 +10,15 @@ module Mutant
|
|
10
10
|
|
11
11
|
children :name, :value
|
12
12
|
|
13
|
-
|
13
|
+
map = {
|
14
14
|
gvasgn: '$',
|
15
15
|
cvasgn: '@@',
|
16
16
|
ivasgn: '@',
|
17
17
|
lvasgn: ''
|
18
|
+
}
|
19
|
+
|
20
|
+
MAP = IceNine.deep_freeze(
|
21
|
+
Hash[map.map { |type, prefix| [type, [prefix, /^#{Regexp.escape(prefix)}/]] }]
|
18
22
|
)
|
19
23
|
|
20
24
|
handle(*MAP.keys)
|
@@ -40,8 +44,9 @@ module Mutant
|
|
40
44
|
# @api private
|
41
45
|
#
|
42
46
|
def mutate_name
|
43
|
-
prefix = MAP.fetch(node.type)
|
44
|
-
|
47
|
+
prefix, regexp = MAP.fetch(node.type)
|
48
|
+
stripped = name.to_s.sub(regexp, EMPTY_STRING)
|
49
|
+
Mutator::Util::Symbol.each(stripped, self) do |name|
|
45
50
|
emit_name(:"#{prefix}#{name}")
|
46
51
|
end
|
47
52
|
end
|
@@ -9,6 +9,8 @@ module Mutant
|
|
9
9
|
|
10
10
|
handle(::Symbol)
|
11
11
|
|
12
|
+
POSTFIX = '__mutant__'.freeze
|
13
|
+
|
12
14
|
private
|
13
15
|
|
14
16
|
# Emit mutations
|
@@ -18,7 +20,7 @@ module Mutant
|
|
18
20
|
# @api private
|
19
21
|
#
|
20
22
|
def dispatch
|
21
|
-
|
23
|
+
emit((input.to_s + POSTFIX).to_sym)
|
22
24
|
end
|
23
25
|
|
24
26
|
end # Symbol
|
data/lib/mutant/node_helpers.rb
CHANGED
@@ -13,7 +13,7 @@ module Mutant
|
|
13
13
|
# @api private
|
14
14
|
#
|
15
15
|
def s(type, *children)
|
16
|
-
|
16
|
+
Parser::AST::Node.new(type, children)
|
17
17
|
end
|
18
18
|
module_function :s
|
19
19
|
|
@@ -21,8 +21,6 @@ module Mutant
|
|
21
21
|
s(:send, s(:float, 0.0), :/, s(:float, 0.0))
|
22
22
|
INFINITY =
|
23
23
|
s(:send, s(:float, 1.0), :/, s(:float, 0.0))
|
24
|
-
NEW_OBJECT =
|
25
|
-
s(:send, s(:const, s(:cbase), :Object), :new)
|
26
24
|
NEGATIVE_INFINITY =
|
27
25
|
s(:send, s(:float, -1.0), :/, s(:float, 0.0))
|
28
26
|
|
data/lib/mutant/reporter.rb
CHANGED
data/lib/mutant/reporter/cli.rb
CHANGED
@@ -4,10 +4,23 @@ module Mutant
|
|
4
4
|
class Reporter
|
5
5
|
# Reporter that reports in human readable format
|
6
6
|
class CLI < self
|
7
|
-
include Concord
|
7
|
+
include Concord.new(:output)
|
8
8
|
|
9
9
|
NL = "\n".freeze
|
10
10
|
|
11
|
+
# Report progress object
|
12
|
+
#
|
13
|
+
# @param [Object] object
|
14
|
+
#
|
15
|
+
# @return [self]
|
16
|
+
#
|
17
|
+
# @api private
|
18
|
+
#
|
19
|
+
def progress(object)
|
20
|
+
Progress.run(output, object)
|
21
|
+
self
|
22
|
+
end
|
23
|
+
|
11
24
|
# Report object
|
12
25
|
#
|
13
26
|
# @param [Object] object
|
@@ -17,7 +30,7 @@ module Mutant
|
|
17
30
|
# @api private
|
18
31
|
#
|
19
32
|
def report(object)
|
20
|
-
|
33
|
+
Report.run(output, object)
|
21
34
|
self
|
22
35
|
end
|
23
36
|
|
@@ -6,120 +6,27 @@ module Mutant
|
|
6
6
|
|
7
7
|
# CLI runner status printer base class
|
8
8
|
class Printer
|
9
|
-
include AbstractType, Adamantium::Flat, Concord.new(:
|
9
|
+
include AbstractType, Delegator, Adamantium::Flat, Concord.new(:output, :object)
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
# Create delegators to object
|
14
|
-
#
|
15
|
-
# @return [undefined]
|
16
|
-
#
|
17
|
-
# @api private
|
18
|
-
#
|
19
|
-
def self.delegate(*names)
|
20
|
-
names.each do |name|
|
21
|
-
define_delegator(name)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
private_class_method :delegate
|
25
|
-
|
26
|
-
# Create delegator to object
|
27
|
-
#
|
28
|
-
# @param [Symbol] name
|
29
|
-
#
|
30
|
-
# @return [undefined]
|
31
|
-
#
|
32
|
-
# @api private
|
33
|
-
#
|
34
|
-
def self.define_delegator(name)
|
35
|
-
define_method(name) do
|
36
|
-
object.public_send(name)
|
37
|
-
end
|
38
|
-
private name
|
39
|
-
end
|
40
|
-
private_class_method :define_delegator
|
41
|
-
|
42
|
-
# Registre handler for class
|
43
|
-
#
|
44
|
-
# @param [Class] klass
|
45
|
-
#
|
46
|
-
# @return [undefined]
|
11
|
+
# Run printer on object to output
|
47
12
|
#
|
48
|
-
# @
|
49
|
-
#
|
50
|
-
def self.handle(klass)
|
51
|
-
REGISTRY[klass] = self
|
52
|
-
end
|
53
|
-
|
54
|
-
# Finalize CLI reporter
|
55
|
-
#
|
56
|
-
# @return [undefined]
|
57
|
-
#
|
58
|
-
# @api private
|
59
|
-
#
|
60
|
-
def self.finalize
|
61
|
-
REGISTRY.freeze
|
62
|
-
end
|
63
|
-
|
64
|
-
# Build printer
|
65
|
-
#
|
66
|
-
# @return [Printer]
|
67
|
-
#
|
68
|
-
# @api private
|
69
|
-
#
|
70
|
-
def self.build(*args)
|
71
|
-
new(*args)
|
72
|
-
end
|
73
|
-
|
74
|
-
# Run printer
|
13
|
+
# @param [IO] output
|
14
|
+
# @param [Object] object
|
75
15
|
#
|
76
16
|
# @return [self]
|
77
17
|
#
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
build(*args).run
|
18
|
+
def self.run(output, object)
|
19
|
+
handler = lookup(object.class)
|
20
|
+
handler.new(output, object).run
|
82
21
|
self
|
83
22
|
end
|
84
23
|
|
85
|
-
#
|
86
|
-
#
|
87
|
-
# @param [Object] object
|
88
|
-
# @param [IO] output
|
89
|
-
#
|
90
|
-
# @return [undefined]
|
91
|
-
#
|
92
|
-
# @api private
|
93
|
-
#
|
94
|
-
def self.visit(object, output)
|
95
|
-
printer = lookup(object.class)
|
96
|
-
printer.run(object, output)
|
97
|
-
end
|
98
|
-
|
99
|
-
# Lookup printer class
|
100
|
-
#
|
101
|
-
# @param [Class] klass
|
102
|
-
#
|
103
|
-
# @return [Class:Printer]
|
104
|
-
# if found
|
24
|
+
# Run printer
|
105
25
|
#
|
106
|
-
# @
|
107
|
-
# otherwise
|
26
|
+
# @return [self]
|
108
27
|
#
|
109
28
|
# @api private
|
110
29
|
#
|
111
|
-
def self.lookup(klass)
|
112
|
-
current = klass
|
113
|
-
until current == Object
|
114
|
-
if REGISTRY.key?(current)
|
115
|
-
return REGISTRY.fetch(current)
|
116
|
-
end
|
117
|
-
current = current.superclass
|
118
|
-
end
|
119
|
-
raise "No printer for: #{klass}"
|
120
|
-
end
|
121
|
-
private_class_method :lookup
|
122
|
-
|
123
30
|
abstract_method :run
|
124
31
|
|
125
32
|
private
|
@@ -130,7 +37,7 @@ module Mutant
|
|
130
37
|
#
|
131
38
|
# @api private
|
132
39
|
#
|
133
|
-
def
|
40
|
+
def status_color
|
134
41
|
success? ? Color::GREEN : Color::RED
|
135
42
|
end
|
136
43
|
|
@@ -143,7 +50,7 @@ module Mutant
|
|
143
50
|
# @api private
|
144
51
|
#
|
145
52
|
def visit(object)
|
146
|
-
self.class.
|
53
|
+
self.class.run(output, object)
|
147
54
|
end
|
148
55
|
|
149
56
|
# Print an info line to output
|
@@ -163,7 +70,7 @@ module Mutant
|
|
163
70
|
# @api private
|
164
71
|
#
|
165
72
|
def status(string, *arguments)
|
166
|
-
puts(colorize(
|
73
|
+
puts(colorize(status_color, sprintf(string, *arguments)))
|
167
74
|
end
|
168
75
|
|
169
76
|
# Print a line to output
|