mutant 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (187) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +7 -0
  3. data/config/flay.yml +1 -1
  4. data/config/reek.yml +1 -0
  5. data/lib/mutant.rb +10 -3
  6. data/lib/mutant/actor.rb +2 -5
  7. data/lib/mutant/actor/env.rb +1 -3
  8. data/lib/mutant/actor/mailbox.rb +2 -4
  9. data/lib/mutant/actor/receiver.rb +0 -2
  10. data/lib/mutant/actor/sender.rb +0 -1
  11. data/lib/mutant/ast.rb +22 -28
  12. data/lib/mutant/ast/meta.rb +8 -88
  13. data/lib/mutant/ast/named_children.rb +1 -8
  14. data/lib/mutant/ast/sexp.rb +0 -2
  15. data/lib/mutant/cache.rb +1 -3
  16. data/lib/mutant/cli.rb +9 -19
  17. data/lib/mutant/color.rb +0 -3
  18. data/lib/mutant/config.rb +6 -2
  19. data/lib/mutant/context.rb +2 -4
  20. data/lib/mutant/context/scope.rb +10 -16
  21. data/lib/mutant/delegator.rb +0 -3
  22. data/lib/mutant/diff.rb +8 -17
  23. data/lib/mutant/env.rb +3 -5
  24. data/lib/mutant/env/bootstrap.rb +32 -39
  25. data/lib/mutant/expression.rb +14 -132
  26. data/lib/mutant/expression/method.rb +25 -42
  27. data/lib/mutant/expression/methods.rb +17 -29
  28. data/lib/mutant/expression/namespace.rb +33 -28
  29. data/lib/mutant/expression/parser.rb +71 -0
  30. data/lib/mutant/integration.rb +17 -16
  31. data/lib/mutant/isolation.rb +14 -14
  32. data/lib/mutant/loader.rb +2 -4
  33. data/lib/mutant/matcher.rb +1 -11
  34. data/lib/mutant/matcher/chain.rb +0 -1
  35. data/lib/mutant/matcher/compiler.rb +19 -52
  36. data/lib/mutant/matcher/config.rb +65 -5
  37. data/lib/mutant/matcher/filter.rb +11 -1
  38. data/lib/mutant/matcher/method.rb +11 -21
  39. data/lib/mutant/matcher/method/instance.rb +2 -16
  40. data/lib/mutant/matcher/method/singleton.rb +3 -20
  41. data/lib/mutant/matcher/methods.rb +11 -21
  42. data/lib/mutant/matcher/namespace.rb +0 -4
  43. data/lib/mutant/matcher/null.rb +0 -1
  44. data/lib/mutant/matcher/scope.rb +0 -12
  45. data/lib/mutant/meta.rb +0 -1
  46. data/lib/mutant/meta/example.rb +12 -26
  47. data/lib/mutant/meta/example/dsl.rb +1 -8
  48. data/lib/mutant/mutation.rb +6 -14
  49. data/lib/mutant/mutator.rb +2 -14
  50. data/lib/mutant/mutator/node.rb +6 -33
  51. data/lib/mutant/mutator/node/and_asgn.rb +0 -1
  52. data/lib/mutant/mutator/node/argument.rb +0 -5
  53. data/lib/mutant/mutator/node/arguments.rb +1 -7
  54. data/lib/mutant/mutator/node/begin.rb +0 -2
  55. data/lib/mutant/mutator/node/binary.rb +0 -3
  56. data/lib/mutant/mutator/node/block.rb +0 -2
  57. data/lib/mutant/mutator/node/break.rb +0 -1
  58. data/lib/mutant/mutator/node/case.rb +0 -3
  59. data/lib/mutant/mutator/node/conditional_loop.rb +0 -1
  60. data/lib/mutant/mutator/node/const.rb +0 -1
  61. data/lib/mutant/mutator/node/define.rb +0 -1
  62. data/lib/mutant/mutator/node/defined.rb +0 -1
  63. data/lib/mutant/mutator/node/dstr.rb +0 -1
  64. data/lib/mutant/mutator/node/dsym.rb +0 -1
  65. data/lib/mutant/mutator/node/generic.rb +0 -1
  66. data/lib/mutant/mutator/node/if.rb +0 -4
  67. data/lib/mutant/mutator/node/kwbegin.rb +0 -1
  68. data/lib/mutant/mutator/node/literal/array.rb +0 -2
  69. data/lib/mutant/mutator/node/literal/boolean.rb +0 -1
  70. data/lib/mutant/mutator/node/literal/fixnum.rb +2 -5
  71. data/lib/mutant/mutator/node/literal/float.rb +1 -4
  72. data/lib/mutant/mutator/node/literal/hash.rb +0 -3
  73. data/lib/mutant/mutator/node/literal/nil.rb +0 -1
  74. data/lib/mutant/mutator/node/literal/range.rb +1 -5
  75. data/lib/mutant/mutator/node/literal/regex.rb +1 -3
  76. data/lib/mutant/mutator/node/literal/string.rb +0 -1
  77. data/lib/mutant/mutator/node/literal/symbol.rb +0 -1
  78. data/lib/mutant/mutator/node/masgn.rb +0 -1
  79. data/lib/mutant/mutator/node/match_current_line.rb +0 -1
  80. data/lib/mutant/mutator/node/mlhs.rb +0 -1
  81. data/lib/mutant/mutator/node/named_value/access.rb +0 -1
  82. data/lib/mutant/mutator/node/named_value/constant_assignment.rb +0 -2
  83. data/lib/mutant/mutator/node/named_value/variable_assignment.rb +0 -2
  84. data/lib/mutant/mutator/node/next.rb +0 -1
  85. data/lib/mutant/mutator/node/noop.rb +0 -1
  86. data/lib/mutant/mutator/node/nthref.rb +0 -1
  87. data/lib/mutant/mutator/node/op_asgn.rb +0 -1
  88. data/lib/mutant/mutator/node/or_asgn.rb +1 -2
  89. data/lib/mutant/mutator/node/resbody.rb +0 -2
  90. data/lib/mutant/mutator/node/rescue.rb +1 -6
  91. data/lib/mutant/mutator/node/return.rb +0 -1
  92. data/lib/mutant/mutator/node/send.rb +16 -17
  93. data/lib/mutant/mutator/node/send/attribute_assignment.rb +0 -3
  94. data/lib/mutant/mutator/node/send/binary.rb +0 -1
  95. data/lib/mutant/mutator/node/send/index.rb +0 -3
  96. data/lib/mutant/mutator/node/splat.rb +0 -1
  97. data/lib/mutant/mutator/node/super.rb +0 -1
  98. data/lib/mutant/mutator/node/when.rb +2 -7
  99. data/lib/mutant/mutator/node/yield.rb +0 -1
  100. data/lib/mutant/mutator/node/zsuper.rb +0 -1
  101. data/lib/mutant/mutator/registry.rb +1 -4
  102. data/lib/mutant/mutator/util.rb +0 -2
  103. data/lib/mutant/mutator/util/array.rb +0 -3
  104. data/lib/mutant/mutator/util/symbol.rb +0 -1
  105. data/lib/mutant/parallel.rb +3 -9
  106. data/lib/mutant/parallel/master.rb +7 -17
  107. data/lib/mutant/parallel/source.rb +2 -7
  108. data/lib/mutant/parallel/worker.rb +1 -5
  109. data/lib/mutant/reporter.rb +0 -4
  110. data/lib/mutant/reporter/cli.rb +1 -8
  111. data/lib/mutant/reporter/cli/format.rb +7 -18
  112. data/lib/mutant/reporter/cli/printer.rb +2 -12
  113. data/lib/mutant/reporter/cli/printer/config.rb +1 -4
  114. data/lib/mutant/reporter/cli/printer/env_progress.rb +3 -7
  115. data/lib/mutant/reporter/cli/printer/env_result.rb +0 -1
  116. data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +0 -2
  117. data/lib/mutant/reporter/cli/printer/mutation_result.rb +3 -11
  118. data/lib/mutant/reporter/cli/printer/status.rb +1 -4
  119. data/lib/mutant/reporter/cli/printer/status_progressive.rb +1 -3
  120. data/lib/mutant/reporter/cli/printer/subject_progress.rb +0 -5
  121. data/lib/mutant/reporter/cli/printer/subject_result.rb +0 -1
  122. data/lib/mutant/reporter/cli/printer/test_result.rb +0 -1
  123. data/lib/mutant/reporter/cli/tput.rb +4 -1
  124. data/lib/mutant/reporter/trace.rb +2 -4
  125. data/lib/mutant/repository.rb +88 -0
  126. data/lib/mutant/require_highjack.rb +0 -1
  127. data/lib/mutant/result.rb +25 -48
  128. data/lib/mutant/runner.rb +7 -16
  129. data/lib/mutant/runner/sink.rb +3 -11
  130. data/lib/mutant/selector.rb +1 -2
  131. data/lib/mutant/selector/expression.rb +1 -2
  132. data/lib/mutant/subject.rb +10 -21
  133. data/lib/mutant/subject/method.rb +11 -12
  134. data/lib/mutant/subject/method/instance.rb +1 -5
  135. data/lib/mutant/subject/method/singleton.rb +1 -3
  136. data/lib/mutant/test.rb +1 -2
  137. data/lib/mutant/version.rb +2 -2
  138. data/lib/mutant/warning_filter.rb +2 -7
  139. data/lib/mutant/zombifier.rb +6 -10
  140. data/meta/send.rb +8 -0
  141. data/spec/spec_helper.rb +5 -1
  142. data/spec/support/corpus.rb +5 -9
  143. data/spec/support/rb_bug.rb +0 -1
  144. data/spec/support/rspec.rb +0 -1
  145. data/spec/support/ruby_vm.rb +0 -2
  146. data/spec/unit/mutant/ast/meta/send_spec.rb +42 -0
  147. data/spec/unit/mutant/ast/named_children_spec.rb +51 -0
  148. data/spec/unit/mutant/ast/sexp_spec.rb +36 -0
  149. data/spec/unit/mutant/ast_spec.rb +8 -0
  150. data/spec/unit/mutant/cli_spec.rb +34 -19
  151. data/spec/unit/mutant/context/scope_spec.rb +11 -0
  152. data/spec/unit/mutant/env/boostrap_spec.rb +5 -2
  153. data/spec/unit/mutant/env_spec.rb +14 -15
  154. data/spec/unit/mutant/expression/method_spec.rb +10 -14
  155. data/spec/unit/mutant/expression/methods_spec.rb +24 -11
  156. data/spec/unit/mutant/expression/namespace/flat_spec.rb +5 -6
  157. data/spec/unit/mutant/expression/namespace/recursive_spec.rb +16 -10
  158. data/spec/unit/mutant/expression/parser_spec.rb +67 -0
  159. data/spec/unit/mutant/expression_spec.rb +24 -57
  160. data/spec/unit/mutant/integration/rspec_spec.rb +7 -7
  161. data/spec/unit/mutant/integration_spec.rb +2 -2
  162. data/spec/unit/mutant/isolation_spec.rb +31 -29
  163. data/spec/unit/mutant/matcher/compiler/subject_prefix_spec.rb +2 -2
  164. data/spec/unit/mutant/matcher/compiler_spec.rb +27 -58
  165. data/spec/unit/mutant/matcher/config_spec.rb +45 -0
  166. data/spec/unit/mutant/matcher/filter_spec.rb +12 -5
  167. data/spec/unit/mutant/matcher/method/instance_spec.rb +0 -1
  168. data/spec/unit/mutant/matcher/method/singleton_spec.rb +0 -1
  169. data/spec/unit/mutant/matcher/namespace_spec.rb +4 -4
  170. data/spec/unit/mutant/parallel/worker_spec.rb +1 -1
  171. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +4 -4
  172. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +7 -7
  173. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +2 -2
  174. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +2 -2
  175. data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +12 -12
  176. data/spec/unit/mutant/reporter/cli/printer/subject_progress_spec.rb +1 -1
  177. data/spec/unit/mutant/reporter/cli_spec.rb +9 -10
  178. data/spec/unit/mutant/repository/diff_spec.rb +80 -0
  179. data/spec/unit/mutant/repository/subject_filter_spec.rb +28 -0
  180. data/spec/unit/mutant/result/env_spec.rb +1 -1
  181. data/spec/unit/mutant/runner_spec.rb +0 -1
  182. data/spec/unit/mutant/selector/expression_spec.rb +14 -14
  183. data/spec/unit/mutant/subject/method/instance_spec.rb +2 -2
  184. data/spec/unit/mutant/subject/method/singleton_spec.rb +2 -2
  185. data/spec/unit/mutant/subject_spec.rb +5 -2
  186. metadata +20 -3
  187. data/spec/support/mutation_verifier.rb +0 -96
