mutant 0.8.24 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (218) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +3 -3
  3. data/Changelog.md +14 -654
  4. data/Gemfile +13 -0
  5. data/Gemfile.lock +59 -64
  6. data/LICENSE +271 -20
  7. data/README.md +73 -140
  8. data/Rakefile +0 -21
  9. data/bin/mutant +7 -2
  10. data/config/reek.yml +2 -1
  11. data/config/rubocop.yml +5 -9
  12. data/docs/incremental.md +76 -0
  13. data/docs/known-problems.md +0 -14
  14. data/docs/mutant-minitest.md +1 -1
  15. data/docs/mutant-rspec.md +2 -24
  16. data/lib/mutant.rb +45 -53
  17. data/lib/mutant/ast/nodes.rb +0 -2
  18. data/lib/mutant/ast/types.rb +1 -117
  19. data/lib/mutant/base.rb +192 -0
  20. data/lib/mutant/bootstrap.rb +145 -0
  21. data/lib/mutant/cli.rb +68 -54
  22. data/lib/mutant/config.rb +119 -6
  23. data/lib/mutant/env.rb +94 -8
  24. data/lib/mutant/expression.rb +6 -1
  25. data/lib/mutant/expression/parser.rb +9 -31
  26. data/lib/mutant/integration.rb +64 -36
  27. data/lib/mutant/isolation.rb +16 -1
  28. data/lib/mutant/isolation/fork.rb +105 -40
  29. data/lib/mutant/license.rb +34 -0
  30. data/lib/mutant/license/subscription.rb +47 -0
  31. data/lib/mutant/license/subscription/commercial.rb +57 -0
  32. data/lib/mutant/license/subscription/opensource.rb +77 -0
  33. data/lib/mutant/loader.rb +27 -4
  34. data/lib/mutant/matcher.rb +48 -1
  35. data/lib/mutant/matcher/chain.rb +1 -1
  36. data/lib/mutant/matcher/config.rb +0 -2
  37. data/lib/mutant/matcher/filter.rb +1 -1
  38. data/lib/mutant/matcher/method.rb +11 -7
  39. data/lib/mutant/matcher/methods.rb +1 -1
  40. data/lib/mutant/matcher/namespace.rb +1 -1
  41. data/lib/mutant/matcher/null.rb +1 -1
  42. data/lib/mutant/matcher/scope.rb +1 -1
  43. data/lib/mutant/meta/example/dsl.rb +0 -8
  44. data/lib/mutant/mutation.rb +1 -2
  45. data/lib/mutant/mutator/node.rb +2 -9
  46. data/lib/mutant/mutator/node/arguments.rb +1 -1
  47. data/lib/mutant/mutator/node/class.rb +0 -8
  48. data/lib/mutant/mutator/node/define.rb +0 -12
  49. data/lib/mutant/mutator/node/generic.rb +30 -44
  50. data/lib/mutant/mutator/node/index.rb +4 -4
  51. data/lib/mutant/mutator/node/literal/regex.rb +0 -39
  52. data/lib/mutant/mutator/node/send.rb +13 -12
  53. data/lib/mutant/parallel.rb +61 -40
  54. data/lib/mutant/parallel/driver.rb +59 -0
  55. data/lib/mutant/parallel/source.rb +6 -2
  56. data/lib/mutant/parallel/worker.rb +63 -45
  57. data/lib/mutant/range.rb +15 -0
  58. data/lib/mutant/reporter/cli.rb +5 -11
  59. data/lib/mutant/reporter/cli/format.rb +3 -46
  60. data/lib/mutant/reporter/cli/printer/config.rb +5 -6
  61. data/lib/mutant/reporter/cli/printer/env.rb +40 -0
  62. data/lib/mutant/reporter/cli/printer/env_progress.rb +13 -17
  63. data/lib/mutant/reporter/cli/printer/isolation_result.rb +17 -3
  64. data/lib/mutant/reporter/cli/printer/mutation_result.rb +2 -3
  65. data/lib/mutant/reporter/cli/printer/status_progressive.rb +19 -10
  66. data/lib/mutant/repository.rb +0 -65
  67. data/lib/mutant/repository/diff.rb +104 -0
  68. data/lib/mutant/repository/diff/ranges.rb +52 -0
  69. data/lib/mutant/result.rb +16 -7
  70. data/lib/mutant/runner.rb +38 -47
  71. data/lib/mutant/runner/sink.rb +1 -1
  72. data/lib/mutant/selector/null.rb +19 -0
  73. data/lib/mutant/subject.rb +3 -1
  74. data/lib/mutant/subject/method/instance.rb +3 -1
  75. data/lib/mutant/transform.rb +511 -0
  76. data/lib/mutant/variable.rb +282 -0
  77. data/lib/mutant/version.rb +1 -1
  78. data/lib/mutant/warnings.rb +113 -0
  79. data/meta/case.rb +1 -0
  80. data/meta/class.rb +0 -9
  81. data/meta/def.rb +1 -26
  82. data/meta/regexp.rb +10 -20
  83. data/meta/send.rb +14 -46
  84. data/mutant-minitest.gemspec +1 -1
  85. data/mutant-rspec.gemspec +2 -2
  86. data/mutant.gemspec +15 -16
  87. data/mutant.yml +6 -0
  88. data/spec/integration/mutant/isolation/fork_spec.rb +22 -5
  89. data/spec/integration/mutant/minitest_spec.rb +3 -2
  90. data/spec/integration/mutant/rspec_spec.rb +4 -3
  91. data/spec/integrations.yml +16 -13
  92. data/spec/shared/base_behavior.rb +45 -0
  93. data/spec/shared/framework_integration_behavior.rb +43 -14
  94. data/spec/spec_helper.rb +21 -17
  95. data/spec/support/corpus.rb +56 -95
  96. data/spec/support/shared_context.rb +37 -14
  97. data/spec/support/xspec.rb +7 -3
  98. data/spec/unit/mutant/bootstrap_spec.rb +216 -0
  99. data/spec/unit/mutant/cli_spec.rb +173 -117
  100. data/spec/unit/mutant/config_spec.rb +126 -0
  101. data/spec/unit/mutant/either_spec.rb +247 -0
  102. data/spec/unit/mutant/env_spec.rb +162 -40
  103. data/spec/unit/mutant/expression/method_spec.rb +16 -0
  104. data/spec/unit/mutant/expression/parser_spec.rb +29 -33
  105. data/spec/unit/mutant/expression_spec.rb +5 -7
  106. data/spec/unit/mutant/integration_spec.rb +100 -9
  107. data/spec/unit/mutant/isolation/fork_spec.rb +125 -67
  108. data/spec/unit/mutant/isolation/result_spec.rb +33 -1
  109. data/spec/unit/mutant/license_spec.rb +257 -0
  110. data/spec/unit/mutant/loader_spec.rb +50 -11
  111. data/spec/unit/mutant/matcher/compiler_spec.rb +0 -78
  112. data/spec/unit/mutant/matcher/method/instance_spec.rb +55 -11
  113. data/spec/unit/mutant/matcher/method/singleton_spec.rb +12 -2
  114. data/spec/unit/mutant/matcher_spec.rb +102 -0
  115. data/spec/unit/mutant/maybe_spec.rb +60 -0
  116. data/spec/unit/mutant/meta/example/dsl_spec.rb +1 -17
  117. data/spec/unit/mutant/mutation_spec.rb +13 -6
  118. data/spec/unit/mutant/parallel/driver_spec.rb +112 -14
  119. data/spec/unit/mutant/parallel/source/array_spec.rb +25 -17
  120. data/spec/unit/mutant/parallel/worker_spec.rb +182 -44
  121. data/spec/unit/mutant/parallel_spec.rb +105 -8
  122. data/spec/unit/mutant/range_spec.rb +141 -0
  123. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +7 -21
  124. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +15 -6
  125. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +10 -2
  126. data/spec/unit/mutant/reporter/cli/printer/isolation_result_spec.rb +12 -4
  127. data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +31 -2
  128. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +4 -4
  129. data/spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb +5 -0
  130. data/spec/unit/mutant/reporter/cli_spec.rb +46 -123
  131. data/spec/unit/mutant/repository/diff/ranges_spec.rb +180 -0
  132. data/spec/unit/mutant/repository/diff_spec.rb +84 -71
  133. data/spec/unit/mutant/require_highjack_spec.rb +1 -1
  134. data/spec/unit/mutant/result/env_spec.rb +39 -9
  135. data/spec/unit/mutant/result/test_spec.rb +14 -0
  136. data/spec/unit/mutant/runner_spec.rb +88 -41
  137. data/spec/unit/mutant/selector/expression_spec.rb +11 -10
  138. data/spec/unit/mutant/selector/null_spec.rb +17 -0
  139. data/spec/unit/mutant/subject/method/instance_spec.rb +44 -5
  140. data/spec/unit/mutant/subject/method/singleton_spec.rb +9 -2
  141. data/spec/unit/mutant/subject_spec.rb +9 -1
  142. data/spec/unit/mutant/transform/array_spec.rb +92 -0
  143. data/spec/unit/mutant/transform/bool_spec.rb +63 -0
  144. data/spec/unit/mutant/transform/error_spec.rb +132 -0
  145. data/spec/unit/mutant/transform/exception_spec.rb +44 -0
  146. data/spec/unit/mutant/transform/hash_spec.rb +236 -0
  147. data/spec/unit/mutant/transform/index_spec.rb +92 -0
  148. data/spec/unit/mutant/transform/named_spec.rb +49 -0
  149. data/spec/unit/mutant/transform/primitive_spec.rb +56 -0
  150. data/spec/unit/mutant/transform/sequence_spec.rb +98 -0
  151. data/spec/unit/mutant/variable_spec.rb +618 -0
  152. data/spec/unit/mutant/warnings_spec.rb +89 -0
  153. data/spec/unit/mutant/world_spec.rb +63 -0
  154. data/test_app/Gemfile.minitest +0 -2
  155. metadata +79 -113
  156. data/.gitattributes +0 -1
  157. data/.ruby-gemset +0 -1
  158. data/config/triage.yml +0 -2
  159. data/lib/mutant/actor.rb +0 -57
  160. data/lib/mutant/actor/env.rb +0 -31
  161. data/lib/mutant/actor/mailbox.rb +0 -34
  162. data/lib/mutant/actor/receiver.rb +0 -42
  163. data/lib/mutant/actor/sender.rb +0 -26
  164. data/lib/mutant/ast/meta/restarg.rb +0 -19
  165. data/lib/mutant/ast/regexp.rb +0 -42
  166. data/lib/mutant/ast/regexp/transformer.rb +0 -187
  167. data/lib/mutant/ast/regexp/transformer/direct.rb +0 -123
  168. data/lib/mutant/ast/regexp/transformer/named_group.rb +0 -59
  169. data/lib/mutant/ast/regexp/transformer/options_group.rb +0 -83
  170. data/lib/mutant/ast/regexp/transformer/quantifier.rb +0 -114
  171. data/lib/mutant/ast/regexp/transformer/recursive.rb +0 -58
  172. data/lib/mutant/ast/regexp/transformer/root.rb +0 -31
  173. data/lib/mutant/ast/regexp/transformer/text.rb +0 -60
  174. data/lib/mutant/env/bootstrap.rb +0 -160
  175. data/lib/mutant/matcher/compiler.rb +0 -60
  176. data/lib/mutant/mutator/node/regexp.rb +0 -35
  177. data/lib/mutant/mutator/node/regexp/alternation_meta.rb +0 -23
  178. data/lib/mutant/mutator/node/regexp/capture_group.rb +0 -28
  179. data/lib/mutant/mutator/node/regexp/character_type.rb +0 -32
  180. data/lib/mutant/mutator/node/regexp/end_of_line_anchor.rb +0 -23
  181. data/lib/mutant/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor.rb +0 -23
  182. data/lib/mutant/mutator/node/regexp/greedy_zero_or_more.rb +0 -27
  183. data/lib/mutant/parallel/master.rb +0 -181
  184. data/lib/mutant/reporter/cli/printer/status.rb +0 -53
  185. data/lib/mutant/reporter/cli/tput.rb +0 -46
  186. data/lib/mutant/warning_filter.rb +0 -61
  187. data/meta/regexp/character_types.rb +0 -23
  188. data/meta/regexp/regexp_alternation_meta.rb +0 -13
  189. data/meta/regexp/regexp_bol_anchor.rb +0 -10
  190. data/meta/regexp/regexp_bos_anchor.rb +0 -18
  191. data/meta/regexp/regexp_capture_group.rb +0 -19
  192. data/meta/regexp/regexp_eol_anchor.rb +0 -10
  193. data/meta/regexp/regexp_eos_anchor.rb +0 -8
  194. data/meta/regexp/regexp_eos_ob_eol_anchor.rb +0 -10
  195. data/meta/regexp/regexp_greedy_zero_or_more.rb +0 -12
  196. data/meta/regexp/regexp_root_expression.rb +0 -10
  197. data/meta/restarg.rb +0 -10
  198. data/spec/support/fake_actor.rb +0 -111
  199. data/spec/support/warning.rb +0 -66
  200. data/spec/unit/mutant/actor/binding_spec.rb +0 -34
  201. data/spec/unit/mutant/actor/env_spec.rb +0 -31
  202. data/spec/unit/mutant/actor/mailbox_spec.rb +0 -28
  203. data/spec/unit/mutant/actor/message_spec.rb +0 -25
  204. data/spec/unit/mutant/actor/receiver_spec.rb +0 -58
  205. data/spec/unit/mutant/actor/sender_spec.rb +0 -24
  206. data/spec/unit/mutant/ast/regexp/parse_spec.rb +0 -19
  207. data/spec/unit/mutant/ast/regexp/transformer/lookup_table/table_spec.rb +0 -21
  208. data/spec/unit/mutant/ast/regexp/transformer/lookup_table_spec.rb +0 -35
  209. data/spec/unit/mutant/ast/regexp/transformer_spec.rb +0 -21
  210. data/spec/unit/mutant/ast/regexp_spec.rb +0 -704
  211. data/spec/unit/mutant/env/bootstrap_spec.rb +0 -188
  212. data/spec/unit/mutant/matcher/compiler/subject_prefix_spec.rb +0 -26
  213. data/spec/unit/mutant/parallel/master_spec.rb +0 -338
  214. data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +0 -121
  215. data/spec/unit/mutant/reporter/cli/tput_spec.rb +0 -50
  216. data/spec/unit/mutant/warning_filter_spec.rb +0 -106
  217. data/spec/unit/mutant_spec.rb +0 -17
  218. data/test_app/Gemfile.rspec3.7 +0 -7
