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