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.
- checksums.yaml +4 -4
- data/Changelog.md +11 -1
- data/README.md +5 -12
- data/bin/mutant +17 -1
- data/config/flay.yml +1 -1
- data/config/flog.yml +1 -1
- data/config/reek.yml +4 -4
- data/config/rubocop.yml +21 -3
- data/lib/mutant.rb +15 -61
- data/lib/mutant/cli.rb +1 -7
- data/lib/mutant/color.rb +2 -2
- data/lib/mutant/config.rb +1 -1
- data/lib/mutant/expression/method.rb +1 -1
- data/lib/mutant/expression/methods.rb +1 -1
- data/lib/mutant/expression/namespace.rb +1 -1
- data/lib/mutant/mutator/node/send.rb +18 -18
- data/lib/mutant/reporter/cli.rb +1 -6
- data/lib/mutant/reporter/cli/format.rb +2 -2
- data/lib/mutant/reporter/cli/printer.rb +5 -500
- data/lib/mutant/reporter/cli/printer/config.rb +32 -0
- data/lib/mutant/reporter/cli/printer/env_progress.rb +66 -0
- data/lib/mutant/reporter/cli/printer/env_result.rb +23 -0
- data/lib/mutant/reporter/cli/printer/mutation_progress_result.rb +37 -0
- data/lib/mutant/reporter/cli/printer/mutation_result.rb +151 -0
- data/lib/mutant/reporter/cli/printer/status.rb +60 -0
- data/lib/mutant/reporter/cli/printer/status_progressive.rb +52 -0
- data/lib/mutant/reporter/cli/printer/subject_progress.rb +90 -0
- data/lib/mutant/reporter/cli/printer/subject_result.rb +28 -0
- data/lib/mutant/reporter/cli/printer/test_result.rb +33 -0
- data/lib/mutant/require_highjack.rb +11 -50
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/zombifier.rb +79 -37
- data/meta/send.rb +1 -1
- data/mutant-rspec.gemspec +1 -1
- data/mutant.gemspec +3 -3
- data/spec/integration/mutant/corpus_spec.rb +2 -2
- data/spec/integration/mutant/rspec_spec.rb +5 -15
- data/spec/integrations.yml +3 -3
- data/spec/spec_helper.rb +1 -0
- data/spec/support/corpus.rb +233 -220
- data/spec/support/file_system.rb +60 -0
- data/spec/support/rb_bug.rb +1 -1
- data/spec/support/ruby_vm.rb +82 -0
- data/spec/support/shared_context.rb +19 -10
- data/spec/unit/mutant/ast_spec.rb +2 -2
- data/spec/unit/mutant/cache_spec.rb +22 -0
- data/spec/unit/mutant/cli_spec.rb +1 -30
- data/spec/unit/mutant/context_spec.rb +1 -0
- data/spec/unit/mutant/expression/method_spec.rb +6 -4
- data/spec/unit/mutant/parallel/master_spec.rb +1 -1
- data/spec/unit/mutant/reporter/cli/printer/config_spec.rb +33 -0
- data/spec/unit/mutant/reporter/cli/printer/env_progress_spec.rb +76 -0
- data/spec/unit/mutant/reporter/cli/printer/env_result_spec.rb +35 -0
- data/spec/unit/mutant/reporter/cli/printer/mutation_progress_result_spec.rb +23 -0
- data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +110 -0
- data/spec/unit/mutant/reporter/cli/printer/status_progressive_spec.rb +51 -0
- data/spec/unit/mutant/reporter/cli/printer/status_spec.rb +145 -0
- data/spec/unit/mutant/reporter/cli/printer/subject_progress_spec.rb +37 -0
- data/spec/unit/mutant/reporter/cli/printer/subject_result_spec.rb +37 -0
- data/spec/unit/mutant/reporter/cli/printer/test_result_spec.rb +14 -0
- data/spec/unit/mutant/reporter/cli/printer_spec.rb +140 -0
- data/spec/unit/mutant/reporter/cli_spec.rb +69 -313
- data/spec/unit/mutant/reporter/trace_spec.rb +12 -0
- data/spec/unit/mutant/require_highjack_spec.rb +25 -28
- data/spec/unit/mutant/warning_filter_spec.rb +7 -0
- data/spec/unit/mutant/zombifier_spec.rb +120 -0
- data/spec/unit/mutant_spec.rb +0 -43
- data/test_app/Gemfile.rspec3.3 +6 -0
- metadata +46 -17
- data/.travis.yml +0 -20
- data/lib/mutant/zombifier/file.rb +0 -100
- data/spec/integration/mutant/zombie_spec.rb +0 -6
@@ -49,7 +49,7 @@ module Mutant
|
|
49
49
|
@tty
|
50
50
|
end
|
51
51
|
|
52
|
-
[
|
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.
|
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
|
-
|
8
|
+
private_class_method :new
|
9
9
|
|
10
|
-
|
10
|
+
delegate :success?
|
11
11
|
|
12
|
-
|
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.
|
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
|