mutant 0.7.9 → 0.8.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 (72) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +11 -1
  3. data/README.md +5 -12
  4. data/bin/mutant +17 -1
  5. data/config/flay.yml +1 -1
  6. data/config/flog.yml +1 -1
  7. data/config/reek.yml +4 -4
  8. data/config/rubocop.yml +21 -3
  9. data/lib/mutant.rb +15 -61
  10. data/lib/mutant/cli.rb +1 -7
  11. data/lib/mutant/color.rb +2 -2
  12. data/lib/mutant/config.rb +1 -1
  13. data/lib/mutant/expression/method.rb +1 -1
  14. data/lib/mutant/expression/methods.rb +1 -1
  15. data/lib/mutant/expression/namespace.rb +1 -1
  16. data/lib/mutant/mutator/node/send.rb +18 -18
  17. data/lib/mutant/reporter/cli.rb +1 -6
  18. data/lib/mutant/reporter/cli/format.rb +2 -2
  19. data/lib/mutant/reporter/cli/printer.rb +5 -500
  20. data/lib/mutant/reporter/cli/printer/config.rb +32 -0
  21. data/lib/mutant/reporter/cli/printer/env_progress.rb +66 -0
  22. data/lib/mutant/reporter/cli/printer/env_result.rb +23 -0
  23. data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +37 -0
  24. data/lib/mutant/reporter/cli/printer/mutation_result.rb +151 -0
  25. data/lib/mutant/reporter/cli/printer/status.rb +60 -0
  26. data/lib/mutant/reporter/cli/printer/status_progressive.rb +52 -0
  27. data/lib/mutant/reporter/cli/printer/subject_progress.rb +90 -0
  28. data/lib/mutant/reporter/cli/printer/subject_result.rb +28 -0
  29. data/lib/mutant/reporter/cli/printer/test_result.rb +33 -0
  30. data/lib/mutant/require_highjack.rb +11 -50
  31. data/lib/mutant/version.rb +1 -1
  32. data/lib/mutant/zombifier.rb +79 -37
  33. data/meta/send.rb +1 -1
  34. data/mutant-rspec.gemspec +1 -1
  35. data/mutant.gemspec +3 -3
  36. data/spec/integration/mutant/corpus_spec.rb +2 -2
  37. data/spec/integration/mutant/rspec_spec.rb +5 -15
  38. data/spec/integrations.yml +3 -3
  39. data/spec/spec_helper.rb +1 -0
  40. data/spec/support/corpus.rb +233 -220
  41. data/spec/support/file_system.rb +60 -0
  42. data/spec/support/rb_bug.rb +1 -1
  43. data/spec/support/ruby_vm.rb +82 -0
  44. data/spec/support/shared_context.rb +19 -10
  45. data/spec/unit/mutant/ast_spec.rb +2 -2
  46. data/spec/unit/mutant/cache_spec.rb +22 -0
  47. data/spec/unit/mutant/cli_spec.rb +1 -30
  48. data/spec/unit/mutant/context_spec.rb +1 -0
  49. data/spec/unit/mutant/expression/method_spec.rb +6 -4
  50. data/spec/unit/mutant/parallel/master_spec.rb +1 -1
  51. data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +33 -0
  52. data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +76 -0
  53. data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +35 -0
  54. data/spec/unit/mutant/reporter/cli/printer/mutation_progress_result_spec.rb +23 -0
  55. data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +110 -0
  56. data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +51 -0
  57. data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +145 -0
  58. data/spec/unit/mutant/reporter/cli/printer/subject_progress_spec.rb +37 -0
  59. data/spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb +37 -0
  60. data/spec/unit/mutant/reporter/cli/printer/test_result_spec.rb +14 -0
  61. data/spec/unit/mutant/reporter/cli/printer_spec.rb +140 -0
  62. data/spec/unit/mutant/reporter/cli_spec.rb +69 -313
  63. data/spec/unit/mutant/reporter/trace_spec.rb +12 -0
  64. data/spec/unit/mutant/require_highjack_spec.rb +25 -28
  65. data/spec/unit/mutant/warning_filter_spec.rb +7 -0
  66. data/spec/unit/mutant/zombifier_spec.rb +120 -0
  67. data/spec/unit/mutant_spec.rb +0 -43
  68. data/test_app/Gemfile.rspec3.3 +6 -0
  69. metadata +46 -17
  70. data/.travis.yml +0 -20
  71. data/lib/mutant/zombifier/file.rb +0 -100
  72. data/spec/integration/mutant/zombie_spec.rb +0 -6
