mutant 0.8.9 → 0.8.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +4 -0
  3. data/config/devtools.yml +1 -1
  4. data/config/flay.yml +1 -1
  5. data/lib/mutant.rb +1 -2
  6. data/lib/mutant/ast/types.rb +3 -2
  7. data/lib/mutant/context.rb +78 -6
  8. data/lib/mutant/diff.rb +7 -13
  9. data/lib/mutant/matcher/method.rb +2 -2
  10. data/lib/mutant/mutation.rb +1 -1
  11. data/lib/mutant/mutator/node/generic.rb +1 -1
  12. data/lib/mutant/reporter/cli/printer.rb +25 -1
  13. data/lib/mutant/reporter/sequence.rb +22 -0
  14. data/lib/mutant/result.rb +4 -9
  15. data/lib/mutant/version.rb +1 -1
  16. data/meta/dsym.rb +7 -7
  17. data/mutant.gemspec +5 -5
  18. data/spec/spec_helper.rb +0 -1
  19. data/spec/unit/mutant/ast/named_children_spec.rb +12 -2
  20. data/spec/unit/mutant/context_spec.rb +85 -1
  21. data/spec/unit/mutant/diff_spec.rb +9 -0
  22. data/spec/unit/mutant/mutation_spec.rb +55 -4
  23. data/spec/unit/mutant/reporter/cli/printer/mutation_result_spec.rb +3 -3
  24. data/spec/unit/mutant/reporter/cli/printer_spec.rb +27 -6
  25. data/spec/unit/mutant/reporter/null_spec.rb +5 -15
  26. data/spec/unit/mutant/reporter/sequence_spec.rb +29 -0
  27. data/spec/unit/mutant/result/class_methods_spec.rb +49 -0
  28. data/spec/unit/mutant/result/mutation_spec.rb +49 -0
  29. data/spec/unit/mutant/result/subject_spec.rb +84 -19
  30. data/spec/unit/mutant/result_spec.rb +18 -10
  31. data/spec/unit/mutant/subject/method/instance_spec.rb +3 -3
  32. data/spec/unit/mutant/subject/method/singleton_spec.rb +1 -1
  33. metadata +19 -22
  34. data/lib/mutant/context/scope.rb +0 -94
  35. data/lib/mutant/delegator.rb +0 -43
  36. data/spec/unit/mutant/context/root_spec.rb +0 -11
  37. data/spec/unit/mutant/context/scope/root_spec.rb +0 -32
  38. data/spec/unit/mutant/context/scope/unqualified_name_spec.rb +0 -25
  39. 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
- class TestMutation < Mutant::Mutation
3
- SYMBOL = 'test'.freeze
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(:object) { TestMutation.new(mutation_subject, Mutant::AST::Nodes::N_NIL) }
7
- let(:context) { instance_double(Mutant::Context) }
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
- context '.call' do
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
- context '#status' do
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
- context '#visit_collection' do
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
- context '#visit' do
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
- context '#info' do
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
- context '#colorize' do
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
- describe '#report' do
6
- subject { object.report(value) }
5
+ %i[progress report start warn].each do |name|
6
+ describe "##{name}" do
7
+ subject { object.public_send(name, value) }
7
8
 
8
- it_should_behave_like 'a command method'
9
- end
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) { instance_double(Mutant::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
- describe '#continue?' do
13
- subject { object.continue? }
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
- context 'when mutation results are empty' do
16
- let(:mutation_results) { [] }
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
- it { should be(true) }
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
- context 'with failing mutation result' do
22
- let(:mutation_results) { [instance_double(Mutant::Result::Mutation, success?: false)] }
46
+ describe '#coverage' do
47
+ subject { object.coverage }
23
48
 
24
- it { should be(false) }
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
- context 'with successful mutation result' do
28
- let(:mutation_results) { [instance_double(Mutant::Result::Mutation, success?: true)] }
62
+ describe '#amount_mutations' do
63
+ subject { object.amount_mutations }
29
64
 
30
- it { should be(true) }
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
- context 'with failed and successful mutation result' do
34
- let(:mutation_results) do
35
- [
36
- instance_double(Mutant::Result::Mutation, success?: true),
37
- instance_double(Mutant::Result::Mutation, success?: false)
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
- it { should be(false) }
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