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.
@@ -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