mutant 0.5.26 → 0.6.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 (127) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -0
  3. data/.travis.yml +1 -0
  4. data/Changelog.md +16 -3
  5. data/Gemfile +0 -2
  6. data/Gemfile.devtools +2 -2
  7. data/README.md +9 -15
  8. data/bin/mutant +0 -1
  9. data/config/flay.yml +1 -1
  10. data/config/flog.yml +1 -1
  11. data/config/mutant.yml +1 -1
  12. data/config/reek.yml +14 -11
  13. data/config/rubocop.yml +1 -1
  14. data/lib/mutant.rb +22 -21
  15. data/lib/mutant/ast.rb +47 -0
  16. data/lib/mutant/cli.rb +7 -4
  17. data/lib/mutant/config.rb +1 -0
  18. data/lib/mutant/context.rb +1 -1
  19. data/lib/mutant/diff.rb +38 -7
  20. data/lib/mutant/env.rb +22 -3
  21. data/lib/mutant/expression.rb +15 -4
  22. data/lib/mutant/integration.rb +1 -1
  23. data/lib/mutant/isolation.rb +2 -4
  24. data/lib/mutant/matcher.rb +1 -1
  25. data/lib/mutant/matcher/method.rb +1 -1
  26. data/lib/mutant/matcher/method/singleton.rb +1 -1
  27. data/lib/mutant/matcher/methods.rb +0 -2
  28. data/lib/mutant/meta/example.rb +0 -2
  29. data/lib/mutant/meta/example/dsl.rb +1 -1
  30. data/lib/mutant/mutator.rb +1 -1
  31. data/lib/mutant/mutator/node.rb +3 -3
  32. data/lib/mutant/mutator/node/begin.rb +1 -1
  33. data/lib/mutant/mutator/node/block.rb +16 -3
  34. data/lib/mutant/mutator/node/if.rb +1 -1
  35. data/lib/mutant/mutator/node/literal/fixnum.rb +1 -1
  36. data/lib/mutant/mutator/node/resbody.rb +0 -2
  37. data/lib/mutant/mutator/node/send.rb +17 -7
  38. data/lib/mutant/mutator/node/send/index.rb +0 -2
  39. data/lib/mutant/mutator/registry.rb +1 -1
  40. data/lib/mutant/mutator/util.rb +1 -1
  41. data/lib/mutant/mutator/util/array.rb +1 -1
  42. data/lib/mutant/reporter.rb +13 -3
  43. data/lib/mutant/reporter/cli.rb +54 -8
  44. data/lib/mutant/reporter/cli/format.rb +197 -0
  45. data/lib/mutant/reporter/cli/printer.rb +402 -22
  46. data/lib/mutant/reporter/cli/tput.rb +27 -0
  47. data/lib/mutant/reporter/null.rb +4 -34
  48. data/lib/mutant/reporter/trace.rb +6 -38
  49. data/lib/mutant/result.rb +44 -56
  50. data/lib/mutant/runner.rb +99 -52
  51. data/lib/mutant/runner/collector.rb +134 -0
  52. data/lib/mutant/subject/method/instance.rb +12 -4
  53. data/lib/mutant/version.rb +1 -1
  54. data/lib/mutant/warning_filter.rb +0 -2
  55. data/lib/mutant/zombifier/file.rb +1 -1
  56. data/meta/block.rb +17 -1
  57. data/meta/send.rb +123 -1
  58. data/mutant-rspec.gemspec +3 -3
  59. data/mutant.gemspec +1 -1
  60. data/spec/integration/mutant/corpus_spec.rb +4 -195
  61. data/spec/integration/mutant/null_spec.rb +1 -3
  62. data/spec/integration/mutant/rspec_spec.rb +1 -3
  63. data/spec/integration/mutant/test_mutator_handles_types_spec.rb +1 -3
  64. data/spec/integration/mutant/zombie_spec.rb +1 -3
  65. data/spec/integrations.yml +7 -0
  66. data/spec/shared/method_matcher_behavior.rb +1 -1
  67. data/spec/spec_helper.rb +1 -0
  68. data/spec/support/compress_helper.rb +1 -0
  69. data/spec/support/corpus.rb +239 -0
  70. data/spec/support/mutation_verifier.rb +2 -4
  71. data/spec/unit/mutant/cli_spec.rb +20 -13
  72. data/spec/unit/mutant/context/root_spec.rb +1 -3
  73. data/spec/unit/mutant/context/scope/root_spec.rb +1 -3
  74. data/spec/unit/mutant/context/scope/unqualified_name_spec.rb +1 -3
  75. data/spec/unit/mutant/diff_spec.rb +37 -19
  76. data/spec/unit/mutant/expression/method_spec.rb +5 -7
  77. data/spec/unit/mutant/expression/methods_spec.rb +5 -7
  78. data/spec/unit/mutant/expression/namespace/flat_spec.rb +6 -8
  79. data/spec/unit/mutant/expression/namespace/recursive_spec.rb +6 -7
  80. data/spec/unit/mutant/expression_spec.rb +14 -5
  81. data/spec/unit/mutant/integration_spec.rb +14 -3
  82. data/spec/unit/mutant/isolation_spec.rb +2 -4
  83. data/spec/unit/mutant/loader/eval_spec.rb +1 -3
  84. data/spec/unit/mutant/matcher/chain_spec.rb +1 -3
  85. data/spec/unit/mutant/matcher/compiler/subject_prefix_spec.rb +21 -0
  86. data/spec/unit/mutant/matcher/compiler_spec.rb +28 -3
  87. data/spec/unit/mutant/matcher/filter_spec.rb +1 -3
  88. data/spec/unit/mutant/matcher/method/instance_spec.rb +3 -5
  89. data/spec/unit/mutant/matcher/method/singleton_spec.rb +22 -4
  90. data/spec/unit/mutant/matcher/methods/instance_spec.rb +7 -6
  91. data/spec/unit/mutant/matcher/methods/singleton_spec.rb +4 -6
  92. data/spec/unit/mutant/matcher/namespace_spec.rb +1 -3
  93. data/spec/unit/mutant/matcher/null_spec.rb +1 -3
  94. data/spec/unit/mutant/mutation_spec.rb +1 -3
  95. data/spec/unit/mutant/mutator/node_spec.rb +1 -3
  96. data/spec/unit/mutant/reporter/cli_spec.rb +444 -206
  97. data/spec/unit/mutant/reporter/null_spec.rb +1 -3
  98. data/spec/unit/mutant/require_highjack_spec.rb +1 -3
  99. data/spec/unit/mutant/runner_spec.rb +42 -28
  100. data/spec/unit/mutant/subject/context_spec.rb +1 -3
  101. data/spec/unit/mutant/subject/method/instance_spec.rb +27 -19
  102. data/spec/unit/mutant/subject/method/singleton_spec.rb +49 -17
  103. data/spec/unit/mutant/subject_spec.rb +1 -3
  104. data/spec/unit/mutant/test_spec.rb +1 -3
  105. data/spec/unit/mutant/warning_expectation.rb +1 -3
  106. data/spec/unit/mutant/warning_filter_spec.rb +1 -3
  107. data/spec/unit/mutant_spec.rb +13 -3
  108. data/test_app/Gemfile.devtools +2 -2
  109. data/test_app/spec/unit/test_app/literal/string_spec.rb +1 -1
  110. metadata +10 -21
  111. data/lib/mutant/matcher/method/finder.rb +0 -72
  112. data/lib/mutant/reporter/cli/progress.rb +0 -10
  113. data/lib/mutant/reporter/cli/progress/config.rb +0 -30
  114. data/lib/mutant/reporter/cli/progress/env.rb +0 -30
  115. data/lib/mutant/reporter/cli/progress/noop.rb +0 -27
  116. data/lib/mutant/reporter/cli/progress/result.rb +0 -12
  117. data/lib/mutant/reporter/cli/progress/result/mutation.rb +0 -45
  118. data/lib/mutant/reporter/cli/progress/result/subject.rb +0 -54
  119. data/lib/mutant/reporter/cli/progress/subject.rb +0 -27
  120. data/lib/mutant/reporter/cli/registry.rb +0 -81
  121. data/lib/mutant/reporter/cli/report.rb +0 -10
  122. data/lib/mutant/reporter/cli/report/env.rb +0 -92
  123. data/lib/mutant/reporter/cli/report/mutation.rb +0 -103
  124. data/lib/mutant/reporter/cli/report/subject.rb +0 -32
  125. data/lib/mutant/reporter/cli/report/test.rb +0 -28
  126. data/lib/mutant/walker.rb +0 -53
  127. data/spec/shared/mutator_behavior.rb +0 -55
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe Mutant::Matcher::Methods::Singleton, '#each' do
1
+ RSpec.describe Mutant::Matcher::Methods::Singleton, '#each' do
4
2
  let(:object) { described_class.new(env, Foo) }
