mutant 0.9.10 → 0.10.0

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 (254) hide show
  1. checksums.yaml +4 -4
  2. data/bin/mutant +16 -11
  3. data/lib/mutant.rb +8 -4
  4. data/lib/mutant/bootstrap.rb +14 -1
  5. data/lib/mutant/cli.rb +9 -162
  6. data/lib/mutant/cli/command.rb +196 -0
  7. data/lib/mutant/cli/command/root.rb +13 -0
  8. data/lib/mutant/cli/command/run.rb +151 -0
  9. data/lib/mutant/cli/command/subscription.rb +54 -0
  10. data/lib/mutant/expression.rb +0 -1
  11. data/lib/mutant/isolation.rb +1 -1
  12. data/lib/mutant/isolation/fork.rb +2 -2
  13. data/lib/mutant/isolation/none.rb +1 -1
  14. data/lib/mutant/license.rb +9 -35
  15. data/lib/mutant/license/subscription.rb +31 -9
  16. data/lib/mutant/license/subscription/commercial.rb +2 -4
  17. data/lib/mutant/license/subscription/opensource.rb +7 -7
  18. data/lib/mutant/matcher/config.rb +2 -0
  19. data/lib/mutant/meta/example.rb +16 -4
  20. data/lib/mutant/meta/example/dsl.rb +33 -16
  21. data/lib/mutant/meta/example/verification.rb +70 -28
  22. data/lib/mutant/minitest/coverage.rb +53 -0
  23. data/lib/mutant/mutator/node.rb +2 -2
  24. data/lib/mutant/mutator/node/block_pass.rb +29 -0
  25. data/lib/mutant/mutator/node/{dstr.rb → dynamic_literal.rb} +7 -5
  26. data/lib/mutant/mutator/node/index.rb +4 -4
  27. data/lib/mutant/mutator/node/literal/range.rb +5 -2
  28. data/lib/mutant/mutator/node/named_value/variable_assignment.rb +1 -1
  29. data/lib/mutant/mutator/node/noop.rb +1 -1
  30. data/lib/mutant/mutator/node/op_asgn.rb +15 -1
  31. data/lib/mutant/mutator/node/send.rb +25 -1
  32. data/lib/mutant/mutator/node/send/attribute_assignment.rb +1 -0
  33. data/lib/mutant/reporter/cli/printer/isolation_result.rb +9 -3
  34. data/lib/mutant/subject/method/instance.rb +1 -1
  35. data/lib/mutant/version.rb +1 -1
  36. metadata +18 -336
  37. data/.github/workflows/ci.yml +0 -121
  38. data/.gitignore +0 -38
  39. data/.rspec +0 -5
  40. data/.rubocop.yml +0 -210
  41. data/Changelog.md +0 -87
  42. data/Gemfile +0 -7
  43. data/Gemfile.lock +0 -107
  44. data/Gemfile.shared +0 -10
  45. data/README.md +0 -199
  46. data/Rakefile +0 -5
  47. data/config/devtools.yml +0 -2
  48. data/config/reek.yml +0 -139
  49. data/config/yardstick.yml +0 -2
  50. data/docs/commercial-support.md +0 -14
  51. data/docs/concurrency.md +0 -39
  52. data/docs/incremental.md +0 -76
  53. data/docs/known-problems.md +0 -30
  54. data/docs/limitations.md +0 -50
  55. data/docs/mutant-minitest.md +0 -149
  56. data/docs/mutant-rspec.md +0 -130
  57. data/docs/nomenclature.md +0 -82
  58. data/docs/reading-reports.md +0 -74
  59. data/lib/mutant/mutator/node/dsym.rb +0 -22
  60. data/meta/and.rb +0 -13
  61. data/meta/and_asgn.rb +0 -14
  62. data/meta/array.rb +0 -27
  63. data/meta/begin.rb +0 -20
  64. data/meta/block.rb +0 -199
  65. data/meta/block_pass.rb +0 -8
  66. data/meta/blockarg.rb +0 -10
  67. data/meta/break.rb +0 -9
  68. data/meta/case.rb +0 -217
  69. data/meta/casgn.rb +0 -25
  70. data/meta/cbase.rb +0 -8
  71. data/meta/class.rb +0 -12
  72. data/meta/const.rb +0 -17
  73. data/meta/csend.rb +0 -10
  74. data/meta/cvar.rb +0 -7
  75. data/meta/cvasgn.rb +0 -9
  76. data/meta/date.rb +0 -59
  77. data/meta/def.rb +0 -196
  78. data/meta/defined.rb +0 -9
  79. data/meta/dstr.rb +0 -13
  80. data/meta/dsym.rb +0 -14
  81. data/meta/ensure.rb +0 -8
  82. data/meta/false.rb +0 -7
  83. data/meta/file.rb +0 -5
  84. data/meta/float.rb +0 -37
  85. data/meta/gvar.rb +0 -7
  86. data/meta/gvasgn.rb +0 -9
  87. data/meta/hash.rb +0 -20
  88. data/meta/if.rb +0 -72
  89. data/meta/index.rb +0 -133
  90. data/meta/indexasgn.rb +0 -31
  91. data/meta/int.rb +0 -18
  92. data/meta/ivar.rb +0 -8
  93. data/meta/ivasgn.rb +0 -22
  94. data/meta/kwarg.rb +0 -10
  95. data/meta/kwbegin.rb +0 -8
  96. data/meta/kwoptarg.rb +0 -13
  97. data/meta/lambda.rb +0 -23
  98. data/meta/line.rb +0 -5
  99. data/meta/lvar.rb +0 -16
  100. data/meta/lvasgn.rb +0 -24
  101. data/meta/masgn.rb +0 -7
  102. data/meta/match_current_line.rb +0 -14
  103. data/meta/next.rb +0 -10
  104. data/meta/nil.rb +0 -5
  105. data/meta/nthref.rb +0 -14
  106. data/meta/op_assgn.rb +0 -17
  107. data/meta/or.rb +0 -13
  108. data/meta/or_asgn.rb +0 -50
  109. data/meta/range.rb +0 -65
  110. data/meta/redo.rb +0 -5
  111. data/meta/regexp.rb +0 -80
  112. data/meta/regopt.rb +0 -10
  113. data/meta/rescue.rb +0 -84
  114. data/meta/return.rb +0 -16
  115. data/meta/sclass.rb +0 -12
  116. data/meta/self.rb +0 -7
  117. data/meta/send.rb +0 -600
  118. data/meta/str.rb +0 -7
  119. data/meta/super.rb +0 -27
  120. data/meta/sym.rb +0 -8
  121. data/meta/true.rb +0 -7
  122. data/meta/until.rb +0 -16
  123. data/meta/while.rb +0 -24
  124. data/meta/yield.rb +0 -9
  125. data/mutant-minitest.gemspec +0 -22
  126. data/mutant-rspec.gemspec +0 -22
  127. data/mutant.gemspec +0 -44
  128. data/mutant.sh +0 -12
  129. data/mutant.yml +0 -6
  130. data/spec/integration/mutant/corpus_spec.rb +0 -15
  131. data/spec/integration/mutant/isolation/fork_spec.rb +0 -28
  132. data/spec/integration/mutant/minitest_spec.rb +0 -11
  133. data/spec/integration/mutant/null_spec.rb +0 -16
  134. data/spec/integration/mutant/rspec_spec.rb +0 -15
  135. data/spec/integration/mutant/test_mutator_handles_types_spec.rb +0 -9
  136. data/spec/integrations.yml +0 -63
  137. data/spec/shared/framework_integration_behavior.rb +0 -70
  138. data/spec/shared/method_matcher_behavior.rb +0 -47
  139. data/spec/spec_helper.rb +0 -90
  140. data/spec/support/corpus.rb +0 -318
  141. data/spec/support/file_system.rb +0 -62
  142. data/spec/support/ice_nine_config.rb +0 -10
  143. data/spec/support/ruby_vm.rb +0 -84
  144. data/spec/support/shared_context.rb +0 -169
  145. data/spec/support/xspec.rb +0 -183
  146. data/spec/unit/mutant/ast/find_metaclass_containing_spec.rb +0 -64
  147. data/spec/unit/mutant/ast/meta/optarg_spec.rb +0 -24
  148. data/spec/unit/mutant/ast/meta/send/proc_predicate_spec.rb +0 -30
  149. data/spec/unit/mutant/ast/meta/send/receiver_possible_top_level_const_predicate_spec.rb +0 -39
  150. data/spec/unit/mutant/ast/meta/send_spec.rb +0 -42
  151. data/spec/unit/mutant/ast/named_children_spec.rb +0 -89
  152. data/spec/unit/mutant/ast/sexp_spec.rb +0 -38
  153. data/spec/unit/mutant/ast_spec.rb +0 -57
  154. data/spec/unit/mutant/bootstrap_spec.rb +0 -216
  155. data/spec/unit/mutant/cli_spec.rb +0 -305
  156. data/spec/unit/mutant/clock_monotonic_spec.rb +0 -52
  157. data/spec/unit/mutant/config_spec.rb +0 -126
  158. data/spec/unit/mutant/context_spec.rb +0 -111
  159. data/spec/unit/mutant/env_spec.rb +0 -229
  160. data/spec/unit/mutant/expression/method_spec.rb +0 -62
  161. data/spec/unit/mutant/expression/methods_spec.rb +0 -66
  162. data/spec/unit/mutant/expression/namespace/exact_spec.rb +0 -28
  163. data/spec/unit/mutant/expression/namespace/recursive_spec.rb +0 -66
  164. data/spec/unit/mutant/expression/parser_spec.rb +0 -65
  165. data/spec/unit/mutant/expression_spec.rb +0 -45
  166. data/spec/unit/mutant/integration/rspec_spec.rb +0 -201
  167. data/spec/unit/mutant/integration_spec.rb +0 -150
  168. data/spec/unit/mutant/isolation/fork_spec.rb +0 -309
  169. data/spec/unit/mutant/isolation/none_spec.rb +0 -23
  170. data/spec/unit/mutant/isolation/result_spec.rb +0 -73
  171. data/spec/unit/mutant/license_spec.rb +0 -305
  172. data/spec/unit/mutant/loader_spec.rb +0 -79
  173. data/spec/unit/mutant/matcher/chain_spec.rb +0 -26
  174. data/spec/unit/mutant/matcher/compiler_spec.rb +0 -0
  175. data/spec/unit/mutant/matcher/config_spec.rb +0 -47
  176. data/spec/unit/mutant/matcher/filter_spec.rb +0 -22
  177. data/spec/unit/mutant/matcher/method/instance_spec.rb +0 -164
  178. data/spec/unit/mutant/matcher/method/metaclass_spec.rb +0 -108
  179. data/spec/unit/mutant/matcher/method/singleton_spec.rb +0 -90
  180. data/spec/unit/mutant/matcher/methods/instance_spec.rb +0 -54
  181. data/spec/unit/mutant/matcher/methods/metaclass_spec.rb +0 -62
  182. data/spec/unit/mutant/matcher/methods/singleton_spec.rb +0 -51
  183. data/spec/unit/mutant/matcher/namespace_spec.rb +0 -39
  184. data/spec/unit/mutant/matcher/null_spec.rb +0 -12
  185. data/spec/unit/mutant/matcher/scope_spec.rb +0 -45
  186. data/spec/unit/mutant/matcher/static_spec.rb +0 -13
  187. data/spec/unit/mutant/matcher_spec.rb +0 -102
  188. data/spec/unit/mutant/meta/example/dsl_spec.rb +0 -108
  189. data/spec/unit/mutant/meta/example/verification_spec.rb +0 -154
  190. data/spec/unit/mutant/meta/example_spec.rb +0 -34
  191. data/spec/unit/mutant/mutation_spec.rb +0 -140
  192. data/spec/unit/mutant/mutator/node_spec.rb +0 -47
  193. data/spec/unit/mutant/mutator_spec.rb +0 -21
  194. data/spec/unit/mutant/parallel/driver_spec.rb +0 -126
  195. data/spec/unit/mutant/parallel/source/array_spec.rb +0 -57
  196. data/spec/unit/mutant/parallel/worker_spec.rb +0 -206
  197. data/spec/unit/mutant/parallel_spec.rb +0 -115
  198. data/spec/unit/mutant/parser_spec.rb +0 -26
  199. data/spec/unit/mutant/range_spec.rb +0 -141
  200. data/spec/unit/mutant/registry_spec.rb +0 -74
  201. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +0 -17
  202. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +0 -85
  203. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +0 -45
  204. data/spec/unit/mutant/reporter/cli/printer/isolation_result_spec.rb +0 -132
  205. data/spec/unit/mutant/reporter/cli/printer/mutation_progress_result_spec.rb +0 -25
  206. data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +0 -153
  207. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +0 -45
  208. data/spec/unit/mutant/reporter/cli/printer/subject_progress_spec.rb +0 -36
  209. data/spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb +0 -44
  210. data/spec/unit/mutant/reporter/cli/printer/test_result_spec.rb +0 -16
  211. data/spec/unit/mutant/reporter/cli/printer_spec.rb +0 -163
  212. data/spec/unit/mutant/reporter/cli_spec.rb +0 -137
  213. data/spec/unit/mutant/reporter/null_spec.rb +0 -14
  214. data/spec/unit/mutant/reporter/sequence_spec.rb +0 -31
  215. data/spec/unit/mutant/repository/diff/ranges_spec.rb +0 -180
  216. data/spec/unit/mutant/repository/diff_spec.rb +0 -122
  217. data/spec/unit/mutant/repository/subject_filter_spec.rb +0 -30
  218. data/spec/unit/mutant/require_highjack_spec.rb +0 -73
  219. data/spec/unit/mutant/result/class_methods_spec.rb +0 -51
  220. data/spec/unit/mutant/result/env_spec.rb +0 -161
  221. data/spec/unit/mutant/result/mutation_spec.rb +0 -70
  222. data/spec/unit/mutant/result/subject_spec.rb +0 -111
  223. data/spec/unit/mutant/result/test_spec.rb +0 -14
  224. data/spec/unit/mutant/result_spec.rb +0 -33
  225. data/spec/unit/mutant/runner/sink_spec.rb +0 -174
  226. data/spec/unit/mutant/runner_spec.rb +0 -121
  227. data/spec/unit/mutant/selector/expression_spec.rb +0 -62
  228. data/spec/unit/mutant/selector/null_spec.rb +0 -17
  229. data/spec/unit/mutant/subject/method/instance_spec.rb +0 -276
  230. data/spec/unit/mutant/subject/method/metaclass_spec.rb +0 -63
  231. data/spec/unit/mutant/subject/method/singleton_spec.rb +0 -61
  232. data/spec/unit/mutant/subject_spec.rb +0 -93
  233. data/spec/unit/mutant/transform/array_spec.rb +0 -92
  234. data/spec/unit/mutant/transform/bool_spec.rb +0 -63
  235. data/spec/unit/mutant/transform/error_spec.rb +0 -132
  236. data/spec/unit/mutant/transform/exception_spec.rb +0 -44
  237. data/spec/unit/mutant/transform/hash_spec.rb +0 -236
  238. data/spec/unit/mutant/transform/index_spec.rb +0 -92
  239. data/spec/unit/mutant/transform/named_spec.rb +0 -49
  240. data/spec/unit/mutant/transform/primitive_spec.rb +0 -56
  241. data/spec/unit/mutant/transform/sequence_spec.rb +0 -98
  242. data/spec/unit/mutant/util/one_spec.rb +0 -22
  243. data/spec/unit/mutant/warnings_spec.rb +0 -89
  244. data/spec/unit/mutant/world_spec.rb +0 -63
  245. data/spec/unit/mutant/zombifier_spec.rb +0 -122
  246. data/test_app/.rspec +0 -1
  247. data/test_app/Gemfile.minitest +0 -6
  248. data/test_app/Gemfile.rspec3.8 +0 -7
  249. data/test_app/lib/test_app.rb +0 -114
  250. data/test_app/lib/test_app/literal.rb +0 -35
  251. data/test_app/lib/test_app/metaclasses.rb +0 -108
  252. data/test_app/spec/spec_helper.rb +0 -9
  253. data/test_app/spec/unit/test_app/literal_spec.rb +0 -20
  254. data/test_app/test/unit/test_app/literal_test.rb +0 -16
