mutant 0.9.9 → 0.9.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (252) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mutant.rb +2 -4
  3. data/lib/mutant/bootstrap.rb +14 -1
  4. data/lib/mutant/cli.rb +6 -0
  5. data/lib/mutant/isolation.rb +1 -1
  6. data/lib/mutant/isolation/fork.rb +2 -2
  7. data/lib/mutant/isolation/none.rb +1 -1
  8. data/lib/mutant/matcher/config.rb +2 -0
  9. data/lib/mutant/meta/example.rb +16 -4
  10. data/lib/mutant/meta/example/dsl.rb +33 -16
  11. data/lib/mutant/meta/example/verification.rb +70 -28
  12. data/lib/mutant/minitest/coverage.rb +53 -0
  13. data/lib/mutant/mutator/node.rb +2 -2
  14. data/lib/mutant/mutator/node/block_pass.rb +29 -0
  15. data/lib/mutant/mutator/node/{dstr.rb → dynamic_literal.rb} +7 -5
  16. data/lib/mutant/mutator/node/index.rb +4 -4
  17. data/lib/mutant/mutator/node/literal/range.rb +4 -1
  18. data/lib/mutant/mutator/node/noop.rb +1 -1
  19. data/lib/mutant/mutator/node/op_asgn.rb +15 -1
  20. data/lib/mutant/mutator/node/send.rb +25 -1
  21. data/lib/mutant/mutator/node/send/attribute_assignment.rb +1 -0
  22. data/lib/mutant/reporter/cli/printer.rb +2 -2
  23. data/lib/mutant/reporter/cli/printer/isolation_result.rb +9 -3
  24. data/lib/mutant/reporter/cli/printer/mutation_result.rb +1 -1
  25. data/lib/mutant/subject/method/instance.rb +41 -2
  26. data/lib/mutant/version.rb +1 -1
  27. metadata +59 -347
  28. data/.github/workflows/ci.yml +0 -121
  29. data/.gitignore +0 -38
  30. data/.rspec +0 -5
  31. data/.rubocop.yml +0 -7
  32. data/Changelog.md +0 -81
  33. data/Gemfile +0 -7
  34. data/Gemfile.lock +0 -167
  35. data/Gemfile.shared +0 -10
  36. data/README.md +0 -178
  37. data/Rakefile +0 -5
  38. data/config/devtools.yml +0 -2
  39. data/config/reek.yml +0 -139
  40. data/config/rubocop.yml +0 -205
  41. data/config/yardstick.yml +0 -2
  42. data/docs/commercial-support.md +0 -14
  43. data/docs/concurrency.md +0 -39
  44. data/docs/incremental.md +0 -76
  45. data/docs/known-problems.md +0 -30
  46. data/docs/limitations.md +0 -50
  47. data/docs/mutant-minitest.md +0 -149
  48. data/docs/mutant-rspec.md +0 -130
  49. data/docs/nomenclature.md +0 -82
  50. data/docs/reading-reports.md +0 -74
  51. data/lib/mutant/color.rb +0 -40
  52. data/lib/mutant/diff.rb +0 -97
  53. data/lib/mutant/mutator/node/dsym.rb +0 -22
  54. data/meta/and.rb +0 -13
  55. data/meta/and_asgn.rb +0 -14
  56. data/meta/array.rb +0 -27
  57. data/meta/begin.rb +0 -20
  58. data/meta/block.rb +0 -199
  59. data/meta/block_pass.rb +0 -8
  60. data/meta/blockarg.rb +0 -10
  61. data/meta/break.rb +0 -9
  62. data/meta/case.rb +0 -217
  63. data/meta/casgn.rb +0 -25
  64. data/meta/cbase.rb +0 -8
  65. data/meta/class.rb +0 -12
  66. data/meta/const.rb +0 -17
  67. data/meta/csend.rb +0 -10
  68. data/meta/cvar.rb +0 -7
  69. data/meta/cvasgn.rb +0 -9
  70. data/meta/date.rb +0 -59
  71. data/meta/def.rb +0 -196
  72. data/meta/defined.rb +0 -9
  73. data/meta/dstr.rb +0 -13
  74. data/meta/dsym.rb +0 -14
  75. data/meta/ensure.rb +0 -8
  76. data/meta/false.rb +0 -7
  77. data/meta/file.rb +0 -5
  78. data/meta/float.rb +0 -37
  79. data/meta/gvar.rb +0 -7
  80. data/meta/gvasgn.rb +0 -9
  81. data/meta/hash.rb +0 -20
  82. data/meta/if.rb +0 -72
  83. data/meta/index.rb +0 -133
  84. data/meta/indexasgn.rb +0 -31
  85. data/meta/int.rb +0 -18
  86. data/meta/ivar.rb +0 -8
  87. data/meta/ivasgn.rb +0 -22
  88. data/meta/kwarg.rb +0 -10
  89. data/meta/kwbegin.rb +0 -8
  90. data/meta/kwoptarg.rb +0 -13
  91. data/meta/lambda.rb +0 -23
  92. data/meta/line.rb +0 -5
  93. data/meta/lvar.rb +0 -16
  94. data/meta/lvasgn.rb +0 -24
  95. data/meta/masgn.rb +0 -7
  96. data/meta/match_current_line.rb +0 -14
  97. data/meta/next.rb +0 -10
  98. data/meta/nil.rb +0 -5
  99. data/meta/nthref.rb +0 -14
  100. data/meta/op_assgn.rb +0 -17
  101. data/meta/or.rb +0 -13
  102. data/meta/or_asgn.rb +0 -50
  103. data/meta/range.rb +0 -39
  104. data/meta/redo.rb +0 -5
  105. data/meta/regexp.rb +0 -80
  106. data/meta/regopt.rb +0 -10
  107. data/meta/rescue.rb +0 -84
  108. data/meta/return.rb +0 -16
  109. data/meta/sclass.rb +0 -12
  110. data/meta/self.rb +0 -7
  111. data/meta/send.rb +0 -600
  112. data/meta/str.rb +0 -7
  113. data/meta/super.rb +0 -27
  114. data/meta/sym.rb +0 -8
  115. data/meta/true.rb +0 -7
  116. data/meta/until.rb +0 -16
  117. data/meta/while.rb +0 -24
  118. data/meta/yield.rb +0 -9
  119. data/mutant-minitest.gemspec +0 -22
  120. data/mutant-rspec.gemspec +0 -22
  121. data/mutant.gemspec +0 -41
  122. data/mutant.sh +0 -12
  123. data/mutant.yml +0 -6
  124. data/spec/integration/mutant/corpus_spec.rb +0 -15
  125. data/spec/integration/mutant/isolation/fork_spec.rb +0 -28
  126. data/spec/integration/mutant/minitest_spec.rb +0 -11
  127. data/spec/integration/mutant/null_spec.rb +0 -16
  128. data/spec/integration/mutant/rspec_spec.rb +0 -15
  129. data/spec/integration/mutant/test_mutator_handles_types_spec.rb +0 -9
  130. data/spec/integrations.yml +0 -63
  131. data/spec/shared/base_behavior.rb +0 -45
  132. data/spec/shared/framework_integration_behavior.rb +0 -70
  133. data/spec/shared/method_matcher_behavior.rb +0 -47
  134. data/spec/spec_helper.rb +0 -75
  135. data/spec/support/corpus.rb +0 -318
  136. data/spec/support/file_system.rb +0 -62
  137. data/spec/support/ice_nine_config.rb +0 -10
  138. data/spec/support/ruby_vm.rb +0 -84
  139. data/spec/support/shared_context.rb +0 -169
  140. data/spec/support/test_app.rb +0 -7
  141. data/spec/support/warnings.yml +0 -6
  142. data/spec/support/xspec.rb +0 -183
  143. data/spec/unit/mutant/ast/find_metaclass_containing_spec.rb +0 -64
  144. data/spec/unit/mutant/ast/meta/optarg_spec.rb +0 -24
  145. data/spec/unit/mutant/ast/meta/send/proc_predicate_spec.rb +0 -30
  146. data/spec/unit/mutant/ast/meta/send/receiver_possible_top_level_const_predicate_spec.rb +0 -39
  147. data/spec/unit/mutant/ast/meta/send_spec.rb +0 -42
  148. data/spec/unit/mutant/ast/named_children_spec.rb +0 -89
  149. data/spec/unit/mutant/ast/sexp_spec.rb +0 -38
  150. data/spec/unit/mutant/ast_spec.rb +0 -57
  151. data/spec/unit/mutant/bootstrap_spec.rb +0 -216
  152. data/spec/unit/mutant/cli_spec.rb +0 -305
  153. data/spec/unit/mutant/clock_monotonic_spec.rb +0 -52
  154. data/spec/unit/mutant/config_spec.rb +0 -126
  155. data/spec/unit/mutant/context_spec.rb +0 -111
  156. data/spec/unit/mutant/diff_spec.rb +0 -189
  157. data/spec/unit/mutant/env_spec.rb +0 -229
  158. data/spec/unit/mutant/expression/method_spec.rb +0 -62
  159. data/spec/unit/mutant/expression/methods_spec.rb +0 -66
  160. data/spec/unit/mutant/expression/namespace/exact_spec.rb +0 -28
  161. data/spec/unit/mutant/expression/namespace/recursive_spec.rb +0 -66
  162. data/spec/unit/mutant/expression/parser_spec.rb +0 -65
  163. data/spec/unit/mutant/expression_spec.rb +0 -45
  164. data/spec/unit/mutant/integration/rspec_spec.rb +0 -201
  165. data/spec/unit/mutant/integration_spec.rb +0 -150
  166. data/spec/unit/mutant/isolation/fork_spec.rb +0 -309
  167. data/spec/unit/mutant/isolation/none_spec.rb +0 -23
  168. data/spec/unit/mutant/isolation/result_spec.rb +0 -73
  169. data/spec/unit/mutant/license_spec.rb +0 -305
  170. data/spec/unit/mutant/loader_spec.rb +0 -79
  171. data/spec/unit/mutant/matcher/chain_spec.rb +0 -26
  172. data/spec/unit/mutant/matcher/compiler_spec.rb +0 -0
  173. data/spec/unit/mutant/matcher/config_spec.rb +0 -47
  174. data/spec/unit/mutant/matcher/filter_spec.rb +0 -22
  175. data/spec/unit/mutant/matcher/method/instance_spec.rb +0 -164
  176. data/spec/unit/mutant/matcher/method/metaclass_spec.rb +0 -108
  177. data/spec/unit/mutant/matcher/method/singleton_spec.rb +0 -90
  178. data/spec/unit/mutant/matcher/methods/instance_spec.rb +0 -54
  179. data/spec/unit/mutant/matcher/methods/metaclass_spec.rb +0 -62
  180. data/spec/unit/mutant/matcher/methods/singleton_spec.rb +0 -51
  181. data/spec/unit/mutant/matcher/namespace_spec.rb +0 -39
  182. data/spec/unit/mutant/matcher/null_spec.rb +0 -12
  183. data/spec/unit/mutant/matcher/scope_spec.rb +0 -45
  184. data/spec/unit/mutant/matcher/static_spec.rb +0 -13
  185. data/spec/unit/mutant/matcher_spec.rb +0 -102
  186. data/spec/unit/mutant/meta/example/dsl_spec.rb +0 -108
  187. data/spec/unit/mutant/meta/example/verification_spec.rb +0 -154
  188. data/spec/unit/mutant/meta/example_spec.rb +0 -34
  189. data/spec/unit/mutant/mutation_spec.rb +0 -140
  190. data/spec/unit/mutant/mutator/node_spec.rb +0 -47
  191. data/spec/unit/mutant/mutator_spec.rb +0 -21
  192. data/spec/unit/mutant/parallel/driver_spec.rb +0 -126
  193. data/spec/unit/mutant/parallel/source/array_spec.rb +0 -57
  194. data/spec/unit/mutant/parallel/worker_spec.rb +0 -206
  195. data/spec/unit/mutant/parallel_spec.rb +0 -115
  196. data/spec/unit/mutant/parser_spec.rb +0 -26
  197. data/spec/unit/mutant/range_spec.rb +0 -141
  198. data/spec/unit/mutant/registry_spec.rb +0 -74
  199. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +0 -17
  200. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +0 -85
  201. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +0 -45
  202. data/spec/unit/mutant/reporter/cli/printer/isolation_result_spec.rb +0 -132
  203. data/spec/unit/mutant/reporter/cli/printer/mutation_progress_result_spec.rb +0 -25
  204. data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +0 -153
  205. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +0 -45
  206. data/spec/unit/mutant/reporter/cli/printer/subject_progress_spec.rb +0 -36
  207. data/spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb +0 -44
  208. data/spec/unit/mutant/reporter/cli/printer/test_result_spec.rb +0 -16
  209. data/spec/unit/mutant/reporter/cli/printer_spec.rb +0 -163
  210. data/spec/unit/mutant/reporter/cli_spec.rb +0 -137
  211. data/spec/unit/mutant/reporter/null_spec.rb +0 -14
  212. data/spec/unit/mutant/reporter/sequence_spec.rb +0 -31
  213. data/spec/unit/mutant/repository/diff/ranges_spec.rb +0 -180
  214. data/spec/unit/mutant/repository/diff_spec.rb +0 -122
  215. data/spec/unit/mutant/repository/subject_filter_spec.rb +0 -30
  216. data/spec/unit/mutant/require_highjack_spec.rb +0 -73
  217. data/spec/unit/mutant/result/class_methods_spec.rb +0 -51
  218. data/spec/unit/mutant/result/env_spec.rb +0 -161
  219. data/spec/unit/mutant/result/mutation_spec.rb +0 -70
  220. data/spec/unit/mutant/result/subject_spec.rb +0 -111
  221. data/spec/unit/mutant/result/test_spec.rb +0 -14
  222. data/spec/unit/mutant/result_spec.rb +0 -33
  223. data/spec/unit/mutant/runner/sink_spec.rb +0 -174
  224. data/spec/unit/mutant/runner_spec.rb +0 -121
  225. data/spec/unit/mutant/selector/expression_spec.rb +0 -62
  226. data/spec/unit/mutant/selector/null_spec.rb +0 -17
  227. data/spec/unit/mutant/subject/method/instance_spec.rb +0 -181
  228. data/spec/unit/mutant/subject/method/metaclass_spec.rb +0 -63
  229. data/spec/unit/mutant/subject/method/singleton_spec.rb +0 -61
  230. data/spec/unit/mutant/subject_spec.rb +0 -93
  231. data/spec/unit/mutant/transform/array_spec.rb +0 -92
  232. data/spec/unit/mutant/transform/bool_spec.rb +0 -63
  233. data/spec/unit/mutant/transform/error_spec.rb +0 -132
  234. data/spec/unit/mutant/transform/exception_spec.rb +0 -44
  235. data/spec/unit/mutant/transform/hash_spec.rb +0 -236
  236. data/spec/unit/mutant/transform/index_spec.rb +0 -92
  237. data/spec/unit/mutant/transform/named_spec.rb +0 -49
  238. data/spec/unit/mutant/transform/primitive_spec.rb +0 -56
  239. data/spec/unit/mutant/transform/sequence_spec.rb +0 -98
  240. data/spec/unit/mutant/util/one_spec.rb +0 -22
  241. data/spec/unit/mutant/warnings_spec.rb +0 -89
  242. data/spec/unit/mutant/world_spec.rb +0 -63
  243. data/spec/unit/mutant/zombifier_spec.rb +0 -122
  244. data/test_app/.rspec +0 -1
  245. data/test_app/Gemfile.minitest +0 -4
  246. data/test_app/Gemfile.rspec3.8 +0 -7
  247. data/test_app/lib/test_app.rb +0 -110
  248. data/test_app/lib/test_app/literal.rb +0 -35
  249. data/test_app/lib/test_app/metaclasses.rb +0 -108
  250. data/test_app/spec/spec_helper.rb +0 -9
  251. data/test_app/spec/unit/test_app/literal_spec.rb +0 -20
  252. data/test_app/test/unit/test_app/literal_test.rb +0 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e6e6e125d0e2736934ed481945e35eada9a1b8fffaf05641a5410a2ed25b9b20
