mutant 0.5.26 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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