mutant 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. data/Changelog.md +12 -1
  2. data/Gemfile +1 -1
  3. data/lib/mutant.rb +3 -1
  4. data/lib/mutant/matcher/method.rb +23 -14
  5. data/lib/mutant/matcher/method/classifier.rb +21 -6
  6. data/lib/mutant/matcher/method/instance.rb +0 -11
  7. data/lib/mutant/matcher/method/singleton.rb +0 -11
  8. data/lib/mutant/matcher/scope_methods.rb +56 -13
  9. data/lib/mutant/mutator/node/block.rb +20 -0
  10. data/lib/mutant/mutator/node/if_statement.rb +2 -2
  11. data/lib/mutant/mutator/node/literal/range.rb +1 -1
  12. data/lib/mutant/strategy/rspec.rb +4 -4
  13. data/lib/mutant/strategy/rspec/example_lookup.rb +16 -2
  14. data/mutant.gemspec +1 -1
  15. data/spec/shared/mutator_behavior.rb +17 -11
  16. data/spec/unit/mutant/matcher/method/classifier/class_methods/run_spec.rb +27 -9
  17. data/spec/unit/mutant/mutator/node/block/mutation_spec.rb +9 -8
  18. data/spec/unit/mutant/mutator/node/define/mutation_spec.rb +2 -2
  19. data/spec/unit/mutant/mutator/node/if_statement/mutation_spec.rb +47 -17
  20. data/spec/unit/mutant/mutator/node/literal/array_spec.rb +1 -1
  21. data/spec/unit/mutant/mutator/node/literal/empty_array_spec.rb +1 -1
  22. data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +1 -1
  23. data/spec/unit/mutant/mutator/node/literal/float_spec.rb +2 -2
  24. data/spec/unit/mutant/mutator/node/literal/hash_spec.rb +13 -13
  25. data/spec/unit/mutant/mutator/node/literal/range_spec.rb +2 -2
  26. data/spec/unit/mutant/strategy/rspec/example_lookup/spec_file_spec.rb +61 -0
  27. metadata +3 -5
  28. data/spec/shared/method_filter_parse_behavior.rb +0 -16
  29. data/spec/unit/mutant/matcher/method/method_spec.rb +0 -11