4
- data.tar.gz: 13e2b48cbc500aab1ef792ccbaff86de593337f7213bdcf7d0d81afa21e7a641
3
+ metadata.gz: 3e92dbf6cbb84cf8d3d5354fc5994cb1ad7cb1fb1364b1927aa89abeedcd0cef
4
+ data.tar.gz: 5c49178b6766424d6ded707a100ebad86cf9c5403a53b2c2c750baf69b4d636f
5
5
  SHA512:
6
- metadata.gz: 7a3bfbaffad39ee2bc7cf41a07c19031704c26c7d05ba9b3f07d59d3b82965311c0822aec10ab359570fc8c3d3235f36d461fbe39cddb6349997b2b8bd0fa5d3
7
- data.tar.gz: a1caa7e5f3318001137239c613ddd50bdeabe981fa132f4e9e5a383019a24a53075da121b290e98dcb61c93a1900f79f8e1207ce7ac282d049b2af0351b26e64
6
+ metadata.gz: e786a6ed55abf722515f3b4b9c08200dac35557e48c27430ae5683471ededf67d1fcb17ff4e5f57f1881765d10f3a8b00ef2993f163a1cceb93531d4b75a37e3
7
+ data.tar.gz: 2a5840a2ecc0ca7c9c6156e8c4596b21808aaf8418ecf134fff9ada56a6c20e94b5ece60a0ebf0b321f1ed51ff0e5c92d26069bcb9473f61276973c46780eb5d
@@ -90,8 +90,7 @@ require 'mutant/mutator/node/arguments'
90
90
  require 'mutant/mutator/node/begin'
