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
@@ -63,6 +63,17 @@ module Mutant
|
|
63
63
|
failed_mutations.empty?
|
64
64
|
end
|
65
65
|
|
66
|
+
# Return tests used to kill mutations on this subject
|
67
|
+
#
|
68
|
+
# @return [Enumerable<Test>]
|
69
|
+
#
|
70
|
+
# @api private
|
71
|
+
#
|
72
|
+
def tests
|
73
|
+
config.strategy.tests(subject)
|
74
|
+
end
|
75
|
+
memoize :tests
|
76
|
+
|
66
77
|
private
|
67
78
|
|
68
79
|
# Perform operation
|
@@ -72,10 +83,9 @@ module Mutant
|
|
72
83
|
# @api private
|
73
84
|
#
|
74
85
|
def run
|
75
|
-
subject
|
76
|
-
|
77
|
-
|
78
|
-
report(self)
|
86
|
+
progress(subject)
|
87
|
+
@mutations = visit_collection(subject.mutations, tests)
|
88
|
+
progress(self)
|
79
89
|
end
|
80
90
|
|
81
91
|
end # Subject
|
data/lib/mutant/strategy.rb
CHANGED
@@ -54,39 +54,53 @@ module Mutant
|
|
54
54
|
self
|
55
55
|
end
|
56
56
|
|
57
|
-
#
|
57
|
+
# Return all available tests by strategy
|
58
58
|
#
|
59
|
-
# @
|
60
|
-
#
|
61
|
-
# @return [Killer]
|
59
|
+
# @return [Enumerable<Test>]
|
62
60
|
#
|
63
61
|
# @api private
|
64
62
|
#
|
65
|
-
|
66
|
-
killer.new(self, mutation)
|
67
|
-
end
|
63
|
+
abstract_method :all_tests
|
68
64
|
|
69
|
-
|
70
|
-
|
71
|
-
#
|
65
|
+
# Return tests for mutation
|
66
|
+
#
|
67
|
+
# TODO: This logic is now centralized but still fucked.
|
72
68
|
#
|
73
|
-
# @
|
69
|
+
# @param [Mutation] mutation
|
70
|
+
#
|
71
|
+
# @return [Enumerable<Test>]
|
74
72
|
#
|
75
73
|
# @api private
|
76
74
|
#
|
77
|
-
def
|
78
|
-
|
75
|
+
def tests(subject)
|
76
|
+
subject.match_prefixes.map do |match_expression|
|
77
|
+
tests = all_tests.select do |test|
|
78
|
+
test.subject_identification.start_with?(match_expression)
|
79
|
+
end
|
80
|
+
return tests if tests.any?
|
81
|
+
end
|
82
|
+
|
83
|
+
[]
|
79
84
|
end
|
80
85
|
|
86
|
+
private
|
87
|
+
|
81
88
|
# Null strategy that never kills a mutation
|
82
89
|
class Null < self
|
83
90
|
|
84
|
-
register
|
91
|
+
register('null')
|
85
92
|
|
86
|
-
|
93
|
+
# Return all tests
|
94
|
+
#
|
95
|
+
# @return [Enumerable<Test>]
|
96
|
+
#
|
97
|
+
# @api private
|
98
|
+
#
|
99
|
+
def all_tests
|
100
|
+
EMPTY_ARRAY
|
101
|
+
end
|
87
102
|
|
88
103
|
end # Null
|
89
104
|
|
90
105
|
end # Strategy
|
91
|
-
|
92
106
|
end # Mutant
|
data/lib/mutant/test.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
module Mutant
|
2
|
+
# Abstract base class for test that might kill a mutation
|
3
|
+
class Test
|
4
|
+
include AbstractType, Adamantium::Flat
|
5
|
+
|
6
|
+
# Object to report test status
|
7
|
+
class Report
|
8
|
+
include Adamantium::Flat, Anima::Update, Anima.new(
|
9
|
+
:test,
|
10
|
+
:output,
|
11
|
+
:success
|
12
|
+
)
|
13
|
+
|
14
|
+
alias_method :success?, :success
|
15
|
+
|
16
|
+
# Test if test failed
|
17
|
+
#
|
18
|
+
# @return [Boolean]
|
19
|
+
#
|
20
|
+
# @api private
|
21
|
+
#
|
22
|
+
def failed?
|
23
|
+
!success?
|
24
|
+
end
|
25
|
+
|
26
|
+
# Return marshallable data
|
27
|
+
#
|
28
|
+
# NOTE:
|
29
|
+
#
|
30
|
+
# The test is intentionally NOT part of the mashalled data.
|
31
|
+
# In rspec the example group cannot deterministically being marshalled, because
|
32
|
+
# they reference a crazy mix of IO objects, global objects etc.
|
33
|
+
#
|
34
|
+
# @return [Array]
|
35
|
+
#
|
36
|
+
# @api private
|
37
|
+
#
|
38
|
+
def marshal_dump
|
39
|
+
[@output, @success]
|
40
|
+
end
|
41
|
+
|
42
|
+
# Load marshalled data
|
43
|
+
#
|
44
|
+
# @param [Array] arry
|
45
|
+
#
|
46
|
+
# @return [undefined]
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
#
|
50
|
+
def marshal_load(array)
|
51
|
+
@output, @success = array
|
52
|
+
end
|
53
|
+
|
54
|
+
end # Report
|
55
|
+
|
56
|
+
# Run tests
|
57
|
+
#
|
58
|
+
# @return [Test::Result]
|
59
|
+
#
|
60
|
+
# @api private
|
61
|
+
#
|
62
|
+
abstract_method :run
|
63
|
+
|
64
|
+
# Return test identification
|
65
|
+
#
|
66
|
+
# @return [String]
|
67
|
+
#
|
68
|
+
# @api private
|
69
|
+
#
|
70
|
+
def identification
|
71
|
+
"#{self.class::PREFIX}:#{subject_identification}"
|
72
|
+
end
|
73
|
+
memoize :identification
|
74
|
+
|
75
|
+
# Return subject identification
|
76
|
+
#
|
77
|
+
# This method is used for current mutants primitive test selection.
|
78
|
+
#
|
79
|
+
# @return [String]
|
80
|
+
#
|
81
|
+
# @api private
|
82
|
+
#
|
83
|
+
abstract_method :subject_identification
|
84
|
+
|
85
|
+
end # Test
|
86
|
+
end # Mutant
|
data/lib/mutant/version.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe 'null integration' do
|
6
|
+
|
7
|
+
let(:base_cmd) { 'bundle exec mutant -I lib --require test_app "::TestApp*"' }
|
8
|
+
|
9
|
+
around do |example|
|
10
|
+
Dir.chdir(TestApp.root) do
|
11
|
+
example.run
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
specify 'it allows to kill mutations' do
|
16
|
+
expect(Kernel.system(base_cmd)).to be(false)
|
17
|
+
end
|
18
|
+
end
|
@@ -10,7 +10,7 @@ describe 'rspec integration' do
|
|
10
10
|
around do |example|
|
11
11
|
Bundler.with_clean_env do
|
12
12
|
Dir.chdir(TestApp.root) do
|
13
|
-
Kernel.system("bundle install --gemfile=#{gemfile}")
|
13
|
+
Kernel.system("bundle install --gemfile=#{gemfile}") || fail('Bundle install failed!')
|
14
14
|
ENV['BUNDLE_GEMFILE'] = gemfile
|
15
15
|
example.run
|
16
16
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,162 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Mutant::Diff do
|
6
|
+
let(:object) { described_class }
|
7
|
+
|
8
|
+
describe '.build' do
|
9
|
+
|
10
|
+
subject { object.build(old_string, new_string) }
|
11
|
+
|
12
|
+
let(:old_string) { "foo\nbar" }
|
13
|
+
let(:new_string) { "bar\nbaz" }
|
14
|
+
|
15
|
+
it { should eql(Mutant::Diff.new(%w(foo bar), %w(bar baz))) }
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '.colorize_line' do
|
20
|
+
let(:object) { described_class }
|
21
|
+
|
22
|
+
subject { object.colorize_line(line) }
|
23
|
+
|
24
|
+
context 'line beginning with "+"' do
|
25
|
+
let(:line) { '+line' }
|
26
|
+
|
27
|
+
it { should eql(Mutant::Color::GREEN.format(line)) }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'line beginning with "-"' do
|
31
|
+
let(:line) { '-line' }
|
32
|
+
|
33
|
+
it { should eql(Mutant::Color::RED.format(line)) }
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'line beginning in other char' do
|
37
|
+
let(:line) { ' line' }
|
38
|
+
|
39
|
+
it { should eql(line) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe '#diff' do
|
44
|
+
let(:object) { described_class.new(old, new) }
|
45
|
+
|
46
|
+
subject { object.diff }
|
47
|
+
|
48
|
+
context 'when there is a diff at begin of hunk' do
|
49
|
+
let(:old) { %w(foo bar) }
|
50
|
+
let(:new) { %w(baz bar) }
|
51
|
+
|
52
|
+
let(:expectation) do
|
53
|
+
strip_indent(<<-STR)
|
54
|
+
@@ -1,3 +1,3 @@
|
55
|
+
-foo
|
56
|
+
+baz
|
57
|
+
bar
|
58
|
+
STR
|
59
|
+
end
|
60
|
+
|
61
|
+
it { should eql(expectation) }
|
62
|
+
|
63
|
+
it_should_behave_like 'an idempotent method'
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when there is a diff NOT at begin of hunk' do
|
67
|
+
let(:old) { %w(foo bar) }
|
68
|
+
let(:new) { %w(foo baz bar) }
|
69
|
+
|
70
|
+
let(:expectation) do
|
71
|
+
strip_indent(<<-STR)
|
72
|
+
@@ -1,3 +1,4 @@
|
73
|
+
foo
|
74
|
+
+baz
|
75
|
+
bar
|
76
|
+
STR
|
77
|
+
end
|
78
|
+
|
79
|
+
it { should eql(expectation) }
|
80
|
+
|
81
|
+
it_should_behave_like 'an idempotent method'
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'when the diff has a long context at begin' do
|
85
|
+
let(:old) { %w(foo bar baz boz a b c) }
|
86
|
+
let(:new) { %w(foo bar baz boz a b c other) }
|
87
|
+
|
88
|
+
let(:expectation) do
|
89
|
+
strip_indent(<<-STR)
|
90
|
+
@@ -1,8 +1,9 @@
|
91
|
+
foo
|
92
|
+
bar
|
93
|
+
baz
|
94
|
+
boz
|
95
|
+
a
|
96
|
+
b
|
97
|
+
c
|
98
|
+
+other
|
99
|
+
STR
|
100
|
+
end
|
101
|
+
|
102
|
+
it { should eql(expectation) }
|
103
|
+
|
104
|
+
it_should_behave_like 'an idempotent method'
|
105
|
+
end
|
106
|
+
|
107
|
+
context 'when the diff has a long context at end, deleting' do
|
108
|
+
let(:old) { %w(other foo bar baz boz a b c) }
|
109
|
+
let(:new) { %w(foo bar baz boz a b c) }
|
110
|
+
|
111
|
+
let(:expectation) do
|
112
|
+
strip_indent(<<-STR)
|
113
|
+
@@ -1,9 +1,8 @@
|
114
|
+
-other
|
115
|
+
foo
|
116
|
+
bar
|
117
|
+
baz
|
118
|
+
boz
|
119
|
+
a
|
120
|
+
b
|
121
|
+
c
|
122
|
+
STR
|
123
|
+
end
|
124
|
+
|
125
|
+
it { should eql(expectation) }
|
126
|
+
|
127
|
+
it_should_behave_like 'an idempotent method'
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'when the diff has a long context at end, inserting' do
|
131
|
+
let(:old) { %w(foo bar baz boz a b c) }
|
132
|
+
let(:new) { %w(other foo bar baz boz a b c) }
|
133
|
+
|
134
|
+
let(:expectation) do
|
135
|
+
strip_indent(<<-STR)
|
136
|
+
@@ -1,8 +1,9 @@
|
137
|
+
+other
|
138
|
+
foo
|
139
|
+
bar
|
140
|
+
baz
|
141
|
+
boz
|
142
|
+
a
|
143
|
+
b
|
144
|
+
c
|
145
|
+
STR
|
146
|
+
end
|
147
|
+
|
148
|
+
it { should eql(expectation) }
|
149
|
+
|
150
|
+
it_should_behave_like 'an idempotent method'
|
151
|
+
end
|
152
|
+
|
153
|
+
context 'when there is no diff' do
|
154
|
+
let(:old) { '' }
|
155
|
+
let(:new) { '' }
|
156
|
+
|
157
|
+
it { should be(nil) }
|
158
|
+
|
159
|
+
it_should_behave_like 'an idempotent method'
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
@@ -4,10 +4,13 @@ require 'spec_helper'
|
|
4
4
|
|
5
5
|
describe Mutant::Mutation do
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
class TestMutation < Mutant::Mutation
|
8
|
+
SYMBOL = 'test'
|
9
|
+
end
|
10
|
+
|
11
|
+
let(:object) { TestMutation.new(mutation_subject, Mutant::NodeHelpers::N_NIL) }
|
12
|
+
let(:mutation_subject) { double('Subject', identification: 'subject', source: 'original') }
|
13
|
+
let(:node) { double('Node') }
|
11
14
|
|
12
15
|
describe '#code' do
|
13
16
|
subject { object.code }
|
@@ -37,7 +40,7 @@ describe Mutant::Mutation do
|
|
37
40
|
|
38
41
|
subject { object.identification }
|
39
42
|
|
40
|
-
it { should eql('subject:8771a') }
|
43
|
+
it { should eql('test:subject:8771a') }
|
41
44
|
|
42
45
|
it_should_behave_like 'an idempotent method'
|
43
46
|
end
|
@@ -3,25 +3,17 @@
|
|
3
3
|
require 'spec_helper'
|
4
4
|
|
5
5
|
describe Mutant::Mutator::Node::OpAsgn, 'and_asgn' do
|
6
|
-
let(:random_fixnum) { 5 }
|
7
|
-
let(:random_string) { 'random' }
|
8
|
-
|
9
6
|
let(:source) { 'a &&= 1' }
|
10
7
|
|
11
8
|
let(:mutations) do
|
12
9
|
mutations = []
|
13
|
-
mutations << '
|
10
|
+
mutations << 'a__mutant__ &&= 1'
|
14
11
|
mutations << 'a &&= nil'
|
15
12
|
mutations << 'a &&= 0'
|
16
13
|
mutations << 'a &&= -1'
|
17
14
|
mutations << 'a &&= 2'
|
18
|
-
mutations << 'a &&= 5'
|
19
15
|
mutations << 'nil'
|
20
16
|
end
|
21
17
|
|
22
|
-
before do
|
23
|
-
Mutant::Random.stub(fixnum: random_fixnum, hex_string: random_string)
|
24
|
-
end
|
25
|
-
|
26
18
|
it_should_behave_like 'a mutator'
|
27
19
|
end
|