mutant 0.7.9 → 0.8.0

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