mutant 0.8.9 → 0.8.10
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 +4 -0
- data/config/devtools.yml +1 -1
- data/config/flay.yml +1 -1
- data/lib/mutant.rb +1 -2
- data/lib/mutant/ast/types.rb +3 -2
- data/lib/mutant/context.rb +78 -6
- data/lib/mutant/diff.rb +7 -13
- data/lib/mutant/matcher/method.rb +2 -2
- data/lib/mutant/mutation.rb +1 -1
- data/lib/mutant/mutator/node/generic.rb +1 -1
- data/lib/mutant/reporter/cli/printer.rb +25 -1
- data/lib/mutant/reporter/sequence.rb +22 -0
- data/lib/mutant/result.rb +4 -9
- data/lib/mutant/version.rb +1 -1
- data/meta/dsym.rb +7 -7
- data/mutant.gemspec +5 -5
- data/spec/spec_helper.rb +0 -1
- data/spec/unit/mutant/ast/named_children_spec.rb +12 -2
- data/spec/unit/mutant/context_spec.rb +85 -1
- data/spec/unit/mutant/diff_spec.rb +9 -0
- data/spec/unit/mutant/mutation_spec.rb +55 -4
- data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +3 -3
- data/spec/unit/mutant/reporter/cli/printer_spec.rb +27 -6
- data/spec/unit/mutant/reporter/null_spec.rb +5 -15
- data/spec/unit/mutant/reporter/sequence_spec.rb +29 -0
- data/spec/unit/mutant/result/class_methods_spec.rb +49 -0
- data/spec/unit/mutant/result/mutation_spec.rb +49 -0
- data/spec/unit/mutant/result/subject_spec.rb +84 -19
- data/spec/unit/mutant/result_spec.rb +18 -10
- data/spec/unit/mutant/subject/method/instance_spec.rb +3 -3
- data/spec/unit/mutant/subject/method/singleton_spec.rb +1 -1
- metadata +19 -22
- data/lib/mutant/context/scope.rb +0 -94
- data/lib/mutant/delegator.rb +0 -43
- data/spec/unit/mutant/context/root_spec.rb +0 -11
- data/spec/unit/mutant/context/scope/root_spec.rb +0 -32
- data/spec/unit/mutant/context/scope/unqualified_name_spec.rb +0 -25
- data/spec/unit/mutant/context/scope_spec.rb +0 -11
@@ -34,6 +34,15 @@ RSpec.describe Mutant::Diff do
|
|
34
34
|
|
35
35
|
it_should_behave_like 'an idempotent method'
|
36
36
|
end
|
37
|
+
|
38
|
+
context 'when there is no diff' do
|
39
|
+
let(:old) { '' }
|
40
|
+
let(:new) { '' }
|
41
|
+
|
42
|
+
it { should be(nil) }
|
43
|
+
|
44
|
+
it_should_behave_like 'an idempotent method'
|
45
|
+
end
|
37
46
|
end
|
38
47
|
|
39
48
|
describe '#diff' do
|
@@ -1,10 +1,16 @@
|
|
1
1
|
RSpec.describe Mutant::Mutation do
|
2
|
-
|
3
|
-
|
2
|
+
let(:mutation_class) do
|
3
|
+
Class.new(Mutant::Mutation) do
|
4
|
+
const_set(:SYMBOL, 'test'.freeze)
|
5
|
+
const_set(:TEST_PASS_SUCCESS, true)
|
6
|
+
end
|
4
7
|
end
|
5
8
|
|
6
|
-
let(:
|
7
|
-
|
9
|
+
let(:context) { instance_double(Mutant::Context) }
|
10
|
+
|
11
|
+
let(:object) do
|
12
|
+
mutation_class.new(mutation_subject, Mutant::AST::Nodes::N_NIL)
|
13
|
+
end
|
8
14
|
|
9
15
|
let(:mutation_subject) do
|
10
16
|
instance_double(
|
@@ -71,6 +77,51 @@ RSpec.describe Mutant::Mutation do
|
|
71
77
|
it_should_behave_like 'an idempotent method'
|
72
78
|
end
|
73
79
|
|
80
|
+
describe '.success?' do
|
81
|
+
subject { mutation_class.success?(test_result) }
|
82
|
+
|
83
|
+
let(:test_result) do
|
84
|
+
instance_double(
|
85
|
+
Mutant::Result::Test,
|
86
|
+
passed: passed
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'on mutation with positive pass expectation' do
|
91
|
+
context 'when Result::Test#passed equals expectation' do
|
92
|
+
let(:passed) { true }
|
93
|
+
|
94
|
+
it { should be(true) }
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'when Result::Test#passed NOT equals expectation' do
|
98
|
+
let(:passed) { false }
|
99
|
+
|
100
|
+
it { should be(false) }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'on mutation with negative pass expectation' do
|
105
|
+
let(:mutation_class) do
|
106
|
+
Class.new(super()) do
|
107
|
+
const_set(:TEST_PASS_SUCCESS, false)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
context 'when Result::Test#passed equals expectation' do
|
112
|
+
let(:passed) { true }
|
113
|
+
|
114
|
+
it { should be(false) }
|
115
|
+
end
|
116
|
+
|
117
|
+
context 'when Result::Test#passed NOT equals expectation' do
|
118
|
+
let(:passed) { false }
|
119
|
+
|
120
|
+
it { should be(true) }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
74
125
|
describe '#identification' do
|
75
126
|
|
76
127
|
subject { object.identification }
|
@@ -50,11 +50,11 @@ RSpec.describe Mutant::Reporter::CLI::Printer::MutationResult do
|
|
50
50
|
Original unparsed source:
|
51
51
|
super
|
52
52
|
Original AST:
|
53
|
-
(lvar :super)
|
53
|
+
s(:lvar, :super)
|
54
54
|
Mutated unparsed source:
|
55
55
|
super
|
56
56
|
Mutated AST:
|
57
|
-
(zsuper)
|
57
|
+
s(:zsuper)
|
58
58
|
-----------------------
|
59
59
|
REPORT
|
60
60
|
end
|
@@ -73,7 +73,7 @@ RSpec.describe Mutant::Reporter::CLI::Printer::MutationResult do
|
|
73
73
|
Original code was inserted unmutated. And the test did NOT PASS.
|
74
74
|
Your tests do not pass initially or you found a bug in mutant / unparser.
|
75
75
|
Subject AST:
|
76
|
-
(true)
|
76
|
+
s(:true)
|
77
77
|
Unparsed Source:
|
78
78
|
true
|
79
79
|
Test Result:
|
@@ -16,7 +16,7 @@ RSpec.describe Mutant::Reporter::CLI::Printer do
|
|
16
16
|
let(:tty?) { true }
|
17
17
|
let(:success?) { true }
|
18
18
|
|
19
|
-
|
19
|
+
describe '.call' do
|
20
20
|
let(:class_under_test) do
|
21
21
|
Class.new(described_class) do
|
22
22
|
def run
|
@@ -30,7 +30,28 @@ RSpec.describe Mutant::Reporter::CLI::Printer do
|
|
30
30
|
it_reports "foo\n"
|
31
31
|
end
|
32
32
|
|
33
|
-
|
33
|
+
describe '.delegate' do
|
34
|
+
let(:reportable) { double(foo: :bar, baz: :boz) }
|
35
|
+
|
36
|
+
let(:class_under_test) do
|
37
|
+
Class.new(described_class) do
|
38
|
+
delegate :foo, :baz
|
39
|
+
|
40
|
+
def run
|
41
|
+
puts(foo)
|
42
|
+
puts(baz)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it_reports "bar\nboz\n"
|
48
|
+
|
49
|
+
it 'sets delegation methods to private visibility' do
|
50
|
+
expect(class_under_test.private_instance_methods).to include(:foo, :baz)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#status' do
|
34
55
|
let(:class_under_test) do
|
35
56
|
Class.new(described_class) do
|
36
57
|
def run
|
@@ -65,7 +86,7 @@ RSpec.describe Mutant::Reporter::CLI::Printer do
|
|
65
86
|
end
|
66
87
|
end
|
67
88
|
|
68
|
-
|
89
|
+
describe '#visit_collection' do
|
69
90
|
let(:class_under_test) do
|
70
91
|
reporter = nested_reporter
|
71
92
|
Class.new(described_class) do
|
@@ -86,7 +107,7 @@ RSpec.describe Mutant::Reporter::CLI::Printer do
|
|
86
107
|
it_reports "foo\nbar\n"
|
87
108
|
end
|
88
109
|
|
89
|
-
|
110
|
+
describe '#visit' do
|
90
111
|
let(:class_under_test) do
|
91
112
|
reporter = nested_reporter
|
92
113
|
Class.new(described_class) do
|
@@ -107,7 +128,7 @@ RSpec.describe Mutant::Reporter::CLI::Printer do
|
|
107
128
|
it_reports "foo\n"
|
108
129
|
end
|
109
130
|
|
110
|
-
|
131
|
+
describe '#info' do
|
111
132
|
let(:class_under_test) do
|
112
133
|
Class.new(described_class) do
|
113
134
|
def run
|
@@ -119,7 +140,7 @@ RSpec.describe Mutant::Reporter::CLI::Printer do
|
|
119
140
|
it_reports "foo - bar\n"
|
120
141
|
end
|
121
142
|
|
122
|
-
|
143
|
+
describe '#colorize' do
|
123
144
|
let(:class_under_test) do
|
124
145
|
Class.new(described_class) do
|
125
146
|
def run
|
@@ -2,21 +2,11 @@ RSpec.describe Mutant::Reporter::Null do
|
|
2
2
|
let(:object) { described_class.new }
|
3
3
|
let(:value) { instance_double(Object) }
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
%i[progress report start warn].each do |name|
|
6
|
+
describe "##{name}" do
|
7
|
+
subject { object.public_send(name, value) }
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
describe '#warn' do
|
12
|
-
subject { object.warn(value) }
|
13
|
-
|
14
|
-
it_should_behave_like 'a command method'
|
15
|
-
end
|
16
|
-
|
17
|
-
describe '#progress' do
|
18
|
-
subject { object.progress(value) }
|
19
|
-
|
20
|
-
it_should_behave_like 'a command method'
|
9
|
+
it_should_behave_like 'a command method'
|
10
|
+
end
|
21
11
|
end
|
22
12
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
RSpec.describe Mutant::Reporter::Sequence do
|
2
|
+
let(:object) { described_class.new([reporter_a, reporter_b]) }
|
3
|
+
let(:value) { instance_double(Object) }
|
4
|
+
let(:reporter_a) { instance_double(Mutant::Reporter, delay: 1.0) }
|
5
|
+
let(:reporter_b) { instance_double(Mutant::Reporter, delay: 2.0) }
|
6
|
+
|
7
|
+
%i[report progress warn start].each do |name|
|
8
|
+
describe "##{name}" do
|
9
|
+
subject { object.public_send(name, value) }
|
10
|
+
|
11
|
+
before do
|
12
|
+
[reporter_a, reporter_b].each do |receiver|
|
13
|
+
expect(receiver).to receive(name)
|
14
|
+
.ordered
|
15
|
+
.with(value)
|
16
|
+
.and_return(receiver)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
it_should_behave_like 'a command method'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#delay' do
|
25
|
+
it 'returns the lowest value' do
|
26
|
+
expect(object.delay).to eql(1.0)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# The effect of this private module is done at boot time.
|
2
|
+
# Hence there is no way to kill the mutations at runtime
|
3
|
+
# so we have to directly hook into the private moduel via
|
4
|
+
# reflection to redo a runtime observable interaction with
|
5
|
+
# it.
|
6
|
+
#
|
7
|
+
# Until mutant gets boot time mutation support there is no
|
8
|
+
# way to to avoid this.
|
9
|
+
RSpec.describe 'Mutant::Result::ClassMethods' do
|
10
|
+
let(:infected_class) do
|
11
|
+
Class.new do
|
12
|
+
include Adamantium::Flat, Concord::Public.new(:collection)
|
13
|
+
extend Mutant::Result.const_get(:ClassMethods)
|
14
|
+
|
15
|
+
sum :length, :collection
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#sum' do
|
20
|
+
let(:object) { infected_class.new(collection) }
|
21
|
+
|
22
|
+
def apply
|
23
|
+
object.length
|
24
|
+
end
|
25
|
+
|
26
|
+
subject { apply }
|
27
|
+
|
28
|
+
before do
|
29
|
+
# memoization behavior
|
30
|
+
expect(collection).to receive(:map)
|
31
|
+
.once
|
32
|
+
.and_call_original
|
33
|
+
|
34
|
+
apply
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'empty collection' do
|
38
|
+
let(:collection) { [] }
|
39
|
+
|
40
|
+
it { should be(0) }
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'non-emtpy collection' do
|
44
|
+
let(:collection) { [[1], [2, 3]] }
|
45
|
+
|
46
|
+
it { should be(3) }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
RSpec.describe Mutant::Result::Mutation do
|
2
|
+
let(:object) do
|
3
|
+
described_class.new(
|
4
|
+
mutation: mutation,
|
5
|
+
test_result: test_result
|
6
|
+
)
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:mutation) do
|
10
|
+
instance_double(
|
11
|
+
Mutant::Mutation,
|
12
|
+
frozen?: true,
|
13
|
+
class: class_double(Mutant::Mutation)
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:test_result) do
|
18
|
+
instance_double(
|
19
|
+
Mutant::Result::Test,
|
20
|
+
runtime: 1.0
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:mutation_subject) do
|
25
|
+
instance_double(
|
26
|
+
Mutant::Subject
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#runtime' do
|
31
|
+
subject { object.runtime }
|
32
|
+
|
33
|
+
it { should eql(1.0) }
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#success?' do
|
37
|
+
subject { object.success? }
|
38
|
+
|
39
|
+
let(:result) { double('result boolean') }
|
40
|
+
|
41
|
+
before do
|
42
|
+
expect(mutation.class).to receive(:success?)
|
43
|
+
.with(test_result)
|
44
|
+
.and_return(result)
|
45
|
+
end
|
46
|
+
|
47
|
+
it { should be(result) }
|
48
|
+
end
|
49
|
+
end
|
@@ -7,38 +7,103 @@ RSpec.describe Mutant::Result::Subject do
|
|
7
7
|
)
|
8
8
|
end
|
9
9
|
|
10
|
-
let(:mutation_subject)
|
10
|
+
let(:mutation_subject) do
|
11
|
+
instance_double(
|
12
|
+
Mutant::Subject,
|
13
|
+
mutations: mutation_results.map { instance_double(Mutant::Mutation) }
|
14
|
+
)
|
15
|
+
end
|
11
16
|
|
12
|
-
|
13
|
-
|
17
|
+
shared_context 'full coverage' do
|
18
|
+
let(:mutation_results) do
|
19
|
+
[
|
20
|
+
instance_double(Mutant::Result::Mutation, success?: true)
|
21
|
+
]
|
22
|
+
end
|
23
|
+
end
|
14
24
|
|
15
|
-
|
16
|
-
|
25
|
+
shared_context 'partial coverage' do
|
26
|
+
let(:mutation_results) do
|
27
|
+
[
|
28
|
+
instance_double(Mutant::Result::Mutation, success?: false),
|
29
|
+
instance_double(Mutant::Result::Mutation, success?: true)
|
30
|
+
]
|
31
|
+
end
|
32
|
+
end
|
17
33
|
|
18
|
-
|
34
|
+
shared_context 'no coverage' do
|
35
|
+
let(:mutation_results) do
|
36
|
+
[
|
37
|
+
instance_double(Mutant::Result::Mutation, success?: false)
|
38
|
+
]
|
19
39
|
end
|
40
|
+
end
|
41
|
+
|
42
|
+
shared_context 'no results' do
|
43
|
+
let(:mutation_results) { [] }
|
44
|
+
end
|
20
45
|
|
21
|
-
|
22
|
-
|
46
|
+
describe '#coverage' do
|
47
|
+
subject { object.coverage }
|
23
48
|
|
24
|
-
|
49
|
+
{
|
50
|
+
'full coverage' => 1r,
|
51
|
+
'partial coverage' => 0.5r,
|
52
|
+
'no coverage' => 0r,
|
53
|
+
'no results' => 1r
|
54
|
+
}.each do |name, expected|
|
55
|
+
context(name) do
|
56
|
+
include_context(name)
|
57
|
+
it { should eql(expected) }
|
58
|
+
end
|
25
59
|
end
|
60
|
+
end
|
26
61
|
|
27
|
-
|
28
|
-
|
62
|
+
describe '#amount_mutations' do
|
63
|
+
subject { object.amount_mutations }
|
29
64
|
|
30
|
-
|
65
|
+
{
|
66
|
+
'full coverage' => 1,
|
67
|
+
'partial coverage' => 2,
|
68
|
+
'no coverage' => 1,
|
69
|
+
'no results' => 0
|
70
|
+
}.each do |name, expected|
|
71
|
+
context(name) do
|
72
|
+
include_context(name)
|
73
|
+
it { should be(expected) }
|
74
|
+
end
|
31
75
|
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe '#amount_mutations_alive' do
|
79
|
+
subject { object.amount_mutations_alive }
|
32
80
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
81
|
+
{
|
82
|
+
'full coverage' => 0,
|
83
|
+
'partial coverage' => 1,
|
84
|
+
'no coverage' => 1,
|
85
|
+
'no results' => 0
|
86
|
+
}.each do |name, expected|
|
87
|
+
context(name) do
|
88
|
+
include_context(name)
|
89
|
+
it { should be(expected) }
|
39
90
|
end
|
91
|
+
end
|
92
|
+
end
|
40
93
|
|
41
|
-
|
94
|
+
describe '#success?' do
|
95
|
+
subject { object.success? }
|
96
|
+
|
97
|
+
{
|
98
|
+
'full coverage' => true,
|
99
|
+
'partial coverage' => false,
|
100
|
+
'no coverage' => false,
|
101
|
+
'no results' => true
|
102
|
+
}.each do |name, expected|
|
103
|
+
context(name) do
|
104
|
+
include_context(name)
|
105
|
+
it { should be(expected) }
|
106
|
+
end
|
42
107
|
end
|
43
108
|
end
|
44
109
|
end
|