@@ -1,62 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module MutantSpec
4
- class FileState
5
- DEFAULTS = IceNine.deep_freeze(
6
- file: false,
7
- contents: nil,
8
- requires: []
9
- )
10
-
11
- include Adamantium, Anima.new(*DEFAULTS.keys)
12
-
13
- def self.new(attributes = DEFAULTS)
14
- super(DEFAULTS.merge(attributes))
15
- end
16
-
17
- DOES_NOT_EXIST = new
18
-
19
- alias_method :file?, :file
20
- end # FileState
21
-
22
- class FakePathname
23
- include Adamantium, Concord.new(:file_system, :pathname)
24
-
25
- def join(*arguments)
26
- self.class.new(
27
- file_system,
28
- pathname.join(*arguments)
29
- )
30
- end
31
-
32
- def read
33
- state.contents
34
- end
35
-
36
- def to_s
37
- pathname.to_s
38
- end
39
-
40
- def file?
41
- state.file?
42
- end
43
-
44
- private
45
-
46
- def state
47
- file_system.state(pathname.to_s)
48
- end
49
- end # FakePathname
50
-
51
- class FileSystem
52
- include Adamantium, Concord.new(:file_states)
53
-
54
- def state(filename)
55
- file_states.fetch(filename, FileState::DOES_NOT_EXIST)
56
- end
57
-
58
- def path(filename)
59
- FakePathname.new(self, Pathname.new(filename))
60
- end
61
- end # FileSystem
62
- end # MutantSpec
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'ice_nine'
4
-
5
- module IceNine
6
- class Freezer
7
- class RSpec < NoFreeze
8
- end # RSpec
9
- end # Freezer
10
- end # IceNine
@@ -1,84 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module MutantSpec
4
- # Not a real VM, just kidding. It connects the require / eval triggers
5
- # require semantics Zombifier relies on in a way we can avoid having to
6
- # mock around everywhere to test every detail.
7
- class RubyVM
8
- include Concord::Public.new(:expected_events)
9
-
10
- # An event being observed by the VM handlers
11
- class EventObservation
12
- include Concord::Public.new(:type, :payload)
13
- end # EventObservation
14
-
15
- # An event being expected, can advance the VM
16
- class EventExpectation
17
- include AbstractType, Anima.new(
18
- :expected_payload,
19
- :trigger_requires,
20
- :return_value
21
- )
22
-
23
- DEFAULTS = IceNine.deep_freeze(trigger_requires: [])
24
-
25
- def initialize(attributes)
26
- super(DEFAULTS.merge(attributes))
27
- end
28
-
29
- def handle(vm, observation) # rubocop:disable Naming/MethodParameterName
30
- unless match?(observation)
31
- fail "Unexpected event observation: #{observation.inspect}, expected #{inspect}"
32
- end
33
-
34
- trigger_requires.each(&vm.method(:require))
35
-
36
- self
37
- end
38
-
39
- private
40
-
41
- def match?(observation)
42
- observation.type.eql?(self.class) && observation.payload.eql?(expected_payload)
43
- end
44
-
45
- # Expectation and advance on require calls
46
- class Require < self
47
- end # Require
48
-
49
- # Expectation and advance on eval calls
50
- class Eval < self
51
- end # Eval
52
- end # EventExpectation
53
-
54
- # A fake implementation of Kernel#require
55
- def require(logical_name)
56
- handle_event(EventObservation.new(EventExpectation::Require, logical_name: logical_name))
57
- end
58
-
59
- # A fake implementation of Kernel#eval
60
- def eval(source, binding, location)
61
- handle_event(
62
- EventObservation.new(
63
- EventExpectation::Eval,
64
- binding: binding,
65
- source: source,
66
- source_location: location
67
- )
68
- )
69
- end
70
-
71
- # Test if VM events where fully processed
72
- def done?
73
- expected_events.empty?
74
- end
75
-
76
- private
77
-
78
- def handle_event(observation)
79
- fail "Unexpected event: #{observation.type} / #{observation.payload}" if expected_events.empty?
80
-
81
- expected_events.slice!(0).handle(self, observation).return_value
82
- end
83
- end # RubyVM
84
- end # MutantSpec
@@ -1,169 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # rubocop:disable Metrics/ModuleLength
4
- module SharedContext
5
- # Prepend an anonymous module with the new `with` method
6
- #
7
- # Using an anonymous module eliminates warnings where `setup_shared_context`
8
- # is used and one of the shared methods is immediately redefined.
9
- def with(name, &block)
10
- new_definition =
11
- Module.new do
12
- define_method(name) do
13
- super().with(instance_eval(&block))
14
- end
15
- end
16
-
17
- prepend(new_definition)
18
- end
19
-
20
- def it_reports(expected_content)
21
- it 'writes expected report to output' do
22
- described_class.call(output, reportable)
23
- output.rewind
24
- expect(output.read).to eql(expected_content)
25
- end
26
- end
27
-
28
- # rubocop:disable Metrics/MethodLength
29
- # rubocop:disable Metrics/AbcSize
30
- def setup_shared_context
31
- let(:mutation_a) { Mutant::Mutation::Evil.new(subject_a, mutation_a_node) }
32
- let(:mutation_a_node) { s(:false) }
33
- let(:mutation_b) { Mutant::Mutation::Evil.new(subject_a, mutation_b_node) }
34
- let(:mutation_b_node) { s(:nil) }
35
- let(:mutations) { [mutation_a, mutation_b] }
36
- let(:output) { StringIO.new }
37
- let(:subject_a_node) { s(:true) }
38
- let(:test_a) { instance_double(Mutant::Test, identification: 'test-a') }
39
- let(:subjects) { [subject_a] }
40
-
41
- let(:job_a) do
42
- Mutant::Parallel::Source::Job.new(
43
- index: 0,
44
- payload: mutation_a
45
- )
46
- end
47
-
48
- let(:job_b) do
49
- Mutant::Parallel::Source::Job.new(
50
- index: 1,
51
- payload: mutation_b
52
- )
53
- end
54
-
55
- let(:env) do
56
- instance_double(
57
- Mutant::Env,
58
- amount_mutations: mutations.length,
59
- amount_selected_tests: selections.values.flatten.to_set.length,
60
- amount_subjects: subjects.length,
61
- amount_total_tests: integration.all_tests.length,
62
- config: config,
63
- integration: integration,
64
- mutations: mutations,
65
- selected_tests: [test_a].to_set,
66
- selections: selections,
67
- subjects: subjects,
68
- test_subject_ratio: Rational(1)
69
- )
70
- end
71
-
72
- let(:selections) do
73
- { subject_a => [test_a] }
74
- end
75
-
76
- let(:integration) do
77
- instance_double(
78
- Mutant::Integration,
79
- all_tests: [test_a]
80
- )
81
- end
82
-
83
- let(:status) do
84
- Mutant::Parallel::Status.new(
85
- active_jobs: [].to_set,
86
- payload: env_result,
87
- done: true
88
- )
89
- end
90
-
91
- let(:config) do
92
- Mutant::Config::DEFAULT.with(
93
- jobs: 1,
94
- reporter: Mutant::Reporter::Null.new
95
- )
96
- end
97
-
98
- let(:subject_a) do
99
- instance_double(
100
- Mutant::Subject,
101
- node: subject_a_node,
102
- source: Unparser.unparse(subject_a_node),
103
- identification: 'subject-a'
104
- )
105
- end
106
-
107
- before do
108
- allow(subject_a).to receive(:mutations).and_return([mutation_a, mutation_b])
109
- end
110
-
111
- let(:env_result) do
112
- Mutant::Result::Env.new(
113
- env: env,
114
- runtime: 4.0,
115
- subject_results: [subject_a_result]
116
- )
117
- end
118
-
119
- let(:mutation_a_result) do
120
- Mutant::Result::Mutation.new(
121
- mutation: mutation_a,
122
- isolation_result: mutation_a_isolation_result,
123
- runtime: 1.0
124
- )
125
- end
126
-
127
- let(:mutation_b_result) do
128
- Mutant::Result::Mutation.new(
129
- isolation_result: mutation_b_isolation_result,
130
- mutation: mutation_b,
131
- runtime: 1.0
132
- )
133
- end
134
-
135
- let(:mutation_a_isolation_result) do
136
- Mutant::Isolation::Result::Success.new(mutation_a_test_result)
137
- end
138
-
139
- let(:mutation_a_test_result) do
140
- Mutant::Result::Test.new(
141
- tests: [test_a],
142
- passed: false,
143
- runtime: 1.0,
144
- output: 'mutation a test result output'
145
- )
146
- end
147
-
148
- let(:mutation_b_test_result) do
149
- Mutant::Result::Test.new(
150
- tests: [test_a],
151
- passed: false,
152
- runtime: 1.0,
153
- output: 'mutation b test result output'
154
- )
155
- end
156
-
157
- let(:mutation_b_isolation_result) do
158
- Mutant::Isolation::Result::Success.new(mutation_b_test_result)
159
- end
160
-
161
- let(:subject_a_result) do
162
- Mutant::Result::Subject.new(
163
- subject: subject_a,
164
- tests: [test_a],
165
- mutation_results: [mutation_a_result, mutation_b_result]
166
- )
167
- end
168
- end
169
- end # SharedContext
@@ -1,183 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module XSpec
4
- class MessageReaction
5
- include Concord.new(:event_list)
6
-
7
- TERMINATE_EVENTS = IceNine.deep_freeze(%i[return exception].to_set)
8
- VALID_EVENTS = IceNine.deep_freeze(%i[return execute exception yields].to_set)
9
-
10
- private_constant(*constants(false))
11
-
12
- def call(observation)
13
- event_list.map do |event, object|
14
- __send__(event, observation, object)
15
- end.last
16
- end
17
-
18
- # Parse events into reaction
19
- #
20
- # @param [Array{Symbol,Object}, Hash{Symbol,Object}]
21
- #
22
- # @return [MessageReaction]
23
- def self.parse(events)
24
- event_list = events.to_a
25
- assert_valid(event_list)
26
- new(event_list)
27
- end
28
-
29
- private
30
-
31
- def return(_event, value)
32
- value
33
- end
34
-
35
- def execute(_event, block)
36
- block.call
37
- end
38
-
39
- def exception(_event, exception)
40
- fail exception
41
- end
42
-
43
- def yields(observation, yields)
44
- block = observation.block or fail 'No block passed where expected'
45
-
46
- validate_block_arity(observation, yields)
47
-
48
- block.call(*yields)
49
- end
50
-
51
- def validate_block_arity(observation, yields)
52
- expected, observed = yields.length, observation.block.arity
53
-
54
- # block allows anything we can skip the check
55
- return if observed.equal?(-1)
56
- fail 'Optargs currently not supported' if observed < -1
57
- block_arity_mismatch(observation, expected, observed) unless expected.equal?(observed)
58
- end
59
-
60
- def block_arity_mismatch(observation, expected, observed)
61
- fail "block arity mismatch, expected #{expected} observed #{observed}\nobservation:\n#{observation.inspect}"
62
- end
63
-
64
- alias_method :yields_return, :yields
65
-
66
- def self.assert_valid(event_list)
67
- assert_not_empty(event_list)
68
- assert_valid_events(event_list)
69
- assert_total(event_list)
70
- end
71
- private_class_method :assert_valid
72
-
73
- def self.assert_valid_events(event_list)
74
- event_list.map(&:first).each do |event|
75
- fail "Invalid event: #{event}" unless VALID_EVENTS.include?(event)
76
- end
77
- end
78
- private_class_method :assert_valid_events
79
-
80
- def self.assert_not_empty(event_list)
81
- fail 'no events' if event_list.empty?
82
- end
83
- private_class_method :assert_not_empty
84
-
85
- def self.assert_total(event_list)
86
- return unless event_list[0..-2].map(&:first).any?(&TERMINATE_EVENTS.method(:include?))
87
-
88
- fail "Reaction not total: #{event_list}"
89
- end
90
- private_class_method :assert_total
91
- end # MessageReaction
92
-
93
- class MessageExpectation
94
- include Anima.new(:receiver, :selector, :arguments, :reaction)
95
-
96
- # rubocop:disable Metrics/ParameterLists
97
- def self.parse(receiver:, selector:, arguments: [], reaction: nil)
98
- new(
99
- receiver: receiver,
100
- selector: selector,
101
- arguments: arguments,
102
- reaction: MessageReaction.parse(reaction || { return: nil })
103
- )
104
- end
105
-
106
- def call(observation)
107
- Verifier.new(self, observation).call
108
- end
109
-
110
- class Verifier
111
- include Concord.new(:expectation, :observation)
112
-
113
- VERIFIED_ATTRIBUTES = IceNine.deep_freeze(%i[receiver selector arguments])
114
-
115
- def call
116
- VERIFIED_ATTRIBUTES.each(&method(:assert_expected_attribute))
117
-
118
- expectation.reaction.call(observation)
119
- end
120
-
121
- private
122
-
123
- def assert_expected_attribute(name)
124
- error("#{name} mismatch") unless observation.public_send(name).eql?(expectation.public_send(name))
125
- end
126
-
127
- def error(message)
128
- fail "#{message},\n observation:\n #{observation.inspect}\n expectation:\n #{expectation.inspect}"
129
- end
130
-
131
- def trigger_exception
132
- exception = expectation.exception
133
- fail exception if exception
134
- end
135
-
136
- end # Verifier
137
- end # MessageExpectation
138
-
139
- class MessageObservation
140
- include Anima.new(:receiver, :selector, :arguments, :block)
141
- end # MessageObservation
142
-
143
- class ExpectationVerifier
144
- include Concord.new(:expectations)
145
-
146
- def call(observation)
147
- expectation = expectations.shift or fail "No expected message but observed #{observation.inspect}"
148
- expectation.call(observation)
149
- end
150
-
151
- def assert_done
152
- expectations.empty? or fail "unconsumed expectations:\n#{expectations.map(&:inspect).join("\n")}"
153
- end
154
-
155
- # rubocop:disable Metrics/MethodLength
156
- def self.verify(rspec_context, expectations)
157
- verifier = new(expectations)
158
-
159
- hooks = expectations
160
- .map { |expectation| [expectation.receiver, expectation.selector] }
161
- .to_set
162
-
163
- hooks.each do |receiver, selector|
164
- rspec_context.instance_eval do
165
- allow(receiver).to receive(selector) do |*arguments, &block|
166
- verifier.call(
167
- MessageObservation.new(
168
- receiver: receiver,
169
- selector: selector,
170
- arguments: arguments,
171
- block: block
172
- )
173
- )
174
- end
175
- end
176
- end
177
-
178
- yield
179
-
180
- verifier.assert_done
181
- end
182
- end # ExpectationVerifier
183
- end # XSpec