@@ -0,0 +1,14 @@
1
+ RSpec.describe Mutant::Reporter::CLI::Printer::TestResult do
2
+ setup_shared_context
3
+
4
+ let(:reportable) { mutation_a_test_result }
5
+
6
+ describe '.call' do
7
+ it_reports <<-'STR'
8
+ - 1 @ runtime: 1.0
9
+ - test-a
10
+ Test Output:
11
+ mutation a test result output
12
+ STR
13
+ end
14
+ end
@@ -0,0 +1,140 @@
1
+ RSpec.describe Mutant::Reporter::CLI::Printer do
2
+ let(:output) { StringIO.new }
3
+
4
+ subject { class_under_test.call(output, reportable) }
5
+
6
+ def self.it_reports(expectation)
7
+ it 'writes expected report' do
8
+ allow(output).to receive(:tty?).and_return(tty?)
9
+ subject
10
+ output.rewind
11
+ expect(output.read).to eql(strip_indent(expectation))
12
+ end
13
+ end
14
+
15
+ let(:reportable) { double('Reportable', success?: success?) }
16
+ let(:tty?) { true }
17
+ let(:success?) { true }
18
+
19
+ context '.call' do
20
+ let(:class_under_test) do
21
+ Class.new(described_class) do
22
+ def run
23
+ puts object
24
+ end
25
+ end
26
+ end
27
+
28
+ let(:reportable) { 'foo' }
29
+
30
+ it_reports "foo\n"
31
+ end
32
+
33
+ context '#status' do
34
+ let(:class_under_test) do
35
+ Class.new(described_class) do
36
+ def run
37
+ status('foo %s', 'bar')
38
+ end
39
+ end
40
+ end
41
+
42
+ context 'on tty' do
43
+ context 'on success' do
44
+ it_reports Mutant::Color::GREEN.format('foo bar') << "\n"
45
+ end
46
+
47
+ context 'on failure' do
48
+ let(:success?) { false }
49
+ it_reports Mutant::Color::RED.format('foo bar') << "\n"
50
+ end
51
+ end
52
+
53
+ context 'on no tty' do
54
+ let(:tty?) { false }
55
+
56
+ context 'on success' do
57
+ it_reports "foo bar\n"
58
+ end
59
+
60
+ context 'on failure' do
61
+ let(:success?) { false }
62
+
63
+ it_reports "foo bar\n"
64
+ end
65
+ end
66
+ end
67
+
68
+ context '#visit_collection' do
69
+ let(:class_under_test) do
70
+ reporter = nested_reporter
71
+ Class.new(described_class) do
72
+ define_method(:run) do
73
+ visit_collection(reporter, %w[foo bar])
74
+ end
75
+ end
76
+ end
77
+
78
+ let(:nested_reporter) do
79
+ Class.new(described_class) do
80
+ def run
81
+ puts object
82
+ end
83
+ end
84
+ end
85
+
86
+ it_reports "foo\nbar\n"
87
+ end
88
+
89
+ context '#visit' do
90
+ let(:class_under_test) do
91
+ reporter = nested_reporter
92
+ Class.new(described_class) do
93
+ define_method(:run) do
94
+ visit(reporter, 'foo')
95
+ end
96
+ end
97
+ end
98
+
99
+ let(:nested_reporter) do
100
+ Class.new(described_class) do
101
+ def run
102
+ puts object
103
+ end
104
+ end
105
+ end
106
+
107
+ it_reports "foo\n"
108
+ end
109
+
110
+ context '#info' do
111
+ let(:class_under_test) do
112
+ Class.new(described_class) do
113
+ def run
114
+ info('%s - %s', 'foo', 'bar')
115
+ end
116
+ end
117
+ end
118
+
119
+ it_reports "foo - bar\n"
120
+ end
121
+
122
+ context '#colorize' do
123
+ let(:class_under_test) do
124
+ Class.new(described_class) do
125
+ def run
126
+ puts(colorize(Mutant::Color::RED, 'foo'))
127
+ end
128
+ end
129
+ end
130
+
131
+ context 'when output is a tty?' do
132
+ it_reports Mutant::Color::RED.format('foo') << "\n"
133
+ end
134
+
135
+ context 'when output is NOT a tty?' do
136
+ let(:tty?) { false }
137
+ it_reports "foo\n"
138
+ end
139
+ end
140
+ end
@@ -19,8 +19,10 @@ RSpec.describe Mutant::Reporter::CLI do
19
19
  )