@@ -1,3 +1,14 @@
1
- # v0.0.1 2012-12-07
1
+ # v0.2.1 xxx
2
+
3
+ * [fixed] Crash on unavailable source location
4
+ * [fixed] Incorrect handling of if and unless statements
5
+ * [fixed] Expand Foo#initialize to spec/unit/foo in rspec dm2 strategy
6
+ * [fixed] Correctly expand [] to element_reader_spec.rb in rspec dm2 strategy
7
+ * [fixed] Correctly expand []= to element_writer_spec.rb in rspec dm2 strategy
8
+ * [fixed] Correctly expand foo= to foo_writer_spec.rb in rspec dm2 strategy
9
+
10
+ [Compare v0.2.0..v0.2.1](https://github.com/mbj/mutant/compare/v0.2.0...v0.2.1)
11
+
12
+ # v0.2.0 2012-12-07
2
13
 
3
14
  First public release!
data/Gemfile CHANGED
@@ -2,5 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'devtools', :git => 'https://github.com/mbj/devtools.git', :branch => :'rspec-2-mutant'
5
+ gem 'devtools', :git => 'https://github.com/mbj/devtools.git'
6
6
  eval(File.read(File.join(File.dirname(__FILE__),'Gemfile.devtools')))
@@ -41,6 +41,8 @@ module Mutant
41
41
  self
42
42
  end
43
43
 
44
+ PID = Process.pid
45
+
44
46
  end
45
47
 
46
48
  require 'mutant/support/method_object'
@@ -84,8 +86,8 @@ require 'mutant/matcher/object_space'
84
86
  require 'mutant/matcher/method'
85
87
  require 'mutant/matcher/method/singleton'
86
88
  require 'mutant/matcher/method/instance'
87
- require 'mutant/matcher/method/classifier'
88
89
  require 'mutant/matcher/scope_methods'
90
+ require 'mutant/matcher/method/classifier'
89
91
  require 'mutant/killer'
90
92
  require 'mutant/killer/static'
91
93
  require 'mutant/killer/rspec'
@@ -28,6 +28,12 @@ module Mutant
28
28
  #
29
29
  def each(&block)
30
30
  return to_enum unless block_given?
31
+
32
+ unless source_location
33
+ $stderr.puts "#{method.inspect} does not have source location unable to emit matcher"
34
+ return self
35
+ end
36
+
31
37
  subject.tap do |subject|
32
38
  yield subject if subject
33
39
  end
@@ -35,21 +41,21 @@ module Mutant
35
41
  self
36
42
  end
37
43
 
38
- # Return scope
44
+ # Return method
39
45
  #
40
- # @return [Class|Module]
46
+ # @return [UnboundMethod, Method]
41
47
  #
42
48
  # @api private
43
49
  #
44
- attr_reader :scope
50
+ attr_reader :method
45
51
 
46
- # Return context
52
+ # Return scope
47
53
  #
48
- # @return [Context::Scope]
54
+ # @return [Class|Module]
49
55
  #
50
56
  # @api private
51
57
  #
52
- attr_reader :context
58
+ attr_reader :scope
53
59
 
54
60
  # Return method name
55
61
  #
@@ -57,7 +63,9 @@ module Mutant
57
63
  #
58
64
  # @api private
59
65
  #
60
- attr_reader :method_name
66
+ def method_name
67
+ method.name
68
+ end
61
69
 
62
70
  # Test if method is public
63
71
  #
@@ -76,26 +84,27 @@ module Mutant
76
84
  # Initialize method filter
77
85
  #
78
86
  # @param [Class|Module] scope
79
- # @param [Symbol] method_name
87
+ # @param [Method, UnboundMethod] method
80
88
  #
81
89
  # @return [undefined]
82
90
  #
83
91
  # @api private
84
92
  #
85
- def initialize(scope, method_name)
86
- @scope, @method_name = scope, method_name.to_sym
87
- @context = Context::Scope.build(scope, source_path)
93
+ def initialize(scope, method)
94
+ @scope, @method = scope, method
88
95
  # FIXME: cache public private should not be needed, loader should not override visibility! (But does currently) :(
89
96
  public?
90
97
  end
91
98
 
92
- # Return method
99
+ # Return context
93
100
  #
94
- # @return [UnboundMethod, Method]
101
+ # @return [Context::Scope]
95
102
  #
96
103
  # @api private
97
104
  #
98
- abstract_method :method
105
+ def context
106
+ Context::Scope.build(scope, source_path)
107
+ end
99
108
 
100
109
  # Return full ast
101
110
  #
@@ -6,15 +6,15 @@ module Mutant
6
6
  include Adamantium::Flat
7
7
 
8
8
  TABLE = {
9
- '.' => Matcher::Method::Singleton,
10
- '#' => Matcher::Method::Instance
9
+ '.' => Matcher::ScopeMethods::Singleton,
10
+ '#' => Matcher::ScopeMethods::Instance
11
11
  }.freeze
12
12
 
13
13
  SCOPE_FORMAT = /\A([^#.]+)(\.|#)(.+)\z/.freeze
14
14
 
15
15
  # Positions of captured regexp groups
16
16
  # Freezing fixnums to avoid their singleton classes are patched.
17
- SCOPE_NAME_POSITION = 1.freeze
17
+ SCOPE_NAME_POSITION = 1.freeze
18
18
  SCOPE_SYMBOL_POSITION = 2.freeze
19
19
  METHOD_NAME_POSITION = 3.freeze
20
20
 
@@ -45,8 +45,22 @@ module Mutant
45
45
  # @api private
46
46
  #
47
47
  def matcher
48
- matcher_class.new(scope, method_name)
48
+ scope_matcher.matcher.new(scope, method)
49
49
  end
50
+ memoize :matcher
51
+
52
+ # Return method
53
+ #
54
+ # @return [Method, UnboundMethod]
55
+ #
56
+ # @api private
57
+ #
58
+ def method
59
+ scope_matcher.methods.detect do |method|
60
+ method.name == method_name
61
+ end || raise("Cannot find #{method_name} for #{scope}")
62
+ end
63
+ memoize :method, :freezer => :noop
50
64
 
51
65
  # Return match
52
66
  #
@@ -117,9 +131,10 @@ module Mutant
117
131
  #
118
132
  # @api private
119
133
  #
120
- def matcher_class
121
- TABLE.fetch(scope_symbol)
134
+ def scope_matcher
135
+ TABLE.fetch(scope_symbol).new(scope)
122
136
  end
137
+ memoize :scope_matcher
123
138
  end
124
139
  end
125
140
  end
@@ -50,17 +50,6 @@ module Mutant
50
50
  node.name == method_name
51
51
  end
52
52
 
53
- # Return method instance
54
- #
55
- # @return [UnboundMethod]
56
- #
57
- # @api private
58
- #
59
- def method
60
- scope.instance_method(method_name)
61
- end
62
- memoize :method, :freezer => :noop
63
-
64
53
  end
65
54
  end
66
55
  end
@@ -33,17 +33,6 @@ module Mutant
33
33
 
34
34
  private
35
35
 
36
- # Return method instance
37
- #
38
- # @return [UnboundMethod]
39
- #
40
- # @api private
41
- #
42
- def method
43
- scope.method(method_name)
44
- end
45
- memoize :method, :freezer => :noop
46
-
47
36
  # Test for node match
48
37
  #
49
38
  # @param [Rubinius::AST::Node] node
@@ -24,6 +24,7 @@ module Mutant
24
24
  #
25
25
  def each(&block)
26
26
  return to_enum unless block_given?
27
+
27
28
  methods.each do |method|
28
29
  emit_matches(method, &block)
29
30
  end
@@ -31,6 +32,29 @@ module Mutant
31
32
  self
32
33
  end
33
34
 
35
+ # Return methods
36
+ #
37
+ # @return [Enumerable<Method, UnboundMethod>]
38
+ #
39
+ # @api private
40
+ #
41
+ def methods
42
+ method_names.map do |name|
43
+ access(name)
44
+ end
45
+ end
46
+ memoize :methods
47
+
48
+ # Return method matcher class
49
+ #
50
+ # @return [Class:Matcher::Method]
51
+ #
52
+ # @api private
53
+ #
54
+ def matcher
55
+ self.class::MATCHER
56
+ end
57
+
34
58
  private
35
59
 
36
60
  # Initialize object
@@ -47,7 +71,7 @@ module Mutant
47
71
 
48
72
  # Emit matches for method
49
73
  #
50
- # @param [UnboundMethod] method
74
+ # @param [UnboundMethod, Method] method
51
75
  #
52
76
  # @return [undefined]
53
77
  #
@@ -59,22 +83,29 @@ module Mutant
59
83
  end
60
84
  end
61
85
 
62
-
63
- abstract_method :methods
64
-
65
- # Return method matcher class
86
+ # Return method names
66
87
  #
67
- # @return [Class:Matcher::Method]
88
+ # @return [Enumerable<Symbol>]
68
89
  #
69
90
  # @api private
70
91
  #
71
- def matcher
72
- self.class::MATCHER
73
- end
92
+ abstract_method :method_names
74
93
 
75
94
  class Singleton < self
76
95
  MATCHER = Mutant::Matcher::Method::Singleton
77
96
 
97
+ # Return method for name
98
+ #
99
+ # @param [Symbol] method_name
100
+ #
101
+ # @return [Method]
102
+ #
103
+ # @api private
104
+ #
105
+ def access(method_name)
106
+ scope.method(method_name)
107
+ end
108
+
78
109
  private
79
110
 
80
111
  # Return singleton methods defined on scope
@@ -85,7 +116,7 @@ module Mutant
85
116
  #
86
117
  # @api private
87
118
  #
88
- def methods
119
+ def method_names
89
120
  singleton_class = scope.singleton_class
90
121
 
91
122
  names =
@@ -93,7 +124,7 @@ module Mutant
93
124
  singleton_class.private_instance_methods(false) +
94
125
  singleton_class.protected_instance_methods(false)
95
126
 
96
- names.map(&:to_sym).sort.reject do |name|
127
+ names.sort.reject do |name|
97
128
  name.to_sym == :__class_init__
98
129
  end
99
130
  end
@@ -102,6 +133,18 @@ module Mutant
102
133
  class Instance < self
103
134
  MATCHER = Mutant::Matcher::Method::Instance
104
135
 
136
+ # Return method for name
137
+ #
138
+ # @param [Symbol] method_name
139
+ #
140
+ # @return [UnboundMethod]
141
+ #
142
+ # @api private
143
+ #
144
+ def access(method_name)
145
+ scope.instance_method(method_name)
146
+ end
147
+
105
148
  private
106
149
 
107
150
  # Return instance methods names of scope
@@ -110,7 +153,7 @@ module Mutant
110
153
  #
111
154
  # @return [Enumerable<Symbol>]
112
155
  #
113
- def methods
156
+ def method_names
114
157
  scope = self.scope
115
158
  return [] unless scope.kind_of?(Module)
116
159
 
@@ -119,7 +162,7 @@ module Mutant
119
162
  scope.private_instance_methods(false) +
120
163
  scope.protected_instance_methods(false)
121
164
 
122
- names.uniq.map(&:to_sym).sort
165
+ names.uniq.sort
123
166
  end
124
167
  end
125
168
  end
@@ -18,6 +18,26 @@ module Mutant
18
18
  array = input.array
19
19
  emit_attribute_mutations(:array)
20
20
  end
21
+
22
+ # Test if node is new
23
+ #
24
+ # FIXME: Remove this hack and make sure empty bodies are not generated
25
+ #
26
+ # @param [Rubinius::AST::Node]
27
+ #
28
+ # @return [true]
29
+ # if node is new
30
+ #
31
+ # @return [false]
32
+ # otherwise
33
+ #
34
+ def new?(node)
35
+ if node.array.empty?
36
+ node.array << new_nil
37
+ end
38
+
39
+ super
40
+ end
21
41
  end
22
42
  end
23
43
  end
@@ -16,8 +16,8 @@ module Mutant
16
16
  #
17
17
  def dispatch
18
18
  emit_attribute_mutations(:condition)
19
- emit_attribute_mutations(:body)
20
- emit_attribute_mutations(:else) if node.else
19
+ emit_attribute_mutations(:body) if node.body.class != Rubinius::AST::NilLiteral
20
+ emit_attribute_mutations(:else) if node.else.class != Rubinius::AST::NilLiteral
21
21
  emit_inverted_condition
22
22
  emit_deleted_if_branch
23
23
  emit_deleted_else_branch
@@ -49,7 +49,7 @@ module Mutant
49
49
  #
50
50
  def emit_finish_mutations
51
51
  finish = node.finish
52
- emit_self(negative_infinity, finish)
52
+ #emit_self(negative_infinity, finish)
53
53
  emit_self(nan, finish)
54
54
  end
55
55
 
@@ -11,7 +11,7 @@ module Mutant
11
11
 
12
12
  # Return filename pattern
13
13
  #
14
- # @return [String]
14
+ # @return [Enumerable<String>]
15
15
  #
16
16
  # @api private
17
17
  #
@@ -25,17 +25,17 @@ module Mutant
25
25
 
26
26
  # Return file name pattern for mutation
27
27
  #
28
- # @return [Mutation]
28
+ # @return [Enumerable<String>]
29
29
  #
30
30
  # @api private
31
31
  #
32
32
  def self.spec_files(mutation)
33
- Dir['spec/unit/**/*_spec.rb']
33
+ ['spec/unit']
34
34
  end
35
35
  end
36
36
 
37
37
  # Run all integration specs per mutation
38
- class Unit < self
38
+ class Integration < self
39
39
 
40
40
  # Return file name pattern for mutation
41
41
  #
@@ -63,13 +63,25 @@ module Mutant
63
63
  # @api private
64
64
  #
65
65
  def spec_file
66
- matcher.method_name.to_s.
66
+ method_name.to_s.
67
+ gsub(/\A\[\]\z/, 'element_reader').
68
+ gsub(/\A\[\]=\z/, 'element_writer').
67
69
  gsub(/\?\z/, '_predicate').
68
- gsub(/\=\z/, '_writer').
70
+ gsub(/=\z/, '_writer').
69
71
  gsub(/!\z/, '_bang') + '_spec.rb'
70
72
  end
71
73
  memoize :spec_file
72
74
 
75
+ # Return method name
76
+ #
77
+ # @return [Symbol]
78
+ #
79
+ # @api private
80
+ #
81
+ def method_name
82
+ matcher.method_name
83
+ end
84
+
73
85
  # Return glob expression
74
86
  #
75
87
  # @return [String]
@@ -77,6 +89,8 @@ module Mutant
77
89
  # @api private
78
90
  #
79
91
  def glob_expression
92
+ return base_path if method_name == :initialize
93
+
80
94
  if mutation.subject.matcher.public?
81
95
  "#{base_path}/#{spec_file}"
82
96
  else
@@ -2,7 +2,7 @@
2
2
 
3
3
  Gem::Specification.new do |gem|
4
4
  gem.name = 'mutant'
5
- gem.version = '0.2.0'
5
+ gem.version = '0.2.1'
6
6
  gem.authors = [ 'Markus Schirp' ]
7
7
  gem.email = [ 'mbj@seonic.net' ]
8
8
  gem.description = 'Mutation testing for ruby under rubinius'
@@ -15,25 +15,31 @@ shared_examples_for 'a mutator' do
15
15
 
16
16
  it { should be_instance_of(to_enum.class) }
17
17
 
18
- let(:expected_mutations) do
19
- mutations.map do |mutation|
20
- if mutation.respond_to?(:to_ast)
21
- mutation.to_ast.to_sexp
22
- else
23
- mutation
24
- end
25
- end.to_set
18
+ unless instance_methods.include?(:expected_mutations)
19
+ let(:expected_mutations) do
20
+ mutations.map do |mutation|
21
+ case mutation
22
+ when String
23
+ mutation.to_ast
24
+ when Rubinius::AST::Node
25
+ mutation
26
+ else
27
+ raise
28
+ end
29
+ end.map do |node|
30
+ ToSource.to_source(node)
31
+ end.to_set
32
+ end
26
33
  end
27
34
 
28
35
  it 'generates the expected mutations' do
29
- generated = self.subject.map(&:to_sexp).to_set
36
+ generated = self.subject.map { |mutation| ToSource.to_source(mutation) }.to_set
30
37
 
31
38
  missing = (expected_mutations - generated).to_a
32
39
  unexpected = (generated - expected_mutations).to_a
33
40
 
34
41
  unless generated == expected_mutations
35
- message = "Missing mutations: %s\nUnexpected mutations: %s" % [missing, unexpected].map(&:inspect)
36
- fail message
42
+ fail "Missing mutations:\n%s\nUnexpected mutations:\n%s" % [missing.join("\n----\n"), unexpected.join("\n----\n")]
37
43
  end
38
44
  end
39
45
  end
@@ -3,25 +3,43 @@ require 'spec_helper'
3
3
  describe Mutant::Matcher::Method::Classifier, '.run' do
4
4
  subject { described_class.run(input) }
5
5
 
6
+ shared_examples_for 'Mutant::Matcher::Method::Classifier.run' do
7
+ before do
8
+ expected_class.stub(:new => response)
9
+ end
10
+
11
+ let(:response) { :Response }
12
+
13
+ it { should be(response) }
14
+
15
+ it 'should initialize method filter with correct arguments' do
16
+ expected_class.should_receive(:new).with(TestApp::Literal, expected_method).and_return(response)
17
+ subject
18
+ end
19
+ end
20
+
6
21
  context 'with explicit toplevel scope' do
7
- let(:input) { '::TestApp::Literal#string' }
8
- let(:expected_class) { Mutant::Matcher::Method::Instance }
22
+ let(:input) { '::TestApp::Literal#string' }
23
+ let(:expected_class) { Mutant::Matcher::Method::Instance }
24
+ let(:expected_method) { TestApp::Literal.instance_method(:string) }
9
25
 
10
- it_should_behave_like 'a method filter parse result'
26
+ it_should_behave_like 'Mutant::Matcher::Method::Classifier.run'
11
27
  end
12
28
 
13
29
  context 'with instance method notation' do
14
- let(:input) { 'TestApp::Literal#string' }
15
- let(:expected_class) { Mutant::Matcher::Method::Instance }
30
+ let(:input) { 'TestApp::Literal#string' }
31
+ let(:expected_method) { TestApp::Literal.instance_method(:string) }
32
+ let(:expected_class) { Mutant::Matcher::Method::Instance }
16
33
 
17
- it_should_behave_like 'a method filter parse result'
34
+ it_should_behave_like 'Mutant::Matcher::Method::Classifier.run'
18
35
  end
19
36
 
20
37
  context 'with singleton method notation' do
21
- let(:input) { 'TestApp::Literal.string' }
22
- let(:expected_class) { Mutant::Matcher::Method::Singleton }
38
+ let(:input) { 'TestApp::Literal.string' }
39
+ let(:expected_method) { TestApp::Literal.method(:string) }
40
+ let(:expected_class) { Mutant::Matcher::Method::Singleton }
23
41
 
24
- it_should_behave_like 'a method filter parse result'
42
+ it_should_behave_like 'Mutant::Matcher::Method::Classifier.run'
25
43
  end
26
44
 
27
45
  context 'with invalid notation' do
@@ -9,26 +9,27 @@ describe Mutant::Mutator, 'block' do
9
9
  mutations = []
10
10
 
11
11
  # Mutation of each statement in block
12
- mutations << "foo\nself.bar"
13
- mutations << "self.foo\nbar"
12
+ mutations << "foo\nself.bar".to_ast
13
+ mutations << "self.foo\nbar".to_ast
14
14
 
15
- ## Remove statement in block
16
- mutations << [:block, 'self.foo'.to_sexp]
17
- mutations << [:block, 'self.bar'.to_sexp]
18
- mutations << [:block]
15
+ # Remove statement in block
16
+ mutations << Rubinius::AST::Block.new(1, ['self.foo'.to_ast])
17
+ mutations << Rubinius::AST::Block.new(1, ['self.bar'.to_ast])
18
+ mutations << Rubinius::AST::Block.new(1, ['nil'.to_ast])
19
19
  end
20
20
 
21
21
  it_should_behave_like 'a mutator'
22
22
  end
23
23
 
24
24
 
25
+
25
26
  context 'with one statement' do
26
27
  let(:node) { Rubinius::AST::Block.new(1, ['self.foo'.to_ast]) }
27
28
 
28
29
  let(:mutations) do
29
30
  mutations = []
30
- mutations << [:block, 'foo'.to_sexp]
31
- mutations << [:block]
31
+ mutations << Rubinius::AST::Block.new(1, ['foo'.to_ast])
32
+ mutations << Rubinius::AST::Block.new(1, ['nil'.to_ast])
32
33
  end
33
34
 
34
35
  it_should_behave_like 'a mutator'
@@ -17,7 +17,7 @@ describe Mutant::Mutator, 'define' do
17
17
  mutations << 'def foo; self.bar; end'
18
18
 
19
19
  # Remove all statements
20
- mutations << [:defn, :foo, [:args], [:scope, [:block]]]
20
+ mutations << 'def foo; end'
21
21
  end
22
22
 
23
23
  it_should_behave_like 'a mutator'
@@ -38,7 +38,7 @@ describe Mutant::Mutator, 'define' do
38
38
  mutations << 'def self.foo; self.baz; end'
39
39
 
40
40
  # Remove all statements
41
- mutations << [:defs, [:self], :foo, [:args], [:scope, [:block]]]
41
+ mutations << 'def self.foo; end'
42
42
  end
43
43
 
44
44
  it_should_behave_like 'a mutator'
@@ -1,30 +1,60 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Mutant::Mutator, 'if statement' do
4
- let(:source) { 'if self.condition; true; else false; end' }
5
4
 
6
- let(:mutations) do
7
- mutants = []
5
+ context 'if with two branches' do
6
+ let(:source) { 'if self.condition; true; else false; end' }
8
7
 
9
- # mutations of condition
10
- mutants << 'if condition; true; else false; end'
8
+ let(:mutations) do
9
+ mutants = []
11
10
 
12
- mutants << 'if !self.condition; true; else false; end'
11
+ # mutations of condition
12
+ mutants << 'if condition; true; else false; end'
13
13
 
14
- # Deleted else branch
15
- mutants << 'if self.condition; true end'
14
+ mutants << 'if !self.condition; true; else false; end'
16
15
 
17
- # Deleted if branch with promoting else branch to if branch
18
- mutants << 'if self.condition; false end'
16
+ # Deleted else branch
17
+ mutants << 'if self.condition; true end'
19
18
 
20
- # mutations of body
21
- mutants << 'if self.condition; false; else false; end'
22
- mutants << 'if self.condition; nil; else false; end'
19
+ # Deleted if branch with promoting else branch to if branch
20
+ mutants << 'if self.condition; false end'
23
21
 
24
- # mutations of else body
25
- mutants << 'if self.condition; true; else true; end'
26
- mutants << 'if self.condition; true; else nil; end'
22
+ # mutations of body
23
+ mutants << 'if self.condition; false; else false; end'
24
+ mutants << 'if self.condition; nil; else false; end'
25
+
26
+ # mutations of else body
27
+ mutants << 'if self.condition; true; else true; end'
28
+ mutants << 'if self.condition; true; else nil; end'
29
+ end
30
+
31
+ it_should_behave_like 'a mutator'
27
32
  end
28
33
 
29
- it_should_behave_like 'a mutator'
34
+ context 'unless with one branch' do
35
+ let(:source) { 'unless condition; true; end' }
36
+
37
+ let(:mutations) do
38
+ mutants = []
39
+ mutants << 'unless !condition; true; end'
40
+ mutants << 'if condition; true; end'
41
+ mutants << 'unless condition; false; end'
42
+ mutants << 'unless condition; nil; end'
43
+ end
44
+
45
+ it_should_behave_like 'a mutator'
46
+ end
47
+
48
+ context 'if with one branch' do
49
+ let(:source) { 'if condition; true; end' }
50
+
51
+ let(:mutations) do
52
+ mutants = []
53
+ mutants << 'if !condition; true; end'
54
+ mutants << 'if condition; false; end'
55
+ mutants << 'if condition; nil; end'
56
+ end
57
+
58
+ it_should_behave_like 'a mutator'
59
+ end
30
60
  end
@@ -7,7 +7,7 @@ describe Mutant::Mutator::Node::Literal, 'array' do
7
7
  mutations = []
8
8
 
9
9
  # Literal replaced with nil
10
- mutations << [:nil]
10
+ mutations << 'nil'
11
11
 
12
12
  # Mutation of each element in array
13
13
  mutations << '[nil, false]'
@@ -7,7 +7,7 @@ describe Mutant::Mutator::Node::Literal, 'empty array' do
7
7
  mutations = []
8
8
 
9
9
  # Literal replaced with nil
10
- mutations << [:nil]
10
+ mutations << 'nil'
11
11
 
12
12
  # Extra element
13
13
  mutations << '[nil]'
@@ -6,7 +6,7 @@ describe Mutant::Mutator::Node::Literal, 'fixnum' do
6
6
  let(:source) { '10' }
7
7
 
8
8
  let(:mutations) do
9
- %W(nil 0 1 #{random_fixnum}) << [:lit, -10]
9
+ %W(nil 0 1 #{random_fixnum} -10)
10
10
  end
11
11
 
12
12
  before do
@@ -11,8 +11,8 @@ describe Mutant::Mutator::Node::Literal, 'float' do
11
11
  mutations << random_float.to_s
12
12
  mutations << '0.0/0.0'
13
13
  mutations << '1.0/0.0'
14
- mutations << [:negate, [:call, [:lit, 1.0], :/, [:arglist, [:lit, 0.0]]]]
15
- mutations << [:lit, -10.0]
14
+ mutations << '-1.0 / 0.0'
15
+ mutations << '-10.0'
16
16
  end
17
17
 
18
18
  let(:random_float) { 7.123 }
@@ -7,27 +7,27 @@ describe Mutant::Mutator::Node::Literal, 'hash' do
7
7
  mutations = []
8
8
 
9
9
  # Literal replaced with nil
10
- mutations << [:nil]
10
+ mutations << 'nil'
11
11
 
12
12
  # Mutation of each key and value in hash
13
- mutations << [:hash, [:false ], [:true ], [:false], [:false]]
14
- mutations << [:hash, [:nil ], [:true ], [:false], [:false]]
15
- mutations << [:hash, [:true ], [:false], [:false], [:false]]
16
- mutations << [:hash, [:true ], [:nil ], [:false], [:false]]
17
- mutations << [:hash, [:true ], [:true ], [:true ], [:false]]
18
- mutations << [:hash, [:true ], [:true ], [:nil ], [:false]]
19
- mutations << [:hash, [:true ], [:true ], [:false], [:true ]]
20
- mutations << [:hash, [:true ], [:true ], [:false], [:nil ]]
13
+ mutations << '{ false => true , false => false }'
14
+ mutations << '{ nil => true , false => false }'
15
+ mutations << '{ true => false , false => false }'
16
+ mutations << '{ true => nil , false => false }'
17
+ mutations << '{ true => true , true => false }'
18
+ mutations << '{ true => true , nil => false }'
19
+ mutations << '{ true => true , false => true }'
20
+ mutations << '{ true => true , false => nil }'
21
21
 
22
22
  # Remove each key once
23
- mutations << [:hash, [:true ], [:true ]]
24
- mutations << [:hash, [:false ], [:false ]]
23
+ mutations << '{ true => true }'
24
+ mutations << '{ false => false }'
25
25
 
26
26
  # Empty hash
27
- mutations << [:hash]
27
+ mutations << '{}'
28
28
 
29
29
  # Extra element
30
- mutations << [:hash, [:true ], [:true ], [:false], [:false ], [:nil], [:nil] ]
30
+ mutations << '{true => true, false => false, nil => nil}'
31
31
  end
32
32
 
33
33
  it_should_behave_like 'a mutator'
@@ -9,7 +9,7 @@ describe Mutant::Mutator::Node::Literal, 'range' do
9
9
  mutations << 'nil'
10
10
  mutations << '1...100'
11
11
  mutations << '(0.0/0.0)..100'
12
- mutations << [:dot2, [:negate, [:call, [:lit, 1.0], :/, [:arglist, [:lit, 0.0]]]], [:lit, 100]]
12
+ #mutations << [:dot2, [:negate, [:call, [:lit, 1.0], :/, [:arglist, [:lit, 0.0]]]], [:lit, 100]]
13
13
  mutations << '1..(1.0/0.0)'
14
14
  mutations << '1..(0.0/0.0)'
15
15
  end
@@ -25,7 +25,7 @@ describe Mutant::Mutator::Node::Literal, 'range' do
25
25
  mutations << 'nil'
26
26
  mutations << '1..100'
27
27
  mutations << '(0.0/0.0)...100'
28
- mutations << [:dot3, [:negate, [:call, [:lit, 1.0], :/, [:arglist, [:lit, 0.0]]]], [:lit, 100]]
28
+ #mutations << [:dot3, [:negate, [:call, [:lit, 1.0], :/, [:arglist, [:lit, 0.0]]]], [:lit, 100]]
29
29
  mutations << '1...(1.0/0.0)'
30
30
  mutations << '1...(0.0/0.0)'
31
31
  end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mutant::Strategy::Rspec::ExampleLookup, '#spec_file' do
4
+
5
+ let(:object) { described_class.new(mutation) }
6
+ let(:mutation) { mock('Mutation', :subject => mutation_subject) }
7
+ let(:mutation_subject) { mock('Subject', :matcher => matcher) }
8
+ let(:matcher) { mock('Matcher', :method_name => method_name) }
9
+
10
+ subject { object.send(:spec_file) }
11
+
12
+ shared_examples_for 'Mutant::Strategy::Rspec::ExampleLookup#spec_file' do
13
+ it_should_behave_like 'an idempotent method'
14
+
15
+ it { should eql(expected_spec_file) }
16
+ it { should be_frozen }
17
+ end
18
+
19
+ context 'with element reader method' do
20
+ let(:method_name) { '[]' }
21
+ let(:expected_spec_file) { 'element_reader_spec.rb' }
22
+
23
+ it_should_behave_like 'Mutant::Strategy::Rspec::ExampleLookup#spec_file'
24
+ end
25
+
26
+ context 'with element writer method' do
27
+ let(:method_name) { '[]=' }
28
+
29
+ let(:expected_spec_file) { 'element_writer_spec.rb' }
30
+
31
+ it_should_behave_like 'Mutant::Strategy::Rspec::ExampleLookup#spec_file'
32
+ end
33
+
34
+ context 'with writer method' do
35
+ let(:method_name) { 'foo=' }
36
+ let(:expected_spec_file) { 'foo_writer_spec.rb' }
37
+
38
+ it_should_behave_like 'Mutant::Strategy::Rspec::ExampleLookup#spec_file'
39
+ end
40
+
41
+ context 'with bang method' do
42
+ let(:method_name) { 'foo!' }
43
+ let(:expected_spec_file) { 'foo_bang_spec.rb' }
44
+
45
+ it_should_behave_like 'Mutant::Strategy::Rspec::ExampleLookup#spec_file'
46
+ end
47
+
48
+ context 'with predicate method' do
49
+ let(:method_name) { 'foo?' }
50
+ let(:expected_spec_file) { 'foo_predicate_spec.rb' }
51
+
52
+ it_should_behave_like 'Mutant::Strategy::Rspec::ExampleLookup#spec_file'
53
+ end
54
+
55
+ context 'with regular method' do
56
+ let(:method_name) { 'foo' }
57
+ let(:expected_spec_file) { 'foo_spec.rb' }
58
+
59
+ it_should_behave_like 'Mutant::Strategy::Rspec::ExampleLookup#spec_file'
60
+ end
61
+ end
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.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -245,7 +245,6 @@ files:
245
245
  - spec/shared/hash_method_behavior.rb
246
246
  - spec/shared/idempotent_method_behavior.rb
247
247
  - spec/shared/invertible_method_behaviour.rb
248
- - spec/shared/method_filter_parse_behavior.rb
249
248
  - spec/shared/method_match_behavior.rb
250
249
  - spec/shared/mutator_behavior.rb
251
250
  - spec/spec_helper.rb
@@ -270,7 +269,6 @@ files:
270
269
  - spec/unit/mutant/matcher/each_spec.rb
271
270
  - spec/unit/mutant/matcher/method/class_methods/parse_spec.rb
272
271
  - spec/unit/mutant/matcher/method/classifier/class_methods/run_spec.rb
273
- - spec/unit/mutant/matcher/method/method_spec.rb
274
272
  - spec/unit/mutant/matcher/object_space/class_methods/parse_spec.rb
275
273
  - spec/unit/mutant/matcher/object_space/each_spec.rb
276
274
  - spec/unit/mutant/mutator/each_spec.rb
@@ -294,6 +292,7 @@ files:
294
292
  - spec/unit/mutant/mutator/node/return/mutation_spec.rb
295
293
  - spec/unit/mutant/mutator/node/send/mutation_spec.rb
296
294
  - spec/unit/mutant/mutator/self_spec.rb
295
+ - spec/unit/mutant/strategy/rspec/example_lookup/spec_file_spec.rb
297
296
  - spec/unit/mutant/subject/class_methods/new_spec.rb
298
297
  - spec/unit/mutant/subject/context_spec.rb
299
298
  - spec/unit/mutant/subject/each_spec.rb
@@ -359,7 +358,6 @@ test_files:
359
358
  - spec/shared/hash_method_behavior.rb
360
359
  - spec/shared/idempotent_method_behavior.rb
361
360
  - spec/shared/invertible_method_behaviour.rb
362
- - spec/shared/method_filter_parse_behavior.rb
363
361
  - spec/shared/method_match_behavior.rb
364
362
  - spec/shared/mutator_behavior.rb
365
363
  - spec/spec_helper.rb
@@ -384,7 +382,6 @@ test_files:
384
382
  - spec/unit/mutant/matcher/each_spec.rb
385
383
  - spec/unit/mutant/matcher/method/class_methods/parse_spec.rb
386
384
  - spec/unit/mutant/matcher/method/classifier/class_methods/run_spec.rb
387
- - spec/unit/mutant/matcher/method/method_spec.rb
388
385
  - spec/unit/mutant/matcher/object_space/class_methods/parse_spec.rb
389
386
  - spec/unit/mutant/matcher/object_space/each_spec.rb
390
387
  - spec/unit/mutant/mutator/each_spec.rb
@@ -408,6 +405,7 @@ test_files:
408
405
  - spec/unit/mutant/mutator/node/return/mutation_spec.rb
409
406
  - spec/unit/mutant/mutator/node/send/mutation_spec.rb
410
407
  - spec/unit/mutant/mutator/self_spec.rb
408
+ - spec/unit/mutant/strategy/rspec/example_lookup/spec_file_spec.rb
411
409
  - spec/unit/mutant/subject/class_methods/new_spec.rb
412
410
  - spec/unit/mutant/subject/context_spec.rb
413
411
  - spec/unit/mutant/subject/each_spec.rb
@@ -1,16 +0,0 @@
1
- shared_examples_for 'a method filter parse result' do
2
- before do
3
- expected_class.stub(:new => response)
4
- end
5
-
6
- let(:response) { mock('Response') }
7
-
8
- it { should be(response) }
9
-
10
- it 'should initialize method filter with correct arguments' do
11
- expected_class.should_receive(:new).with(TestApp::Literal, :string).and_return(response)
12
- subject
13
- end
14
- end
15
-
16
-
@@ -1,11 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Mutant::Matcher::Method, '#method' do
4
- subject { object.send(:method) }
5
-
6
- let(:object) { described_class.allocate }
7
-
8
- it 'should raise error' do
9
- expect { subject }.to raise_error(NotImplementedError, 'Mutant::Matcher::Method#method is not implemented')
10
- end
11
- end