mutant 0.2.9 → 0.2.11

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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 parameters
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?
@@ -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.self_class?(node)
21
+ def self.keyword_name?(node)
22
22
  node.kind_of?(Rubinius::AST::Send) &&
23
- node.name == :class &&
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.self_class?(receiver)
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.self_class?(node)
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
- MAPPING[method_name]
87
+ OPERATOR_EXPANSIONS[method_name]
118
88
  end
119
89
 
120
90
  # Return expanded name
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = 'mutant'
5
- gem.version = '0.2.9'
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.7')
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.9
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-02 00:00:00.000000000 Z
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.7
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.7
29
+ version: 0.2.8
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: ice_nine
32
32
  requirement: !ruby/object:Gem::Requirement