@@ -0,0 +1,247 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe Mutant::Either do
4
+ describe '.wrap_error' do
5
+ def apply
6
+ described_class.wrap_error(error, &block)
7
+ end
8
+
9
+ let(:error) { TestError }
10
+
11
+ class TestError < RuntimeError; end
12
+
13
+ context 'when block returns' do
14
+ let(:value) { instance_double(Object, 'value') }
15
+ let(:block) { -> { value } }
16
+
17
+ it 'returns right wrapping block value' do
18
+ expect(apply).to eql(described_class::Right.new(value))
19
+ end
20
+ end
21
+
22
+ context 'when block raises' do
23
+ let(:exception) { error.new }
24
+ let(:block) { -> { fail exception } }
25
+
26
+ context 'with covered exception' do
27
+ it 'returns left wrapping exception' do
28
+ expect(apply).to eql(described_class::Left.new(exception))
29
+ end
30
+ end
31
+
32
+ context 'with uncovered exception' do
33
+ let(:exception) { StandardError.new }
34
+
35
+ it 'returns raises error' do
36
+ expect { apply }.to raise_error(StandardError)
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ RSpec.describe Mutant::Either::Left do
44
+ subject { described_class.new(value) }
45
+
46
+ let(:block_result) { instance_double(Object, 'block result') }
47
+ let(:value) { instance_double(Object, 'value') }
48
+ let(:yields) { [] }
49
+
50
+ let(:block) do
51
+ lambda do |value|
52
+ yields << value
53
+ block_result
54
+ end
55
+ end
56
+
57
+ class TestError < RuntimeError; end
58
+
59
+ describe '#fmap' do
60
+ def apply
61
+ subject.fmap(&block)
62
+ end
63
+
64
+ include_examples 'no block evaluation'
65
+ include_examples 'requires block'
66
+ include_examples 'returns self'
67
+ end
68
+
69
+ describe '#apply' do
70
+ def apply
71
+ subject.apply(&block)
72
+ end
73
+
74
+ include_examples 'no block evaluation'
75
+ include_examples 'requires block'
76
+ include_examples 'returns self'
77
+ end
78
+
79
+ describe '#from_left' do
80
+ def apply
81
+ subject.from_left(&block)
82
+ end
83
+
84
+ it 'returns left value' do
85
+ expect(apply).to be(value)
86
+ end
87
+
88
+ include_examples 'no block evaluation'
89
+ end
90
+
91
+ describe '#from_right' do
92
+ def apply
93
+ subject.from_right(&block)
94
+ end
95
+
96
+ context 'without block' do
97
+ let(:block) { nil }
98
+
99
+ it 'raises RuntimeError error' do
100
+ expect { apply }.to raise_error(
101
+ RuntimeError,
102
+ "Expected right value, got #{subject.inspect}"
103
+ )
104
+ end
105
+ end
106
+
107
+ context 'with block' do
108
+ let(:yields) { [] }
109
+ let(:block_return) { instance_double(Object, 'block-return') }
110
+
111
+ let(:block) do
112
+ lambda do |value|
113
+ yields << value
114
+ block_return
115
+ end
116
+ end
117
+
118
+ it 'calls block with left value' do
119
+ expect { apply }.to change(yields, :to_a).from([]).to([value])
120
+ end
121
+
122
+ it 'returns block value' do
123
+ expect(apply).to be(block_return)
124
+ end
125
+ end
126
+ end
127
+
128
+ describe '#lmap' do
129
+ def apply
130
+ subject.lmap(&block)
131
+ end
132
+
133
+ include_examples 'requires block'
134
+ include_examples 'Functor#fmap block evaluation'
135
+ end
136
+
137
+ describe '#either' do
138
+ def apply
139
+ subject.either(block, -> { fail })
140
+ end
141
+
142
+ include_examples '#apply block evaluation'
143
+ end
144
+ end
145
+
146
+ RSpec.describe Mutant::Either::Right do
147
+ subject { described_class.new(value) }
148
+
149
+ let(:block_result) { instance_double(Object, 'block result') }
150
+ let(:value) { instance_double(Object, 'value') }
151
+ let(:yields) { [] }
152
+
153
+ let(:block) do
154
+ lambda do |value|
155
+ yields << value
156
+ block_result
157
+ end
158
+ end
159
+
160
+ describe '#fmap' do
161
+ def apply
162
+ subject.fmap(&block)
163
+ end
164
+
165
+ include_examples 'requires block'
166
+ include_examples 'Functor#fmap block evaluation'
167
+ end
168
+
169
+ describe '#apply' do
170
+ def apply
171
+ subject.apply(&block)
172
+ end
173
+
174
+ include_examples 'requires block'
175
+ include_examples '#apply block evaluation'
176
+ end
177
+
178
+ describe '#from_left' do
179
+ def apply
180
+ subject.from_left(&block)
181
+ end
182
+
183
+ context 'without block' do
184
+ let(:block) { nil }
185
+
186
+ it 'raises RuntimeError error' do
187
+ expect { apply }.to raise_error(
188
+ RuntimeError,
189
+ "Expected left value, got #{subject.inspect}"
190
+ )
191
+ end
192
+ end
193
+
194
+ context 'with block' do
195
+ let(:yields) { [] }
196
+ let(:block_return) { instance_double(Object, 'block-return') }
197
+
198
+ let(:block) do
199
+ lambda do |value|
200
+ yields << value
201
+ block_return
202
+ end
203
+ end
204
+
205
+ it 'calls block with right value' do
206
+ expect { apply }.to change(yields, :to_a).from([]).to([value])
207
+ end
208
+
209
+ it 'returns block value' do
210
+ expect(apply).to be(block_return)
211
+ end
212
+ end
213
+ end
214
+
215
+ describe '#from_right' do
216
+ def apply
217
+ subject.from_right(&block)
218
+ end
219
+
220
+ it 'returns right value' do
221
+ expect(apply).to be(value)
222
+ end
223
+
224
+ include_examples 'no block evaluation'
225
+ end
226
+
227
+ describe '#lmap' do
228
+ def apply
229
+ subject.lmap(&block)
230
+ end
231
+
232
+ include_examples 'requires block'
233
+ include_examples 'no block evaluation'
234
+
235
+ it 'returns self' do
236
+ expect(apply).to be(subject)
237
+ end
238
+ end
239
+
240
+ describe '#either' do
241
+ def apply
242
+ subject.either(-> { fail }, block)
243
+ end
244
+
245
+ include_examples '#apply block evaluation'
246
+ end
247
+ end
@@ -1,57 +1,86 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  RSpec.describe Mutant::Env do
4
- let(:object) do
4
+ subject do
5
5
  described_class.new(
6
- actor_env: Mutant::Actor::Env.new(Thread),
7
6
  config: config,
8
7
  integration: integration,
9
8
  matchable_scopes: [],
10
9
  mutations: [],
11
10
  selector: selector,
12
- subjects: [mutation_subject],
13
- parser: Mutant::Parser.new
11
+ subjects: subjects,
12
+ parser: Mutant::Parser.new,
13
+ world: world
14
14
  )
