mutant 0.6.0 → 0.6.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog.md +11 -1
- data/README.md +34 -40
- data/config/flay.yml +1 -1
- data/config/reek.yml +2 -1
- data/lib/mutant/ast.rb +17 -11
- data/lib/mutant/ast/meta.rb +33 -5
- data/lib/mutant/diff.rb +1 -1
- data/lib/mutant/matcher/method.rb +14 -16
- data/lib/mutant/matcher/method/instance.rb +4 -4
- data/lib/mutant/matcher/namespace.rb +1 -1
- data/lib/mutant/meta.rb +2 -1
- data/lib/mutant/meta/example.rb +3 -3
- data/lib/mutant/meta/example/dsl.rb +5 -4
- data/lib/mutant/mutator/node.rb +17 -1
- data/lib/mutant/mutator/node/literal/boolean.rb +1 -1
- data/lib/mutant/mutator/node/rescue.rb +77 -1
- data/lib/mutant/mutator/node/send/index.rb +1 -1
- data/lib/mutant/require_highjack.rb +3 -3
- data/lib/mutant/runner.rb +1 -1
- data/lib/mutant/subject.rb +0 -4
- data/lib/mutant/version.rb +1 -1
- data/meta/def.rb +30 -0
- data/meta/if.rb +1 -1
- data/meta/rescue.rb +5 -0
- data/meta/super.rb +1 -1
- data/mutant.gemspec +1 -1
- data/spec/shared/method_matcher_behavior.rb +1 -1
- data/spec/unit/mutant/ast_spec.rb +38 -0
- data/spec/unit/mutant/matcher/method/instance_spec.rb +39 -69
- data/spec/unit/mutant/matcher/method/singleton_spec.rb +13 -55
- data/test_app/lib/test_app.rb +94 -0
- metadata +18 -17
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 001bd8f243257cdce0da86ebe626d0e1efbef248
|
4
|
+
data.tar.gz: 9b1bc583e1321da8437ec18716a6e9b5911018dc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 006d6d7657e04e6e23fdaef408516abf6119ce24c1eaaacda8f2f8d3e20993168c450391adf8f9bda5e78f13d6ca9e765a2a83db04db1fcf4c233389e4585727
|
7
|
+
data.tar.gz: 343f8f579a4db3aa5b49c96b2e16a61cf963f92dc7781a7d1ef514a670885f745912450ec264659a46e96ae471772366f36ae6f92ee4389a428f63d6df92dcd3
|
data/Changelog.md
CHANGED
@@ -1,4 +1,14 @@
|
|
1
|
-
# v0.6.
|
1
|
+
# v0.6.2 2014-08-16
|
2
|
+
|
3
|
+
* Fix matcher to ignore metaprogrammed defines [#254](https://github.com/mbj/mutant/issues/254)
|
4
|
+
* Add rescue resbody body concat-promotion mutation
|
5
|
+
* Add rescue else body concat-promotion mutation #245
|
6
|
+
|
7
|
+
# v0.6.1 2014-08-16
|
8
|
+
|
9
|
+
* Incorrectly released on partial state. Yanked.
|
10
|
+
|
11
|
+
# v0.6.0 2014-08-11
|
2
12
|
|
3
13
|
* Parallel execution / reporting.
|
4
14
|
* Add -j, --jobs flag to control concurrency.
|
data/README.md
CHANGED
@@ -7,19 +7,27 @@ mutant
|
|
7
7
|
[![Inline docs](http://inch-ci.org/github/mbj/mutant.png)](http://inch-ci.org/github/mbj/mutant)
|
8
8
|
[![Gem Version](https://img.shields.io/gem/v/mutant.svg)](https://rubygems.org/gems/mutant)
|
9
9
|
|
10
|
-
Mutant is a mutation testing tool for
|
10
|
+
Mutant is a mutation testing tool for Ruby.
|
11
11
|
|
12
12
|
The idea is that if code can be changed and your tests do not notice, either that code isn't being covered
|
13
13
|
or it does not have a speced side effect.
|
14
14
|
|
15
|
-
Mutant supports MRI and RBX 1.9, 2.0 and 2.1, while support for
|
16
|
-
It should also work under any
|
15
|
+
Mutant supports MRI and RBX 1.9, 2.0 and 2.1, while support for JRuby is planned.
|
16
|
+
It should also work under any Ruby engine that supports POSIX-fork(2) semantics.
|
17
17
|
|
18
|
-
Mutant uses a pure
|
18
|
+
Mutant uses a pure Ruby [parser](https://github.com/whitequark/parser) and an [unparser](https://github.com/mbj/unparser)
|
19
19
|
to do its magic.
|
20
20
|
|
21
21
|
Mutant does not have really good "getting started" documentation currently so please refer to presentations and blog posts below.
|
22
22
|
|
23
|
+
Mutation-Operators:
|
24
|
+
-------------------
|
25
|
+
|
26
|
+
Mutant supports a wide range of mutation operators. An exhaustive list can be found in the [mutant-meta](https://github.com/mbj/mutant/tree/master/meta).
|
27
|
+
The `mutant-meta` is arranged to the AST-Node-Types of parser. Refer to parsers [AST documentation](https://github.com/whitequark/parser/blob/master/doc/AST_FORMAT.md) in doubt.
|
28
|
+
|
29
|
+
There is no easy and universal way to count the number of mutation operators a tool supports.
|
30
|
+
|
23
31
|
Presentations
|
24
32
|
-------------
|
25
33
|
|
@@ -39,7 +47,7 @@ Blog-Posts
|
|
39
47
|
Projects using Mutant
|
40
48
|
---------------------
|
41
49
|
|
42
|
-
The following projects adopted mutant, and aim 100% mutation coverage:
|
50
|
+
The following projects adopted mutant, and aim for 100% mutation coverage:
|
43
51
|
|
44
52
|
* [axiom](https://github.com/dkubb/axiom)
|
45
53
|
* [axiom-types](https://github.com/dkubb/axiom-types)
|
@@ -65,8 +73,8 @@ Install the gem `mutant` via your preferred method.
|
|
65
73
|
gem install mutant
|
66
74
|
```
|
67
75
|
|
68
|
-
If you plan to use the
|
69
|
-
Please add an explicit dependency to `rspec-core` for the
|
76
|
+
If you plan to use the RSpec integration you'll have to install `mutant-rspec` also.
|
77
|
+
Please add an explicit dependency to `rspec-core` for the RSpec version you want to use.
|
70
78
|
|
71
79
|
```ruby
|
72
80
|
gem install mutant-rspec
|
@@ -74,38 +82,6 @@ gem install mutant-rspec
|
|
74
82
|
|
75
83
|
The minitest integration is still in the works.
|
76
84
|
|
77
|
-
Mutations
|
78
|
-
---------
|
79
|
-
|
80
|
-
Mutant supports a very wide range of mutation operators. Listing them all in detail would blow this document up.
|
81
|
-
|
82
|
-
It is planned to parse a list of mutation operators from the source. In the meantime please refer to the
|
83
|
-
[code](https://github.com/mbj/mutant/tree/master/lib/mutant/mutator/node) each subclass of `Mutant::Mutator::Node`
|
84
|
-
emits around 3-6 mutations.
|
85
|
-
|
86
|
-
Currently mutant covers the majority of ruby's complex nodes that often occur in method bodies.
|
87
|
-
|
88
|
-
NOTE: The textbook examples you find on mutation testing are intentionally not implemented. This is subjected to change.
|
89
|
-
|
90
|
-
Some stats from the [axiom](https://github.com/dkubb/axiom) library:
|
91
|
-
|
92
|
-
```
|
93
|
-
Subjects: 424 # Amount of subjects being mutated (currently only methods)
|
94
|
-
Mutations: 6760 # Amount of mutations mutant generated (~13 mutations per method)
|
95
|
-
Kills: 6664 # Amount of successfully killed mutations
|
96
|
-
Runtime: 5123.13s # Total runtime
|
97
|
-
Killtime: 5092.63s # Time spend killing mutations
|
98
|
-
Overhead: 0.60%
|
99
|
-
Coverage: 98.58% # Coverage score
|
100
|
-
Alive: 96 # Amount of alive mutations.
|
101
|
-
```
|
102
|
-
|
103
|
-
|
104
|
-
Nodes still missing a dedicated mutator are handled via the
|
105
|
-
[Generic](https://github.com/mbj/mutant/blob/master/lib/mutant/mutator/node/generic.rb) mutator.
|
106
|
-
The goal is to remove this mutator and have dedicated mutator for every type of node and removing
|
107
|
-
the Generic handler altogether.
|
108
|
-
|
109
85
|
Examples
|
110
86
|
--------
|
111
87
|
|
@@ -139,6 +115,24 @@ Example for a subject like `Foo::Bar#baz` it will run all example groups with de
|
|
139
115
|
`Foo::Bar#baz`, `Foo::Bar` and `Foo`. The order is important, so if mutant finds example groups in the
|
140
116
|
current prefix level, these example groups *must* kill the mutation.
|
141
117
|
|
118
|
+
Rails
|
119
|
+
-------
|
120
|
+
|
121
|
+
Assuming you are using rspec, you can mutation test Rails models by adding the following lines to your Gemfile:
|
122
|
+
|
123
|
+
```ruby
|
124
|
+
group :test do
|
125
|
+
gem 'mutant'
|
126
|
+
gem 'mutant-rspec'
|
127
|
+
end
|
128
|
+
```
|
129
|
+
|
130
|
+
Next, run bundle and comment out ```require 'rspec/autorun'``` from your spec_helper.rb file. Having done so you should be able to use commands like the following:
|
131
|
+
|
132
|
+
```sh
|
133
|
+
RAILS_ENV=test bundle exec mutant -r ./config/environment --use rspec User
|
134
|
+
```
|
135
|
+
|
142
136
|
Support
|
143
137
|
-------
|
144
138
|
|
@@ -150,7 +144,7 @@ Your options:
|
|
150
144
|
* Ping me on [twitter](https://twitter.com/_m_b_j_)
|
151
145
|
|
152
146
|
There is also the [#mutant] channel on freenode. As my OSS time budged is very limited I cannot
|
153
|
-
join it often. Please prefer to use
|
147
|
+
join it often. Please prefer to use GitHub issues with a 'Question: ' prefix in title.
|
154
148
|
|
155
149
|
Credits
|
156
150
|
-------
|
data/config/flay.yml
CHANGED
data/config/reek.yml
CHANGED
@@ -37,6 +37,7 @@ FeatureEnvy:
|
|
37
37
|
- Mutant::Matcher::Method::Singleton#receiver?
|
38
38
|
- Mutant::Mutation::Evil#success?
|
39
39
|
- Mutant::Mutation::Neutral#success?
|
40
|
+
- Mutant::Mutator::Node#children_indices
|
40
41
|
# False positive, its a utility
|
41
42
|
- Mutant::Meta::Example::Verification#format_mutation
|
42
43
|
- Mutant::Reporter::CLI#subject_results
|
@@ -67,7 +68,7 @@ NestedIterators:
|
|
67
68
|
- Mutant::Mutator::Node::Resbody#mutate_captures
|
68
69
|
- Mutant::Mutator::Node::Arguments#emit_argument_mutations
|
69
70
|
- Mutant::RequireHighjack#infect
|
70
|
-
- Mutant::RequireHighjack#
|
71
|
+
- Mutant::RequireHighjack#disinfect
|
71
72
|
- Mutant::Subject#tests
|
72
73
|
- Parser::Lexer#self.new
|
73
74
|
max_allowed_nesting: 1
|
data/lib/mutant/ast.rb
CHANGED
@@ -4,7 +4,8 @@ module Mutant
|
|
4
4
|
|
5
5
|
# Walk all ast nodes
|
6
6
|
#
|
7
|
-
# @param [Parser::AST::Node]
|
7
|
+
# @param [Parser::AST::Node] root
|
8
|
+
# @param [Array<Parser::AST::Node>] stack
|
8
9
|
#
|
9
10
|
# @yield [Parser::AST::Node]
|
10
11
|
# all nodes recursively including root
|
@@ -13,21 +14,24 @@ module Mutant
|
|
13
14
|
#
|
14
15
|
# @api private
|
15
16
|
#
|
16
|
-
def self.walk(node, &block)
|
17
|
+
def self.walk(node, stack, &block)
|
17
18
|
raise ArgumentError, 'block expected' unless block_given?
|
18
19
|
|
19
|
-
block.call(node)
|
20
|
+
block.call(node, stack)
|
20
21
|
node.children.grep(Parser::AST::Node).each do |child|
|
21
|
-
|
22
|
+
stack.push(child)
|
23
|
+
walk(child, stack, &block)
|
24
|
+
stack.pop
|
22
25
|
end
|
23
26
|
|
24
27
|
self
|
25
28
|
end
|
29
|
+
private_class_method :walk
|
26
30
|
|
27
|
-
# Find last node
|
31
|
+
# Find last node satisfying predicate (as block)
|
28
32
|
#
|
29
33
|
# @return [Parser::AST::Node]
|
30
|
-
# if
|
34
|
+
# if satisfying node is found
|
31
35
|
#
|
32
36
|
# @yield [Parser::AST::Node]
|
33
37
|
#
|
@@ -39,13 +43,15 @@ module Mutant
|
|
39
43
|
#
|
40
44
|
# @api private
|
41
45
|
#
|
42
|
-
def self.
|
46
|
+
def self.find_last_path(node, &predicate)
|
43
47
|
raise ArgumentError, 'block expected' unless block_given?
|
44
|
-
|
45
|
-
walk(node) do |candidate|
|
46
|
-
|
48
|
+
path = []
|
49
|
+
walk(node, [node]) do |candidate, stack|
|
50
|
+
if predicate.call(candidate, &predicate)
|
51
|
+
path = stack.dup
|
52
|
+
end
|
47
53
|
end
|
48
|
-
|
54
|
+
path
|
49
55
|
end
|
50
56
|
|
51
57
|
end # AST
|
data/lib/mutant/ast/meta.rb
CHANGED
@@ -17,14 +17,42 @@ module Mutant
|
|
17
17
|
REGISTRY.fetch(node.type, Generic).new(node)
|
18
18
|
end
|
19
19
|
|
20
|
-
#
|
20
|
+
# Mixin to define meta nodes
|
21
|
+
class Node < Module
|
22
|
+
include Concord.new(:type)
|
23
|
+
|
24
|
+
CONCORD = Concord.new(:node)
|
25
|
+
|
26
|
+
# Hook called when module gets included
|
27
|
+
#
|
28
|
+
# @param [Class, Module] host
|
29
|
+
#
|
30
|
+
# @return [undefined]
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
#
|
34
|
+
def included(host)
|
35
|
+
REGISTRY[type] = host
|
36
|
+
host.class_eval do
|
37
|
+
include CONCORD, NamedChildren
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
end # Node
|
42
|
+
|
43
|
+
# Metadata for resbody nods
|
44
|
+
class Resbody
|
45
|
+
include Node.new(:resbody)
|
46
|
+
|
47
|
+
children :captures, :assignment, :body
|
48
|
+
end # Resbody
|
49
|
+
|
50
|
+
# Metadata for send nodes
|
21
51
|
class Send
|
22
|
-
include
|
52
|
+
include Node.new(:send)
|
23
53
|
|
24
54
|
children :receiver, :selector
|
25
55
|
|
26
|
-
REGISTRY[:send] = self
|
27
|
-
|
28
56
|
INDEX_ASSIGNMENT_SELECTOR = :[]=
|
29
57
|
ATTRIBUTE_ASSIGNMENT_SELECTOR_SUFFIX = '='.freeze
|
30
58
|
|
@@ -100,7 +128,7 @@ module Mutant
|
|
100
128
|
|
101
129
|
end # Send
|
102
130
|
|
103
|
-
# Generic node
|
131
|
+
# Generic node metadata
|
104
132
|
class Generic
|
105
133
|
include Adamantium, Concord.new(:node)
|
106
134
|
|
data/lib/mutant/diff.rb
CHANGED
@@ -2,8 +2,8 @@ module Mutant
|
|
2
2
|
class Matcher
|
3
3
|
# Matcher for subjects that are a specific method
|
4
4
|
class Method < self
|
5
|
-
include Adamantium::Flat, Concord::Public.new(:env, :scope, :
|
6
|
-
include Equalizer.new(:identification)
|
5
|
+
include Adamantium::Flat, Concord::Public.new(:env, :scope, :target_method)
|
6
|
+
include AST::NodePredicates, Equalizer.new(:identification)
|
7
7
|
|
8
8
|
# Methods within rbx kernel directory are precompiled and their source
|
9
9
|
# cannot be accessed via reading source location. Same for methods created by eval.
|
@@ -40,7 +40,10 @@ module Mutant
|
|
40
40
|
def skip?
|
41
41
|
location = source_location
|
42
42
|
if location.nil? || BLACKLIST.match(location.first)
|
43
|
-
env.warn(format('%s does not have valid source location unable to emit
|
43
|
+
env.warn(format('%s does not have valid source location unable to emit subject', target_method.inspect))
|
44
|
+
true
|
45
|
+
elsif matched_node_path.any?(&method(:n_block?))
|
46
|
+
env.warn(format('%s is defined from a 3rd party lib unable to emit subject', target_method.inspect))
|
44
47
|
true
|
45
48
|
else
|
46
49
|
false
|
@@ -54,7 +57,7 @@ module Mutant
|
|
54
57
|
# @api private
|
55
58
|
#
|
56
59
|
def method_name
|
57
|
-
|
60
|
+
target_method.name
|
58
61
|
end
|
59
62
|
|
60
63
|
# Return context
|
@@ -104,7 +107,7 @@ module Mutant
|
|
104
107
|
# @api private
|
105
108
|
#
|
106
109
|
def source_location
|
107
|
-
|
110
|
+
target_method.source_location
|
108
111
|
end
|
109
112
|
|
110
113
|
# Return subject
|
@@ -118,27 +121,22 @@ module Mutant
|
|
118
121
|
# @api private
|
119
122
|
#
|
120
123
|
def subject
|
121
|
-
node =
|
124
|
+
node = matched_node_path.last
|
122
125
|
return unless node
|
123
126
|
self.class::SUBJECT_CLASS.new(env.config, context, node)
|
124
127
|
end
|
125
128
|
memoize :subject
|
126
129
|
|
127
|
-
# Return matched node
|
128
|
-
#
|
129
|
-
# @return [Parser::AST::Node]
|
130
|
-
# if node could be found
|
130
|
+
# Return matched node path
|
131
131
|
#
|
132
|
-
# @return [
|
133
|
-
# otherwise
|
132
|
+
# @return [Array<Parser::AST::Node>]
|
134
133
|
#
|
135
134
|
# @api private
|
136
135
|
#
|
137
|
-
def
|
138
|
-
AST.
|
139
|
-
match?(node)
|
140
|
-
end
|
136
|
+
def matched_node_path
|
137
|
+
AST.find_last_path(ast, &method(:match?))
|
141
138
|
end
|
139
|
+
memoize :matched_node_path
|
142
140
|
|
143
141
|
end # Method
|
144
142
|
end # Matcher
|
@@ -15,10 +15,10 @@ module Mutant
|
|
15
15
|
#
|
16
16
|
# @api private
|
17
17
|
#
|
18
|
-
def self.build(env, scope,
|
19
|
-
name =
|
18
|
+
def self.build(env, scope, target_method)
|
19
|
+
name = target_method.name
|
20
20
|
if scope.ancestors.include?(::Memoizable) && scope.memoized?(name)
|
21
|
-
return Memoized.new(env, scope,
|
21
|
+
return Memoized.new(env, scope, target_method)
|
22
22
|
end
|
23
23
|
super
|
24
24
|
end
|
@@ -68,7 +68,7 @@ module Mutant
|
|
68
68
|
# @api private
|
69
69
|
#
|
70
70
|
def source_location
|
71
|
-
scope.unmemoized_instance_method(
|
71
|
+
scope.unmemoized_instance_method(method_name).source_location
|
72
72
|
end
|
73
73
|
|
74
74
|
end # Memoized
|
data/lib/mutant/meta.rb
CHANGED
data/lib/mutant/meta/example.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Mutant
|
2
2
|
module Meta
|
3
3
|
class Example
|
4
|
-
include Adamantium, Concord::Public.new(:node, :mutations)
|
4
|
+
include Adamantium, Concord::Public.new(:file, :node, :mutations)
|
5
5
|
|
6
6
|
# Return a verification instance
|
7
7
|
#
|
@@ -26,7 +26,7 @@ module Mutant
|
|
26
26
|
|
27
27
|
# Return generated mutations
|
28
28
|
#
|
29
|
-
# @return [
|
29
|
+
# @return [Enumerable<Mutant::Mutation>]
|
30
30
|
#
|
31
31
|
# @api private
|
32
32
|
#
|
@@ -97,7 +97,7 @@ module Mutant
|
|
97
97
|
def mutation_report
|
98
98
|
original_node = example.node
|
99
99
|
[
|
100
|
-
|
100
|
+
"#{example.file}, Original-AST:",
|
101
101
|
original_node.inspect,
|
102
102
|
'Original-Source:',
|
103
103
|
example.source,
|
@@ -12,8 +12,8 @@ module Mutant
|
|
12
12
|
#
|
13
13
|
# @api private
|
14
14
|
#
|
15
|
-
def self.run(block)
|
16
|
-
instance = new
|
15
|
+
def self.run(file, block)
|
16
|
+
instance = new(file)
|
17
17
|
instance.instance_eval(&block)
|
18
18
|
instance.example
|
19
19
|
end
|
@@ -24,7 +24,8 @@ module Mutant
|
|
24
24
|
#
|
25
25
|
# @api private
|
26
26
|
#
|
27
|
-
def initialize
|
27
|
+
def initialize(file)
|
28
|
+
@file = file
|
28
29
|
@source = nil
|
29
30
|
@expected = []
|
30
31
|
end
|
@@ -40,7 +41,7 @@ module Mutant
|
|
40
41
|
#
|
41
42
|
def example
|
42
43
|
raise 'source not defined' unless @source
|
43
|
-
Example.new(@source, @expected)
|
44
|
+
Example.new(@file, @source, @expected)
|
44
45
|
end
|
45
46
|
|
46
47
|
private
|
data/lib/mutant/mutator/node.rb
CHANGED
@@ -8,6 +8,8 @@ module Mutant
|
|
8
8
|
include AbstractType, Unparser::Constants
|
9
9
|
include AST::NamedChildren, AST::NodePredicates, AST::Sexp, AST::Nodes
|
10
10
|
|
11
|
+
TAUTOLOGY = ->(_input) { true }
|
12
|
+
|
11
13
|
# Helper to define a named child
|
12
14
|
#
|
13
15
|
# @param [Parser::AST::Node] node
|
@@ -79,7 +81,7 @@ module Mutant
|
|
79
81
|
# @api private
|
80
82
|
#
|
81
83
|
def mutate_child(index, mutator = Mutator, &block)
|
82
|
-
block ||=
|
84
|
+
block ||= TAUTOLOGY
|
83
85
|
child = children.at(index)
|
84
86
|
mutator.each(child, self) do |mutation|
|
85
87
|
next unless block.call(mutation)
|
@@ -211,6 +213,20 @@ module Mutant
|
|
211
213
|
AST::Types::OP_ASSIGN.include?(parent_type) && parent.node.children.first.equal?(node)
|
212
214
|
end
|
213
215
|
|
216
|
+
# Return children indices
|
217
|
+
#
|
218
|
+
# @param [Range] range
|
219
|
+
#
|
220
|
+
# @return [Enumerable<Fixnum>]
|
221
|
+
#
|
222
|
+
# @api pirvate
|
223
|
+
#
|
224
|
+
def children_indices(range)
|
225
|
+
range_end = range.end
|
226
|
+
last_index = range_end >= 0 ? range_end : children.length + range_end
|
227
|
+
range.begin.upto(last_index)
|
228
|
+
end
|
229
|
+
|
214
230
|
end # Node
|
215
231
|
end # Mutator
|
216
232
|
end # Mutant
|
@@ -2,10 +2,86 @@ module Mutant
|
|
2
2
|
class Mutator
|
3
3
|
class Node
|
4
4
|
# Mutator for rescue nodes
|
5
|
-
class Rescue <
|
5
|
+
class Rescue < self
|
6
6
|
|
7
7
|
handle :rescue
|
8
8
|
|
9
|
+
children :body
|
10
|
+
|
11
|
+
define_named_child(:else_body, -1)
|
12
|
+
|
13
|
+
RESCUE_INDICES = (1..-2).freeze
|
14
|
+
|
15
|
+
# Emit mutations
|
16
|
+
#
|
17
|
+
# @return [undefined]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
#
|
21
|
+
def dispatch
|
22
|
+
mutate_body
|
23
|
+
mutate_rescue_bodies
|
24
|
+
mutate_else_body
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Mutate child by name
|
30
|
+
#
|
31
|
+
# @return [undefined]
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
#
|
35
|
+
def mutate_rescue_bodies
|
36
|
+
children_indices(RESCUE_INDICES).each do |index|
|
37
|
+
rescue_body = children.at(index)
|
38
|
+
next unless rescue_body
|
39
|
+
mutate_child(index)
|
40
|
+
resbody_body = AST::Meta.for(rescue_body).body
|
41
|
+
emit_concat(resbody_body) if resbody_body
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# Emit concatenation with body
|
46
|
+
#
|
47
|
+
# @param [Parser::AST::Node] child
|
48
|
+
#
|
49
|
+
# @return [undefined]
|
50
|
+
#
|
51
|
+
# @api private
|
52
|
+
#
|
53
|
+
def emit_concat(child)
|
54
|
+
if body
|
55
|
+
emit(s(:begin, body, child))
|
56
|
+
else
|
57
|
+
emit(child)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Emit body mutations
|
62
|
+
#
|
63
|
+
# @return [undefined]
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
#
|
67
|
+
def mutate_body
|
68
|
+
return unless body
|
69
|
+
emit_body_mutations
|
70
|
+
emit(body)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Emit else body mutations
|
74
|
+
#
|
75
|
+
# @return [undefined]
|
76
|
+
#
|
77
|
+
# @api private
|
78
|
+
#
|
79
|
+
def mutate_else_body
|
80
|
+
return unless else_body
|
81
|
+
emit_else_body_mutations
|
82
|
+
emit_concat(else_body)
|
83
|
+
end
|
84
|
+
|
9
85
|
end # Rescue
|
10
86
|
end # Node
|
11
87
|
end # Mutator
|
@@ -22,7 +22,7 @@ module Mutant
|
|
22
22
|
yield
|
23
23
|
self
|
24
24
|
ensure
|
25
|
-
|
25
|
+
disinfect
|
26
26
|
end
|
27
27
|
|
28
28
|
# Infect kernel with highjack
|
@@ -43,13 +43,13 @@ module Mutant
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
# Imperfectly
|
46
|
+
# Imperfectly disinfect kernel from highjack
|
47
47
|
#
|
48
48
|
# @return [self]
|
49
49
|
#
|
50
50
|
# @api private
|
51
51
|
#
|
52
|
-
def
|
52
|
+
def disinfect
|
53
53
|
original = @original
|
54
54
|
target.module_eval do
|
55
55
|
undef :require
|
data/lib/mutant/runner.rb
CHANGED
data/lib/mutant/subject.rb
CHANGED
data/lib/mutant/version.rb
CHANGED
data/meta/def.rb
CHANGED
@@ -13,6 +13,36 @@ Mutant::Meta::Example.add do
|
|
13
13
|
mutation 'def foo; nil; rescue; end'
|
14
14
|
mutation 'def foo; self; rescue; end'
|
15
15
|
mutation 'def foo; end'
|
16
|
+
|
17
|
+
# Promote rescue resbody bodies
|
18
|
+
mutation 'def foo; foo; end'
|
19
|
+
end
|
20
|
+
|
21
|
+
Mutant::Meta::Example.add do
|
22
|
+
source 'def a; foo; rescue; bar; else; baz; end'
|
23
|
+
|
24
|
+
# Mutate all bodies
|
25
|
+
mutation 'def a; nil; rescue; bar; else; baz; end'
|
26
|
+
mutation 'def a; self; rescue; bar; else; baz; end'
|
27
|
+
mutation 'def a; foo; rescue; nil; else; baz; end'
|
28
|
+
mutation 'def a; foo; rescue; self; else; baz; end'
|
29
|
+
mutation 'def a; foo; rescue; bar; else; nil; end'
|
30
|
+
mutation 'def a; foo; rescue; bar; else; self; end'
|
31
|
+
|
32
|
+
# Promote and concat rescue resbody bodies
|
33
|
+
mutation 'def a; foo; bar; end'
|
34
|
+
|
35
|
+
# Promote and concat else body
|
36
|
+
mutation 'def a; foo; baz; end'
|
37
|
+
|
38
|
+
# Promote rescue body
|
39
|
+
mutation 'def a; foo; end'
|
40
|
+
|
41
|
+
# Empty body
|
42
|
+
mutation 'def a; end'
|
43
|
+
|
44
|
+
# Failing body
|
45
|
+
mutation 'def a; raise; end'
|
16
46
|
end
|
17
47
|
|
18
48
|
Mutant::Meta::Example.add do
|
data/meta/if.rb
CHANGED
@@ -14,7 +14,7 @@ Mutant::Meta::Example.add do
|
|
14
14
|
# Deleted else branch
|
15
15
|
mutation 'if condition; true end'
|
16
16
|
|
17
|
-
# Deleted if branch
|
17
|
+
# Deleted if branch resulting in unless rendering
|
18
18
|
mutation 'unless condition; false; end'
|
19
19
|
|
20
20
|
# Deleted if branch with promoting else branch to if branch
|
data/meta/rescue.rb
CHANGED
@@ -9,6 +9,8 @@ Mutant::Meta::Example.add do
|
|
9
9
|
mutation 'begin; rescue ExceptionA, self => error; true; end'
|
10
10
|
mutation 'begin; rescue ExceptionA, ExceptionB => error; false; end'
|
11
11
|
mutation 'begin; rescue ExceptionA, ExceptionB => error; nil; end'
|
12
|
+
mutation 'begin; true; end'
|
13
|
+
|
12
14
|
end
|
13
15
|
|
14
16
|
Mutant::Meta::Example.add do
|
@@ -19,6 +21,7 @@ Mutant::Meta::Example.add do
|
|
19
21
|
mutation 'begin; rescue SomeException => error; false; end'
|
20
22
|
mutation 'begin; rescue SomeException => error; nil; end'
|
21
23
|
mutation 'begin; rescue self => error; true; end'
|
24
|
+
mutation 'begin; true; end'
|
22
25
|
end
|
23
26
|
|
24
27
|
Mutant::Meta::Example.add do
|
@@ -28,6 +31,7 @@ Mutant::Meta::Example.add do
|
|
28
31
|
mutation 'begin; rescue => error; false; end'
|
29
32
|
mutation 'begin; rescue => error; nil; end'
|
30
33
|
mutation 'begin; rescue; true; end'
|
34
|
+
mutation 'begin; true; end'
|
31
35
|
end
|
32
36
|
|
33
37
|
Mutant::Meta::Example.add do
|
@@ -36,4 +40,5 @@ Mutant::Meta::Example.add do
|
|
36
40
|
singleton_mutations
|
37
41
|
mutation 'begin; rescue; false; end'
|
38
42
|
mutation 'begin; rescue; nil; end'
|
43
|
+
mutation 'begin; true end'
|
39
44
|
end
|
data/meta/super.rb
CHANGED
data/mutant.gemspec
CHANGED
@@ -26,6 +26,7 @@ Gem::Specification.new do |gem|
|
|
26
26
|
gem.add_runtime_dependency('parser', '~> 2.1')
|
27
27
|
gem.add_runtime_dependency('ast', '~> 2.0')
|
28
28
|
gem.add_runtime_dependency('diff-lcs', '~> 1.2')
|
29
|
+
gem.add_runtime_dependency('parallel', '~> 1.3')
|
29
30
|
gem.add_runtime_dependency('morpher', '~> 0.2.3')
|
30
31
|
gem.add_runtime_dependency('procto', '~> 0.0.2')
|
31
32
|
gem.add_runtime_dependency('abstract_type', '~> 0.0.7')
|
@@ -37,7 +38,6 @@ Gem::Specification.new do |gem|
|
|
37
38
|
gem.add_runtime_dependency('inflecto', '~> 0.0.2')
|
38
39
|
gem.add_runtime_dependency('anima', '~> 0.2.0')
|
39
40
|
gem.add_runtime_dependency('concord', '~> 0.1.5')
|
40
|
-
gem.add_runtime_dependency('parallel', '~> 1.2.0')
|
41
41
|
|
42
42
|
gem.add_development_dependency('bundler', '~> 1.3', '>= 1.3.5')
|
43
43
|
end
|
@@ -17,7 +17,7 @@ RSpec.shared_examples_for 'a method matcher' do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
it 'should have correct line number' do
|
20
|
-
expect(node.location.expression.line
|
20
|
+
expect(node.location.expression.line).to eql(method_line)
|
21
21
|
end
|
22
22
|
|
23
23
|
it 'should have correct arity' do
|
@@ -0,0 +1,38 @@
|
|
1
|
+
RSpec.describe Mutant::AST do
|
2
|
+
let(:object) { described_class }
|
3
|
+
|
4
|
+
describe '.find_last_path' do
|
5
|
+
subject { object.find_last_path(root, &block) }
|
6
|
+
|
7
|
+
let(:root) { s(:root, parent) }
|
8
|
+
let(:child_a) { s(:child_a) }
|
9
|
+
let(:child_b) { s(:child_b) }
|
10
|
+
let(:parent) { s(:parent, child_a, child_b) }
|
11
|
+
|
12
|
+
def path
|
13
|
+
subject.map(&:type)
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'when no node matches' do
|
17
|
+
let(:block) { ->(_) { false } }
|
18
|
+
|
19
|
+
it { should eql([]) }
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'when one node matches' do
|
23
|
+
let(:block) { ->(node) { node.equal?(child_a) } }
|
24
|
+
|
25
|
+
it 'returns the full path' do
|
26
|
+
expect(path).to eql([:root, :parent, :child_a])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'when two nodes match' do
|
31
|
+
let(:block) { ->(node) { node.equal?(child_a) || node.equal?(child_b) } }
|
32
|
+
|
33
|
+
it 'returns the last full path' do
|
34
|
+
expect(path).to eql([:root, :parent, :child_b])
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -11,10 +11,10 @@ RSpec.describe Mutant::Matcher::Method::Instance do
|
|
11
11
|
let(:method) { scope.instance_method(method_name) }
|
12
12
|
let(:yields) { [] }
|
13
13
|
let(:namespace) { self.class }
|
14
|
-
let(:scope) { self.class::Foo }
|
15
14
|
let(:type) { :def }
|
16
|
-
let(:method_name) { :
|
15
|
+
let(:method_name) { :foo }
|
17
16
|
let(:method_arity) { 0 }
|
17
|
+
let(:base) { TestApp::InstanceMethodTests }
|
18
18
|
|
19
19
|
def name
|
20
20
|
node.children[0]
|
@@ -36,109 +36,79 @@ RSpec.describe Mutant::Matcher::Method::Instance do
|
|
36
36
|
it 'does warn' do
|
37
37
|
subject
|
38
38
|
expect(reporter.warn_calls.last).to(
|
39
|
-
eql("#{method.inspect} does not have valid source location unable to emit
|
39
|
+
eql("#{method.inspect} does not have valid source location unable to emit subject")
|
40
40
|
)
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
44
|
context 'when method is defined once' do
|
45
|
-
let(:
|
46
|
-
|
47
|
-
def bar; end
|
48
|
-
end
|
49
|
-
|
50
|
-
let(:method_line) { 2 }
|
45
|
+
let(:scope) { base::DefinedOnce }
|
46
|
+
let(:method_line) { 7 }
|
51
47
|
|
52
48
|
it_should_behave_like 'a method matcher'
|
53
49
|
end
|
54
50
|
|
55
51
|
context 'when method is defined once with a memoizer' do
|
56
|
-
let(:
|
57
|
-
|
58
|
-
def bar; end
|
59
|
-
include Adamantium
|
60
|
-
memoize :bar
|
61
|
-
end
|
62
|
-
|
63
|
-
let(:method_line) { 2 }
|
52
|
+
let(:scope) { base::WithMemoizer }
|
53
|
+
let(:method_line) { 12 }
|
64
54
|
|
65
55
|
it_should_behave_like 'a method matcher'
|
66
56
|
end
|
67
57
|
|
68
58
|
context 'when method is defined multiple times' do
|
69
59
|
context 'on different lines' do
|
70
|
-
let(:
|
71
|
-
|
72
|
-
|
73
|
-
end
|
74
|
-
|
75
|
-
def bar(_arg)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
let(:method_line) { 5 }
|
80
|
-
let(:method_arity) { 1 }
|
60
|
+
let(:scope) { base::DefinedMultipleTimes::DifferentLines }
|
61
|
+
let(:method_line) { 21 }
|
62
|
+
let(:method_arity) { 1 }
|
81
63
|
|
82
64
|
it_should_behave_like 'a method matcher'
|
83
65
|
end
|
84
66
|
|
85
67
|
context 'on the same line' do
|
86
|
-
let(:
|
87
|
-
|
88
|
-
|
89
|
-
end
|
90
|
-
|
91
|
-
let(:method_line) { 2 }
|
92
|
-
let(:method_arity) { 1 }
|
68
|
+
let(:scope) { base::DefinedMultipleTimes::SameLineSameScope }
|
69
|
+
let(:method_line) { 26 }
|
70
|
+
let(:method_arity) { 1 }
|
93
71
|
|
94
72
|
it_should_behave_like 'a method matcher'
|
95
73
|
end
|
96
74
|
|
97
75
|
context 'on the same line with different scope' do
|
98
|
-
let(:
|
99
|
-
|
100
|
-
|
101
|
-
end
|
102
|
-
|
103
|
-
let(:method_line) { 2 }
|
104
|
-
let(:method_arity) { 1 }
|
76
|
+
let(:scope) { base::DefinedMultipleTimes::SameLineDifferentScope }
|
77
|
+
let(:method_line) { 30 }
|
78
|
+
let(:method_arity) { 1 }
|
105
79
|
|
106
80
|
it_should_behave_like 'a method matcher'
|
107
81
|
end
|
108
82
|
|
109
|
-
context '
|
110
|
-
let(:
|
83
|
+
context 'in module eval' do
|
84
|
+
let(:scope) { base::InModuleEval }
|
111
85
|
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
def baz
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
let(:method_line) { 3 }
|
122
|
-
let(:method_name) { :baz }
|
123
|
-
let(:scope) { self.class::Foo::Bar }
|
86
|
+
it 'does not emit matcher' do
|
87
|
+
subject
|
88
|
+
expect(yields.length).to be(0)
|
89
|
+
end
|
124
90
|
|
125
|
-
|
91
|
+
it 'does warn' do
|
92
|
+
subject
|
93
|
+
expect(reporter.warn_calls.last).to(
|
94
|
+
eql("#{method.inspect} is defined from a 3rd party lib unable to emit subject")
|
95
|
+
)
|
126
96
|
end
|
97
|
+
end
|
127
98
|
|
128
|
-
|
129
|
-
|
130
|
-
module self::Foo
|
131
|
-
class Bar
|
132
|
-
def baz
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
99
|
+
context 'in class eval' do
|
100
|
+
let(:scope) { base::InClassEval }
|
136
101
|
|
137
|
-
|
138
|
-
|
139
|
-
|
102
|
+
it 'does not emit matcher' do
|
103
|
+
subject
|
104
|
+
expect(yields.length).to be(0)
|
105
|
+
end
|
140
106
|
|
141
|
-
|
107
|
+
it 'does warn' do
|
108
|
+
subject
|
109
|
+
expect(reporter.warn_calls.last).to(
|
110
|
+
eql("#{method.inspect} is defined from a 3rd party lib unable to emit subject")
|
111
|
+
)
|
142
112
|
end
|
143
113
|
end
|
144
114
|
end
|
@@ -6,10 +6,10 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#each' do
|
|
6
6
|
let(:method) { scope.method(method_name) }
|
7
7
|
let(:env) { Fixtures::TEST_ENV }
|
8
8
|
let(:yields) { [] }
|
9
|
-
let(:namespace) { self.class }
|
10
|
-
let(:scope) { self.class::Foo }
|
11
9
|
let(:type) { :defs }
|
10
|
+
let(:method_name) { :foo }
|
12
11
|
let(:method_arity) { 0 }
|
12
|
+
let(:base) { TestApp::SingletonMethodTests }
|
13
13
|
|
14
14
|
def name
|
15
15
|
node.children[1]
|
@@ -22,14 +22,8 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#each' do
|
|
22
22
|
context 'on singleton methods' do
|
23
23
|
|
24
24
|
context 'when also defined on lvar' do
|
25
|
-
let(:
|
26
|
-
|
27
|
-
a = Object.new
|
28
|
-
def a.bar; end; def self.bar; end
|
29
|
-
end
|
30
|
-
|
31
|
-
let(:method_name) { :bar }
|
32
|
-
let(:method_line) { 3 }
|
25
|
+
let(:scope) { base::AlsoDefinedOnLvar }
|
26
|
+
let(:method_line) { 63 }
|
33
27
|
|
34
28
|
it_should_behave_like 'a method matcher'
|
35
29
|
|
@@ -42,13 +36,8 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#each' do
|
|
42
36
|
end
|
43
37
|
|
44
38
|
context 'when defined on self' do
|
45
|
-
let(:
|
46
|
-
|
47
|
-
def self.bar; end
|
48
|
-
end
|
49
|
-
|
50
|
-
let(:method_name) { :bar }
|
51
|
-
let(:method_line) { 2 }
|
39
|
+
let(:scope) { base::DefinedOnSelf }
|
40
|
+
let(:method_line) { 58 }
|
52
41
|
|
53
42
|
it_should_behave_like 'a method matcher'
|
54
43
|
end
|
@@ -56,34 +45,15 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#each' do
|
|
56
45
|
context 'when defined on constant' do
|
57
46
|
|
58
47
|
context 'inside namespace' do
|
59
|
-
let(:
|
60
|
-
|
61
|
-
class Foo
|
62
|
-
def Foo.bar
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
let(:scope) { self.class::Namespace::Foo }
|
68
|
-
let(:method_name) { :bar }
|
69
|
-
let(:method_line) { 3 }
|
48
|
+
let(:scope) { base::DefinedOnConstant::InsideNamespace }
|
49
|
+
let(:method_line) { 68 }
|
70
50
|
|
71
51
|
it_should_behave_like 'a method matcher'
|
72
52
|
end
|
73
53
|
|
74
54
|
context 'outside namespace' do
|
75
|
-
let(:
|
76
|
-
|
77
|
-
class Foo
|
78
|
-
end
|
79
|
-
|
80
|
-
def Foo.bar
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
let(:method_name) { :bar }
|
85
|
-
let(:method_line) { 5 }
|
86
|
-
let(:scope) { self.class::Namespace::Foo }
|
55
|
+
let(:method_line) { 75 }
|
56
|
+
let(:scope) { base::DefinedOnConstant::OutsideNamespace }
|
87
57
|
|
88
58
|
it_should_behave_like 'a method matcher'
|
89
59
|
end
|
@@ -91,21 +61,9 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#each' do
|
|
91
61
|
|
92
62
|
context 'when defined multiple times in the same line' do
|
93
63
|
context 'with method on different scope' do
|
94
|
-
let(:
|
95
|
-
|
96
|
-
|
97
|
-
module Bar
|
98
|
-
def self.baz
|
99
|
-
end
|
100
|
-
def Foo.baz(_arg)
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
let(:scope) { self.class::Namespace::Bar }
|
106
|
-
let(:method_name) { :baz }
|
107
|
-
let(:method_line) { 4 }
|
108
|
-
let(:method_arity) { 0 }
|
64
|
+
let(:scope) { base::DefinedMultipleTimes::SameLine::DifferentScope }
|
65
|
+
let(:method_line) { 94 }
|
66
|
+
let(:method_arity) { 1 }
|
109
67
|
|
110
68
|
it_should_behave_like 'a method matcher'
|
111
69
|
end
|
data/test_app/lib/test_app.rb
CHANGED
@@ -2,6 +2,100 @@
|
|
2
2
|
|
3
3
|
# Namespace for test application
|
4
4
|
module TestApp
|
5
|
+
module InstanceMethodTests
|
6
|
+
module DefinedOnce
|
7
|
+
def foo; end
|
8
|
+
end
|
9
|
+
|
10
|
+
class WithMemoizer
|
11
|
+
include Adamantium
|
12
|
+
def foo; end
|
13
|
+
memoize :foo
|
14
|
+
end
|
15
|
+
|
16
|
+
module DefinedMultipleTimes
|
17
|
+
class DifferentLines
|
18
|
+
def foo
|
19
|
+
end
|
20
|
+
|
21
|
+
def foo(_arg)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class SameLineSameScope
|
26
|
+
def foo; end; def foo(_arg); end
|
27
|
+
end
|
28
|
+
|
29
|
+
class SameLineDifferentScope
|
30
|
+
def self.foo; end; def foo(_arg); end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class InClassEval
|
35
|
+
class_eval do
|
36
|
+
def foo
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class InModuleEval
|
42
|
+
module_eval do
|
43
|
+
def foo
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class InInstanceEval
|
49
|
+
module_eval do
|
50
|
+
def foo
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
module SingletonMethodTests
|
57
|
+
module DefinedOnSelf
|
58
|
+
def self.foo; end
|
59
|
+
end
|
60
|
+
|
61
|
+
module AlsoDefinedOnLvar
|
62
|
+
a = Object.new
|
63
|
+
def a.foo; end; def self.foo; end
|
64
|
+
end
|
65
|
+
|
66
|
+
module DefinedOnConstant
|
67
|
+
module InsideNamespace
|
68
|
+
def InsideNamespace.foo
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
module OutsideNamespace
|
73
|
+
end
|
74
|
+
|
75
|
+
def OutsideNamespace.foo
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
module DefinedMultipleTimes
|
80
|
+
module DifferentLines
|
81
|
+
def self.foo
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.foo(_arg)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
module SameLine
|
89
|
+
module SameScope
|
90
|
+
def self.foo; end; def self.foo(_arg); end;
|
91
|
+
end
|
92
|
+
|
93
|
+
module DifferentScope
|
94
|
+
def self.foo; end; def DifferentScope.foo(_arg); end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
5
99
|
end
|
6
100
|
|
7
101
|
require 'test_app/literal'
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mutant
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Markus Schirp
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parser
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: parallel
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '1.3'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '1.3'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: morpher
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -206,20 +220,6 @@ dependencies:
|
|
206
220
|
- - "~>"
|
207
221
|
- !ruby/object:Gem::Version
|
208
222
|
version: 0.1.5
|
209
|
-
- !ruby/object:Gem::Dependency
|
210
|
-
name: parallel
|
211
|
-
requirement: !ruby/object:Gem::Requirement
|
212
|
-
requirements:
|
213
|
-
- - "~>"
|
214
|
-
- !ruby/object:Gem::Version
|
215
|
-
version: 1.2.0
|
216
|
-
type: :runtime
|
217
|
-
prerelease: false
|
218
|
-
version_requirements: !ruby/object:Gem::Requirement
|
219
|
-
requirements:
|
220
|
-
- - "~>"
|
221
|
-
- !ruby/object:Gem::Version
|
222
|
-
version: 1.2.0
|
223
223
|
- !ruby/object:Gem::Dependency
|
224
224
|
name: bundler
|
225
225
|
requirement: !ruby/object:Gem::Requirement
|
@@ -465,6 +465,7 @@ files:
|
|
465
465
|
- spec/support/mutation_verifier.rb
|
466
466
|
- spec/support/rspec.rb
|
467
467
|
- spec/support/test_app.rb
|
468
|
+
- spec/unit/mutant/ast_spec.rb
|
468
469
|
- spec/unit/mutant/cli_spec.rb
|
469
470
|
- spec/unit/mutant/context/root_spec.rb
|
470
471
|
- spec/unit/mutant/context/scope/root_spec.rb
|
@@ -541,6 +542,7 @@ test_files:
|
|
541
542
|
- spec/integration/mutant/rspec_spec.rb
|
542
543
|
- spec/integration/mutant/test_mutator_handles_types_spec.rb
|
543
544
|
- spec/integration/mutant/zombie_spec.rb
|
545
|
+
- spec/unit/mutant/ast_spec.rb
|
544
546
|
- spec/unit/mutant/cli_spec.rb
|
545
547
|
- spec/unit/mutant/context/root_spec.rb
|
546
548
|
- spec/unit/mutant/context/scope/root_spec.rb
|
@@ -578,4 +580,3 @@ test_files:
|
|
578
580
|
- spec/unit/mutant/warning_expectation.rb
|
579
581
|
- spec/unit/mutant/warning_filter_spec.rb
|
580
582
|
- spec/unit/mutant_spec.rb
|
581
|
-
has_rdoc:
|