5
3
  let(:env) { Fixtures::TEST_ENV }
6
4
 
@@ -40,11 +38,11 @@ describe Mutant::Matcher::Methods::Singleton, '#each' do
40
38
 
41
39
  before do
42
40
  matcher = Mutant::Matcher::Method::Singleton
43
- matcher.stub(:new)
41
+ allow(matcher).to receive(:new)
44
42
  .with(env, Foo, Foo.method(:method_a)).and_return([subject_a])
45
- matcher.stub(:new)
43
+ allow(matcher).to receive(:new)
46
44
  .with(env, Foo, Foo.method(:method_b)).and_return([subject_b])
47
- matcher.stub(:new)
45
+ allow(matcher).to receive(:new)
48
46
  .with(env, Foo, Foo.method(:method_c)).and_return([subject_c])
49
47
  end
50
48
 
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe Mutant::Matcher::Namespace do
1
+ RSpec.describe Mutant::Matcher::Namespace do
4
2
  let(:object) { described_class.new(env, Mutant::Expression.parse('TestApp*')) }
5
3
  let(:yields) { [] }
6
4
  let(:env) { double('Env') }
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe Mutant::Matcher::Null do
1
+ RSpec.describe Mutant::Matcher::Null do
4
2
  let(:object) { described_class.new }
