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
data/lib/mutant/killer/forked.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Killer
|
5
|
-
|
6
|
-
# Killer that executes other killer in forked environment
|
7
|
-
class Forked < self
|
8
|
-
|
9
|
-
# Initialize object
|
10
|
-
#
|
11
|
-
# @param [Killer] killer
|
12
|
-
# @param [Strategy] strategy
|
13
|
-
# @param [Mutation] mutation
|
14
|
-
#
|
15
|
-
# @api private
|
16
|
-
#
|
17
|
-
def initialize(killer, strategy, mutation)
|
18
|
-
@killer = killer
|
19
|
-
super(strategy, mutation)
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
# Run killer
|
25
|
-
#
|
26
|
-
# @return [true]
|
27
|
-
# if mutant was killed
|
28
|
-
#
|
29
|
-
# @return [false]
|
30
|
-
# otherwise
|
31
|
-
#
|
32
|
-
# @api private
|
33
|
-
#
|
34
|
-
def run
|
35
|
-
pid = fork do
|
36
|
-
killer = @killer.new(strategy, mutation)
|
37
|
-
exit(killer.killed? ? CLI::EXIT_SUCCESS : CLI::EXIT_FAILURE)
|
38
|
-
end
|
39
|
-
|
40
|
-
status = Process.wait2(pid).last
|
41
|
-
status.exited? && status.success?
|
42
|
-
end
|
43
|
-
|
44
|
-
end # Forked
|
45
|
-
end # Killer
|
46
|
-
end # Mutant
|
@@ -1,46 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Killer
|
5
|
-
|
6
|
-
# A killer that executes other killer in forked environemnts
|
7
|
-
class Forking < self
|
8
|
-
include Equalizer.new(:killer)
|
9
|
-
|
10
|
-
# Return killer
|
11
|
-
#
|
12
|
-
# @return [Killer]
|
13
|
-
#
|
14
|
-
# @api private
|
15
|
-
#
|
16
|
-
attr_reader :killer
|
17
|
-
|
18
|
-
# Initalize killer
|
19
|
-
#
|
20
|
-
# @param [Killer] killer
|
21
|
-
# the killer that will be used
|
22
|
-
#
|
23
|
-
# @return [undefined]
|
24
|
-
#
|
25
|
-
# @api private
|
26
|
-
#
|
27
|
-
def initialize(killer)
|
28
|
-
@killer = killer
|
29
|
-
end
|
30
|
-
|
31
|
-
# Return killer instance
|
32
|
-
#
|
33
|
-
# @param [Strategy] strategy
|
34
|
-
# @param [Mutation] mutation
|
35
|
-
#
|
36
|
-
# @return [Killer::Forked]
|
37
|
-
#
|
38
|
-
# @api private
|
39
|
-
#
|
40
|
-
def new(strategy, mutation)
|
41
|
-
Forked.new(killer, strategy, mutation)
|
42
|
-
end
|
43
|
-
|
44
|
-
end # Forking
|
45
|
-
end # Killer
|
46
|
-
end # Mutant
|
data/lib/mutant/killer/static.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Killer
|
5
|
-
# Abstract base class for killer with static result
|
6
|
-
class Static < self
|
7
|
-
|
8
|
-
# Return result
|
9
|
-
#
|
10
|
-
# @return [true]
|
11
|
-
# if mutation was killed
|
12
|
-
#
|
13
|
-
# @return [false]
|
14
|
-
# otherwise
|
15
|
-
#
|
16
|
-
# @api private
|
17
|
-
#
|
18
|
-
def run
|
19
|
-
self.class::RESULT
|
20
|
-
end
|
21
|
-
|
22
|
-
# Killer that is always successful
|
23
|
-
class Success < self
|
24
|
-
RESULT = true
|
25
|
-
end # Success
|
26
|
-
|
27
|
-
# Killer that always fails
|
28
|
-
class Fail < self
|
29
|
-
RESULT = false
|
30
|
-
end # Fail
|
31
|
-
|
32
|
-
end # Static
|
33
|
-
end # Killer
|
34
|
-
end # Mutant
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Mutator
|
5
|
-
class Node
|
6
|
-
class Literal
|
7
|
-
# Abstract mutations on dynamic literals
|
8
|
-
class Dynamic < self
|
9
|
-
include AbstractType
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
# Emit mutants
|
14
|
-
#
|
15
|
-
# @return [undefined]
|
16
|
-
#
|
17
|
-
# @api private
|
18
|
-
#
|
19
|
-
def dispatch
|
20
|
-
emit_nil
|
21
|
-
end
|
22
|
-
|
23
|
-
end # Dynamic
|
24
|
-
end # Literal
|
25
|
-
end # Node
|
26
|
-
end # Mutator
|
27
|
-
end # Mutant
|
data/lib/mutant/random.rb
DELETED
@@ -1,38 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
# Module for generating random values
|
5
|
-
module Random
|
6
|
-
|
7
|
-
# Return random hex string
|
8
|
-
#
|
9
|
-
# @return [String]
|
10
|
-
#
|
11
|
-
# @api private
|
12
|
-
#
|
13
|
-
def self.hex_string
|
14
|
-
SecureRandom.hex(10)
|
15
|
-
end
|
16
|
-
|
17
|
-
# Return random fixnum
|
18
|
-
#
|
19
|
-
# @return [Fixnum]
|
20
|
-
#
|
21
|
-
# @api private
|
22
|
-
#
|
23
|
-
def self.fixnum
|
24
|
-
::Random.rand(1000)
|
25
|
-
end
|
26
|
-
|
27
|
-
# Return random float
|
28
|
-
#
|
29
|
-
# @return [Float]
|
30
|
-
#
|
31
|
-
# @api private
|
32
|
-
#
|
33
|
-
def self.float
|
34
|
-
::Random.rand
|
35
|
-
end
|
36
|
-
|
37
|
-
end # Random
|
38
|
-
end # Mutant
|
@@ -1,154 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Reporter
|
5
|
-
class CLI
|
6
|
-
class Printer
|
7
|
-
|
8
|
-
# Printer for configuration
|
9
|
-
class Config < self
|
10
|
-
|
11
|
-
handle(Mutant::Config)
|
12
|
-
|
13
|
-
delegate :matcher, :strategy, :expected_coverage
|
14
|
-
|
15
|
-
# Report configuration
|
16
|
-
#
|
17
|
-
# @param [Mutant::Config] config
|
18
|
-
#
|
19
|
-
# @return [self]
|
20
|
-
#
|
21
|
-
# @api private
|
22
|
-
#
|
23
|
-
def run
|
24
|
-
info 'Mutant configuration:'
|
25
|
-
info 'Matcher: %s', matcher.inspect
|
26
|
-
info 'Strategy: %s', strategy.inspect
|
27
|
-
info 'Expect Coverage: %02f%%', expected_coverage.inspect
|
28
|
-
self
|
29
|
-
end
|
30
|
-
|
31
|
-
# Config results printer
|
32
|
-
class Runner < self
|
33
|
-
|
34
|
-
handle(Mutant::Runner::Config)
|
35
|
-
|
36
|
-
delegate(
|
37
|
-
:amount_kills, :amount_mutations, :amount_kils,
|
38
|
-
:coverage, :subjects, :failed_subjects, :runtime, :mutations
|
39
|
-
)
|
40
|
-
|
41
|
-
# Run printer
|
42
|
-
#
|
43
|
-
# @return [self]
|
44
|
-
#
|
45
|
-
# @api private
|
46
|
-
#
|
47
|
-
def run
|
48
|
-
print_mutations
|
49
|
-
info 'Subjects: %s', amount_subjects
|
50
|
-
info 'Mutations: %s', amount_mutations
|
51
|
-
info 'Kills: %s', amount_kills
|
52
|
-
info 'Alive: %s', amount_alive
|
53
|
-
info 'Runtime: %0.2fs', runtime
|
54
|
-
info 'Killtime: %0.2fs', killtime
|
55
|
-
info 'Overhead: %0.2f%%', overhead
|
56
|
-
status 'Coverage: %0.2f%%', coverage
|
57
|
-
status 'Expected: %0.2f%%', object.config.expected_coverage
|
58
|
-
print_generic_stats
|
59
|
-
self
|
60
|
-
end
|
61
|
-
|
62
|
-
private
|
63
|
-
|
64
|
-
# Print generic stats
|
65
|
-
#
|
66
|
-
# @return [undefined]
|
67
|
-
#
|
68
|
-
# @api private
|
69
|
-
#
|
70
|
-
def print_generic_stats
|
71
|
-
stats = generic_stats.to_a.sort_by(&:last)
|
72
|
-
return if stats.empty?
|
73
|
-
info('Nodes handled by generic mutator (type:occurrences):')
|
74
|
-
stats.reverse_each do |type, amount|
|
75
|
-
info('%-10s: %d', type, amount)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
# Return stats for nodes handled by generic mutator
|
80
|
-
#
|
81
|
-
# @return [Hash<Symbo, Fixnum>]
|
82
|
-
#
|
83
|
-
# @api private
|
84
|
-
#
|
85
|
-
def generic_stats
|
86
|
-
subjects.each_with_object(Hash.new(0)) do |runner, stats|
|
87
|
-
Walker.run(runner.subject.node) do |node|
|
88
|
-
if Mutator::Registry.lookup(node) == Mutator::Node::Generic
|
89
|
-
stats[node.type] += 1
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
# Return amount of subjects
|
96
|
-
#
|
97
|
-
# @return [Fixnum]
|
98
|
-
#
|
99
|
-
# @api private
|
100
|
-
#
|
101
|
-
def amount_subjects
|
102
|
-
subjects.length
|
103
|
-
end
|
104
|
-
|
105
|
-
# Print mutations
|
106
|
-
#
|
107
|
-
# @return [undefined]
|
108
|
-
#
|
109
|
-
# @api private
|
110
|
-
#
|
111
|
-
def print_mutations
|
112
|
-
failed_subjects.each do |subject|
|
113
|
-
Subject::Runner::Details.run(subject, output)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
# Return amount of time in killers
|
118
|
-
#
|
119
|
-
# @return [Float]
|
120
|
-
#
|
121
|
-
# @api private
|
122
|
-
#
|
123
|
-
def killtime
|
124
|
-
mutations.map(&:runtime).inject(0, :+)
|
125
|
-
end
|
126
|
-
memoize :killtime
|
127
|
-
|
128
|
-
# Return mutant overhead
|
129
|
-
#
|
130
|
-
# @return [Float]
|
131
|
-
#
|
132
|
-
# @api private
|
133
|
-
#
|
134
|
-
def overhead
|
135
|
-
return 0 if runtime.zero?
|
136
|
-
Rational(runtime - killtime, runtime) * 100
|
137
|
-
end
|
138
|
-
|
139
|
-
# Return amount of alive mutations
|
140
|
-
#
|
141
|
-
# @return [Fixnum]
|
142
|
-
#
|
143
|
-
# @api private
|
144
|
-
#
|
145
|
-
def amount_alive
|
146
|
-
object.amount_mutations - amount_kills
|
147
|
-
end
|
148
|
-
|
149
|
-
end # Runner
|
150
|
-
end # Config
|
151
|
-
end # Printer
|
152
|
-
end # CLI
|
153
|
-
end # Reporter
|
154
|
-
end # Mutant
|
@@ -1,103 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Reporter
|
5
|
-
class CLI
|
6
|
-
class Printer
|
7
|
-
# Mutation printer
|
8
|
-
class Mutation < self
|
9
|
-
|
10
|
-
handle(Runner::Mutation)
|
11
|
-
|
12
|
-
# Build printer
|
13
|
-
#
|
14
|
-
# @param [Runner::Mutation] runner
|
15
|
-
# @param [IO] output
|
16
|
-
#
|
17
|
-
# @return [Printer::Mutation]
|
18
|
-
#
|
19
|
-
# @api private
|
20
|
-
#
|
21
|
-
def self.build(runner, output)
|
22
|
-
mutation = runner.mutation
|
23
|
-
lookup(mutation.class).new(runner, output)
|
24
|
-
end
|
25
|
-
|
26
|
-
# Run mutation printer
|
27
|
-
#
|
28
|
-
# @return [undefined]
|
29
|
-
#
|
30
|
-
# @api private
|
31
|
-
#
|
32
|
-
def run
|
33
|
-
status('%s', mutation.identification)
|
34
|
-
puts(details)
|
35
|
-
end
|
36
|
-
|
37
|
-
private
|
38
|
-
|
39
|
-
# Return mutation
|
40
|
-
#
|
41
|
-
# @return [Mutation]
|
42
|
-
#
|
43
|
-
# @api private
|
44
|
-
#
|
45
|
-
def mutation
|
46
|
-
object.mutation
|
47
|
-
end
|
48
|
-
|
49
|
-
# Reporter for noop mutations
|
50
|
-
class Noop < self
|
51
|
-
|
52
|
-
handle(Mutant::Mutation::Neutral::Noop)
|
53
|
-
|
54
|
-
MESSAGE = [
|
55
|
-
'Parsed subject AST:',
|
56
|
-
'%s',
|
57
|
-
'Unparsed source:',
|
58
|
-
'%s'
|
59
|
-
].join("\n")
|
60
|
-
|
61
|
-
private
|
62
|
-
|
63
|
-
# Return details
|
64
|
-
#
|
65
|
-
# @return [String]
|
66
|
-
#
|
67
|
-
# @api private
|
68
|
-
#
|
69
|
-
def details
|
70
|
-
sprintf(
|
71
|
-
MESSAGE,
|
72
|
-
mutation.subject.node.inspect,
|
73
|
-
mutation.original_source
|
74
|
-
)
|
75
|
-
end
|
76
|
-
|
77
|
-
end # Noop
|
78
|
-
|
79
|
-
# Reporter for neutral and evil mutations
|
80
|
-
class Diff < self
|
81
|
-
|
82
|
-
handle(Mutant::Mutation::Neutral)
|
83
|
-
handle(Mutant::Mutation::Evil)
|
84
|
-
|
85
|
-
# Return diff
|
86
|
-
#
|
87
|
-
# @return [String]
|
88
|
-
#
|
89
|
-
# @api private
|
90
|
-
#
|
91
|
-
def details
|
92
|
-
original, current = mutation.original_source, mutation.source
|
93
|
-
differ = Differ.build(original, current)
|
94
|
-
color? ? differ.colorized_diff : differ.diff
|
95
|
-
end
|
96
|
-
|
97
|
-
end # Evil
|
98
|
-
|
99
|
-
end # Mutantion
|
100
|
-
end # Printer
|
101
|
-
end # CLI
|
102
|
-
end # Reporter
|
103
|
-
end # Mutant
|