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
@@ -49,7 +49,7 @@ module Mutant
49
49
  @tty
50
50
  end
51
51
 
52
- [:puts, :write].each do |name|
52
+ %i[puts write].each do |name|
53
53
  define_method(name) do |*args, &block|
54
54
  buffer.public_send(name, *args, &block)
55
55
  end
@@ -69,7 +69,7 @@ module Mutant
69
69
  #
70
70
  def format(printer, object)
71
71
  buffer = new_buffer
72
- printer.run(Output.new(tty, buffer), object)
72
+ printer.call(Output.new(tty, buffer), object)
73
73
  buffer.rewind
74
74
  buffer.read
75
75
  end
@@ -3,24 +3,13 @@ module Mutant
3
3
  class CLI
4
4
  # CLI runner status printer base class
5
5
  class Printer
6
- include AbstractType, Delegator, Adamantium::Flat, Concord.new(:output, :object)
6
+ include AbstractType, Delegator, Adamantium::Flat, Concord.new(:output, :object), Procto.call(:run)
7
7
 
8
- delegate(:success?)
8
+ private_class_method :new
9
9
 
10
- NL = "\n".freeze
10
+ delegate :success?
11
11
 
12
- # Run printer on object to output
13
- #
14
- # @param [IO] output
15
- # @param [Object] object
16
- #
17
- # @return [self]
18
- #
19
- # @api private
20
- #
21
- def self.run(output, object)
22
- new(output, object).run
23
- end
12
+ NL = "\n".freeze
24
13
 
25
14
  # Run printer
26
15
  #
@@ -67,7 +56,7 @@ module Mutant
67
56
  # @api private
68
57
  #
69
58
  def visit(printer, object)
70
- printer.run(output, object)
59
+ printer.call(output, object)
71
60
  end
72
61
 
73
62
  # Print an info line to output
@@ -133,490 +122,6 @@ module Mutant
133
122
  # @api private
134
123
  #
135
124
  alias_method :color?, :tty?
