mutant 0.9.9 → 0.9.14

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 (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)