mutant 0.8.3 → 0.8.4

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +8 -0
  3. data/Gemfile +1 -4
  4. data/Gemfile.shared +3 -0
  5. data/Rakefile +0 -2
  6. data/config/flay.yml +1 -1
  7. data/config/rubocop.yml +8 -0
  8. data/lib/mutant.rb +2 -0
  9. data/lib/mutant/ast/meta/restarg.rb +15 -0
  10. data/lib/mutant/ast/meta/symbol.rb +15 -0
  11. data/lib/mutant/cli.rb +11 -11
  12. data/lib/mutant/config.rb +1 -1
  13. data/lib/mutant/env.rb +1 -1
  14. data/lib/mutant/matcher/config.rb +2 -2
  15. data/lib/mutant/mutator/node/block.rb +16 -0
  16. data/lib/mutant/mutator/node/define.rb +14 -0
  17. data/lib/mutant/mutator/node/send.rb +12 -1
  18. data/lib/mutant/mutator/node/send/binary.rb +25 -1
  19. data/lib/mutant/parallel.rb +2 -2
  20. data/lib/mutant/result.rb +1 -1
  21. data/lib/mutant/runner/sink.rb +2 -2
  22. data/lib/mutant/version.rb +1 -1
  23. data/meta/begin.rb +0 -2
  24. data/meta/block.rb +15 -0
  25. data/meta/def.rb +25 -0
  26. data/meta/or_asgn.rb +9 -0
  27. data/meta/send.rb +41 -1
  28. data/mutant-rspec.gemspec +0 -2
  29. data/mutant.gemspec +5 -6
  30. data/spec/spec_helper.rb +1 -1
  31. data/spec/support/corpus.rb +1 -0
  32. data/spec/support/shared_context.rb +5 -5
  33. data/spec/unit/mutant/cli_spec.rb +6 -6
  34. data/spec/unit/mutant/env/boostrap_spec.rb +3 -3
  35. data/spec/unit/mutant/env_spec.rb +1 -1
  36. data/spec/unit/mutant/matcher/compiler_spec.rb +1 -1
  37. data/spec/unit/mutant/parallel/master_spec.rb +2 -2
  38. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +1 -1
  39. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +3 -3
  40. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +1 -1
  41. data/spec/unit/mutant/reporter/cli/printer/mutation_progress_result_spec.rb +2 -2
  42. data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +3 -3
  43. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +5 -5
  44. data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +5 -5
  45. data/spec/unit/mutant/reporter/cli/printer/subject_progress_spec.rb +2 -2
  46. data/spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb +2 -2
  47. data/spec/unit/mutant/reporter/cli_spec.rb +6 -4
  48. data/spec/unit/mutant/result_spec.rb +23 -0
  49. data/spec/unit/mutant/runner/sink/mutation_spec.rb +8 -8
  50. data/spec/unit/mutant/selector/expression_spec.rb +1 -1
  51. data/test_app/Gemfile.rspec3.2 +1 -0
  52. data/test_app/Gemfile.rspec3.3 +1 -0
  53. data/test_app/spec/unit/test_app/literal_spec.rb +0 -2
  54. metadata +27 -18
  55. data/Guardfile +0 -16
  56. data/test_app/Gemfile.rspec3.0 +0 -6
  57. data/test_app/Gemfile.rspec3.1 +0 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d31268248349a065fe46a960fe2a0d0ace09f0d8
4
- data.tar.gz: c35d18b21c3761d28fece74e573ef7f6ab0dfd69
3
+ metadata.gz: a7008d6d94f2de1e1c8d276c943491b0fb6cfdc1
4
+ data.tar.gz: 70b30707970890aa21961febe6a7657aa1889522
5
5
  SHA512:
6
- metadata.gz: 3aec0dac703c7e91f164c60baa26d941e9a2d2149bd4542fcaac33f8e4794d9431ce4e226a5af29b88ec13e77f1ab2e32b6c4431a2a514ea4f2e1cb4200ea3bd
7
- data.tar.gz: 9fb92420b95b0ae6fd1df55941e3df971b89d80ff7bef55a06c9823d1c96d6b4d50aedb88814a1c308ca57f99aa30e8d12ddc6275a6036073c21ca16d6d74aa9
6
+ metadata.gz: b9fe654b8233c2666adadd104d7b6cfe4a5409b81913d9d446364424920a659becb763659c24e308915263a1a6a52e20ea8d7895ca27effb057ea169b1d51f79
7
+ data.tar.gz: 5ea82f2c27289e2f307a5809f6c21a8d95315191069f240488419d6c5a65d360bc64ccf8a5d8f8b1f7eca4f23d283107c3a37768472d6a3970d52a9c2e114571
@@ -1,3 +1,11 @@
1
+ # v0.8.4 2015-09-10
2
+
3
+ * Add mutation from `a != b` to `!a.eql?(b)` and `!a.equal?(b)` #417
4
+ * Add mutation `A.const_get(:B)` -> `A::B` #426
5
+ * Add mutation `def foo(*args); end` into `def foo(*args); args = []; end` #423
6
+ * Add mutation from `foo.baz { bar }` to `foo.bar` #416
7
+ * Update anima dependency to 0.3.0
8
+
1
9
  # v0.8.3 2015-09-01
2
10
 
3
11
  * Remove invalid mutation `super(...)` to `super`
data/Gemfile CHANGED
@@ -1,8 +1,5 @@
1
- # encoding: utf-8
2
-
3
1
  source 'https://rubygems.org'
4
2
 
5
3
  gemspec name: 'mutant'
6
4
 
7
- gem 'morpher', git: 'https://github.com/mbj/morpher.git'
8
- gem 'devtools', git: 'https://github.com/rom-rb/devtools.git'
5
+ eval_gemfile File.expand_path('../Gemfile.shared', __FILE__)
@@ -0,0 +1,3 @@
1
+ # Place for shared git sources, used for developing updates to depedencies
2
+ # where the git sources (without this file) need to be consistently edited
3
+ # into multiple Gemfiles.
data/Rakefile CHANGED
@@ -1,5 +1,3 @@
1
- # encoding: utf-8
2
-
3
1
  require 'devtools'
4
2
 
5
3
  Devtools.init_rake_tasks
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 18
3
- total_score: 1200
3
+ total_score: 1234
@@ -132,3 +132,11 @@ SpaceAroundOperators:
132
132
  # We use parallel assignments with great success
133
133
  ParallelAssignment:
134
134
  Enabled: false
135
+
136
+ # Allow additional specs
137
+ ExtraSpacing:
138
+ Enabled: false
139
+
140
+ # Buggy
141
+ FormatParameterMismatch:
142
+ Enabled: false
@@ -49,8 +49,10 @@ require 'mutant/ast/named_children'
49
49
  require 'mutant/ast/node_predicates'
50
50
  require 'mutant/ast/meta'
51
51
  require 'mutant/ast/meta/send'
52
+ require 'mutant/ast/meta/symbol'
52
53
  require 'mutant/ast/meta/optarg'
53
54
  require 'mutant/ast/meta/resbody'
55
+ require 'mutant/ast/meta/restarg'
54
56
  require 'mutant/actor'
55
57
  require 'mutant/actor/receiver'
56
58
  require 'mutant/actor/sender'
@@ -0,0 +1,15 @@
1
+ module Mutant
2
+ module AST
3
+ # Node meta information mixin
4
+ module Meta
5
+
6
+ # Metadata for restarg nodes
7
+ class Restarg
8
+ include NamedChildren, Concord.new(:node)
9
+
10
+ children :name
11
+ end # Restarg
12
+
13
+ end # Meta
14
+ end # AST
15
+ end # Mutant
@@ -0,0 +1,15 @@
1
+ module Mutant
2
+ module AST
3
+ # Node meta information mixin
4
+ module Meta
5
+
6
+ # Metadata for symbol nodes
7
+ class Symbol
8
+ include NamedChildren, Concord.new(:node)
9
+
10
+ children :name
11
+
12
+ end # Symbol
13
+ end # Meta
14
+ end # AST
15
+ end # Mutant
@@ -98,7 +98,7 @@ module Mutant
98
98
  def add_environment_options(opts)
99
99
  opts.separator('Environment:')
100
100
  opts.on('--zombie', 'Run mutant zombified') do
101
- update(zombie: true)
101
+ with(zombie: true)
102
102
  end
103
103
  opts.on('-I', '--include DIRECTORY', 'Add DIRECTORY to $LOAD_PATH') do |directory|