15
15
  end
16
16
 
17
- let(:integration) { instance_double(Mutant::Integration) }
18
- let(:test_a) { instance_double(Mutant::Test) }
19
- let(:test_b) { instance_double(Mutant::Test) }
20
- let(:tests) { [test_a, test_b] }
21
- let(:selector) { instance_double(Mutant::Selector) }
22
17
  let(:integration_class) { Mutant::Integration::Null }
23
18
  let(:isolation) { Mutant::Isolation::None.new }
24
- let(:mutation_subject) { instance_double(Mutant::Subject) }
19
+ let(:kernel) { instance_double(Object, 'kernel') }
20
+ let(:reporter) { instance_double(Mutant::Reporter) }
21
+ let(:selector) { instance_double(Mutant::Selector) }
22
+ let(:subject_a) { instance_double(Mutant::Subject, :a) }
23
+ let(:subject_b) { instance_double(Mutant::Subject, :b) }
24
+ let(:subjects) { [subject_a, subject_b] }
25
+ let(:test_a) { instance_double(Mutant::Test, :a) }
26
+ let(:test_b) { instance_double(Mutant::Test, :b) }
27
+ let(:test_c) { instance_double(Mutant::Test, :c) }
28
+
29
+ let(:integration) do
30
+ instance_double(Mutant::Integration, all_tests: [test_a, test_b, test_c])
31
+ end
25
32
 