@@ -1,4 +1,4 @@
1
1
  module Mutant
2
- # The current mutant version
3
- VERSION = '0.8.0'.freeze
2
+ # Current mutant version
3
+ VERSION = '0.8.1'.freeze
4
4
  end # Mutant
@@ -12,28 +12,25 @@ module Mutant
12
12
  # @return [undefined]
13
13
  #
14
14
  # @api private
15
- #
16
15
  def initialize(target)
17
16
  @target = target
18
17
  @warnings = []
19
18
  end
20
19
 
21
- # Return filtered warnings
20
+ # Warnings captured by filter
22
21
  #
23
22
  # @return [Array<String>]
24
23
  #
25
24
  # @api private
26
- #
27
25
  attr_reader :warnings
28
26
 
29
- # Return target
27
+ # Target stream to capture warnings on
30
28
  #
31
29
  # @return [#write] target
32
30
  #
33
31
  # @return [undefined]
34
32
  #
35
33
  # @api private
36
- #
37
34
  attr_reader :target
38
35
  protected :target
39
36
 
@@ -44,7 +41,6 @@ module Mutant
44
41
  # @return [self]
45
42
  #
46
43
  # @api private
47
- #
48
44
  def write(message)
49
45
  if WARNING_PATTERN =~ message
50
46
  warnings << message