20
20
  end
21
21
 
22
+ let(:tty?) { false }
23
+
22
24
  let(:progressive_format) do
23
- described_class::Format::Progressive.new(tty: false)
25
+ described_class::Format::Progressive.new(tty: tty?)
24
26
  end
25
27
 
26
28
  let(:format) { framed_format }
@@ -32,7 +34,7 @@ RSpec.describe Mutant::Reporter::CLI do
32
34
 
33
35
  def self.it_reports(expected_content)
34
36
  it 'writes expected report to output' do
35
- subject
37
+ expect(subject).to be(object)
36
38
  expect(contents).to eql(strip_indent(expected_content))
37
39
  end
38
40
  end
@@ -128,21 +130,85 @@ RSpec.describe Mutant::Reporter::CLI do
128
130
  REPORT
129
131
  end
130
132
 
133
+ context 'with non default coverage expectation' do
134
+ let(:format) { progressive_format }
135
+ update(:config) { { expected_coverage: 0.1r } }
136
+
137
+ it_reports(<<-REPORT)
138
+ Mutant configuration:
139
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
140
+ Integration: null
141
+ Expect Coverage: 10.00%
142
+ Jobs: 1
143
+ Includes: []
144
+ Requires: []
145
+ REPORT
146
+ end
147
+
131
148
  context 'on framed format' do
132
149
  it_reports '[tput-prepare]'
133
150
  end
134
151
  end
135
152
 
153
+ describe '#report' do
154
+ subject { object.report(env_result) }
155
+
156
+ it_reports(<<-REPORT)
157
+ Mutant configuration:
158
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
159
+ Integration: null
160
+ Expect Coverage: 100.00%
161
+ Jobs: 1
162
+ Includes: []
163
+ Requires: []
164
+ Subjects: 1
165
+ Mutations: 2
166
+ Kills: 2
167
+ Alive: 0
168
+ Runtime: 4.00s
169
+ Killtime: 2.00s
170
+ Overhead: 100.00%
171
+ Coverage: 100.00%
172
+ Expected: 100.00%
173
+ REPORT
174
+ end
175
+
136
176
  describe '#progress' do
137
177
  subject { object.progress(status) }
138
178
 
179
+ context 'on framed format' do
180
+ let(:format) { framed_format }
181
+
182
+ it_reports(<<-REPORT)
183
+ [tput-restore]Mutant configuration:
184
+ Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
185
+ Integration: null
186
+ Expect Coverage: 100.00%
187
+ Jobs: 1
188
+ Includes: []
189
+ Requires: []
190
+ Subjects: 1
191
+ Mutations: 2
192
+ Kills: 2
193
+ Alive: 0
194
+ Runtime: 4.00s
195
+ Killtime: 2.00s
196
+ Overhead: 100.00%
197
+ Coverage: 100.00%
198
+ Expected: 100.00%
199
+ Active subjects: 0
200
+ REPORT
201
+ end
202
+
139
203
  context 'on progressive format' do
140
204
  let(:format) { progressive_format }
141
205
 
142
206
  context 'with empty scheduler' do
143
207
  update(:env_result) { { subject_results: [] } }
144
208
 
145
- it_reports "(00/02) 0% - killtime: 0.00s runtime: 4.00s overhead: 4.00s\n"
209
+ let(:tty?) { true }
210
+
211
+ it_reports Mutant::Color::RED.format('(00/02) 0% - killtime: 0.00s runtime: 4.00s overhead: 4.00s') << "\n"
146
212
  end
147
213
 
148
214
  context 'with last mutation present' do
@@ -159,315 +225,5 @@ RSpec.describe Mutant::Reporter::CLI do
159
225
  end
160
226
  end
161
227
 