26
33
  let(:mutation) do
27
34
  instance_double(
28
35
  Mutant::Mutation,
29
- subject: mutation_subject
36
+ subject: subject_a
30
37
  )
31
38
  end
32
39
 
33
40
  let(:config) do
34
- Mutant::Config::DEFAULT.with(
35
- isolation: isolation,
41
+ instance_double(
42
+ Mutant::Config,
36
43
  integration: integration_class,
37
- kernel: class_double(Kernel)
44
+ isolation: isolation,
45
+ reporter: reporter
46
+ )
47
+ end
48
+
49
+ let(:world) do
50
+ instance_double(
51
+ Mutant::World,
52
+ kernel: kernel
38
53
  )
39
54
  end
40
55
 
41
56
  before do
42
57
  allow(selector).to receive(:call)
43
- .with(mutation_subject)
44
- .and_return(tests)
58
+ .with(subject_a)
59
+ .and_return([test_a, test_b])
60
+
61
+ allow(selector).to receive(:call)
62
+ .with(subject_b)
63
+ .and_return([test_b, test_c])
45
64
 
46
65
  allow(Mutant::Timer).to receive(:now).and_return(2.0, 3.0)
47
66
  end
48
67
 
49
68
  describe '#kill' do
50
- subject { object.kill(mutation) }
69
+ def apply
70
+ subject.kill(mutation)
71
+ end
72
+
73
+ before do
74
+ allow(isolation).to receive(:call) do |&block|
75
+ Mutant::Isolation::Result::Success.new(block.call)
76
+ end
77
+
78
+ allow(mutation).to receive_messages(insert: loader_result)
79
+ end
51
80
 
52
- shared_examples_for 'mutation kill' do
53
- specify do
54
- should eql(
81
+ shared_examples 'mutation kill' do
82
+ it 'returns expected result' do
83
+ expect(apply).to eql(
55
84
  Mutant::Result::Mutation.new(
56
85
  isolation_result: isolation_result,
57
86
  mutation: mutation,
@@ -61,36 +90,41 @@ RSpec.describe Mutant::Env do
61
90
  end
62
91
  end
63
92
 
64
- context 'when isolation does not raise error' do
65
- let(:test_result) { instance_double(Mutant::Result::Test) }
93
+ context 'when loader is successful' do
94
+ let(:loader_result) { Mutant::Loader::Result::Success.instance }
95
+ let(:test_result) { instance_double(Mutant::Result::Test) }
96
+
97
+ let(:isolation_result) do
98
+ Mutant::Isolation::Result::Success.new(test_result)
99
+ end
66
100
 
67
101
  before do
68
- expect(mutation).to receive(:insert)
69
- .ordered
70
- .with(config.kernel)
71
-
72
- expect(integration).to receive(:call)
73
- .ordered
74
- .with(tests)
75
- .and_return(test_result)
102
+ allow(integration).to receive_messages(call: test_result)
76
103
  end
77
104
 
78
- let(:isolation_result) do
79
- Mutant::Isolation::Result::Success.new(test_result)
105
+ it 'performs IO in expected sequence' do
106
+ apply
107
+
108
+ expect(isolation).to have_received(:call).ordered
109
+ expect(mutation).to have_received(:insert).ordered.with(kernel)
110
+ expect(integration).to have_received(:call).ordered.with([test_a, test_b])
80
111
  end
81
112
 
82
113
  include_examples 'mutation kill'
83
114
  end
84
115
 
85
- context 'when code does raise error' do
86
- let(:exception) { RuntimeError.new('foo') }
116
+ context 'when loader reports void value' do
117
+ let(:loader_result) { Mutant::Loader::Result::VoidValue.instance }
87
118
 
88
- before do
89
- expect(mutation).to receive(:insert).and_raise(exception)
119
+ let(:isolation_result) do
120
+ Mutant::Isolation::Result::Success.new(Mutant::Result::Test::VoidValue.instance)
90
121
  end
91
122
 
92
- let(:isolation_result) do
93
- Mutant::Isolation::Result::Exception.new(exception)
123
+ it 'performs IO in expected sequence' do
124
+ apply
125
+
126
+ expect(isolation).to have_received(:call).ordered
127
+ expect(mutation).to have_received(:insert).ordered.with(kernel)
94
128
  end
95
129
 
96
130
  include_examples 'mutation kill'
@@ -98,10 +132,98 @@ RSpec.describe Mutant::Env do
98
132
  end
99
133
 
100
134
  describe '#selections' do
101
- subject { object.selections }
135
+ def apply
136
+ subject.selections
137
+ end
102
138
 
103
139
  it 'returns expected selections' do
104
- expect(subject).to eql(mutation_subject => tests)
140
+ expect(apply).to eql(
141
+ subject_a => [test_a, test_b],
142
+ subject_b => [test_b, test_c]
143
+ )
144
+ end
145
+ end
146
+
147
+ describe '#warn' do
148
+ def apply
149
+ subject.warn(message)
150
+ end
151
+
152
+ before do
153
+ allow(reporter).to receive_messages(warn: reporter)
154
+ end
155
+
156
+ let(:message) { 'test-warning' }
157
+
158
+ it 'warns via the reporter' do
159
+ apply
160
+
161
+ expect(reporter).to have_received(:warn).with(message)
162
+ end
163
+
164
+ it 'returns self' do
165
+ expect(apply).to be(subject)
166
+ end
167
+ end
168
+
169
+ describe '#amount_mutations' do
170
+ def apply
171
+ subject.amount_mutations
172
+ end
173
+
174
+ it 'returns expected value' do
175
+ expect(apply).to be(0)
176
+ end
177
+ end
178
+
179
+ describe '#amount_total_tests' do
180
+ def apply
181
+ subject.amount_total_tests
182
+ end
183
+
184
+ it 'returns expected value' do
185
+ expect(apply).to be(3)
186
+ end
187
+ end
188
+
189
+ describe '#test_subject_ratio' do
190
+ def apply
191
+ subject.test_subject_ratio
192
+ end
193
+
194
+ context 'on empty subjects' do
195
+ let(:subjects) { [] }
196
+
197
+ it 'returns expected value' do
198
+ expect(apply).to eql(Rational(0))
199
+ end
200
+ end
201
+
202
+ context 'on non empty subjects' do
203
+ it 'returns expected value' do
204
+ expect(apply).to eql(Rational(3, 2))
205
+ end
206
+ end
207
+ end
208
+
209
+ describe '.empty' do
210
+ def apply
211
+ described_class.empty(world, config)
212
+ end
213
+
214
+ it 'returns empty env' do
215
+ expect(apply).to eql(
216
+ described_class.new(
217
+ config: config,
218
+ integration: Mutant::Integration::Null.new(config),
219
+ matchable_scopes: Mutant::EMPTY_ARRAY,
220
+ mutations: Mutant::EMPTY_ARRAY,
221
+ parser: Mutant::Parser.new,
222
+ selector: Mutant::Selector::Null.new,
223
+ subjects: Mutant::EMPTY_ARRAY,
224
+ world: world
225
+ )
226
+ )
105
227
  end
106
228
  end
107
229
  end