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
@@ -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
|