5
3
 
6
4
  describe '#each' do
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe Mutant::Mutation do
1
+ RSpec.describe Mutant::Mutation do
4
2
 
5
3
  class TestMutation < Mutant::Mutation
6
4
  SYMBOL = 'test'.freeze
@@ -1,6 +1,4 @@
1
- require 'spec_helper'
2
-
3
- describe Mutant::Mutator::Node do
1
+ RSpec.describe Mutant::Mutator::Node do
4
2
  Mutant::Meta::Example::ALL.each do |example|
5
3
  context "on #{example.node.type.inspect}" do
6
4
  it 'generates the correct mutations' do
@@ -1,26 +1,39 @@
1
- require 'spec_helper'
2
-
3
- describe Mutant::Reporter::CLI do
4
- let(:object) { described_class.new(output) }
1
+ RSpec.describe Mutant::Reporter::CLI do
2
+ let(:object) { described_class.new(output, format) }
5
3
  let(:output) { StringIO.new }
6
4
 
5
+ let(:framed_format) do
6
+ described_class::Format::Framed.new(
7
+ tty: false,
8
+ tput: described_class::Tput::UNAVAILABLE
9
+ )
10
+ end
11
+
12
+ let(:progressive_format) do
13
+ described_class::Format::Progressive.new(tty: false)
14
+ end
15
+
16
+ let(:format) { framed_format }
17
+
7
18
  def contents
8
19
  output.rewind
9
20
  output.read
10
21
  end
11
22
 
12
- describe '#warn' do
13
- subject { object.warn(message) }
14
-
15
- let(:message) { 'message' }
16
-
17
- it 'writes message to output' do
18
- expect { subject }.to change { contents }.from('').to("message\n")
23
+ def self.it_reports(expected_content)
24
+ it 'writes expected report to output' do
25
+ subject
26
+ expect(contents).to eql(strip_indent(expected_content))
19
27
  end
20
28
  end
21
29
 
30
+ before do
31
+ allow(Time).to receive(:now).and_return(Time.now)
32
+ end
33
+
22
34
  let(:result) do
23
35
  Mutant::Result::Env.new(
36
+ done: true,
24
37
  env: env,
25
38
  runtime: 1.1,
26
39
  subject_results: subject_results
@@ -33,22 +46,34 @@ describe Mutant::Reporter::CLI do
33
46
  class: Mutant::Env,
34
47
  matchable_scopes: matchable_scopes,
35
48
  config: config,
36
- subjects: subjects
49
+ subjects: subjects,
50
+ mutations: subjects.flat_map(&:mutations)
37
51
  )
38
52
  end
39
53
 
40
- let(:config) { Mutant::Config::DEFAULT }
41
- let(:mutation_class) { Mutant::Mutation::Evil }
42
- let(:matchable_scopes) { double('Matchable Scopes', length: 10) }
54
+ let(:config) { Mutant::Config::DEFAULT.update(processes: 1) }
55
+ let(:mutation_class) { Mutant::Mutation::Evil }
56
+ let(:matchable_scopes) { double('Matchable Scopes', length: 10) }
43
57
 