136
-
137
- # Printer for runner status
138
- class Status < self
139
-
140
- delegate(:active_jobs, :payload)
141
-
142
- # Print progress for collector
143
- #
144
- # @return [self]
145
- #
146
- # @api private
147
- #
148
- def run
149
- visit(EnvProgress, payload)
150
- info('Active subjects: %d', active_subject_results.length)
151
- visit_collection(SubjectProgress, active_subject_results)
152
- job_status
153
- self
154
- end
155
-
156
- private
157
-
158
- # Print worker status
159
- #
160
- # @return [undefined]
161
- #
162
- # @api private
163
- #
164
- def job_status
165
- return if active_jobs.empty?
166
- info('Active Jobs:')
167
- active_jobs.sort_by(&:index).each do |job|
168
- info('%d: %s', job.index, job.payload.identification)
169
- end
170
- end
171
-
172
- # Return active subject results
173
- #
174
- # @return [Array<Result::Subject>]
175
- #
176
- # @api private
177
- #
178
- def active_subject_results
179
- active_mutation_jobs = active_jobs.select { |job| job.payload.kind_of?(Mutation) }
180
- active_subjects = active_mutation_jobs.map(&:payload).flat_map(&:subject).to_set
181
-
182
- payload.subject_results.select do |subject_result|
183
- active_subjects.include?(subject_result.subject)
184
- end
185
- end
186
-
187
- end # Status
188
-
189
- # Progress printer for configuration
190
- class Config < self
191
-
192
- # Report configuration
193
- #
194
- # @param [Mutant::Config] config
195
- #
196
- # @return [self]
197
- #
198
- # @api private
199
- #
200
- # rubocop:disable AbcSize
201
- #
202
- def run
203
- info 'Mutant configuration:'
204
- info 'Matcher: %s', object.matcher.inspect
205
- info 'Integration: %s', object.integration.name
206
- info 'Expect Coverage: %0.2f%%', (object.expected_coverage * 100)
207
- info 'Jobs: %d', object.jobs
208
- info 'Includes: %s', object.includes.inspect
209
- info 'Requires: %s', object.requires.inspect
210
- self
211
- end
212
-
213
- end # Config
214
-
215
- # Env progress printer
216
- class EnvProgress < self
217
-
218
- delegate(
219
- :coverage,
220
- :amount_subjects,
221
- :amount_mutations,
222
- :amount_mutations_alive,
223
- :amount_mutations_killed,
224
- :runtime,
225
- :killtime,
226
- :overhead,
227
- :env
228
- )
229
-
230
- # Run printer
231
- #
232
- # @return [self]
233
- #
234
- # @api private
235
- #
236
- # rubocop:disable MethodLength
237
- #
238
- def run
239
- visit(Config, env.config)
240
- info 'Subjects: %s', amount_subjects
241
- info 'Mutations: %s', amount_mutations
242
- info 'Kills: %s', amount_mutations_killed
243
- info 'Alive: %s', amount_mutations_alive
244
- info 'Runtime: %0.2fs', runtime
245
- info 'Killtime: %0.2fs', killtime
246
- info 'Overhead: %0.2f%%', overhead_percent
247
- status 'Coverage: %0.2f%%', coverage_percent
248
- status 'Expected: %0.2f%%', (env.config.expected_coverage * 100)
249
- self
250
- end
251
-
252
- private
253
-
254
- # Return coverage percent
255
- #
256
- # @return [Float]
257
- #
258
- # @api private
259
- #
260
- def coverage_percent
261
- coverage * 100
262
- end
263
-
264
- # Return overhead percent
265
- #
266
- # @return [Float]
267
- #
268
- # @api private
269
- #
270
- def overhead_percent
271
- (overhead / killtime) * 100
272
- end
273
-
274
- end # EnvProgress
275
-
276
- # Full env result reporter
277
- class EnvResult < self
278
-
279
- delegate(:failed_subject_results)
280
-
281
- # Run printer
282
- #
283
- # @return [self]
284
- #
285
- # @api private
286
- #
287
- def run
288
- visit_collection(SubjectResult, failed_subject_results)
289
- visit(EnvProgress, object)
290
- self
291
- end
292
-
293
- end # EnvResult
294
-
295
- # Subject report printer
296
- class SubjectResult < self
297
-
298
- delegate :subject, :failed_mutations, :tests
299
-
300
- # Run report printer
301
- #
302
- # @return [self]
303
- #
304
- # @api private
305
- #
306
- def run
307
- status(subject.identification)
308
- tests.each do |test|
309
- puts("- #{test.identification}")
310
- end
311
- visit_collection(MutationResult, object.alive_mutation_results)
312
- self
313
- end
314
-
315
- end # Subject
316
-
317
- # Printer for mutation progress results
318
- class MutationProgressResult < self
319
-
320
- SUCCESS = '.'.freeze
321
- FAILURE = 'F'.freeze
322
-
323
- # Run printer
324
- #
325
- # @return [self]
326
- #
327
- # @api private
328
- #
329
- def run
330
- char(success? ? SUCCESS : FAILURE)
331
- end
332
-
333
- private
334
-
335
- # Write colorized char
336
- #
337
- # @param [String] char
338
- #
339
- # @return [undefined]
340
- #
341
- # @api private
342
- #
343
- def char(char)
344
- output.write(colorize(status_color, char))
345
- end
346
-
347
- end # MutationProgressResult
348
-
349
- # Reporter for progressive output format on scheduler Status objects
350
- class StatusProgressive < self
351
-
352
- FORMAT = '(%02d/%02d) %3d%% - killtime: %0.02fs runtime: %0.02fs overhead: %0.02fs'.freeze
353
-
354
- delegate(
355
- :coverage,
356
- :runtime,
357
- :amount_mutations_killed,
358
- :amount_mutations,
359
- :amount_mutation_results,
360
- :killtime,
361
- :overhead
362
- )
363
-
364
- # Run printer
365
- #
366
- # @return [self]
367
- #
368
- # @api private
369
- #
370
- def run
371
- status(
372
- FORMAT,
373
- amount_mutations_killed,
374
- amount_mutations,
375
- coverage * 100,
376
- killtime,
377
- runtime,
378
- overhead
379
- )
380
-
381
- self
382
- end
383
-
384
- private
385
-
386
- # Return object being printed
387
- #
388
- # @return [Result::Env]
389
- #
390
- # @api private
391
- #
392
- def object
393
- super().payload
394
- end
395
- end
396
-
397
- # Reporter for subject progress
398
- class SubjectProgress < self
399
-
400
- FORMAT = '(%02d/%02d) %3d%% - killtime: %0.02fs runtime: %0.02fs overhead: %0.02fs'.freeze
401
-
402
- delegate(
403
- :tests,
404
- :subject,
405
- :coverage,
406
- :runtime,
407
- :amount_mutations_killed,
408
- :amount_mutations,
409
- :amount_mutation_results,
410
- :killtime,
411
- :overhead
412
- )
413
-
414
- # Run printer
415
- #
416
- # @return [self]
417
- #
418
- # @api private
419
- #
420
- def run
421
- puts("#{subject.identification} mutations: #{amount_mutations}")
422
- print_tests
423
- print_mutation_results
424
- print_progress_bar_finish
425
- print_stats
426
- self
427
- end
428
-
429
- private
430
-
431
- # Print stats
432
- #
433
- # @return [undefined]
434
- #
435
- # @api private
436
- #
437
- def print_stats
438
- status(
439
- FORMAT,
440
- amount_mutations_killed,
441
- amount_mutations,
442
- coverage * 100,
443
- killtime,
444
- runtime,
445
- overhead
446
- )
447
- end
448
-
449
- # Print tests
450
- #
451
- # @return [undefined]
452
- #
453
- # @api private
454
- #
455
- def print_tests
456
- tests.each do |test|
457
- puts "- #{test.identification}"
458
- end
459
- end
460
-
461
- # Print progress bar finish
462
- #
463
- # @return [undefined]
464
- #
465
- # @api private
466
- #
467
- def print_progress_bar_finish
468
- puts(NL) unless amount_mutation_results.zero?
469
- end
470
-
471
- # Print mutation results
472
- #
473
- # @return [undefined]
474
- #
475
- # @api private
476
- #
477
- def print_mutation_results
478
- visit_collection(MutationProgressResult, object.mutation_results)
479
- end
480
-
481
- end # Subject
482
-
483
- # Reporter for mutation results
484
- class MutationResult < self
485
-
486
- delegate :mutation, :test_result
487
-
488
- DIFF_ERROR_MESSAGE =
489
- 'BUG: Mutation NOT resulted in exactly one diff hunk. Please report a reproduction!'.freeze
490
-
491
- MAP = {
492
- Mutant::Mutation::Evil => :evil_details,
493
- Mutant::Mutation::Neutral => :neutral_details,
494
- Mutant::Mutation::Noop => :noop_details
495
- }.freeze
496
-
497
- NEUTRAL_MESSAGE =
498
- "--- Neutral failure ---\n" \
499
- "Original code was inserted unmutated. And the test did NOT PASS.\n" \
500
- "Your tests do not pass initially or you found a bug in mutant / unparser.\n" \
501
- "Subject AST:\n" \
502
- "%s\n" \
503
- "Unparsed Source:\n" \
504
- "%s\n" \
505
- "Test Result:\n".freeze
506
-
507
- NOOP_MESSAGE =
508
- "---- Noop failure -----\n" \
509
- "No code was inserted. And the test did NOT PASS.\n" \
510
- "This is typically a problem of your specs not passing unmutated.\n" \
511
- "Test Result:\n".freeze
512
-
513
- FOOTER = '-----------------------'.freeze
514
-
515
- # Run report printer
516
- #
517
- # @return [self]
518
- #
519
- # @api private
520
- #
521
- def run
522
- puts(mutation.identification)
523
- print_details
524
- puts(FOOTER)
525
- self
526
- end
527
-
528
- private
529
-
530
- # Return details
531
- #
532
- # @return [undefined]
533
- #
534
- # @api private
535
- #
536
- def print_details
537
- send(MAP.fetch(mutation.class))
538
- end
539
-
540
- # Return evil details
541
- #
542
- # @return [String]
543
- #
544
- # @api private
545
- #
546
- def evil_details
547
- original, current = mutation.original_source, mutation.source
548
- diff = Mutant::Diff.build(original, current)
549
- diff = color? ? diff.colorized_diff : diff.diff
550
- puts(diff || ['Original source:', original, 'Mutated Source:', current, DIFF_ERROR_MESSAGE])
551
- end
552
-
553
- # Noop details
554
- #
555
- # @return [String]
556
- #
557
- # @api private
558
- #
559
- def noop_details
560
- info(NOOP_MESSAGE)
561
- visit_test_result
562
- end
563
-
564
- # Neutral details
565
- #
566
- # @return [String]
567
- #
568
- # @api private
569
- #
570
- def neutral_details
571
- info(NEUTRAL_MESSAGE, mutation.subject.node.inspect, mutation.source)
572
- visit_test_result
573
- end
574
-
575
- # Visit failed test results
576
- #
577
- # @return [undefined]
578
- #
579
- # @api private
580
- #
581
- def visit_test_result
582
- visit(TestResult, test_result)
583
- end
584
-
585
- end # MutationResult
586
-
587
- # Test result reporter
588
- class TestResult < self
589
-
590
- delegate :tests, :runtime
591
-
592
- # Run test result reporter
593
- #
594
- # @return [self]
595
- #
596
- # @api private
597
- #
598
- def run
599
- status('- %d @ runtime: %s', tests.length, runtime)
600
- tests.each do |test|
601
- puts(" - #{test.identification}")
602
- end
603
- puts('Test Output:')
604
- puts(object.output)
605
- end
606
-
607
- # Test if test result is successful
608
- #
609
- # Only used to determine color.
610
- #
611
- # @return [false]
612
- #
613
- # @api private
614
- #
615
- def success?
616
- false
617
- end
618
-
619
- end # TestResult
620
125
  end # Printer
621
126
  end # CLI
622
127
  end # Reporter