mutant 0.9.8 → 0.9.9
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/.github/workflows/ci.yml +2 -2
- data/Changelog.md +6 -0
- data/README.md +63 -23
- data/config/reek.yml +1 -0
- data/lib/mutant.rb +4 -0
- data/lib/mutant/ast.rb +0 -9
- data/lib/mutant/ast/find_metaclass_containing.rb +48 -0
- data/lib/mutant/ast/meta/send.rb +0 -6
- data/lib/mutant/bootstrap.rb +0 -36
- data/lib/mutant/cli.rb +5 -49
- data/lib/mutant/color.rb +0 -3
- data/lib/mutant/config.rb +0 -8
- data/lib/mutant/context.rb +0 -3
- data/lib/mutant/diff.rb +0 -17
- data/lib/mutant/env.rb +0 -6
- data/lib/mutant/expression/method.rb +6 -6
- data/lib/mutant/expression/methods.rb +6 -6
- data/lib/mutant/expression/parser.rb +0 -6
- data/lib/mutant/integration.rb +0 -18
- data/lib/mutant/isolation/fork.rb +0 -22
- data/lib/mutant/license.rb +11 -0
- data/lib/mutant/matcher.rb +0 -14
- data/lib/mutant/matcher/config.rb +0 -11
- data/lib/mutant/matcher/method.rb +0 -31
- data/lib/mutant/matcher/method/instance.rb +0 -8
- data/lib/mutant/matcher/method/metaclass.rb +86 -0
- data/lib/mutant/matcher/method/singleton.rb +0 -25
- data/lib/mutant/matcher/methods.rb +17 -28
- data/lib/mutant/matcher/namespace.rb +0 -10
- data/lib/mutant/matcher/scope.rb +2 -4
- data/lib/mutant/meta/example/dsl.rb +0 -21
- data/lib/mutant/meta/example/verification.rb +0 -20
- data/lib/mutant/mutation.rb +0 -3
- data/lib/mutant/mutator.rb +1 -29
- data/lib/mutant/mutator/node.rb +1 -66
- data/lib/mutant/mutator/node/and_asgn.rb +0 -3
- data/lib/mutant/mutator/node/argument.rb +0 -15
- data/lib/mutant/mutator/node/arguments.rb +0 -20
- data/lib/mutant/mutator/node/begin.rb +0 -3
- data/lib/mutant/mutator/node/binary.rb +0 -23
- data/lib/mutant/mutator/node/block.rb +0 -15
- data/lib/mutant/mutator/node/break.rb +0 -3
- data/lib/mutant/mutator/node/case.rb +0 -9
- data/lib/mutant/mutator/node/class.rb +0 -3
- data/lib/mutant/mutator/node/conditional_loop.rb +0 -3
- data/lib/mutant/mutator/node/const.rb +0 -3
- data/lib/mutant/mutator/node/define.rb +0 -11
- data/lib/mutant/mutator/node/defined.rb +0 -3
- data/lib/mutant/mutator/node/dstr.rb +0 -3
- data/lib/mutant/mutator/node/dsym.rb +0 -3
- data/lib/mutant/mutator/node/generic.rb +0 -3
- data/lib/mutant/mutator/node/if.rb +0 -12
- data/lib/mutant/mutator/node/index.rb +0 -27
- data/lib/mutant/mutator/node/kwbegin.rb +0 -3
- data/lib/mutant/mutator/node/literal.rb +0 -3
- data/lib/mutant/mutator/node/literal/array.rb +0 -6
- data/lib/mutant/mutator/node/literal/boolean.rb +0 -4
- data/lib/mutant/mutator/node/literal/float.rb +0 -9
- data/lib/mutant/mutator/node/literal/hash.rb +0 -9
- data/lib/mutant/mutator/node/literal/integer.rb +0 -9
- data/lib/mutant/mutator/node/literal/nil.rb +0 -3
- data/lib/mutant/mutator/node/literal/range.rb +0 -6
- data/lib/mutant/mutator/node/literal/regex.rb +0 -6
- data/lib/mutant/mutator/node/literal/string.rb +0 -3
- data/lib/mutant/mutator/node/literal/symbol.rb +0 -3
- data/lib/mutant/mutator/node/masgn.rb +0 -3
- data/lib/mutant/mutator/node/match_current_line.rb +0 -3
- data/lib/mutant/mutator/node/mlhs.rb +0 -3
- data/lib/mutant/mutator/node/named_value/access.rb +2 -14
- data/lib/mutant/mutator/node/named_value/constant_assignment.rb +0 -9
- data/lib/mutant/mutator/node/named_value/variable_assignment.rb +0 -6
- data/lib/mutant/mutator/node/next.rb +0 -3
- data/lib/mutant/mutator/node/noop.rb +0 -3
- data/lib/mutant/mutator/node/nthref.rb +0 -3
- data/lib/mutant/mutator/node/op_asgn.rb +0 -3
- data/lib/mutant/mutator/node/or_asgn.rb +0 -3
- data/lib/mutant/mutator/node/procarg_zero.rb +0 -3
- data/lib/mutant/mutator/node/regopt.rb +0 -6
- data/lib/mutant/mutator/node/resbody.rb +0 -6
- data/lib/mutant/mutator/node/rescue.rb +2 -19
- data/lib/mutant/mutator/node/return.rb +0 -3
- data/lib/mutant/mutator/node/sclass.rb +20 -0
- data/lib/mutant/mutator/node/send.rb +2 -61
- data/lib/mutant/mutator/node/send/attribute_assignment.rb +0 -9
- data/lib/mutant/mutator/node/send/binary.rb +0 -11
- data/lib/mutant/mutator/node/send/conditional.rb +0 -3
- data/lib/mutant/mutator/node/splat.rb +0 -3
- data/lib/mutant/mutator/node/super.rb +0 -3
- data/lib/mutant/mutator/node/when.rb +0 -19
- data/lib/mutant/mutator/node/yield.rb +0 -3
- data/lib/mutant/mutator/node/zsuper.rb +0 -3
- data/lib/mutant/mutator/util/array.rb +0 -6
- data/lib/mutant/mutator/util/symbol.rb +0 -3
- data/lib/mutant/parallel.rb +0 -13
- data/lib/mutant/parallel/driver.rb +0 -10
- data/lib/mutant/parallel/worker.rb +0 -22
- data/lib/mutant/reporter/cli.rb +0 -5
- data/lib/mutant/reporter/cli/format.rb +0 -9
- data/lib/mutant/reporter/cli/printer.rb +0 -40
- data/lib/mutant/reporter/cli/printer/env_progress.rb +0 -15
- data/lib/mutant/reporter/cli/printer/isolation_result.rb +0 -18
- data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +0 -5
- data/lib/mutant/reporter/cli/printer/mutation_result.rb +0 -21
- data/lib/mutant/reporter/cli/printer/status_progressive.rb +0 -8
- data/lib/mutant/reporter/cli/printer/subject_progress.rb +0 -9
- data/lib/mutant/repository/diff.rb +1 -13
- data/lib/mutant/repository/diff/ranges.rb +0 -11
- data/lib/mutant/result.rb +0 -3
- data/lib/mutant/runner.rb +0 -18
- data/lib/mutant/runner/sink.rb +0 -5
- data/lib/mutant/subject.rb +0 -8
- data/lib/mutant/subject/method.rb +0 -3
- data/lib/mutant/subject/method/instance.rb +0 -5
- data/lib/mutant/subject/method/metaclass.rb +30 -0
- data/lib/mutant/transform.rb +0 -92
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/warnings.rb +0 -6
- data/lib/mutant/zombifier.rb +2 -34
- data/meta/and.rb +0 -2
- data/meta/array.rb +0 -3
- data/meta/begin.rb +0 -3
- data/meta/block.rb +0 -3
- data/meta/break.rb +0 -1
- data/meta/case.rb +0 -6
- data/meta/casgn.rb +0 -3
- data/meta/cvasgn.rb +0 -1
- data/meta/def.rb +0 -7
- data/meta/ensure.rb +0 -1
- data/meta/false.rb +0 -1
- data/meta/gvasgn.rb +0 -1
- data/meta/hash.rb +0 -4
- data/meta/if.rb +0 -5
- data/meta/ivasgn.rb +0 -1
- data/meta/kwbegin.rb +0 -1
- data/meta/lvasgn.rb +0 -1
- data/meta/match_current_line.rb +0 -1
- data/meta/next.rb +0 -1
- data/meta/or.rb +0 -2
- data/meta/regexp.rb +0 -1
- data/meta/rescue.rb +0 -6
- data/meta/sclass.rb +12 -0
- data/meta/send.rb +0 -4
- data/meta/true.rb +0 -1
- data/meta/until.rb +0 -1
- data/meta/while.rb +0 -2
- data/meta/yield.rb +0 -1
- data/mutant.sh +12 -0
- data/spec/unit/mutant/ast/find_metaclass_containing_spec.rb +64 -0
- data/spec/unit/mutant/expression/methods_spec.rb +7 -2
- data/spec/unit/mutant/license_spec.rb +15 -3
- data/spec/unit/mutant/matcher/method/metaclass_spec.rb +108 -0
- data/spec/unit/mutant/matcher/methods/metaclass_spec.rb +62 -0
- data/spec/unit/mutant/matcher/namespace_spec.rb +3 -1
- data/spec/unit/mutant/matcher/scope_spec.rb +11 -1
- data/spec/unit/mutant/meta/example_spec.rb +3 -3
- data/spec/unit/mutant/mutator/node_spec.rb +1 -6
- data/spec/unit/mutant/subject/method/metaclass_spec.rb +63 -0
- data/test_app/lib/test_app.rb +1 -0
- data/test_app/lib/test_app/metaclasses.rb +108 -0
- metadata +17 -2
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Mutant
|
|
4
|
+
class Matcher
|
|
5
|
+
class Method
|
|
6
|
+
# Matcher for metaclass methods
|
|
7
|
+
# i.e. ones defined using class << self or class << CONSTANT. It might??
|
|
8
|
+
# work for methods defined like class << obj, but I don't think the
|
|
9
|
+
# plumbing will be in place in the subject for that to work
|
|
10
|
+
class Metaclass < self
|
|
11
|
+
|
|
12
|
+
# New singleton method matcher
|
|
13
|
+
#
|
|
14
|
+
# @param [Class, Module] scope
|
|
15
|
+
# @param [Symbol] method_name
|
|
16
|
+
#
|
|
17
|
+
# @return [Matcher::Method::Singleton]
|
|
18
|
+
def self.new(scope, method_name)
|
|
19
|
+
super(scope, method_name, Evaluator)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Metaclass method evaluator
|
|
23
|
+
class Evaluator < Evaluator
|
|
24
|
+
# Terminology note: the "receiver" is the `self` in `class << self`
|
|
25
|
+
SUBJECT_CLASS = Subject::Method::Metaclass
|
|
26
|
+
NAME_INDEX = 0
|
|
27
|
+
CONST_NAME_INDEX = 1
|
|
28
|
+
SCLASS_RECEIVER_INDEX = 0
|
|
29
|
+
RECEIVER_WARNING = 'Can only match :def inside :sclass on ' \
|
|
30
|
+
':self or :const, got :sclass on %p ' \
|
|
31
|
+
'unable to match'
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def match?(node)
|
|
36
|
+
n_def?(node) &&
|
|
37
|
+
name?(node) &&
|
|
38
|
+
line?(node) &&
|
|
39
|
+
metaclass_receiver?(node)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def metaclass_receiver?(node)
|
|
43
|
+
candidate = metaclass_containing(node)
|
|
44
|
+
candidate && metaclass_target?(candidate)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def metaclass_containing(node)
|
|
48
|
+
AST::FindMetaclassContaining.call(ast, node)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def line?(node)
|
|
52
|
+
node
|
|
53
|
+
.location
|
|
54
|
+
.line
|
|
55
|
+
.equal?(source_line)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def name?(node)
|
|
59
|
+
node.children.fetch(NAME_INDEX).equal?(method_name)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def metaclass_target?(node)
|
|
63
|
+
receiver = node.children.fetch(SCLASS_RECEIVER_INDEX)
|
|
64
|
+
case receiver.type
|
|
65
|
+
when :self
|
|
66
|
+
true
|
|
67
|
+
when :const
|
|
68
|
+
sclass_const_name?(receiver)
|
|
69
|
+
else
|
|
70
|
+
env.warn(RECEIVER_WARNING % receiver.type)
|
|
71
|
+
nil
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def sclass_const_name?(node)
|
|
76
|
+
name = node.children.fetch(CONST_NAME_INDEX)
|
|
77
|
+
name.to_s.eql?(context.unqualified_name)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
end # Evaluator
|
|
81
|
+
|
|
82
|
+
private_constant(*constants(false))
|
|
83
|
+
end # Singleton
|
|
84
|
+
end # Method
|
|
85
|
+
end # Matcher
|
|
86
|
+
end # Mutant
|
|
@@ -25,20 +25,10 @@ module Mutant
|
|
|
25
25
|
|
|
26
26
|
private
|
|
27
27
|
|
|
28
|
-
# Test for node match
|
|
29
|
-
#
|
|
30
|
-
# @param [Parser::AST::Node] node
|
|
31
|
-
#
|
|
32
|
-
# @return [Boolean]
|
|
33
28
|
def match?(node)
|
|
34
29
|
n_defs?(node) && line?(node) && name?(node) && receiver?(node)
|
|
35
30
|
end
|
|
36
31
|
|
|
37
|
-
# Test for line match
|
|
38
|
-
#
|
|
39
|
-
# @param [Parser::AST::Node] node
|
|
40
|
-
#
|
|
41
|
-
# @return [Boolean]
|
|
42
32
|
def line?(node)
|
|
43
33
|
node
|
|
44
34
|
.location
|
|
@@ -46,20 +36,10 @@ module Mutant
|
|
|
46
36
|
.equal?(source_line)
|
|
47
37
|
end
|
|
48
38
|
|
|
49
|
-
# Test for name match
|
|
50
|
-
#
|
|
51
|
-
# @param [Parser::AST::Node] node
|
|
52
|
-
#
|
|
53
|
-
# @return [Boolean]
|
|
54
39
|
def name?(node)
|
|
55
40
|
node.children.fetch(NAME_INDEX).equal?(method_name)
|
|
56
41
|
end
|
|
57
42
|
|
|
58
|
-
# Test for receiver match
|
|
59
|
-
#
|
|
60
|
-
# @param [Parser::AST::Node] node
|
|
61
|
-
#
|
|
62
|
-
# @return [Boolean]
|
|
63
43
|
def receiver?(node)
|
|
64
44
|
receiver = node.children.fetch(RECEIVER_INDEX)
|
|
65
45
|
case receiver.type
|
|
@@ -73,11 +53,6 @@ module Mutant
|
|
|
73
53
|
end
|
|
74
54
|
end
|
|
75
55
|
|
|
76
|
-
# Test if receiver name matches context
|
|
77
|
-
#
|
|
78
|
-
# @param [Parser::AST::Node] node
|
|
79
|
-
#
|
|
80
|
-
# @return [Boolean]
|
|
81
56
|
def receiver_name?(node)
|
|
82
57
|
name = node.children.fetch(NAME_INDEX)
|
|
83
58
|
name.to_s.eql?(context.unqualified_name)
|
|
@@ -27,16 +27,10 @@ module Mutant
|
|
|
27
27
|
|
|
28
28
|
private
|
|
29
29
|
|
|
30
|
-
# method matcher class
|
|
31
|
-
#
|
|
32
|
-
# @return [Class:Matcher::Method]
|
|
33
30
|
def matcher
|
|
34
31
|
self.class::MATCHER
|
|
35
32
|
end
|
|
36
33
|
|
|
37
|
-
# Available methods scope
|
|
38
|
-
#
|
|
39
|
-
# @return [Enumerable<Method, UnboundMethod>]
|
|
40
34
|
def methods
|
|
41
35
|
candidate_names.each_with_object([]) do |name, methods|
|
|
42
36
|
method = access(name)
|
|
@@ -45,9 +39,6 @@ module Mutant
|
|
|
45
39
|
end
|
|
46
40
|
memoize :methods
|
|
47
41
|
|
|
48
|
-
# Candidate method names on target scope
|
|
49
|
-
#
|
|
50
|
-
# @return [Enumerable<Symbol>]
|
|
51
42
|
def candidate_names
|
|
52
43
|
CANDIDATE_NAMES
|
|
53
44
|
.map(&candidate_scope.method(:public_send))
|
|
@@ -55,10 +46,8 @@ module Mutant
|
|
|
55
46
|
.sort
|
|
56
47
|
end
|
|
57
48
|
|
|
58
|
-
# Candidate scope
|
|
59
|
-
#
|
|
60
|
-
# @return [Class, Module]
|
|
61
49
|
abstract_method :candidate_scope
|
|
50
|
+
private :candidate_scope
|
|
62
51
|
|
|
63
52
|
# Matcher for singleton methods
|
|
64
53
|
class Singleton < self
|
|
@@ -66,18 +55,10 @@ module Mutant
|
|
|
66
55
|
|
|
67
56
|
private
|
|
68
57
|
|
|
69
|
-
# Method object on scope
|
|
70
|
-
#
|
|
71
|
-
# @param [Symbol] method_name
|
|
72
|
-
#
|
|
73
|
-
# @return [Method]
|
|
74
58
|
def access(method_name)
|
|
75
59
|
scope.method(method_name)
|
|
76
60
|
end
|
|
77
61
|
|
|
78
|
-
# Candidate scope
|
|
79
|
-
#
|
|
80
|
-
# @return [Class]
|
|
81
62
|
def candidate_scope
|
|
82
63
|
scope.singleton_class
|
|
83
64
|
end
|
|
@@ -85,24 +66,32 @@ module Mutant
|
|
|
85
66
|
|
|
86
67
|
end # Singleton
|
|
87
68
|
|
|
69
|
+
# Matcher for metaclass methods
|
|
70
|
+
class Metaclass < self
|
|
71
|
+
MATCHER = Matcher::Method::Metaclass
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def access(method_name)
|
|
76
|
+
scope.method(method_name)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def candidate_scope
|
|
80
|
+
scope.singleton_class
|
|
81
|
+
end
|
|
82
|
+
memoize :candidate_scope, freezer: :noop
|
|
83
|
+
end # Metaclass
|
|
84
|
+
|
|
88
85
|
# Matcher for instance methods
|
|
89
86
|
class Instance < self
|
|
90
87
|
MATCHER = Matcher::Method::Instance
|
|
91
88
|
|
|
92
89
|
private
|
|
93
90
|
|
|
94
|
-
# Method object on scope
|
|
95
|
-
#
|
|
96
|
-
# @param [Symbol] method_name
|
|
97
|
-
#
|
|
98
|
-
# @return [UnboundMethod]
|
|
99
91
|
def access(method_name)
|
|
100
92
|
scope.instance_method(method_name)
|
|
101
93
|
end
|
|
102
94
|
|
|
103
|
-
# Candidate scope
|
|
104
|
-
#
|
|
105
|
-
# @return [Class, Module]
|
|
106
95
|
def candidate_scope
|
|
107
96
|
scope
|
|
108
97
|
end
|
|
@@ -19,22 +19,12 @@ module Mutant
|
|
|
19
19
|
|
|
20
20
|
private
|
|
21
21
|
|
|
22
|
-
# The matched scopes
|
|
23
|
-
#
|
|
24
|
-
# @param [Env] env
|
|
25
|
-
#
|
|
26
|
-
# @return [Enumerable<Scope>]
|
|
27
22
|
def matched_scopes(env)
|
|
28
23
|
env
|
|
29
24
|
.matchable_scopes
|
|
30
25
|
.select(&method(:match?))
|
|
31
26
|
end
|
|
32
27
|
|
|
33
|
-
# Test scope if matches expression
|
|
34
|
-
#
|
|
35
|
-
# @param [Scope] scope
|
|
36
|
-
#
|
|
37
|
-
# @return [Boolean]
|
|
38
28
|
def match?(scope)
|
|
39
29
|
expression.prefix?(scope.expression)
|
|
40
30
|
end
|
data/lib/mutant/matcher/scope.rb
CHANGED
|
@@ -13,7 +13,8 @@ module Mutant
|
|
|
13
13
|
|
|
14
14
|
MATCHERS = [
|
|
15
15
|
Matcher::Methods::Singleton,
|
|
16
|
-
Matcher::Methods::Instance
|
|
16
|
+
Matcher::Methods::Instance,
|
|
17
|
+
Matcher::Methods::Metaclass
|
|
17
18
|
].freeze
|
|
18
19
|
|
|
19
20
|
private_constant(*constants(false))
|
|
@@ -29,9 +30,6 @@ module Mutant
|
|
|
29
30
|
|
|
30
31
|
private
|
|
31
32
|
|
|
32
|
-
# Effective matchers
|
|
33
|
-
#
|
|
34
|
-
# @return [Enumerable<Matcher>]
|
|
35
33
|
def effective_matchers
|
|
36
34
|
MATCHERS.map { |matcher| matcher.new(scope) }
|
|
37
35
|
end
|
|
@@ -49,21 +49,11 @@ module Mutant
|
|
|
49
49
|
|
|
50
50
|
private
|
|
51
51
|
|
|
52
|
-
# Set original source
|
|
53
|
-
#
|
|
54
|
-
# @param [String,Parser::AST::Node] input
|
|
55
|
-
#
|
|
56
|
-
# @return [undefined]
|
|
57
52
|
def source(input)
|
|
58
53
|
fail 'source already defined' if @node
|
|
59
54
|
@node = node(input)
|
|
60
55
|
end
|
|
61
56
|
|
|
62
|
-
# Add expected mutation
|
|
63
|
-
#
|
|
64
|
-
# @param [String,Parser::AST::Node] input
|
|
65
|
-
#
|
|
66
|
-
# @return [undefined]
|
|
67
57
|
def mutation(input)
|
|
68
58
|
node = node(input)
|
|
69
59
|
if @expected.include?(node)
|
|
@@ -72,22 +62,11 @@ module Mutant
|
|
|
72
62
|
@expected << node
|
|
73
63
|
end
|
|
74
64
|
|
|
75
|
-
# Add singleton mutations
|
|
76
|
-
#
|
|
77
|
-
# @return [undefined]
|
|
78
65
|
def singleton_mutations
|
|
79
66
|
mutation('nil')
|
|
80
67
|
mutation('self')
|
|
81
68
|
end
|
|
82
69
|
|
|
83
|
-
# Helper method to coerce input to node
|
|
84
|
-
#
|
|
85
|
-
# @param [String,Parser::AST::Node] input
|
|
86
|
-
#
|
|
87
|
-
# @return [Parser::AST::Node]
|
|
88
|
-
#
|
|
89
|
-
# @raise [RuntimeError]
|
|
90
|
-
# in case input cannot be coerced
|
|
91
70
|
def node(input)
|
|
92
71
|
case input
|
|
93
72
|
when String
|
|
@@ -35,9 +35,6 @@ module Mutant
|
|
|
35
35
|
|
|
36
36
|
private
|
|
37
37
|
|
|
38
|
-
# Unexpected mutations
|
|
39
|
-
#
|
|
40
|
-
# @return [Array<Mutation>]
|
|
41
38
|
def unexpected
|
|
42
39
|
mutations.reject do |mutation|
|
|
43
40
|
example.expected.include?(mutation.node)
|
|
@@ -45,9 +42,6 @@ module Mutant
|
|
|
45
42
|
end
|
|
46
43
|
memoize :unexpected
|
|
47
44
|
|
|
48
|
-
# Missing mutations
|
|
49
|
-
#
|
|
50
|
-
# @return [Array<Mutation>]
|
|
51
45
|
def missing
|
|
52
46
|
(example.expected - mutations.map(&:node)).map do |node|
|
|
53
47
|
Mutation::Evil.new(self, node)
|
|
@@ -55,9 +49,6 @@ module Mutant
|
|
|
55
49
|
end
|
|
56
50
|
memoize :missing
|
|
57
51
|
|
|
58
|
-
# Mutations that generated invalid syntax
|
|
59
|
-
#
|
|
60
|
-
# @return [Enumerable<Mutation>]
|
|
61
52
|
def invalid_syntax
|
|
62
53
|
mutations.reject do |mutation|
|
|
63
54
|
::Parser::CurrentRuby.parse(mutation.source)
|
|
@@ -66,19 +57,11 @@ module Mutant
|
|
|
66
57
|
end
|
|
67
58
|
memoize :invalid_syntax
|
|
68
59
|
|
|
69
|
-
# Mutations with no diff to original
|
|
70
|
-
#
|
|
71
|
-
# @return [Enumerable<Mutation>]
|
|
72
60
|
def no_diffs
|
|
73
61
|
mutations.select { |mutation| mutation.source.eql?(example.source) }
|
|
74
62
|
end
|
|
75
63
|
memoize :no_diffs
|
|
76
64
|
|
|
77
|
-
# Mutation report
|
|
78
|
-
#
|
|
79
|
-
# @param [Array<Mutation>] mutations
|
|
80
|
-
#
|
|
81
|
-
# @return [Array<Hash>]
|
|
82
65
|
def format_mutations(mutations)
|
|
83
66
|
mutations.map do |mutation|
|
|
84
67
|
{
|
|
@@ -88,9 +71,6 @@ module Mutant
|
|
|
88
71
|
end
|
|
89
72
|
end
|
|
90
73
|
|
|
91
|
-
# No diff mutation report
|
|
92
|
-
#
|
|
93
|
-
# @return [Array, nil]
|
|
94
74
|
def no_diff_report
|
|
95
75
|
no_diffs.map do |mutation|
|
|
96
76
|
{
|
data/lib/mutant/mutation.rb
CHANGED
data/lib/mutant/mutator.rb
CHANGED
|
@@ -18,9 +18,6 @@ module Mutant
|
|
|
18
18
|
self::REGISTRY.lookup(node.type).call(node, parent)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
# Register node class handler
|
|
22
|
-
#
|
|
23
|
-
# @return [undefined]
|
|
24
21
|
def self.handle(*types)
|
|
25
22
|
types.each do |type|
|
|
26
23
|
self::REGISTRY.register(type, self)
|
|
@@ -35,13 +32,6 @@ module Mutant
|
|
|
35
32
|
|
|
36
33
|
private
|
|
37
34
|
|
|
38
|
-
# Initialize object
|
|
39
|
-
#
|
|
40
|
-
# @param [Object] input
|
|
41
|
-
# @param [Object] parent
|
|
42
|
-
# @param [#call(node)] block
|
|
43
|
-
#
|
|
44
|
-
# @return [undefined]
|
|
45
35
|
def initialize(_input, _parent = nil)
|
|
46
36
|
super
|
|
47
37
|
|
|
@@ -50,41 +40,23 @@ module Mutant
|
|
|
50
40
|
dispatch
|
|
51
41
|
end
|
|
52
42
|
|
|
53
|
-
# Test if generated object is not guarded from emitting
|
|
54
|
-
#
|
|
55
|
-
# @param [Object] object
|
|
56
|
-
#
|
|
57
|
-
# @return [Boolean]
|
|
58
43
|
def new?(object)
|
|
59
44
|
!object.eql?(input)
|
|
60
45
|
end
|
|
61
46
|
|
|
62
|
-
# Dispatch node generations
|
|
63
|
-
#
|
|
64
|
-
# @return [undefined]
|
|
65
47
|
abstract_method :dispatch
|
|
48
|
+
private :dispatch
|
|
66
49
|
|
|
67
|
-
# Emit generated mutation if object is not equivalent to input
|
|
68
|
-
#
|
|
69
|
-
# @param [Object] object
|
|
70
|
-
#
|
|
71
|
-
# @return [undefined]
|
|
72
50
|
def emit(object)
|
|
73
51
|
return unless new?(object)
|
|
74
52
|
|
|
75
53
|
output << object
|
|
76
54
|
end
|
|
77
55
|
|
|
78
|
-
# Run input with mutator
|
|
79
|
-
#
|
|
80
|
-
# @return [undefined]
|
|
81
56
|
def run(mutator)
|
|
82
57
|
mutator.call(input).each(&method(:emit))
|
|
83
58
|
end
|
|
84
59
|
|
|
85
|
-
# Shortcut to create a new unfrozen duplicate of input
|
|
86
|
-
#
|
|
87
|
-
# @return [Object]
|
|
88
60
|
def dup_input
|
|
89
61
|
input.dup
|
|
90
62
|
end
|