44
58
  before do
45
- allow(mutation).to receive(:subject).and_return(_subject)
59
+ allow(mutation_a).to receive(:subject).and_return(_subject)
60
+ allow(mutation_b).to receive(:subject).and_return(_subject)
61
+ end
62
+
63
+ let(:mutation_a) do
64
+ double(
65
+ 'Mutation',
66
+ identification: 'mutation_id-a',
67
+ class: mutation_class,
68
+ original_source: 'true',
69
+ source: mutation_source
70
+ )
46
71
  end
47
72
 
48
- let(:mutation) do
73
+ let(:mutation_b) do
49
74
  double(
50
75
  'Mutation',
51
- identification: 'mutation_id',
76
+ identification: 'mutation_id-b',
52
77
  class: mutation_class,
53
78
  original_source: 'true',
54
79
  source: mutation_source
@@ -63,13 +88,15 @@ describe Mutant::Reporter::CLI do
63
88
  class: Mutant::Subject,
64
89
  node: s(:true),
65
90
  identification: 'subject_id',
66
- mutations: [mutation],
91
+ mutations: subject_mutations,
67
92
  tests: [
68
93
  double('Test', identification: 'test_id')
69
94
  ]
70
95
  )
71
96
  end
72
97
 
98
+ let(:subject_mutations) { [mutation_a] }
99
+
73
100
  let(:test_results) do