91
91
  require 'mutant/mutator/node/binary'
92
92
  require 'mutant/mutator/node/const'
93
- require 'mutant/mutator/node/dstr'
94
- require 'mutant/mutator/node/dsym'
93
+ require 'mutant/mutator/node/dynamic_literal'
95
94
  require 'mutant/mutator/node/kwbegin'
96
95
  require 'mutant/mutator/node/named_value/access'
97
96
  require 'mutant/mutator/node/named_value/constant_assignment'
@@ -120,6 +119,7 @@ require 'mutant/mutator/node/nthref'
120
119
  require 'mutant/mutator/node/masgn'
121
120
  require 'mutant/mutator/node/return'
122
121
  require 'mutant/mutator/node/block'
122
+ require 'mutant/mutator/node/block_pass'
123
123
  require 'mutant/mutator/node/if'
124
124
  require 'mutant/mutator/node/case'
125
125
  require 'mutant/mutator/node/splat'
@@ -165,8 +165,6 @@ require 'mutant/selector/expression'
165
165
  require 'mutant/selector/null'
166
166
  require 'mutant/config'
167
167
  require 'mutant/cli'
168
- require 'mutant/color'
169
- require 'mutant/diff'
170
168
  require 'mutant/runner'
171
169
  require 'mutant/runner/sink'