104
104
  add(:includes, directory)
@@ -107,7 +107,7 @@ module Mutant
107
107
  add(:requires, name)
108
108
  end
109
109
  opts.on('-j', '--jobs NUMBER', 'Number of kill jobs. Defaults to number of processors.') do |number|
110
- update(jobs: Integer(number))
110
+ with(jobs: Integer(number))
111
111
  end
112
112
  end
113
113
 
@@ -119,7 +119,7 @@ module Mutant
119
119
  #
120
120
  # @api private
121
121
  def setup_integration(name)
122
- update(integration: Integration.setup(name))
122
+ with(integration: Integration.setup(name))
123
123
  rescue LoadError
124
124
  raise Error, "Could not load integration #{name.inspect} (you may want to try installing the gem mutant-#{name})"
125
125
  end
@@ -139,7 +139,7 @@ module Mutant
139
139
  '--expected-coverage COVERAGE',
140
140
  'Fail unless COVERAGE is not reached exactly, parsed via Rational()'
141
141
  ) do |coverage|
142
- update(expected_coverage: Rational(coverage))
142
+ with(expected_coverage: Rational(coverage))
143
143
  end
144
144
  opts.on('--use INTEGRATION', 'Use INTEGRATION to kill mutations', &method(:setup_integration))
145
145
  end
@@ -169,14 +169,14 @@ module Mutant
169
169
  # @api private
170
170
  def add_debug_options(opts)
171
171
  opts.on('--fail-fast', 'Fail fast') do
172
- update(fail_fast: true)
172
+ with(fail_fast: true)
173
173
  end
174
174
  opts.on('--version', 'Print mutants version') do
175
175
  puts("mutant-#{VERSION}")
176
176
  Kernel.exit(EXIT_SUCCESS)
177
177
  end
178
178
  opts.on('-d', '--debug', 'Enable debugging output') do
179
- update(debug: true)
179
+ with(debug: true)
180
180
  end
181
181
  opts.on_tail('-h', '--help', 'Show this message') do
182
182
  puts(opts.to_s)
@@ -184,15 +184,15 @@ module Mutant
184
184
  end
185
185
  end
186
186
 
187
- # Update configuration
187
+ # With configuration
188
188
  #
189
189
  # @param [Hash<Symbol, Object>] attributes
190
190
  #
191
191
  # @return [undefined]
192
192
  #
193
193
  # @api private
194
- def update(attributes)
195
- @config = @config.update(attributes)
194
+ def with(attributes)
195
+ @config = @config.with(attributes)
196
196
  end
197
197
 
198
198
  # Add configuration
@@ -207,7 +207,7 @@ module Mutant
207
207
  #
208
208
  # @api private
209
209
  def add(attribute, value)
210
- update(attribute => config.public_send(attribute).dup << value)
210
+ with(attribute => config.public_send(attribute) + [value])
211
211
  end
212
212
 
213
213
  # Add matcher configuration
@@ -222,7 +222,7 @@ module Mutant
222
222
  #
223
223
  # @api private
224
224
  def add_matcher(attribute, value)
225
- update(matcher: config.matcher.add(attribute, value))
225
+ with(matcher: config.matcher.add(attribute, value))
226
226
  end
227
227
 
228
228
  end # CLI
@@ -4,7 +4,7 @@ module Mutant
4
4
  # Does not reference any "external" volatile state. The configuration applied
5
5
  # to current environment is being represented by the Mutant::Env object.
6
6
  class Config