162
- context 'on framed format' do
163
- context 'with empty scheduler' do
164
- update(:env_result) { { subject_results: [] } }
165
-
166
- it_reports <<-REPORT
167
- [tput-restore]Mutant configuration:
168
- Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
169
- Integration: null
170
- Expect Coverage: 100.00%
171
- Jobs: 1
172
- Includes: []
173
- Requires: []
174
- Subjects: 1
175
- Mutations: 2
176
- Kills: 0
177
- Alive: 0
178
- Runtime: 4.00s
179
- Killtime: 0.00s
180
- Overhead: Inf%
181
- Coverage: 0.00%
182
- Expected: 100.00%
183
- Active subjects: 0
184
- REPORT
185
- end
186
-
187
- context 'with scheduler active on one subject' do
188
- context 'without progress' do
189
- update(:status) { { active_jobs: [].to_set } }
190
-
191
- it_reports(<<-REPORT)
192
- [tput-restore]Mutant configuration:
193
- Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
194
- Integration: null
195
- Expect Coverage: 100.00%
196
- Jobs: 1
197
- Includes: []
198
- Requires: []
199
- Subjects: 1
200
- Mutations: 2
201
- Kills: 2
202
- Alive: 0
203
- Runtime: 4.00s
204
- Killtime: 2.00s
205
- Overhead: 100.00%
206
- Coverage: 100.00%
207
- Expected: 100.00%
208
- Active subjects: 0
209
- REPORT
210
- end
211
-
212
- context 'with progress' do
213
- update(:status) { { active_jobs: [job_a].to_set } }
214
-
215
- context 'on failure' do
216
- update(:mutation_a_test_result) { { passed: true } }
217
-
218
- it_reports(<<-REPORT)
219
- [tput-restore]Mutant configuration:
220
- Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
221
- Integration: null
222
- Expect Coverage: 100.00%
223
- Jobs: 1
224
- Includes: []
225
- Requires: []
226
- Subjects: 1
227
- Mutations: 2
228
- Kills: 1
229
- Alive: 1
230
- Runtime: 4.00s
231
- Killtime: 2.00s
232
- Overhead: 100.00%
233
- Coverage: 50.00%
234
- Expected: 100.00%
235
- Active subjects: 1
236
- subject-a mutations: 2
237
- - test-a
238
- F.
239
- (01/02) 50% - killtime: 2.00s runtime: 2.00s overhead: 0.00s
240
- Active Jobs:
241
- 0: evil:subject-a:d27d2
242
- REPORT
243
- end
244
-
245
- context 'on success' do
246
- it_reports(<<-REPORT)
247
- [tput-restore]Mutant configuration:
248
- Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
249
- Integration: null
250
- Expect Coverage: 100.00%
251
- Jobs: 1
252
- Includes: []
253
- Requires: []
254
- Subjects: 1
255
- Mutations: 2
256
- Kills: 2
257
- Alive: 0
258
- Runtime: 4.00s
259
- Killtime: 2.00s
260
- Overhead: 100.00%
261
- Coverage: 100.00%
262
- Expected: 100.00%
263
- Active subjects: 1
264
- subject-a mutations: 2
265
- - test-a
266
- ..
267
- (02/02) 100% - killtime: 2.00s runtime: 2.00s overhead: 0.00s
268
- Active Jobs:
269
- 0: evil:subject-a:d27d2
270
- REPORT
271
- end
272
- end
273
- end
274
- end
275
-
276
- describe '#report' do
277
- subject { object.report(status.payload) }
278
-
279
- context 'with full coverage' do
280
- it_reports(<<-REPORT)
281
- Mutant configuration:
282
- Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
283
- Integration: null
284
- Expect Coverage: 100.00%
285
- Jobs: 1
286
- Includes: []
287
- Requires: []
288
- Subjects: 1
289
- Mutations: 2
290
- Kills: 2
291
- Alive: 0
292
- Runtime: 4.00s
293
- Killtime: 2.00s
294
- Overhead: 100.00%
295
- Coverage: 100.00%
296
- Expected: 100.00%
297
- REPORT
298
- end
299
-
300
- context 'and partial coverage' do
301
- update(:mutation_a_test_result) { { passed: true } }
302
-
303
- context 'on evil mutation' do
304
- context 'with a diff' do
305
- it_reports(<<-REPORT)
306
- subject-a
307
- - test-a
308
- evil:subject-a:d27d2
309
- @@ -1,2 +1,2 @@
310
- -true
311
- +false
312
- -----------------------
313
- Mutant configuration:
314
- Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
315
- Integration: null
316
- Expect Coverage: 100.00%
317
- Jobs: 1
318
- Includes: []
319
- Requires: []
320
- Subjects: 1
321
- Mutations: 2
322
- Kills: 1
323
- Alive: 1
324
- Runtime: 4.00s
325
- Killtime: 2.00s
326
- Overhead: 100.00%
327
- Coverage: 50.00%
328
- Expected: 100.00%
329
- REPORT
330
- end
331
-
332
- context 'without a diff' do
333
- let(:mutation_a_node) { s(:true) }
334
-
335
- it_reports(<<-REPORT)
336
- subject-a
337
- - test-a
338
- evil:subject-a:d5318
339
- Original source:
340
- true
341
- Mutated Source:
342
- true
343
- BUG: Mutation NOT resulted in exactly one diff hunk. Please report a reproduction!
344
- -----------------------
345
- Mutant configuration:
346
- Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
347
- Integration: null
348
- Expect Coverage: 100.00%
349
- Jobs: 1
350
- Includes: []
351
- Requires: []
352
- Subjects: 1
353
- Mutations: 2
354
- Kills: 1
355
- Alive: 1
356
- Runtime: 4.00s
357
- Killtime: 2.00s
358
- Overhead: 100.00%
359
- Coverage: 50.00%
360
- Expected: 100.00%
361
- REPORT
362
- end
363
- end
364
-
365
- context 'on neutral mutation' do
366
- update(:mutation_a_test_result) { { passed: false } }
367
-
368
- let(:mutation_a) do
369
- Mutant::Mutation::Neutral.new(subject_a, s(:true))
370
- end
371
-
372
- it_reports(<<-REPORT)
373
- subject-a
374
- - test-a
375
- neutral:subject-a:d5318
376
- --- Neutral failure ---
377
- Original code was inserted unmutated. And the test did NOT PASS.
378
- Your tests do not pass initially or you found a bug in mutant / unparser.
379
- Subject AST:
380
- (true)
381
- Unparsed Source:
382
- true
383
- Test Result:
384
- - 1 @ runtime: 1.0
385
- - test-a
386
- Test Output:
387
- mutation a test result output
388
- -----------------------
389
- neutral:subject-a:d5318
390
- --- Neutral failure ---
391
- Original code was inserted unmutated. And the test did NOT PASS.
392
- Your tests do not pass initially or you found a bug in mutant / unparser.
393
- Subject AST:
394
- (true)
395
- Unparsed Source:
396
- true
397
- Test Result:
398
- - 1 @ runtime: 1.0
399
- - test-a
400
- Test Output:
401
- mutation b test result output
402
- -----------------------
403
- Mutant configuration:
404
- Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
405
- Integration: null
406
- Expect Coverage: 100.00%
407
- Jobs: 1
408
- Includes: []
409
- Requires: []
410
- Subjects: 1
411
- Mutations: 2
412
- Kills: 0
413
- Alive: 2
414
- Runtime: 4.00s
415
- Killtime: 2.00s
416
- Overhead: 100.00%
417
- Coverage: 0.00%
418
- Expected: 100.00%
419
- REPORT
420
- end
421
-
422
- context 'on noop mutation' do
423
- update(:mutation_a_test_result) { { passed: false } }
424
-
425
- let(:mutation_a) do
426
- Mutant::Mutation::Noop.new(subject_a, s(:true))
427
- end
428
-
429
- it_reports(<<-REPORT)
430
- subject-a
431
- - test-a
432
- noop:subject-a:d5318
433
- ---- Noop failure -----
434
- No code was inserted. And the test did NOT PASS.
435
- This is typically a problem of your specs not passing unmutated.
436
- Test Result:
437
- - 1 @ runtime: 1.0
438
- - test-a
439
- Test Output:
440
- mutation a test result output
441
- -----------------------
442
- noop:subject-a:d5318
443
- ---- Noop failure -----
444
- No code was inserted. And the test did NOT PASS.
445
- This is typically a problem of your specs not passing unmutated.
446
- Test Result:
447
- - 1 @ runtime: 1.0
448
- - test-a
449
- Test Output:
450
- mutation b test result output
451
- -----------------------
452
- Mutant configuration:
453
- Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
454
- Integration: null
455
- Expect Coverage: 100.00%
456
- Jobs: 1
457
- Includes: []
458
- Requires: []
459
- Subjects: 1
460
- Mutations: 2
461
- Kills: 0
462
- Alive: 2
463
- Runtime: 4.00s
464
- Killtime: 2.00s
465
- Overhead: 100.00%
466
- Coverage: 0.00%
467
- Expected: 100.00%
468
- REPORT
469
- end
470
- end
471
- end
472
228
  end
473
229
  end