mutant 0.2.9 → 0.2.11
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.
- data/.travis.yml +3 -0
- data/Changelog.md +13 -0
- data/TODO +7 -1
- data/lib/mutant.rb +48 -0
- data/lib/mutant/mutator/node/send.rb +77 -4
- data/lib/mutant/strategy/rspec/example_lookup.rb +1 -31
- data/mutant.gemspec +2 -2
- data/spec/unit/mutant/mutator/node/send/mutation_spec.rb +60 -6
- metadata +4 -4
data/.travis.yml
CHANGED
@@ -4,12 +4,15 @@ rvm:
|
|
4
4
|
- 1.8.7
|
5
5
|
- 1.9.2
|
6
6
|
- 1.9.3
|
7
|
+
- ruby-head
|
7
8
|
- rbx-19mode
|
8
9
|
matrix:
|
9
10
|
allow_failures:
|
10
11
|
# No mutators for 1.8 specifc AST nodes
|
11
12
|
- rvm: rbx-18mode
|
12
13
|
- rvm: 1.8.7
|
14
|
+
# We'll see what happens
|
15
|
+
- rvm: ruby-head
|
13
16
|
notifications:
|
14
17
|
email:
|
15
18
|
- mbj@seonic.net
|
data/Changelog.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
# v0.2.11 2013-01-03
|
2
|
+
|
3
|
+
* [change] Handle binary operator methods in dedicated mutator
|
4
|
+
* [fixed] Do not crash when mutating binary operator method
|
5
|
+
|
6
|
+
[Compare v0.2.10..v0.2.11](https://github.com/mbj/mutant/compare/v0.2.10...v0.2.11)
|
7
|
+
|
8
|
+
# v0.2.10 2013-01-03
|
9
|
+
|
10
|
+
* [fixed] Do not mutate receivers away when message name is a keyword
|
11
|
+
|
12
|
+
[Compare v0.2.9..v0.2.10](https://github.com/mbj/mutant/compare/v0.2.9...v0.2.10)
|
13
|
+
|
1
14
|
# v0.2.9 2013-01-02
|
2
15
|
|
3
16
|
* [feature] Mutate instance and global variable assignments
|
data/TODO
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
Code:
|
2
2
|
* Test mutant with dynamically created zombie.
|
3
|
-
* Fix ugly code within default
|
3
|
+
* Fix ugly code within default parameter mutations
|
4
|
+
* Break up lib/mutant/mutator/node/send.rb in class specific files
|
4
5
|
|
5
6
|
AST:
|
6
7
|
* Fix the rubinius AST to allow setting @vcall_style variable in Rubinius::AST::Send nodes.
|
7
8
|
|
8
9
|
Mutations:
|
10
|
+
* Add binary operator specific mutations (YAY, finally reached this point)
|
9
11
|
* Add some kind of a "do not touch me object" that raises on all messages.
|
10
12
|
It can be used to make sure each literal value is touched.
|
11
13
|
* Replace nil or add "do not touch me object" to literal mutations.
|
@@ -29,6 +31,10 @@ Killers:
|
|
29
31
|
* Add a general master <=> killer IPC interface. So different strategies of isolation
|
30
32
|
(fork, vs jruby runtime creation) will work without big impact.
|
31
33
|
|
34
|
+
Strategy:
|
35
|
+
* Provide "expicit files to kill with" strategy
|
36
|
+
* Automatically load ./spec/spec_helper.rb for rspec strategies (No need to specify -I and -r anymore)
|
37
|
+
|
32
38
|
Matcher:
|
33
39
|
* Allow matches on attr_reader with literal name argument(s)?
|
34
40
|
* Allow matches on define_method with literal name argument?
|
data/lib/mutant.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'backports'
|
2
|
+
require 'set'
|
2
3
|
require 'adamantium'
|
3
4
|
require 'ice_nine'
|
4
5
|
require 'abstract_type'
|
@@ -29,6 +30,53 @@ end
|
|
29
30
|
# Library namespace
|
30
31
|
module Mutant
|
31
32
|
|
33
|
+
# The list of ruby kewords from http://ruby-doc.org/docs/keywords/1.9/
|
34
|
+
KEYWORDS = %w(
|
35
|
+
BEGIN END __ENCODING__ __END__ __FILE__
|
36
|
+
__LINE__ alias and begin break case class
|
37
|
+
def define do else elsif end ensure false
|
38
|
+
for if in module next nil not or redo
|
39
|
+
rescue retry return self super then true
|
40
|
+
undef unless until when while yield
|
41
|
+
).map(&:to_sym).to_set.freeze
|
42
|
+
|
43
|
+
BINARY_METHOD_OPERATOR_EXPANSIONS = {
|
44
|
+
:<=> => :spaceship_operator,
|
45
|
+
:=== => :case_equality_operator,
|
46
|
+
:[]= => :element_writer,
|
47
|
+
:[] => :element_reader,
|
48
|
+
:<= => :less_than_or_equal_to_operator,
|
49
|
+
:>= => :greater_than_or_equal_to_operator,
|
50
|
+
:== => :equality_operator,
|
51
|
+
:'!~' => :nomatch_operator,
|
52
|
+
:'!=' => :inequality_operator,
|
53
|
+
:=~ => :match_operator,
|
54
|
+
:<< => :left_shift_operator,
|
55
|
+
:>> => :right_shift_operator,
|
56
|
+
:** => :exponentation_operator,
|
57
|
+
:* => :multiplication_operator,
|
58
|
+
:% => :modulo_operator,
|
59
|
+
:/ => :division_operator,
|
60
|
+
:| => :bitwise_or_operator,
|
61
|
+
:^ => :bitwise_xor_operator,
|
62
|
+
:& => :bitwise_and_operator,
|
63
|
+
:< => :less_than_operator,
|
64
|
+
:> => :greater_than_operator,
|
65
|
+
:+ => :addition_operator,
|
66
|
+
:- => :substraction_operator
|
67
|
+
}.freeze
|
68
|
+
|
69
|
+
UNARY_METHOD_OPERATOR_EXPANSIONS = {
|
70
|
+
:~@ => :unary_match_operator,
|
71
|
+
:+@ => :unary_addition_operator,
|
72
|
+
:-@ => :unary_substraction_operator,
|
73
|
+
:'!' => :negation_operator
|
74
|
+
}.freeze
|
75
|
+
|
76
|
+
BINARY_METHOD_OPERATORS = BINARY_METHOD_OPERATOR_EXPANSIONS.keys.to_set.freeze
|
77
|
+
|
78
|
+
OPERATOR_EXPANSIONS = BINARY_METHOD_OPERATOR_EXPANSIONS.merge(UNARY_METHOD_OPERATOR_EXPANSIONS).freeze
|
79
|
+
|
32
80
|
# Define instance of subclassed superclass as constant
|
33
81
|
#
|
34
82
|
# @param [Class] superclass
|
@@ -18,9 +18,9 @@ module Mutant
|
|
18
18
|
#
|
19
19
|
# @api private
|
20
20
|
#
|
21
|
-
def self.
|
21
|
+
def self.keyword_name?(node)
|
22
22
|
node.kind_of?(Rubinius::AST::Send) &&
|
23
|
-
node.name
|
23
|
+
Mutant::KEYWORDS.include?(node.name) &&
|
24
24
|
node.receiver.kind_of?(Rubinius::AST::Self)
|
25
25
|
end
|
26
26
|
|
@@ -73,7 +73,7 @@ module Mutant
|
|
73
73
|
def emit_receiver_mutations
|
74
74
|
util = self.class
|
75
75
|
|
76
|
-
unless to_self? or util.
|
76
|
+
unless to_self? or util.keyword_name?(receiver)
|
77
77
|
emit_attribute_mutations(:receiver)
|
78
78
|
end
|
79
79
|
end
|
@@ -151,7 +151,7 @@ module Mutant
|
|
151
151
|
#
|
152
152
|
def emit_implicit_self_receiver
|
153
153
|
return unless to_self?
|
154
|
-
return if self.class.
|
154
|
+
return if self.class.keyword_name?(node)
|
155
155
|
mutant = dup_node
|
156
156
|
mutant.privately = true
|
157
157
|
# TODO: Fix rubinius to allow this as an attr_accessor
|
@@ -163,6 +163,48 @@ module Mutant
|
|
163
163
|
|
164
164
|
handle(Rubinius::AST::SendWithArguments)
|
165
165
|
|
166
|
+
class BinaryOperatorMethod < Node
|
167
|
+
|
168
|
+
private
|
169
|
+
|
170
|
+
# Emit mutations
|
171
|
+
#
|
172
|
+
# @return [undefined]
|
173
|
+
#
|
174
|
+
# @api private
|
175
|
+
#
|
176
|
+
def dispatch
|
177
|
+
emit_left_mutations
|
178
|
+
emit_right_mutations
|
179
|
+
end
|
180
|
+
|
181
|
+
# Emit left mutations
|
182
|
+
#
|
183
|
+
# @return [undefined]
|
184
|
+
#
|
185
|
+
# @api private
|
186
|
+
#
|
187
|
+
def emit_left_mutations
|
188
|
+
emit_attribute_mutations(:receiver)
|
189
|
+
end
|
190
|
+
|
191
|
+
# Emit right mutations
|
192
|
+
#
|
193
|
+
# @return [undefined]
|
194
|
+
#
|
195
|
+
# @api private
|
196
|
+
#
|
197
|
+
def emit_right_mutations
|
198
|
+
right = node.arguments.array.first
|
199
|
+
Mutator.each(right).each do |mutated|
|
200
|
+
dup = dup_node
|
201
|
+
dup.arguments.array[0] = mutated
|
202
|
+
emit(dup)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
166
208
|
private
|
167
209
|
|
168
210
|
# Emit mutations
|
@@ -174,6 +216,37 @@ module Mutant
|
|
174
216
|
def dispatch
|
175
217
|
super
|
176
218
|
emit_call_remove_mutation
|
219
|
+
emit_argument_mutations
|
220
|
+
end
|
221
|
+
|
222
|
+
# Test if message is a binary operator
|
223
|
+
#
|
224
|
+
# @return [true]
|
225
|
+
# if message is a binary operator
|
226
|
+
#
|
227
|
+
# @return [false]
|
228
|
+
# otherwise
|
229
|
+
#
|
230
|
+
# @api private
|
231
|
+
#
|
232
|
+
def binary_operator?
|
233
|
+
Mutant::BINARY_METHOD_OPERATORS.include?(node.name)
|
234
|
+
end
|
235
|
+
|
236
|
+
# Emit argument mutations
|
237
|
+
#
|
238
|
+
# @api private
|
239
|
+
#
|
240
|
+
# @return [undefined]
|
241
|
+
#
|
242
|
+
# @api private
|
243
|
+
#
|
244
|
+
def emit_argument_mutations
|
245
|
+
if binary_operator?
|
246
|
+
run(BinaryOperatorMethod)
|
247
|
+
return
|
248
|
+
end
|
249
|
+
|
177
250
|
emit_attribute_mutations(:arguments)
|
178
251
|
end
|
179
252
|
|
@@ -56,36 +56,6 @@ module Mutant
|
|
56
56
|
mutation.subject.matcher
|
57
57
|
end
|
58
58
|
|
59
|
-
MAPPING = {
|
60
|
-
:<=> => :spaceship_operator,
|
61
|
-
:=== => :case_equality_operator,
|
62
|
-
:[]= => :element_writer,
|
63
|
-
:[] => :element_reader,
|
64
|
-
:<= => :less_than_or_equal_to_operator,
|
65
|
-
:>= => :greater_than_or_equal_to_operator,
|
66
|
-
:~@ => :unary_match_operator,
|
67
|
-
:+@ => :unary_addition_operator,
|
68
|
-
:-@ => :unary_substraction_operator,
|
69
|
-
:== => :equality_operator,
|
70
|
-
:'!~' => :nomatch_operator,
|
71
|
-
:'!=' => :inequality_operator,
|
72
|
-
:=~ => :match_operator,
|
73
|
-
:<< => :left_shift_operator,
|
74
|
-
:>> => :right_shift_operator,
|
75
|
-
:** => :exponentation_operator,
|
76
|
-
:* => :multiplication_operator,
|
77
|
-
:% => :modulo_operator,
|
78
|
-
:/ => :division_operator,
|
79
|
-
:| => :bitwise_or_operator,
|
80
|
-
:'!' => :negation_operator,
|
81
|
-
:^ => :bitwise_xor_operator,
|
82
|
-
:& => :bitwise_and_operator,
|
83
|
-
:< => :less_than_operator,
|
84
|
-
:> => :greater_than_operator,
|
85
|
-
:+ => :addition_operator,
|
86
|
-
:- => :substraction_operator
|
87
|
-
}
|
88
|
-
|
89
59
|
EXPANSIONS = {
|
90
60
|
/\?\z/ => '_predicate',
|
91
61
|
/=\z/ => '_writer',
|
@@ -114,7 +84,7 @@ module Mutant
|
|
114
84
|
# @api private
|
115
85
|
#
|
116
86
|
def mapped_name
|
117
|
-
|
87
|
+
OPERATOR_EXPANSIONS[method_name]
|
118
88
|
end
|
119
89
|
|
120
90
|
# Return expanded name
|
data/mutant.gemspec
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
4
|
gem.name = 'mutant'
|
5
|
-
gem.version = '0.2.
|
5
|
+
gem.version = '0.2.11'
|
6
6
|
gem.authors = [ 'Markus Schirp' ]
|
7
7
|
gem.email = [ 'mbj@seonic.net' ]
|
8
8
|
gem.description = 'Mutation testing for ruby under rubinius'
|
@@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.extra_rdoc_files = %w[TODO LICENSE]
|
16
16
|
gem.executables = [ 'mutant' ]
|
17
17
|
|
18
|
-
gem.add_runtime_dependency('to_source', '~> 0.2.
|
18
|
+
gem.add_runtime_dependency('to_source', '~> 0.2.8')
|
19
19
|
gem.add_runtime_dependency('ice_nine', '~> 0.6.0')
|
20
20
|
gem.add_runtime_dependency('descendants_tracker', '~> 0.0.1')
|
21
21
|
gem.add_runtime_dependency('backports', '~> 2.6')
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
+
# FIXME: This spec needs to be structured better!
|
3
4
|
describe Mutant::Mutator, 'send' do
|
4
5
|
context 'send without arguments' do
|
5
6
|
context 'with self as receiver' do
|
@@ -20,6 +21,15 @@ describe Mutant::Mutator, 'send' do
|
|
20
21
|
|
21
22
|
it_should_behave_like 'a mutator'
|
22
23
|
end
|
24
|
+
|
25
|
+
context 'explicit with keyword message name' do
|
26
|
+
Mutant::KEYWORDS.each do |keyword|
|
27
|
+
context "with keyword: #{keyword}" do
|
28
|
+
let(:source) { "self.#{keyword}" }
|
29
|
+
it_should_behave_like 'a noop mutator'
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
23
33
|
end
|
24
34
|
|
25
35
|
context 'to some object' do
|
@@ -33,12 +43,6 @@ describe Mutant::Mutator, 'send' do
|
|
33
43
|
it_should_behave_like 'a mutator'
|
34
44
|
end
|
35
45
|
|
36
|
-
context 'to self.class' do
|
37
|
-
let(:source) { 'self.class' }
|
38
|
-
|
39
|
-
it_should_behave_like 'a noop mutator'
|
40
|
-
end
|
41
|
-
|
42
46
|
context 'to self.class.foo' do
|
43
47
|
let(:source) { 'self.class.foo' }
|
44
48
|
|
@@ -66,6 +70,56 @@ describe Mutant::Mutator, 'send' do
|
|
66
70
|
it_should_behave_like 'a mutator'
|
67
71
|
end
|
68
72
|
|
73
|
+
context 'with explicit self as receiver' do
|
74
|
+
let(:source) { 'self.foo(nil)' }
|
75
|
+
|
76
|
+
let(:mutations) do
|
77
|
+
mutations = []
|
78
|
+
mutations << 'self.foo'
|
79
|
+
mutations << 'foo(nil)'
|
80
|
+
mutations << 'nil'
|
81
|
+
mutations << 'self.foo(Object.new)'
|
82
|
+
end
|
83
|
+
|
84
|
+
it_should_behave_like 'a mutator'
|
85
|
+
end
|
86
|
+
|
87
|
+
context 'to some object with keyword in method name' do
|
88
|
+
Mutant::KEYWORDS.each do |keyword|
|
89
|
+
context "with keyword #{keyword}" do
|
90
|
+
let(:source) { "foo.#{keyword}(nil)" }
|
91
|
+
|
92
|
+
let(:mutations) do
|
93
|
+
mutations = []
|
94
|
+
mutations << "foo.#{keyword}"
|
95
|
+
mutations << "foo"
|
96
|
+
mutations << 'nil'
|
97
|
+
mutations << "foo.#{keyword}(Object.new)"
|
98
|
+
end
|
99
|
+
|
100
|
+
it_should_behave_like 'a mutator'
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
context 'binary operator methods' do
|
106
|
+
Mutant::BINARY_METHOD_OPERATORS.each do |operator|
|
107
|
+
let(:source) { "true #{operator} false" }
|
108
|
+
|
109
|
+
let(:mutations) do
|
110
|
+
mutations = []
|
111
|
+
mutations << "((false) #{operator} (false))"
|
112
|
+
mutations << "((nil) #{operator} (false))"
|
113
|
+
mutations << "((true) #{operator} (true))"
|
114
|
+
mutations << "((true) #{operator} (nil))"
|
115
|
+
mutations << 'true'
|
116
|
+
mutations << 'false'
|
117
|
+
end
|
118
|
+
|
119
|
+
it_should_behave_like 'a mutator'
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
69
123
|
context 'two arguments' do
|
70
124
|
let(:source) { 'foo(nil, nil)' }
|
71
125
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mutant
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.11
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: to_source
|
@@ -18,7 +18,7 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.2.
|
21
|
+
version: 0.2.8
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
24
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
requirements:
|
27
27
|
- - ~>
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.2.
|
29
|
+
version: 0.2.8
|
30
30
|
- !ruby/object:Gem::Dependency
|
31
31
|
name: ice_nine
|
32
32
|
requirement: !ruby/object:Gem::Requirement
|