7
- include Adamantium::Flat, Anima::Update, Anima.new(
7
+ include Adamantium::Flat, Anima.new(
8
8
  :debug,
9
9
  :integration,
10
10
  :matcher,
@@ -1,7 +1,7 @@
1
1
  module Mutant
2
2
  # Abstract base class for mutant environments
3
3
  class Env
4
- include Adamantium::Flat, Anima::Update, Anima.new(
4
+ include Adamantium::Flat, Anima.new(
5
5
  :config,
6
6
  :actor_env,
7
7
  :cache,
@@ -2,7 +2,7 @@ module Mutant
2
2
  class Matcher
3
3
  # Subject matcher configuration
4
4
  class Config
5
- include Adamantium, Anima::Update, Anima.new(
5
+ include Adamantium, Anima.new(
6
6
  :match_expressions,
7
7
  :ignore_expressions,
8
8
  :subject_filters
@@ -41,7 +41,7 @@ module Mutant
41
41
  #
42
42
  # @api private
43
43
  def add(attribute, value)
44
- update(attribute => public_send(attribute).dup << value)
44
+ with(attribute => public_send(attribute) + [value])
45
45
  end
46
46
 
47
47
  private
@@ -36,6 +36,22 @@ module Mutant
36
36
  return unless body
37
37
  emit(body)
38
38
  emit_body_mutations
39
+
40
+ mutate_body_receiver
41
+ end
42
+
43
+ # Mutate method send in body scope of `send`
44
+ #
45
+ # @return [undefined]
46
+ #
47
+ # @api private
48
+ def mutate_body_receiver
49
+ return unless n_send?(body)
50
+
51
+ body_meta = AST::Meta::Send.new(body)
52
+ send_meta = AST::Meta::Send.new(send)
53
+
54
+ emit(s(:send, send_meta.receiver, body_meta.selector, *body_meta.arguments))
39
55
  end
40
56
 
41
57
  end # Block
@@ -14,6 +14,7 @@ module Mutant
14
14
  def dispatch
15
15
  emit_arguments_mutations
16
16
  emit_optarg_body_assignments
17
+ emit_restarg_body_mutation
17
18
  emit_body(N_RAISE)
18
19
  emit_body(nil)
19
20
  emit_body_mutations if body
@@ -32,6 +33,19 @@ module Mutant
32
33
  end
33
34
  end
34
35
 
36
+ # Emit mutation with arg splat as empty array signment in method
37
+ #
38
+ # @return [undefined]
39
+ #
40
+ # @api private
41
+ def emit_restarg_body_mutation
42
+ arguments.children.each do |argument|
43
+ next unless n_restarg?(argument) && argument.children.one?
44
+
45
+ emit_body_prepend(s(:lvasgn, AST::Meta::Restarg.new(argument).name, s(:array)))
46
+ end
47
+ end
48
+
35
49
  # Emit valid body ASTs depending on instance body
36
50
  #
37
51
  # @param node [Parser::AST::Node]
@@ -90,11 +90,23 @@ module Mutant
90
90
  def normal_dispatch
91
91
  emit_naked_receiver
92
92
  emit_selector_replacement
93
+ emit_const_get_mutation
93
94
  emit_argument_propagation
94
95
  mutate_receiver
95
96
  mutate_arguments
96
97
  end
97
98
 
99
+ # Emit mutation from `const_get` to const literal
100
+ #
101
+ # @return [undefined]
102
+ #
103
+ # @api private
104
+ def emit_const_get_mutation
105
+ return unless selector.equal?(:const_get) && n_sym?(arguments.first)
106
+
107
+ emit(s(:const, receiver, AST::Meta::Symbol.new(arguments.first).name))
108
+ end
109
+
98
110
  # Emit selector replacement
99
111
  #
100
112
  # @return [undefined]
@@ -158,7 +170,6 @@ module Mutant
158
170
  emit_receiver(nil) if n_self?(receiver) && !(
159
171
  KEYWORDS.include?(selector) ||
160
172
  METHOD_OPERATORS.include?(selector) ||
161
- OP_ASSIGN.include?(parent_type) ||
162
173
  meta.attribute_assignment?
163
174
  )
164
175
  end
@@ -19,8 +19,32 @@ module Mutant
19
19
  emit(left)
20
20
  emit_left_mutations
21
21
  emit_selector_replacement
22
- emit(right) unless n_splat?(right)
22
+ emit(right)
23
23
  emit_right_mutations
24
+ emit_not_equality_mutations
25
+ end
26
+
27
+ # Emit mutations for `!=`
28
+ #
29
+ # @return [undefined]
30
+ #
31
+ # @api private
32
+ def emit_not_equality_mutations
33
+ return unless operator.equal?(:'!=')
34
+
35
+ emit_not_equality_mutation(:eql?)
36
+ emit_not_equality_mutation(:equal?)
37
+ end
38
+
39
+ # Emit negated method sends with specified operator
40
+ #
41
+ # @param new_operator [Symbol] selector to be negated
42
+ #
43
+ # @return [undefined]
44
+ #
45
+ # @api private
46
+ def emit_not_equality_mutation(new_operator)
47
+ emit(n_not(s(:send, left, new_operator, right)))
24
48
  end
25
49
 
26
50
  end # Binary
@@ -75,12 +75,12 @@ module Mutant
75
75
 
76
76
  # Parallel run configuration
77
77
  class Config
78
- include Anima::Update, Adamantium::Flat, Anima.new(:env, :processor, :source, :sink, :jobs)
78
+ include Adamantium::Flat, Anima.new(:env, :processor, :source, :sink, :jobs)
79
79
  end # Config
80
80
 
81
81
  # Parallel execution status
82
82
  class Status
83
- include Adamantium::Flat, Anima::Update, Anima.new(:payload, :done, :active_jobs)
83
+ include Adamantium::Flat, Anima.new(:payload, :done, :active_jobs)
84
84
  end
85
85
 
86
86
  end # Parallel
@@ -67,7 +67,7 @@ module Mutant
67
67
  # @api private
68
68
  def self.included(host)
69
69
  host.class_eval do
70
- include Adamantium, Anima::Update
70
+ include Adamantium
71
71
  extend ClassMethods
72
72
  end
73
73
  end
@@ -78,8 +78,8 @@ module Mutant
78
78
 
79
79
  original = @subject_results[mutation.subject]
80
80
 
81
- @subject_results[mutation.subject] = original.update(
82
- mutation_results: (original.mutation_results.dup << mutation_result),
81
+ @subject_results[mutation.subject] = original.with(
82
+ mutation_results: (original.mutation_results + [mutation_result]),
83
83
  tests: mutation_result.test_result.tests
84
84
  )
85
85
 
@@ -1,4 +1,4 @@
1
1
  module Mutant
2
2
  # Current mutant version
3
- VERSION = '0.8.3'.freeze
3
+ VERSION = '0.8.4'.freeze
4
4
  end # Mutant
@@ -12,8 +12,6 @@ Mutant::Meta::Example.add do
12
12
  mutation 'false'
13
13
  end
14
14
 
15
- # encoding: utf-8
16
-
17
15
  Mutant::Meta::Example.add do
18
16
 
19
17
  source s(:begin, s(:true))
@@ -69,3 +69,18 @@ Mutant::Meta::Example.add do
69
69
  mutation 'foo { |(_a)| }'
70
70
  mutation 'foo'
71
71
  end
72
+
73
+ Mutant::Meta::Example.add do
74
+ source 'self.foo { bar(nil) }'
75
+
76
+ singleton_mutations
77
+ mutation 'self.foo'
78
+ mutation 'foo { bar(nil) }'
79
+ mutation 'self.foo { bar }'
80
+ mutation 'self.foo { nil }'
81
+ mutation 'self.foo {}'
82
+ mutation 'self.foo { self }'
83
+ mutation 'self.foo { raise }'
84
+ mutation 'bar(nil)'
85
+ mutation 'self.bar(nil)'
86
+ end
@@ -5,6 +5,31 @@ Mutant::Meta::Example.add do
5
5
  mutation 'remove_method :foo'
6
6
  end
7
7
 
8
+ Mutant::Meta::Example.add do
9
+ source 'def foo(a, *b); nil; end'
10
+
11
+ mutation 'def foo(_a, *b); nil; end'
12
+ mutation 'def foo; nil; end'
13
+ mutation 'def foo(a, *b); end'
14
+ mutation 'def foo(a, *b); raise; end'
15
+ mutation 'def foo(a); nil; end'
16
+ mutation 'def foo(*b); nil; end'
17
+ mutation 'def foo(a, *b); b = []; nil; end'
18
+ mutation 'remove_method :foo'
19
+ end
20
+
21
+ Mutant::Meta::Example.add do
22
+ source 'def foo(a, *); nil; end'
23
+
24
+ mutation 'def foo(_a, *); nil; end'
25
+ mutation 'def foo; nil; end'
26
+ mutation 'def foo(a, *); end'
27
+ mutation 'def foo(a, *); raise; end'
28
+ mutation 'def foo(a); nil; end'
29
+ mutation 'def foo(*); nil; end'
30
+ mutation 'remove_method :foo'
31
+ end
32
+
8
33
  Mutant::Meta::Example.add do
9
34
  source 'def foo; foo; rescue; end'
10
35