172
170
  require 'mutant/result'
@@ -36,7 +36,7 @@ module Mutant
36
36
  .tap(&method(:infect))
37
37
  .with(matchable_scopes: matchable_scopes(world, config))
38
38
 
39
- subjects = Matcher.from_config(env.config.matcher).call(env)
39
+ subjects = start_subject(env, Matcher.from_config(env.config.matcher).call(env))
40
40
 
41
41
  Integration.setup(env).fmap do |integration|
42
42
  env.with(
@@ -49,6 +49,19 @@ module Mutant
49
49
  end
50
50
  # rubocop:enable Metrics/MethodLength
51
51
 
52
+ def self.start_subject(env, subjects)
53
+ start_expressions = env.config.matcher.start_expressions
54
+
55
+ return subjects if start_expressions.empty?
56
+
57
+ subjects.drop_while do |subject|
58
+ start_expressions.none? do |expression|
59
+ expression.prefix?(subject.expression)
60
+ end
61
+ end
62
+ end
63
+ private_class_method :start_subject
64
+
52
65
  def self.infect(env)
53
66
  config, world = env.config, env.world
54
67
 
@@ -2,6 +2,8 @@
2
2
 
3
3
  module Mutant
4
4
  # Commandline parser / runner
5
+ #
6
+ # rubocop:disable Metrics/ClassLength
5
7
  class CLI
6
8
  include Concord.new(:world, :config)
7
9
 
@@ -126,6 +128,9 @@ module Mutant
126
128
  opts.on('--ignore-subject EXPRESSION', 'Ignore subjects that match EXPRESSION as prefix') do |pattern|
127
129
  add_matcher(:ignore_expressions, config.expression_parser.apply(pattern).from_right)
128
130
  end
131
+ opts.on('--start-subject EXPRESSION', 'Start mutation testing at a specific subject') do |pattern|
132
+ add_matcher(:start_expressions, config.expression_parser.apply(pattern).from_right)
133
+ end
129
134
  opts.on('--since REVISION', 'Only select subjects touched since REVISION') do |revision|
130
135
  add_matcher(
131
136
  :subject_filters,
@@ -165,4 +170,5 @@ module Mutant
165
170
  with(matcher: config.matcher.add(attribute, value))
166
171
  end
167
172
  end # CLI
173
+ # rubocop:enable Metrics/ClassLength
168
174
  end # Mutant
@@ -40,7 +40,7 @@ module Mutant
40
40
  instance_of?(Success)
41
41
  end
42
42
 
43
- # Succesful result producing value
43
+ # Successful result producing value
44
44
  class Success < self
45
45
  include Concord::Public.new(:value, :log)
46
46
 
@@ -10,12 +10,12 @@ module Mutant
10
10
 
11
11
  ATTRIBUTES = %i[block log_pipe result_pipe world].freeze
12
12
 
13
- # Unsucessful result as child exited nonzero
13
+ # Unsuccessful result as child exited nonzero
14
14
  class ChildError < Result
15
15
  include Concord::Public.new(:value, :log)
16
16
  end # ChildError
17
17
 
18
- # Unsucessful result as fork failed
18
+ # Unsuccessful result as fork failed
19
19
  class ForkError < Result
20
20
  include Equalizer.new
21
21
  end # ForkError
@@ -3,7 +3,7 @@
3
3
  module Mutant
4
4
  # Module providing isolation
5
5
  class Isolation
6
- # Absolutly no isolation
6
+ # Absolutely no isolation
7
7
  #
8
8
  # Only useful for debugging.
9
9
  class None < self
@@ -7,6 +7,7 @@ module Mutant
7
7
  include Adamantium, Anima.new(
8
8
  :ignore_expressions,
9
9
  :match_expressions,
10
+ :start_expressions,
10
11
  :subject_filters
11
12
  )
12
13
 
@@ -18,6 +19,7 @@ module Mutant
18
19
  PRESENTATIONS = IceNine.deep_freeze(
19
20
  ignore_expressions: :syntax,
20
21
  match_expressions: :syntax,
22
+ start_expressions: :syntax,
21
23
  subject_filters: :inspect
22
24
  )
23
25
  private_constant(*constants(false))
@@ -3,7 +3,19 @@
3
3
  module Mutant
4
4
  module Meta
5
5
  class Example
6
- include Adamantium, Anima.new(:file, :node, :types, :expected)
6
+ include Adamantium
7
+ include Anima.new(
8
+ :expected,
9
+ :file,
10
+ :lvars,
11
+ :node,
12
+ :original_source,
13
+ :types
14
+ )
15
+
16
+ class Expected
17
+ include Anima.new(:original_source, :node)
18
+ end
7
19
 
8
20
  # Verification instance for example
9
21
  #
@@ -13,13 +25,13 @@ module Mutant
13
25
  end
14
26
  memoize :verification
15
27
 
16
- # Normalized source
28
+ # Original source as generated by unparser
17
29
  #
18
30
  # @return [String]
19
- def source
31
+ def original_source_generated
20
32
  Unparser.unparse(node)
21
33
  end
22
- memoize :source
34
+ memoize :original_source_generated
23
35
 
24
36
  # Generated mutations on example source
25
37
  #
@@ -25,10 +25,11 @@ module Mutant
25
25
  #
26
26
  # @return [undefined]
27
27
  def initialize(file, types)
28
+ @expected = []
28
29
  @file = file
30
+ @lvars = []
31
+ @source = nil
29
32
  @types = types
30
- @node = nil
31
- @expected = []
32
33
  end
33
34
 
34
35
  # Example captured by DSL
@@ -38,28 +39,41 @@ module Mutant
38
39
  # @raise [RuntimeError]
39
40
  # in case example cannot be build
40
41
  def example
41
- fail 'source not defined' unless @node
42
+ fail 'source not defined' unless @source
42
43
  Example.new(
43
- file: @file,
44
- node: @node,
45
- types: @types,
46
- expected: @expected
44
+ expected: @expected,
45
+ file: @file,
46
+ lvars: @lvars,
47
+ node: @node,
48
+ original_source: @source,
49
+ types: @types
47
50
  )
48
51
  end
49
52
 
53
+ # Declare a local variable
54
+ #
55
+ # @param [Symbol]
56
+ def declare_lvar(name)
57
+ @lvars << name
58
+ end
59
+
50
60
  private
51
61
 
52
62
  def source(input)
53
- fail 'source already defined' if @node
54
- @node = node(input)
63
+ fail 'source already defined' if @source
64
+
65
+ @source = input
66
+ @node = node(input)
55
67
  end
56
68
 
57
69
  def mutation(input)
58
- node = node(input)
59
- if @expected.include?(node)
70
+ expected = Expected.new(original_source: input, node: node(input))
71
+
72
+ if @expected.include?(expected)
60
73
  fail "Mutation for input: #{input.inspect} is already expected"
61
74
  end
62
- @expected << node
75
+
76
+ @expected << expected
63
77
  end
64
78
 
65
79
  def singleton_mutations
@@ -70,14 +84,17 @@ module Mutant
70
84
  def node(input)
71
85
  case input
72
86
  when String
73
- Unparser::Preprocessor.run(Unparser.parse(input))
74
- when ::Parser::AST::Node
75
- input
87
+ parser.parse(Unparser.buffer(input))
76
88
  else
77
- fail "Cannot coerce to node: #{input.inspect}"
89
+ fail "Unsupported input: #{input.inspect}"
78
90
  end
79
91
  end
80
92
 
93
+ def parser
94
+ Unparser.parser.tap do |parser|
95
+ @lvars.each(&parser.static_env.public_method(:declare))
96
+ end
97
+ end
81
98
  end # DSL
82
99
  end # Example
83
100
  end # Meta
@@ -11,54 +11,96 @@ module Mutant
11
11
  #
12
12
  # @return [Boolean]
13
13
  def success?
14
- [missing, unexpected, no_diffs, invalid_syntax].all?(&:empty?)
14
+ [
15
+ original_verification,
16
+ invalid,
17
+ missing,
18
+ no_diffs,
19
+ unexpected
20
+ ].all?(&:empty?)
15
21
  end
16
22
  memoize :success?
17
23
 
18
- # Error report
19
- #
20
- # @return [String]
21
24
  def error_report
22
- fail 'no error report on successful validation' if success?
23
-
24
- YAML.dump(
25
- 'file' => example.file,
26
- 'original_ast' => example.node.inspect,
27
- 'original_source' => example.source,
28
- 'missing' => format_mutations(missing),
29
- 'unexpected' => format_mutations(unexpected),
30
- 'invalid_syntax' => format_mutations(invalid_syntax),
31
- 'no_diff' => no_diff_report
32
- )
25
+ reports.join("\n")
33
26
  end
34
- memoize :error_report
35
27
 
36
28
  private
37
29
 
30
+ def reports
31
+ reports = [example.file]
32
+ reports.concat(original)
33
+ reports.concat(original_verification)
34
+ reports.concat(make_report('Missing mutations:', missing))
35
+ reports.concat(make_report('Unexpected mutations:', unexpected))
36
+ reports.concat(make_report('No-Diff mutations:', no_diffs))
37
+ reports.concat(invalid)
38
+ end
39
+
40
+ def make_report(label, mutations)
41
+ if mutations.any?
42
+ [label, mutations.map(&method(:report_mutation))]
43
+ else
44
+ []
45
+ end
46
+ end
47
+
48
+ def report_mutation(mutation)
49
+ [
50
+ mutation.node.inspect,
51
+ mutation.source
52
+ ]
53
+ end
54
+
55
+ def original
56
+ [
57
+ 'Original:',
58
+ example.node,
59
+ example.original_source
60
+ ]
61
+ end
62
+
63
+ def original_verification
64
+ validation = Unparser::Validation.from_string(example.original_source)
65
+ if validation.success?
66
+ []
67
+ else
68
+ [
69
+ prefix('[original]', validation.report)
70
+ ]
71
+ end
72
+ end
73
+
74
+ def prefix(prefix, string)
75
+ string.each_line.map do |line|
76
+ "#{prefix} #{line}"
77
+ end.join
78
+ end
79
+
80
+ def invalid
81
+ mutations.each_with_object([]) do |mutation, aggregate|
82
+ validation = Unparser::Validation.from_node(mutation.node)
83
+ aggregate << prefix('[invalid-mutation]', validation.report) unless validation.success?
84
+ end
85
+ end
86
+ memoize :invalid
87
+
38
88
  def unexpected
39
89
  mutations.reject do |mutation|
40
- example.expected.include?(mutation.node)
90
+ example.expected.any? { |expected| expected.node.eql?(mutation.node) }
41
91
  end
42
92
  end
43
93
  memoize :unexpected
44
94
 
45
95
  def missing
46
- (example.expected - mutations.map(&:node)).map do |node|
47
- Mutation::Evil.new(self, node)
96
+ (example.expected.map(&:node) - mutations.map(&:node)).map do |node|
97
+ Mutation::Evil.new(nil, node)
48
98
  end
49
99
  end
50
100
  memoize :missing
51
101
 
52
- def invalid_syntax
53
- mutations.reject do |mutation|
54
- ::Parser::CurrentRuby.parse(mutation.source)
55
- rescue ::Parser::SyntaxError # rubocop:disable Lint/SuppressedException
56
- end
57
- end
58
- memoize :invalid_syntax
59
-
60
102
  def no_diffs
61
- mutations.select { |mutation| mutation.source.eql?(example.source) }
103
+ mutations.select { |mutation| mutation.source.eql?(example.original_source_generated) }
62
104
  end
63
105
  memoize :no_diffs
64
106
 
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest'
4
+
5
+ module Mutant
6
+ module Minitest
7
+ module Coverage
8
+ # Setup coverage declaration for current class
9
+ #
10
+ # @param [String]
11
+ #
12
+ # @example
13
+ #
14
+ # class MyTest < MiniTest::Test
15
+ # cover 'MyCode*'
16
+ #
17
+ # def test_some_stuff
18
+ # end
19
+ # end
20
+ #
21
+ # @api public
22
+ def cover(expression)
23
+ if defined?(@cover_expression)
24
+ fail "#{self} already declares to cover: #{@cover_expression.inspect}"
25
+ end
26
+
27
+ @cover_expression = expression
28
+ end
29
+
30
+ # Effective coverage expression
31
+ #
32
+ # @return [String, nil]
33
+ #
34
+ # @api private
35
+ def resolve_cover_expression
36
+ return @cover_expression if defined?(@cover_expression)
37
+
38
+ try_superclass_cover_expression
39
+ end
40
+
41
+ private
42
+
43
+ def try_superclass_cover_expression
44
+ return if superclass.equal?(::Minitest::Runnable)
45
+
46
+ superclass.resolve_cover_expression
47
+ end
48
+
49
+ end # Coverage
50
+ end # Minitest
51
+ end # Mutant
52
+
53
+ Minitest::Test.extend(Mutant::Minitest::Coverage)