mutant 0.5.12 → 0.5.13
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 +10 -0
- data/circle.yml +1 -1
- data/config/flay.yml +1 -1
- data/config/flog.yml +1 -1
- data/config/mutant.yml +1 -2
- data/config/reek.yml +12 -3
- data/config/rubocop.yml +4 -0
- data/lib/mutant.rb +45 -16
- data/lib/mutant/constants.rb +11 -11
- data/lib/mutant/delegator.rb +50 -0
- data/lib/mutant/{differ.rb → diff.rb} +5 -5
- data/lib/mutant/killer.rb +29 -106
- data/lib/mutant/matcher/method.rb +2 -11
- data/lib/mutant/mutation.rb +17 -3
- data/lib/mutant/mutation/evil.rb +2 -10
- data/lib/mutant/mutation/neutral.rb +4 -30
- data/lib/mutant/mutator/node/literal/fixnum.rb +0 -1
- data/lib/mutant/mutator/node/literal/float.rb +0 -1
- data/lib/mutant/mutator/node/literal/string.rb +0 -1
- data/lib/mutant/mutator/node/literal/symbol.rb +6 -2
- data/lib/mutant/mutator/node/named_value/variable_assignment.rb +8 -3
- data/lib/mutant/mutator/util/symbol.rb +3 -1
- data/lib/mutant/node_helpers.rb +1 -3
- data/lib/mutant/reporter.rb +10 -0
- data/lib/mutant/reporter/cli.rb +15 -2
- data/lib/mutant/reporter/cli/printer.rb +12 -105
- data/lib/mutant/reporter/cli/progress.rb +12 -0
- data/lib/mutant/reporter/cli/progress/config.rb +32 -0
- data/lib/mutant/reporter/cli/{printer/killer.rb → progress/mutation.rb} +9 -16
- data/lib/mutant/reporter/cli/progress/noop.rb +22 -0
- data/lib/mutant/reporter/cli/progress/subject.rb +118 -0
- data/lib/mutant/reporter/cli/registry.rb +77 -0
- data/lib/mutant/reporter/cli/report.rb +12 -0
- data/lib/mutant/reporter/cli/report/config.rb +118 -0
- data/lib/mutant/reporter/cli/report/mutation.rb +112 -0
- data/lib/mutant/reporter/cli/report/subject.rb +33 -0
- data/lib/mutant/reporter/null.rb +13 -0
- data/lib/mutant/reporter/trace.rb +41 -0
- data/lib/mutant/runner.rb +22 -20
- data/lib/mutant/runner/config.rb +6 -5
- data/lib/mutant/runner/killer.rb +59 -0
- data/lib/mutant/runner/mutation.rb +17 -10
- data/lib/mutant/runner/subject.rb +14 -4
- data/lib/mutant/strategy.rb +30 -16
- data/lib/mutant/subject/method/instance.rb +1 -1
- data/lib/mutant/test.rb +86 -0
- data/lib/mutant/version.rb +1 -1
- data/spec/integration/mutant/null_spec.rb +18 -0
- data/spec/integration/mutant/rspec_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -2
- data/spec/unit/mutant/diff_spec.rb +162 -0
- data/spec/unit/mutant/mutation_spec.rb +8 -5
- data/spec/unit/mutant/mutator/node/and_asgn_spec.rb +1 -9
- data/spec/unit/mutant/mutator/node/block_spec.rb +6 -18
- data/spec/unit/mutant/mutator/node/case_spec.rb +10 -16
- data/spec/unit/mutant/mutator/node/define_spec.rb +5 -17
- data/spec/unit/mutant/mutator/node/dstr_spec.rb +0 -6
- data/spec/unit/mutant/mutator/node/dsym_spec.rb +0 -5
- data/spec/unit/mutant/mutator/node/if_spec.rb +13 -17
- data/spec/unit/mutant/mutator/node/literal/fixnum_spec.rb +1 -7
- data/spec/unit/mutant/mutator/node/literal/float_spec.rb +0 -9
- data/spec/unit/mutant/mutator/node/literal/range_spec.rb +0 -10
- data/spec/unit/mutant/mutator/node/literal/string_spec.rb +1 -5
- data/spec/unit/mutant/mutator/node/literal/symbol_spec.rb +1 -5
- data/spec/unit/mutant/mutator/node/named_value/access_spec.rb +4 -7
- data/spec/unit/mutant/mutator/node/named_value/constant_assignment_spec.rb +1 -5
- data/spec/unit/mutant/mutator/node/named_value/variable_assignment_spec.rb +4 -8
- data/spec/unit/mutant/mutator/node/op_assgn_spec.rb +0 -7
- data/spec/unit/mutant/mutator/node/or_asgn_spec.rb +1 -9
- data/spec/unit/mutant/mutator/node/rescue_spec.rb +0 -4
- data/spec/unit/mutant/reporter/null_spec.rb +11 -0
- data/spec/unit/mutant/runner/config_spec.rb +6 -7
- data/spec/unit/mutant/runner/mutation_spec.rb +101 -0
- data/spec/unit/mutant/runner/subject_spec.rb +10 -7
- data/spec/unit/mutant_spec.rb +53 -0
- metadata +65 -62
- data/lib/mutant/killer/forked.rb +0 -46
- data/lib/mutant/killer/forking.rb +0 -46
- data/lib/mutant/killer/static.rb +0 -34
- data/lib/mutant/mutator/node/literal/dynamic.rb +0 -27
- data/lib/mutant/random.rb +0 -38
- data/lib/mutant/reporter/cli/printer/config.rb +0 -154
- data/lib/mutant/reporter/cli/printer/mutation.rb +0 -103
- data/lib/mutant/reporter/cli/printer/subject.rb +0 -150
- data/spec/unit/mutant/differ/diff_spec.rb +0 -123
- data/spec/unit/mutant/differ_spec.rb +0 -42
- data/spec/unit/mutant/killer/success_predicate_spec.rb +0 -30
- data/spec/unit/mutant/rspec/killer_spec.rb +0 -57
- data/spec/unit/mutant/runner/mutation/killer_spec.rb +0 -44
@@ -0,0 +1,32 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Reporter
|
3
|
+
class CLI
|
4
|
+
class Progress
|
5
|
+
# Progress printer for configuration
|
6
|
+
class Config < self
|
7
|
+
|
8
|
+
handle(Mutant::Config)
|
9
|
+
|
10
|
+
delegate :matcher, :strategy, :expected_coverage
|
11
|
+
|
12
|
+
# Report configuration
|
13
|
+
#
|
14
|
+
# @param [Mutant::Config] config
|
15
|
+
#
|
16
|
+
# @return [self]
|
17
|
+
#
|
18
|
+
# @api private
|
19
|
+
#
|
20
|
+
def run
|
21
|
+
info 'Mutant configuration:'
|
22
|
+
info 'Matcher: %s', matcher.inspect
|
23
|
+
info 'Strategy: %s', strategy.inspect
|
24
|
+
info 'Expect Coverage: %02f%%', expected_coverage.inspect
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
end # Progress
|
29
|
+
end # Printer
|
30
|
+
end # CLI
|
31
|
+
end # Reporter
|
32
|
+
end # Mutant
|
@@ -1,14 +1,12 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
1
|
module Mutant
|
4
2
|
class Reporter
|
5
3
|
class CLI
|
6
|
-
class
|
4
|
+
class Progress
|
7
5
|
|
8
|
-
#
|
9
|
-
class
|
6
|
+
# Mutation progress reporter
|
7
|
+
class Mutation < self
|
10
8
|
|
11
|
-
handle(
|
9
|
+
handle(Runner::Mutation)
|
12
10
|
|
13
11
|
SUCCESS = '.'.freeze
|
14
12
|
FAILURE = 'F'.freeze
|
@@ -20,11 +18,7 @@ module Mutant
|
|
20
18
|
# @api private
|
21
19
|
#
|
22
20
|
def run
|
23
|
-
|
24
|
-
char(SUCCESS, Color::GREEN)
|
25
|
-
else
|
26
|
-
char(FAILURE, Color::RED)
|
27
|
-
end
|
21
|
+
char(success? ? SUCCESS : FAILURE)
|
28
22
|
end
|
29
23
|
|
30
24
|
private
|
@@ -32,19 +26,18 @@ module Mutant
|
|
32
26
|
# Write colorized char
|
33
27
|
#
|
34
28
|
# @param [String] char
|
35
|
-
# @param [Color]
|
36
29
|
#
|
37
30
|
# @return [undefined]
|
38
31
|
#
|
39
32
|
# @api private
|
40
33
|
#
|
41
|
-
def char(char
|
42
|
-
output.write(colorize(
|
34
|
+
def char(char)
|
35
|
+
output.write(colorize(status_color, char))
|
43
36
|
output.flush
|
44
37
|
end
|
45
38
|
|
46
|
-
end #
|
47
|
-
end #
|
39
|
+
end # Mutation
|
40
|
+
end # Progress
|
48
41
|
end # CLI
|
49
42
|
end # Reporter
|
50
43
|
end # Mutant
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Reporter
|
3
|
+
class CLI
|
4
|
+
class Progress
|
5
|
+
# Noop CLI progress reporter
|
6
|
+
class Noop < self
|
7
|
+
|
8
|
+
handle(Mutant::Mutation)
|
9
|
+
|
10
|
+
# Noop progress report
|
11
|
+
#
|
12
|
+
# @return [self]
|
13
|
+
#
|
14
|
+
def run
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
end # Noop
|
19
|
+
end # Progress
|
20
|
+
end # CLI
|
21
|
+
end # Reporter
|
22
|
+
end # Mutant
|
@@ -0,0 +1,118 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Reporter
|
3
|
+
class CLI
|
4
|
+
class Progress
|
5
|
+
# Subject results printer
|
6
|
+
class Subject < self
|
7
|
+
|
8
|
+
handle(Mutant::Subject)
|
9
|
+
|
10
|
+
# Run subject results printer
|
11
|
+
#
|
12
|
+
# @return [undefined]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
def run
|
17
|
+
puts(object.identification)
|
18
|
+
end
|
19
|
+
|
20
|
+
end # Subject
|
21
|
+
|
22
|
+
# Reporter for subject runners
|
23
|
+
class SubjectRunner < self
|
24
|
+
|
25
|
+
FORMAT = '(%02d/%02d) %3d%% - %0.02fs'.freeze
|
26
|
+
|
27
|
+
handle(Mutant::Runner::Subject)
|
28
|
+
|
29
|
+
# Run printer
|
30
|
+
#
|
31
|
+
# @return [undefined]
|
32
|
+
#
|
33
|
+
# @api private
|
34
|
+
#
|
35
|
+
def run
|
36
|
+
print_progress_bar_finish
|
37
|
+
print_stats
|
38
|
+
self
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# Return mutation time on subject
|
44
|
+
#
|
45
|
+
# @return [Float]
|
46
|
+
#
|
47
|
+
# @api private
|
48
|
+
#
|
49
|
+
def time
|
50
|
+
mutations.map(&:runtime).inject(0, :+)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Print stats
|
54
|
+
#
|
55
|
+
# @return [undefined]
|
56
|
+
#
|
57
|
+
# @api private
|
58
|
+
#
|
59
|
+
def print_stats
|
60
|
+
status(FORMAT, amount_kills, amount_mutations, coverage, time)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Print progress bar finish
|
64
|
+
#
|
65
|
+
# @return [undefined]
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
#
|
69
|
+
def print_progress_bar_finish
|
70
|
+
puts unless amount_mutations.zero?
|
71
|
+
end
|
72
|
+
|
73
|
+
# Return kills
|
74
|
+
#
|
75
|
+
# @return [Fixnum]
|
76
|
+
#
|
77
|
+
# @api private
|
78
|
+
#
|
79
|
+
def amount_kills
|
80
|
+
amount_mutations - object.failed_mutations.length
|
81
|
+
end
|
82
|
+
|
83
|
+
# Return amount of mutations
|
84
|
+
#
|
85
|
+
# @return [Array<Mutation>]
|
86
|
+
#
|
87
|
+
# @api private
|
88
|
+
#
|
89
|
+
def amount_mutations
|
90
|
+
mutations.length
|
91
|
+
end
|
92
|
+
|
93
|
+
# Return mutations
|
94
|
+
#
|
95
|
+
# @return [Array<Mutation>]
|
96
|
+
#
|
97
|
+
# @api private
|
98
|
+
#
|
99
|
+
def mutations
|
100
|
+
object.mutations
|
101
|
+
end
|
102
|
+
|
103
|
+
# Return subject coverage
|
104
|
+
#
|
105
|
+
# @return [Float]
|
106
|
+
#
|
107
|
+
# @api private
|
108
|
+
#
|
109
|
+
def coverage
|
110
|
+
return 0 if amount_mutations.zero?
|
111
|
+
Rational(amount_kills, amount_mutations) * 100
|
112
|
+
end
|
113
|
+
|
114
|
+
end # Runner
|
115
|
+
end # Progress
|
116
|
+
end # CLI
|
117
|
+
end # Reporter
|
118
|
+
end # Mutant
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Reporter
|
3
|
+
class CLI
|
4
|
+
# Mixin to generate registry semantics
|
5
|
+
class Registry < Module
|
6
|
+
include Concord.new(:registry)
|
7
|
+
|
8
|
+
# Return new registry
|
9
|
+
#
|
10
|
+
# @return [Registry]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
#
|
14
|
+
def self.new
|
15
|
+
super({})
|
16
|
+
end
|
17
|
+
|
18
|
+
# Register handler for class
|
19
|
+
#
|
20
|
+
# @param [Class] klass
|
21
|
+
#
|
22
|
+
# @return [self]
|
23
|
+
#
|
24
|
+
# @api private
|
25
|
+
#
|
26
|
+
def handle(subject, handler)
|
27
|
+
raise "Duplicate registration of #{subject}" if registry.key?(subject)
|
28
|
+
registry[subject] = handler
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
# Lookup handler
|
33
|
+
#
|
34
|
+
# @param [Class] subject
|
35
|
+
#
|
36
|
+
# @return [Object]
|
37
|
+
# if found
|
38
|
+
#
|
39
|
+
# @raise [RuntimeError]
|
40
|
+
# otherwise
|
41
|
+
#
|
42
|
+
# @api private
|
43
|
+
#
|
44
|
+
def lookup(subject)
|
45
|
+
current = subject
|
46
|
+
until current == Object
|
47
|
+
if registry.key?(current)
|
48
|
+
return registry.fetch(current)
|
49
|
+
end
|
50
|
+
current = current.superclass
|
51
|
+
end
|
52
|
+
raise "No printer for: #{subject}"
|
53
|
+
end
|
54
|
+
|
55
|
+
# Hook called when module is included
|
56
|
+
#
|
57
|
+
# @param [Class,Module] host
|
58
|
+
#
|
59
|
+
# @return [undefined]
|
60
|
+
#
|
61
|
+
def included(host)
|
62
|
+
object = self
|
63
|
+
host.class_eval do
|
64
|
+
define_singleton_method(:lookup, &object.method(:lookup))
|
65
|
+
private_class_method :lookup
|
66
|
+
|
67
|
+
define_singleton_method(:handle) do |subject|
|
68
|
+
object.handle(subject, self)
|
69
|
+
end
|
70
|
+
private_class_method :handle
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end # Registry
|
75
|
+
end # CLI
|
76
|
+
end # Reporter
|
77
|
+
end # Mutant
|
@@ -0,0 +1,118 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Reporter
|
5
|
+
class CLI
|
6
|
+
class Report
|
7
|
+
|
8
|
+
# Printer for configuration
|
9
|
+
class Config < self
|
10
|
+
|
11
|
+
handle(Mutant::Runner::Config)
|
12
|
+
|
13
|
+
delegate(
|
14
|
+
:amount_kills, :amount_mutations, :amount_kils,
|
15
|
+
:coverage, :subjects, :failed_subjects, :runtime, :mutations
|
16
|
+
)
|
17
|
+
|
18
|
+
# Run printer
|
19
|
+
#
|
20
|
+
# @return [self]
|
21
|
+
#
|
22
|
+
# @api private
|
23
|
+
#
|
24
|
+
def run
|
25
|
+
failed_subjects.each(&method(:visit))
|
26
|
+
info 'Subjects: %s', amount_subjects
|
27
|
+
info 'Mutations: %s', amount_mutations
|
28
|
+
info 'Kills: %s', amount_kills
|
29
|
+
info 'Alive: %s', amount_alive
|
30
|
+
info 'Runtime: %0.2fs', runtime
|
31
|
+
info 'Killtime: %0.2fs', killtime
|
32
|
+
info 'Overhead: %0.2f%%', overhead
|
33
|
+
status 'Coverage: %0.2f%%', coverage
|
34
|
+
status 'Expected: %0.2f%%', object.config.expected_coverage
|
35
|
+
print_generic_stats
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Print generic stats
|
42
|
+
#
|
43
|
+
# @return [undefined]
|
44
|
+
#
|
45
|
+
# @api private
|
46
|
+
#
|
47
|
+
def print_generic_stats
|
48
|
+
stats = generic_stats.to_a.sort_by(&:last)
|
49
|
+
return if stats.empty?
|
50
|
+
info('Nodes handled by generic mutator (type:occurrences):')
|
51
|
+
stats.reverse_each do |type, amount|
|
52
|
+
info('%-10s: %d', type, amount)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Return stats for nodes handled by generic mutator
|
57
|
+
#
|
58
|
+
# @return [Hash<Symbo, Fixnum>]
|
59
|
+
#
|
60
|
+
# @api private
|
61
|
+
#
|
62
|
+
def generic_stats
|
63
|
+
subjects.each_with_object(Hash.new(0)) do |runner, stats|
|
64
|
+
Walker.run(runner.subject.node) do |node|
|
65
|
+
if Mutator::Registry.lookup(node) == Mutator::Node::Generic
|
66
|
+
stats[node.type] += 1
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Return amount of subjects
|
73
|
+
#
|
74
|
+
# @return [Fixnum]
|
75
|
+
#
|
76
|
+
# @api private
|
77
|
+
#
|
78
|
+
def amount_subjects
|
79
|
+
subjects.length
|
80
|
+
end
|
81
|
+
|
82
|
+
# Return amount of time in killers
|
83
|
+
#
|
84
|
+
# @return [Float]
|
85
|
+
#
|
86
|
+
# @api private
|
87
|
+
#
|
88
|
+
def killtime
|
89
|
+
mutations.map(&:runtime).inject(0, :+)
|
90
|
+
end
|
91
|
+
memoize :killtime
|
92
|
+
|
93
|
+
# Return mutant overhead
|
94
|
+
#
|
95
|
+
# @return [Float]
|
96
|
+
#
|
97
|
+
# @api private
|
98
|
+
#
|
99
|
+
def overhead
|
100
|
+
return 0 if runtime.zero?
|
101
|
+
Rational(runtime - killtime, runtime) * 100
|
102
|
+
end
|
103
|
+
|
104
|
+
# Return amount of alive mutations
|
105
|
+
#
|
106
|
+
# @return [Fixnum]
|
107
|
+
#
|
108
|
+
# @api private
|
109
|
+
#
|
110
|
+
def amount_alive
|
111
|
+
object.amount_mutations - amount_kills
|
112
|
+
end
|
113
|
+
|
114
|
+
end # Config
|
115
|
+
end # Report
|
116
|
+
end # CLI
|
117
|
+
end # Reporter
|
118
|
+
end # Mutant
|