mutant 0.8.0 → 0.8.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 (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'