74
101
  [
75
102
  double(
@@ -83,253 +110,464 @@ describe Mutant::Reporter::CLI do
83
110
  ]
84
111
  end
85
112
 
113
+ let(:mutation_a_result) do
114
+ double(
115
+ 'Mutation Result',
116
+ class: Mutant::Result::Mutation,
117
+ mutation: mutation_a,
118
+ killtime: 0.5,
119
+ runtime: 1.0,
120
+ index: 0,
121
+ success?: mutation_result_success,
122
+ test_results: test_results,
123
+ failed_test_results: mutation_result_success ? [] : test_results
124
+ )
125
+ end
126
+
86
127
  let(:subject_results) do
87
128
  [
88
129
  Mutant::Result::Subject.new(
89
130
  subject: _subject,
90
131
  runtime: 1.0,
91
- mutation_results: [
92
- double(
93
- 'Mutation Result',
94
- class: Mutant::Result::Mutation,
95
- mutation: mutation,
96
- killtime: 0.5,
97
- success?: mutation_result_success,
98
- test_results: test_results,
99
- failed_test_results: mutation_result_success ? [] : test_results
100
- )
101
- ]
132
+ mutation_results: [mutation_a_result]
102
133
  )
103
134
  ]
104
135
  end
105
136
 
106
137
  let(:subjects) { [_subject] }
107
138
 
108
- describe '#progress' do
109
- subject { object.progress(reportable) }
139
+ describe '.build' do
140
+ subject { described_class.build(output) }
110
141
 
111
- context 'with env' do
112
- let(:reportable) { env }
142
+ let(:progressive_format) do
143
+ described_class::Format::Progressive.new(tty: tty?)
144
+ end
113
145
 
114
- it 'writes report to output' do
115
- subject
116
- expect(contents).to eql(strip_indent(<<-REPORT))
117
- Mutant configuration:
118
- Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
119
- Integration: null
120
- Expect Coverage: 100.00%
121
- Available Subjects: 10
122
- Subjects: 1
123
- REPORT
124
- end
146
+ let(:framed_format) do
147
+ described_class::Format::Framed.new(
148
+ tty: true,
149
+ tput: described_class::Tput::INSTANCE
150
+ )
125
151
  end
126
152
 
127
- context 'with subject' do
128
- let(:reportable) { _subject }
153
+ before do
154
+ expect(ENV).to receive(:key?).with('CI').and_return(ci?)
155
+ end
129
156
 
130
- it 'writes report to output' do
131
- subject
132
- expect(contents).to eql(strip_indent(<<-REPORT))
133
- subject_id mutations: 1
134
- - test_id
135
- REPORT
136
- end
157
+ let(:output) { double('Output', tty?: tty?) }
158
+ let(:tty?) { true }
159
+ let(:ci?) { false }
160
+
161
+ context 'when not on CI and on a tty' do
162
+ it { should eql(described_class.new(output, framed_format)) }
137
163
  end
138
164
 
139
- context 'with subject report' do
140
- let(:reportable) { subject_results.first }
141
- let(:mutation_result_success) { true }
165
+ context 'when on CI' do
166
+ let(:ci?) { true }
167
+ it { should eql(described_class.new(output, progressive_format)) }
168
+ end
142
169
 
143
- it 'writes report to output' do
144
- subject
145
- expect(contents).to eql("\n(01/01) 100% - killtime: 0.50s runtime: 1.00s overhead: 0.50s\n")
146
- end
170
+ context 'when output is not a tty?' do
171
+ let(:tty?) { false }
172
+ it { should eql(described_class.new(output, progressive_format)) }
147
173
  end
148
174
 
149
- context 'with mutation result' do
150
- let(:reportable) { subject_results.first.mutation_results.first }
175
+ context 'when output does not respond to #tty?' do
176
+ let(:output) { double('Output') }
177
+ let(:tty?) { false }
151
178
 
152
- context 'when mutation results in success' do
153
- let(:mutation_result_success) { true }
179
+ it { should eql(described_class.new(output, progressive_format)) }
180
+ end
181
+ end
154
182
 
155
- it 'writes report to output' do
156
- subject
157
- expect(contents).to eql('.')
158
- end
183
+ describe '#warn' do
184
+ subject { object.warn(message) }
185
+
186
+ let(:message) { 'message' }
187
+
188
+ it_reports("message\n")
189
+ end
190
+
191
+ describe '#start' do
192
+ subject { object.start(env) }
193
+
194
+ context 'on progressive format' do
195
+ let(:format) { progressive_format }
196
+
197
+ it_reports(<<-REPORT)
198
+ Mutant configuration:
199
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
200
+ Integration: null
201
+ Expect Coverage: 100.00%
202
+ Processes: 1
203
+ Includes: []
204
+ Requires: []
205
+ REPORT
206
+ end
207
+
208
+ context 'on framed format' do
209
+ it_reports ''
210
+ end
211
+ end
212
+
213
+ describe '#progress' do
214
+ subject { object.progress(collector) }
215
+
216
+ let(:collector) do
217
+ Mutant::Runner::Collector.new(env)
218
+ end
219
+
220
+ let(:mutation_result_success) { true }
221
+
222
+ context 'on progressive format' do
223
+
224
+ let(:format) { progressive_format }
225
+
226
+ context 'with empty collector' do
227
+
228
+ it_reports ''
159
229
  end
160
230
 
161
- context 'when mutation results in failure' do
162
- let(:mutation_result_success) { false }
231
+ context 'with last mutation present' do
232
+
233
+ before do
234
+ collector.start(mutation_a)
235
+ collector.finish(mutation_a_result)
236
+ end
163
237
 
164
- it 'writes report to output' do
165
- subject
166
- expect(contents).to eql('F')
238
+ context 'when mutation is successful' do
239
+ it_reports '.'
240
+ end
241
+
242
+ context 'when mutation is NOT successful' do
243
+ let(:mutation_result_success) { false }
244
+
245
+ it_reports 'F'
167
246
  end
168
247
  end
169
248
  end
170
- end
171
249
 
172
- describe '#report' do
173
- subject { object.report(result) }
250
+ context 'on framed format' do
174
251
 
175
- context 'with subjects' do
252
+ let(:mutation_result_success) { true }
176
253
 
177
- context 'and full covergage' do
178
- let(:mutation_result_success) { true }
254
+ context 'with empty collector' do
255
+ it_reports <<-REPORT
256
+ Mutant configuration:
257
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
258
+ Integration: null
259
+ Expect Coverage: 100.00%
260
+ Processes: 1
261
+ Includes: []
262
+ Requires: []
263
+ Available Subjects: 1
264
+ Subjects: 1
265
+ Mutations: 1
266
+ Kills: 0
267
+ Alive: 0
268
+ Runtime: 0.00s
269
+ Killtime: 0.00s
270
+ Overhead: NaN%
271
+ Coverage: 0.00%
272
+ Expected: 100.00%
273
+ Active subjects: 0
274
+ REPORT
275
+ end
179
276
 
180
- it 'writes report to output' do
181
- subject
182
- expect(contents).to eql(strip_indent(<<-REPORT))
183
- Subjects: 1
184
- Mutations: 1
185
- Kills: 1
186
- Alive: 0
187
- Runtime: 1.10s
188
- Killtime: 0.50s
189
- Overhead: 120.00%
190
- Coverage: 100.00%
191
- Expected: 100.00%
277
+ context 'with collector active on one subject' do
278
+ before do
279
+ collector.start(mutation_a)
280
+ end
281
+
282
+ context 'without progress' do
283
+
284
+ it_reports(<<-REPORT)
285
+ Mutant configuration:
286
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
287
+ Integration: null
288
+ Expect Coverage: 100.00%
289
+ Processes: 1
290
+ Includes: []
291
+ Requires: []
292
+ Available Subjects: 1
293
+ Subjects: 1
294
+ Mutations: 1
295
+ Kills: 0
296
+ Alive: 0
297
+ Runtime: 0.00s
298
+ Killtime: 0.00s
299
+ Overhead: NaN%
300
+ Coverage: 0.00%
301
+ Expected: 100.00%
302
+ Active subjects: 1
303
+ subject_id mutations: 1
304
+ - test_id
305
+ (00/01) 0% - killtime: 0.00s runtime: 0.00s overhead: 0.00s
192
306
  REPORT
193
307
  end
308
+
309
+ context 'with progress' do
310
+
311
+ let(:subject_mutations) { [mutation_a, mutation_b] }
312
+
313
+ before do
314
+ collector.start(mutation_b)
315
+ collector.finish(mutation_a_result)
316
+ end
317
+
318
+ context 'on failure' do
319
+ let(:mutation_result_success) { false }
320
+
321
+ it_reports(<<-REPORT)
322
+ Mutant configuration:
323
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
324
+ Integration: null
325
+ Expect Coverage: 100.00%
326
+ Processes: 1
327
+ Includes: []
328
+ Requires: []
329
+ Available Subjects: 1
330
+ Subjects: 1
331
+ Mutations: 2
332
+ Kills: 0
333
+ Alive: 1
334
+ Runtime: 0.00s
335
+ Killtime: 0.50s
336
+ Overhead: -100.00%
337
+ Coverage: 0.00%
338
+ Expected: 100.00%
339
+ Active subjects: 1
340
+ subject_id mutations: 2
341
+ - test_id
342
+ F
343
+ (00/02) 0% - killtime: 0.50s runtime: 1.00s overhead: 0.50s
344
+ REPORT
345
+ end
346
+
347
+ context 'on success' do
348
+ it_reports(<<-REPORT)
349
+ Mutant configuration:
350
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
351
+ Integration: null
352
+ Expect Coverage: 100.00%
353
+ Processes: 1
354
+ Includes: []
355
+ Requires: []
356
+ Available Subjects: 1
357
+ Subjects: 1
358
+ Mutations: 2
359
+ Kills: 1
360
+ Alive: 0
361
+ Runtime: 0.00s
362
+ Killtime: 0.50s
363
+ Overhead: -100.00%
364
+ Coverage: 100.00%
365
+ Expected: 100.00%
366
+ Active subjects: 1
367
+ subject_id mutations: 2
368
+ - test_id
369
+ .
370
+ (01/02) 100% - killtime: 0.50s runtime: 1.00s overhead: 0.50s
371
+ REPORT
372
+ end
373
+ end
194
374
  end
375
+ end
376
+
377
+ describe '#report' do
378
+ subject { object.report(result) }
379
+
380
+ context 'with full coverage' do
381
+ let(:mutation_result_success) { true }
195
382
 
196
- context 'and partial covergage' do
383
+ it_reports(<<-REPORT)
384
+ Mutant configuration:
385
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
386
+ Integration: null
387
+ Expect Coverage: 100.00%
388
+ Processes: 1
389
+ Includes: []
390
+ Requires: []
391
+ Available Subjects: 1
392
+ Subjects: 1
393
+ Mutations: 1
394
+ Kills: 1
395
+ Alive: 0
396
+ Runtime: 1.10s
397
+ Killtime: 0.50s
398
+ Overhead: 120.00%
399
+ Coverage: 100.00%
400
+ Expected: 100.00%
401
+ REPORT
402
+ end
403
+
404
+ context 'and partial coverage' do
197
405
  let(:mutation_result_success) { false }
198
406
 
199
407
  context 'on evil mutation' do
200
408
  context 'with a diff' do
201
- it 'writes report to output' do
202
- subject
203
- expect(contents).to eql(strip_indent(<<-REPORT))
204
- subject_id
205
- - test_id
206
- mutation_id
207
- @@ -1,2 +1,2 @@
208
- -true
209
- +false
210
- -----------------------
211
- Subjects: 1
212
- Mutations: 1
213
- Kills: 0
214
- Alive: 1
215
- Runtime: 1.10s
216
- Killtime: 0.50s
217
- Overhead: 120.00%
218
- Coverage: 0.00%
219
- Expected: 100.00%
220
- REPORT
221
- end
409
+ it_reports(<<-REPORT)
410
+ subject_id
411
+ - test_id
412
+ mutation_id-a
413
+ @@ -1,2 +1,2 @@
414
+ -true
415
+ +false
416
+ -----------------------
417
+ Mutant configuration:
418
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
419
+ Integration: null
420
+ Expect Coverage: 100.00%
421
+ Processes: 1
422
+ Includes: []
423
+ Requires: []
424
+ Available Subjects: 1
425
+ Subjects: 1
426
+ Mutations: 1
427
+ Kills: 0
428
+ Alive: 1
429
+ Runtime: 1.10s
430
+ Killtime: 0.50s
431
+ Overhead: 120.00%
432
+ Coverage: 0.00%
433
+ Expected: 100.00%
434
+ REPORT
222
435
  end
223
436
 
224
437
  context 'without a diff' do
225
438
  let(:mutation_source) { 'true' }
226
439
 
227
- it 'writes report to output' do
228
- subject
229
- expect(contents).to eql(strip_indent(<<-REPORT))
230
- subject_id
231
- - test_id
232
- mutation_id
233
- BUG: Mutation NOT resulted in exactly one diff. Please report a reproduction!
234
- -----------------------
235
- Subjects: 1
236
- Mutations: 1
237
- Kills: 0
238
- Alive: 1
239
- Runtime: 1.10s
240
- Killtime: 0.50s
241
- Overhead: 120.00%
242
- Coverage: 0.00%
243
- Expected: 100.00%
244
- REPORT
245
- end
246
- end
247
- end
248
-
249
- context 'on neutral mutation' do
250
- let(:mutation_class) { Mutant::Mutation::Neutral }
251
- let(:mutation_source) { 'true' }
252
-
253
- it 'writes report to output' do
254
- subject
255
- expect(contents).to eql(strip_indent(<<-REPORT))
440
+ it_reports(<<-REPORT)
256
441
  subject_id
257
442
  - test_id
258
- mutation_id
259
- --- Neutral failure ---
260
- Original code was inserted unmutated. And the test did NOT PASS.
261
- Your tests do not pass initially or you found a bug in mutant / unparser.
262
- Subject AST:
263
- (true)
264
- Unparsed Source:
443
+ mutation_id-a
444
+ Original source:
445
+ true
446
+ Mutated Source:
265
447
  true
266
- Test Reports: 1
267
- - test_id / runtime: 1.0
268
- Test Output:
269
- test-output
448
+ BUG: Mutation NOT resulted in exactly one diff. Please report a reproduction!
270
449
  -----------------------
271
- Subjects: 1
272
- Mutations: 1
273
- Kills: 0
274
- Alive: 1
275
- Runtime: 1.10s
276
- Killtime: 0.50s
277
- Overhead: 120.00%
278
- Coverage: 0.00%
279
- Expected: 100.00%
450
+ Mutant configuration:
451
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
452
+ Integration: null
453
+ Expect Coverage: 100.00%
454
+ Processes: 1
455
+ Includes: []
456
+ Requires: []
457
+ Available Subjects: 1
458
+ Subjects: 1
459
+ Mutations: 1
460
+ Kills: 0
461
+ Alive: 1
462
+ Runtime: 1.10s
463
+ Killtime: 0.50s
464
+ Overhead: 120.00%
465
+ Coverage: 0.00%
466
+ Expected: 100.00%
280
467
  REPORT
281
468
  end
282
469
  end
283
470
 
284
471
  context 'on neutral mutation' do
472
+ let(:mutation_class) { Mutant::Mutation::Neutral }
473
+ let(:mutation_source) { 'true' }
474
+
475
+ it_reports(<<-REPORT)
476
+ subject_id
477
+ - test_id
478
+ mutation_id-a
479
+ --- Neutral failure ---
480
+ Original code was inserted unmutated. And the test did NOT PASS.
481
+ Your tests do not pass initially or you found a bug in mutant / unparser.
482
+ Subject AST:
483
+ (true)
484
+ Unparsed Source:
485
+ true
486
+ Test Reports: 1
487
+ - test_id / runtime: 1.0
488
+ Test Output:
489
+ test-output
490
+ -----------------------
491
+ Mutant configuration:
492
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
493
+ Integration: null
494
+ Expect Coverage: 100.00%
495
+ Processes: 1
496
+ Includes: []
497
+ Requires: []
498
+ Available Subjects: 1
499
+ Subjects: 1
500
+ Mutations: 1
501
+ Kills: 0
502
+ Alive: 1
503
+ Runtime: 1.10s
504
+ Killtime: 0.50s
505
+ Overhead: 120.00%
506
+ Coverage: 0.00%
507
+ Expected: 100.00%
508
+ REPORT
509
+ end
510
+
511
+ context 'on noop mutation' do
285
512
  let(:mutation_class) { Mutant::Mutation::Noop }
286
513
 
287
- it 'writes report to output' do
288
- subject
289
- expect(contents).to eql(strip_indent(<<-REPORT))
290
- subject_id
291
- - test_id
292
- mutation_id
293
- ---- Noop failure -----
294
- No code was inserted. And the test did NOT PASS.
295
- This is typically a problem of your specs not passing unmutated.
296
- Test Reports: 1
297
- - test_id / runtime: 1.0
298
- Test Output:
299
- test-output
300
- -----------------------
301
- Subjects: 1
302
- Mutations: 1
303
- Kills: 0
304
- Alive: 1
305
- Runtime: 1.10s
306
- Killtime: 0.50s
307
- Overhead: 120.00%
308
- Coverage: 0.00%
309
- Expected: 100.00%
310
- REPORT
311
- end
514
+ it_reports(<<-REPORT)
515
+ subject_id
516
+ - test_id
517
+ mutation_id-a
518
+ ---- Noop failure -----
519
+ No code was inserted. And the test did NOT PASS.
520
+ This is typically a problem of your specs not passing unmutated.
521
+ Test Reports: 1
522
+ - test_id / runtime: 1.0
523
+ Test Output:
524
+ test-output
525
+ -----------------------
526
+ Mutant configuration:
527
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
528
+ Integration: null
529
+ Expect Coverage: 100.00%
530
+ Processes: 1
531
+ Includes: []
532
+ Requires: []
533
+ Available Subjects: 1
534
+ Subjects: 1
535
+ Mutations: 1
536
+ Kills: 0
537
+ Alive: 1
538
+ Runtime: 1.10s
539
+ Killtime: 0.50s
540
+ Overhead: 120.00%
541
+ Coverage: 0.00%
542
+ Expected: 100.00%
543
+ REPORT
312
544
  end
313
545
  end
314
- end
315
546
 
316
- context 'without subjects' do
317
-
318
- let(:subjects) { [] }
319
- let(:subject_results) { [] }
320
-
321
- it 'writes report to output' do
322
- subject
323
- expect(contents).to eql(strip_indent(<<-REPORT))
324
- Subjects: 0
325
- Mutations: 0
326
- Kills: 0
327
- Alive: 0
328
- Runtime: 1.10s
329
- Killtime: 0.00s
330
- Overhead: Inf%
331
- Coverage: 0.00%
332
- Expected: 100.00%
547
+ context 'without subjects' do
548
+ let(:subjects) { [] }
549
+ let(:subject_results) { [] }
550
+
551
+ let(:config) { Mutant::Config::DEFAULT.update(processes: 1, includes: %w[include-dir], requires: %w[require-name]) }
552
+
553
+ it_reports(<<-REPORT)
554
+ Mutant configuration:
555
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
556
+ Integration: null
557
+ Expect Coverage: 100.00%
558
+ Processes: 1
559
+ Includes: ["include-dir"]
560
+ Requires: ["require-name"]
561
+ Available Subjects: 0
562
+ Subjects: 0
563
+ Mutations: 0
564
+ Kills: 0
565
+ Alive: 0
566
+ Runtime: 1.10s
567
+ Killtime: 0.00s
568
+ Overhead: Inf%
569
+ Coverage: 0.00%
570
+ Expected: 100.00%
333
571
  REPORT
334
572
  end
335
573
  end