mutant 0.2.0 → 0.2.1

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