@@ -60,7 +56,6 @@ module Mutant
60
56
  # @return [Array<String>]
61
57
  #
62
58
  # @api private
63
- #
64
59
  def self.use
65
60
  original = $stderr
66
61
  $stderr = filter = new(original)
@@ -22,13 +22,17 @@ module Mutant
22
22
  # @return [undefined]
23
23
  #
24
24
  # @api private
25
- #
26
25
  def initialize(*)
27
26
  super
28
27
  @includes = %r{\A#{Regexp.union(includes)}(?:/.*)?\z}
29
28
  @zombified = Set.new
30
29
  end
31
30
 
31
+ # Call zombifier
32
+ #
33
+ # @return [self]
34
+ #
35
+ # @api private
32
36
  def self.call(*args)
33
37
  new(*args).__send__(:call)
34
38
  self
@@ -41,7 +45,6 @@ module Mutant
41
45
  # @return [undefined]
42
46
  #
43
47
  # @api private
44
- #
45
48
  def call
46
49
  @original = require_highjack.call(method(:require))
47
50
  require(root_require)
@@ -52,7 +55,6 @@ module Mutant
52
55
  # @param [String]
53
56
  #
54
57
  # @api private
55
- #
56
58
  def include?(logical_name)
57
59
  !@zombified.include?(logical_name) && @includes =~ logical_name
58
60
  end
@@ -64,7 +66,6 @@ module Mutant
64
66
  # @return [undefined]
65
67
  #
66
68
  # @api private
67
- #
68
69
  def require(logical_name)
69
70
  logical_name = logical_name.to_s
70
71
  @original.call(logical_name)
@@ -83,7 +84,6 @@ module Mutant
83
84
  # otherwise
84
85
  #
85
86
  # @api private
86
- #
87
87
  def find(logical_name)
88
88
  file_name = "#{logical_name}.rb"
89
89
 
@@ -104,9 +104,6 @@ module Mutant
104
104
  # @return [undefined]
105
105
  #
106
106
  # @api private
107
- #
108
- # rubocop:disable Lint/Eval
109
- #
110
107
  def zombify(source_path)
111
108
  kernel.eval(
112
109
  Unparser.unparse(namespaced_node(source_path)),
@@ -115,14 +112,13 @@ module Mutant
115
112
  )
116
113
  end
117
114
 
118
- # Return namespaced root
115
+ # Namespaced root node
119
116
  #
120
117
  # @param [Symbol] namespace
121
118
  #
122
119
  # @return [Parser::AST::Node]
123
120
  #
124
121
  # @api private
125
- #
126
122
  def namespaced_node(source_path)
127
123
  s(:module, s(:const, nil, namespace), Parser::CurrentRuby.parse(source_path.read))
128
124
  end
@@ -367,6 +367,8 @@ Mutant::Meta::Example.add do
367
367
  mutation '1'
368
368
  mutation 'foo'
369
369
  mutation 'foo[]'
370
+ mutation 'foo.at(1)'
371
+ mutation 'foo.fetch(1)'
370
372
  mutation 'self[1]'
371
373
  mutation 'foo[0]'
372
374
  mutation 'foo[2]'
@@ -380,6 +382,8 @@ Mutant::Meta::Example.add do
380
382
 
381
383
  singleton_mutations
382
384
  mutation 'self.foo'
385
+ mutation 'self.foo.at()'
386
+ mutation 'self.foo.fetch()'
383
387
  mutation 'self[]'
384
388
  mutation 'foo[]'
385
389
  end
@@ -391,6 +395,8 @@ Mutant::Meta::Example.add do
391
395
  mutation 'self[self]'
392
396
  mutation 'self[nil]'
393
397
  mutation 'self[]'
398
+ mutation 'self.at(foo)'
399
+ mutation 'self.fetch(foo)'
394
400
  mutation 'foo'
395
401
  end
396
402
 
@@ -400,6 +406,8 @@ Mutant::Meta::Example.add do
400
406
  singleton_mutations
401
407
  mutation 'foo'
402
408
  mutation 'foo[]'
409
+ mutation 'foo.at(*bar)'
410
+ mutation 'foo.fetch(*bar)'
403
411
  mutation 'foo[nil]'
404
412
  mutation 'foo[self]'
405
413
  mutation 'foo[bar]'
@@ -35,7 +35,7 @@ require 'test_app'
35
35
  module Fixtures
36
36
  TEST_CONFIG = Mutant::Config::DEFAULT.update(reporter: Mutant::Reporter::Trace.new)
37
37
  TEST_CACHE = Mutant::Cache.new
38
- TEST_ENV = Mutant::Env::Bootstrap.call(TEST_CONFIG, TEST_CACHE)
38
+ TEST_ENV = Mutant::Env::Bootstrap.(TEST_CONFIG, TEST_CACHE)
39
39
  end # Fixtures
40
40
 
41
41
  module ParserHelper
@@ -46,6 +46,10 @@ module ParserHelper
46
46
  def parse(string)
47
47
  Unparser::Preprocessor.run(Parser::CurrentRuby.parse(string))
48
48
  end
49
+
50
+ def parse_expression(string)
51
+ Mutant::Config::DEFAULT.expression_parser.(string)
52
+ end
49
53
  end
50
54
 
51
55
  module MessageHelper
@@ -31,6 +31,7 @@ module MutantSpec
31
31
  #
32
32
  # @raise [Exception]
33
33
  #
34
+ # @api private
34
35
  def verify_mutation_coverage
35
36
  checkout
36
37
  Dir.chdir(repo_path) do
@@ -60,6 +61,7 @@ module MutantSpec
60
61
  #
61
62
  # rubocop:disable AbcSize
62
63
  #
64
+ # @api private
63
65
  def verify_mutation_generation
64
66
  checkout
65
67
  start = Time.now
@@ -99,7 +101,6 @@ module MutantSpec
99
101
  # @return [self]
100
102
  #
101
103
  # @api private
102
- #
103
104
  def checkout
104
105
  return self if noinstall?
105
106
  TMP.mkdir unless TMP.directory?
@@ -126,7 +127,6 @@ module MutantSpec
126
127
  # @return [undefined]
127
128
  #
128
129
  # @api private
129
- #
130
130
  def install_mutant
131
131
  return if noinstall?
132
132
  relative = ROOT.relative_path_from(repo_path)
@@ -142,12 +142,11 @@ module MutantSpec
142
142
  # Not in the docs. Number from chatting with their support.
143
143
  CIRCLE_CI_CONTAINER_PROCESSES = 2
144
144
 
145
- # Return number of parallel processes to use
145
+ # Number of parallel processes to use
146
146
  #
147
147
  # @return [Fixnum]
148
148
  #
149
149
  # @api private
150
- #
151
150
  def parallel_processes
152
151
  if ENV['CI']
153
152
  Mutant::Config::DEFAULT.jobs
@@ -156,12 +155,11 @@ module MutantSpec
156
155
  end
157
156
  end
158
157
 
159
- # Return repository path
158
+ # Repository path
160
159
  #
161
160
  # @return [Pathname]
162
161
  #
163
162
  # @api private
164
- #
165
163
  def repo_path
166
164
  TMP.join(name)
167
165
  end
@@ -171,7 +169,6 @@ module MutantSpec
171
169
  # @return [Boolean]
172
170
  #
173
171
  # @api private
174
- #
175
172
  def noinstall?
176
173
  ENV.key?('NOINSTALL')
177
174
  end
@@ -208,13 +205,12 @@ module MutantSpec
208
205
  # @param [Array<String>] arguments
209
206
  #
210
207
  # @api private
211
- #
212
208
  def system(arguments)
213
209
  return if Kernel.system(*arguments)
214
210
  if block_given?
215
211
  yield
216
212
  else
217
- fail 'System command failed!'
213
+ fail "System command failed!: #{arguments.join(' ')}"
218
214
  end
219
215
  end
220
216
 
@@ -10,7 +10,6 @@ module RbBug
10
10
  # @return [undefined]
11
11
  #
12
12
  # @api private
13
- #
14
13
  def self.call
15
14
  rb_bug('%s', :string, 'test bug')
16
15
  end
@@ -6,7 +6,6 @@ module Rspec
6
6
  # returns the value of block
7
7
  #
8
8
  # @api private
9
- #
10
9
  def self.nest
11
10
  original_world, original_configuration =
12
11
  ::RSpec.instance_variable_get(:@world),
@@ -2,8 +2,6 @@ module MutantSpec
2
2
  # Not a real VM, just kidding. It connects the require / eval triggers
3
3
  # require semantics Zombifier relies on in a way we can avoid having to
4
4
  # mock around everywhere to test every detail.
5
- #
6
- # rubocop:disable LineLength
7
5
  class RubyVM
8
6
  include Concord.new(:expected_events)
9
7
 
@@ -0,0 +1,42 @@
1
+ RSpec.describe Mutant::AST::Meta::Send do
2
+ let(:object) { described_class.new(node) }
3
+
4
+ def parse(source)
5
+ Parser::CurrentRuby.parse(source)
6
+ end
7
+
8
+ let(:method_call) { parse('foo.bar(baz)') }
9
+ let(:attribute_read) { parse('foo.bar') }
10
+ let(:index_assignment) { parse('foo[0] = bar') }
11
+ let(:attribute_assignment) { parse('foo.bar = baz') }
12
+ let(:binary_method_operator) { parse('foo == bar') }
13
+
14
+ class Expectation
15
+ include Adamantium, Anima.new(:name, :assignment, :attribute_assignment, :index_assignment, :binary_method_operator)
16
+
17
+ ALL = [
18
+ [:method_call, false, false, false, false],
19
+ [:attribute_read, false, false, false, false],
20
+ [:index_assignment, true, false, true, false],
21
+ [:attribute_assignment, true, true, false, false],
22
+ [:binary_method_operator, false, false, false, true]
23
+ ].map do |values|
24
+ new(Hash[anima.attribute_names.zip(values)])
25
+ end.freeze
26
+ end
27
+
28
+ # Rspec should have a build in for this kind of "n-dimensional assertion with context"
29
+ (Expectation.anima.attribute_names - %i[name]).each do |name|
30
+ describe "##{name}?" do
31
+ subject { object.public_send(:"#{name}?") }
32
+
33
+ Expectation::ALL.each do |expectation|
34
+ context "on #{expectation.name}" do
35
+ let(:node) { public_send(expectation.name) }
36
+
37
+ it { should be(expectation.public_send(name)) }
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,51 @@
1
+ RSpec.describe Mutant::AST::NamedChildren do
2
+ describe '.included' do
3
+ let(:klass) do
4
+ Class.new do
5
+ include Mutant::AST::NamedChildren, Concord.new(:node)
6
+
7
+ children :foo, :bar
8
+ end
9
+ end
10
+
11
+ let(:instance) { klass.new(node) }
12
+
13
+ let(:node_foo) { s(:foo) }
14
+ let(:node_bar) { s(:bar) }
15
+ let(:node_baz) { s(:baz) }
16
+
17
+ let(:node) { s(:node, node_foo, node_bar, node_baz) }
18
+
19
+ describe 'generated methods' do
20
+ describe '#remaining_children' do
21
+ it 'returns remaining unnamed children' do
22
+ expect(instance.remaining_children).to eql([node_baz])
23
+ end
24
+ end
25
+
26
+ describe '#remaining_children_indices' do
27
+ it 'returns remaining unnamed children indices' do
28
+ expect(instance.remaining_children_indices).to eql([2])
29
+ end
30
+ end
31
+
32
+ describe '#remaining_children_with_index' do
33
+ it 'returns remaining unnamed children indices' do
34
+ expect(instance.remaining_children_with_index).to eql([[node_baz, 2]])
35
+ end
36
+ end
37
+
38
+ describe '#foo' do
39
+ it 'returns named child foo' do
40
+ expect(instance.foo).to be(node_foo)
41
+ end
42
+ end
43
+
44
+ describe '#bar' do
45
+ it 'returns named child bar' do
46
+ expect(instance.bar).to be(node_bar)
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,36 @@
1
+ RSpec.describe Mutant::AST::Sexp do
2
+ let(:object) do
3
+ Class.new do
4
+ include Mutant::AST::Sexp
5
+
6
+ public :n_not
7
+ public :s
8
+ end.new
9
+ end
10
+
11
+ describe '#n_not' do
12
+ subject { object.n_not(node) }
13
+
14
+ let(:node) { s(:true) }
15
+
16
+ it 'returns negated ast' do
17
+ expect(subject).to eql(s(:send, s(:true), :!))
18
+ end
19
+ end
20
+
21
+ describe '#s' do
22
+ subject { object.s(*arguments) }
23
+
24
+ context 'with single argument' do
25
+ let(:arguments) { %i[foo] }
26
+
27
+ it { should eql(Parser::AST::Node.new(:foo)) }
28
+ end
29
+
30
+ context 'with single multiple arguments' do
31
+ let(:arguments) { %i[foo bar baz] }
32
+
33
+ it { should eql(Parser::AST::Node.new(:foo, %i[bar baz])) }
34
+ end
35
+ end
36
+ end
@@ -19,6 +19,14 @@ RSpec.describe Mutant::AST do
19
19
  it { should eql([]) }
20
20
  end
21
21
 
22
+ context 'when called without block' do
23
+ let(:block) { nil }
24
+
25
+ it 'raises error' do
26
+ expect { subject }.to raise_error(ArgumentError, 'block expected')
27
+ end
28
+ end
29
+
22
30
  context 'when one node matches' do
23
31
  let(:block) { ->(node) { node.equal?(child_a) } }
24
32
 
@@ -1,20 +1,20 @@
1
- RSpec.shared_examples_for 'an invalid cli run' do
2
- it 'raises error' do
3
- expect do
4
- subject
5
- end.to raise_error(Mutant::CLI::Error, expected_message)
6
- end
7
- end
8
-
9
- RSpec.shared_examples_for 'a cli parser' do
10
- it { expect(subject.config.integration).to eql(expected_integration) }
11
- it { expect(subject.config.reporter).to eql(expected_reporter) }
12
- it { expect(subject.config.matcher).to eql(expected_matcher_config) }
13
- end
14
-
15
1
  RSpec.describe Mutant::CLI do
16
2
  let(:object) { described_class }
17
3
 
4
+ shared_examples_for 'an invalid cli run' do
5
+ it 'raises error' do
6
+ expect do
7
+ subject
8
+ end.to raise_error(Mutant::CLI::Error, expected_message)
9
+ end
10
+ end
11
+
12
+ shared_examples_for 'a cli parser' do
13
+ it { expect(subject.config.integration).to eql(expected_integration) }
14
+ it { expect(subject.config.reporter).to eql(expected_reporter) }
15
+ it { expect(subject.config.matcher).to eql(expected_matcher_config) }
16
+ end
17
+
18
18
  describe '.run' do
19
19
  subject { object.run(arguments) }
20
20
 
@@ -67,13 +67,13 @@ RSpec.describe Mutant::CLI do
67
67
 
68
68
  # Defaults
69
69
  let(:expected_filter) { Morpher.evaluator(s(:true)) }
70
- let(:expected_integration) { Mutant::Integration::Null.new }
70
+ let(:expected_integration) { Mutant::Integration::Null }
71
71
  let(:expected_reporter) { Mutant::Config::DEFAULT.reporter }
72
72
  let(:expected_matcher_config) { default_matcher_config }
73
73
 
74
74
  let(:default_matcher_config) do
75
75
  Mutant::Matcher::Config::DEFAULT
76
- .update(match_expressions: expressions.map(&Mutant::Expression.method(:parse)))
76
+ .update(match_expressions: expressions.map(&method(:parse_expression)))
77
77
  end
78
78
 
79
79
  let(:flags) { [] }
@@ -127,7 +127,8 @@ Environment:
127
127
  Options:
128
128
  --expected-coverage COVERAGE Fail unless COVERAGE is not reached exactly, parsed via Rational()
129
129
  --use INTEGRATION Use INTEGRATION to kill mutations
130
- --ignore-subject PATTERN Ignore subjects that match PATTERN
130
+ --ignore-subject EXPRESSION Ignore subjects that match EXPRESSION as prefix
131
+ --since REVISION Only select subjects touched since REVISION
131
132
  --fail-fast Fail fast
132
133
  --version Print mutants version
133
134
  -d, --debug Enable debugging output
@@ -152,7 +153,7 @@ Options:
152
153
 
153
154
  it_should_behave_like 'a cli parser'
154
155
 
155
- let(:expected_integration) { Mutant::Integration::Rspec.new }
156
+ let(:expected_integration) { Mutant::Integration::Rspec }
156
157
  end
157
158
 
158
159
  context 'when integration does NOT exist' do
@@ -230,11 +231,25 @@ Options:
230
231
  end
231
232
  end
232
233
 
234
+ context 'with --since flag' do
235
+ let(:flags) { %w[--since master] }
236
+
237
+ let(:expected_matcher_config) do
238
+ default_matcher_config.update(
239
+ subject_filters: [
240
+ Mutant::Repository::SubjectFilter.new(Mutant::Repository::Diff.new('HEAD', 'master'))
241
+ ]
242
+ )
243
+ end
244
+
245
+ it_should_behave_like 'a cli parser'
246
+ end
247
+
233
248
  context 'with subject-ignore flag' do
234
249
  let(:flags) { %w[--ignore-subject Foo::Bar] }
235
250
 
236
251
  let(:expected_matcher_config) do
237
- default_matcher_config.update(subject_ignores: [Mutant::Expression.parse('Foo::Bar')])
252
+ default_matcher_config.update(ignore_expressions: [parse_expression('Foo::Bar')])
238
253
  end
239
254
 
240
255
  it_should_behave_like 'a cli parser'