mutant 0.6.3 → 0.6.4
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/.travis.yml +2 -2
- data/Changelog.md +6 -0
- data/Gemfile.devtools +1 -1
- data/bin/mutant +2 -1
- data/config/flay.yml +1 -1
- data/config/reek.yml +3 -0
- data/lib/mutant.rb +5 -3
- data/lib/mutant/cli.rb +2 -2
- data/lib/mutant/config.rb +1 -1
- data/lib/mutant/diff.rb +1 -1
- data/lib/mutant/env.rb +1 -1
- data/lib/mutant/expression/methods.rb +16 -0
- data/lib/mutant/isolation.rb +16 -2
- data/lib/mutant/mutator/node/const.rb +1 -1
- data/lib/mutant/mutator/node/generic.rb +1 -1
- data/lib/mutant/mutator/registry.rb +1 -1
- data/lib/mutant/reporter/cli.rb +1 -1
- data/lib/mutant/reporter/cli/format.rb +0 -12
- data/lib/mutant/reporter/cli/printer.rb +1 -1
- data/lib/mutant/result.rb +1 -1
- data/lib/mutant/runner.rb +50 -29
- data/lib/mutant/runner/collector.rb +10 -11
- data/lib/mutant/subject.rb +1 -4
- data/lib/mutant/subject/method.rb +11 -0
- data/lib/mutant/version.rb +1 -1
- data/meta/send.rb +13 -0
- data/mutant.gemspec +2 -2
- data/spec/spec_helper.rb +2 -9
- data/spec/support/corpus.rb +5 -5
- data/spec/support/rb_bug.rb +18 -0
- data/spec/unit/mutant/cli_spec.rb +2 -2
- data/spec/unit/mutant/expression/methods_spec.rb +7 -1
- data/spec/unit/mutant/isolation_spec.rb +22 -2
- data/spec/unit/mutant/matcher/method/instance_spec.rb +5 -5
- data/spec/unit/mutant/matcher/method/singleton_spec.rb +5 -5
- data/spec/unit/mutant/reporter/cli_spec.rb +13 -14
- data/spec/unit/mutant/runner/collector_spec.rb +198 -0
- data/spec/unit/mutant/runner_spec.rb +2 -3
- data/spec/unit/mutant/subject/method/instance_spec.rb +8 -0
- data/spec/unit/mutant/subject/method/singleton_spec.rb +8 -0
- data/spec/unit/mutant/warning_filter_spec.rb +1 -1
- data/test_app/Gemfile.devtools +1 -1
- data/test_app/lib/test_app.rb +4 -0
- metadata +22 -19
- data/lib/parser_extensions.rb +0 -25
data/lib/mutant/subject.rb
CHANGED
@@ -32,6 +32,17 @@ module Mutant
|
|
32
32
|
end
|
33
33
|
memoize :expression
|
34
34
|
|
35
|
+
# Return match expressions
|
36
|
+
#
|
37
|
+
# @return [Array<Expression>]
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
#
|
41
|
+
def match_expressions
|
42
|
+
[expression].concat(context.match_expressions)
|
43
|
+
end
|
44
|
+
memoize :match_expressions
|
45
|
+
|
35
46
|
private
|
36
47
|
|
37
48
|
# Return scope
|
data/lib/mutant/version.rb
CHANGED
data/meta/send.rb
CHANGED
@@ -145,6 +145,19 @@ Mutant::Meta::Example.add do
|
|
145
145
|
mutation 'foo.instance_of?(bar)'
|
146
146
|
end
|
147
147
|
|
148
|
+
Mutant::Meta::Example.add do
|
149
|
+
source 'foo.is_a?(bar)'
|
150
|
+
|
151
|
+
singleton_mutations
|
152
|
+
mutation 'foo'
|
153
|
+
mutation 'bar'
|
154
|
+
mutation 'foo.is_a?'
|
155
|
+
mutation 'foo.is_a?(nil)'
|
156
|
+
mutation 'foo.is_a?(self)'
|
157
|
+
mutation 'self.is_a?(bar)'
|
158
|
+
mutation 'foo.instance_of?(bar)'
|
159
|
+
end
|
160
|
+
|
148
161
|
Mutant::Meta::Example.add do
|
149
162
|
source 'foo.kind_of?(bar)'
|
150
163
|
|
data/mutant.gemspec
CHANGED
@@ -30,14 +30,14 @@ Gem::Specification.new do |gem|
|
|
30
30
|
gem.add_runtime_dependency('morpher', '~> 0.2.3')
|
31
31
|
gem.add_runtime_dependency('procto', '~> 0.0.2')
|
32
32
|
gem.add_runtime_dependency('abstract_type', '~> 0.0.7')
|
33
|
-
gem.add_runtime_dependency('unparser', '~> 0.1.
|
33
|
+
gem.add_runtime_dependency('unparser', '~> 0.1.15')
|
34
34
|
gem.add_runtime_dependency('ice_nine', '~> 0.11.0')
|
35
35
|
gem.add_runtime_dependency('adamantium', '~> 0.2.0')
|
36
36
|
gem.add_runtime_dependency('memoizable', '~> 0.4.2')
|
37
37
|
gem.add_runtime_dependency('equalizer', '~> 0.0.9')
|
38
|
-
gem.add_runtime_dependency('inflecto', '~> 0.0.2')
|
39
38
|
gem.add_runtime_dependency('anima', '~> 0.2.0')
|
40
39
|
gem.add_runtime_dependency('concord', '~> 0.1.5')
|
41
40
|
|
42
41
|
gem.add_development_dependency('bundler', '~> 1.3', '>= 1.3.5')
|
42
|
+
gem.add_development_dependency('ffi', '~> 1.9.6')
|
43
43
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,6 @@
|
|
1
1
|
if ENV['COVERAGE'] == 'true'
|
2
2
|
require 'simplecov'
|
3
3
|
|
4
|
-
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
5
|
-
SimpleCov::Formatter::HTMLFormatter,
|
6
|
-
]
|
7
|
-
|
8
4
|
SimpleCov.start do
|
9
5
|
command_name 'spec:unit'
|
10
6
|
|
@@ -16,10 +12,11 @@ if ENV['COVERAGE'] == 'true'
|
|
16
12
|
add_filter 'lib/mutant/zombifier'
|
17
13
|
add_filter 'lib/mutant/zombifier/*'
|
18
14
|
|
19
|
-
minimum_coverage
|
15
|
+
minimum_coverage 97.64 # TODO: raise this to 100, then mutation test
|
20
16
|
end
|
21
17
|
end
|
22
18
|
|
19
|
+
require 'tempfile'
|
23
20
|
require 'concord'
|
24
21
|
require 'adamantium'
|
25
22
|
require 'devtools/spec_helper'
|
@@ -52,8 +49,4 @@ RSpec.configure do |config|
|
|
52
49
|
config.include(CompressHelper)
|
53
50
|
config.include(ParserHelper)
|
54
51
|
config.include(Mutant::AST::Sexp)
|
55
|
-
|
56
|
-
config.expect_with :rspec do |rspec|
|
57
|
-
rspec.syntax = :expect
|
58
|
-
end
|
59
52
|
end
|
data/spec/support/corpus.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'morpher'
|
2
2
|
require 'anima'
|
3
|
+
require 'mutant'
|
3
4
|
|
4
5
|
# Namespace module for corpus testing
|
5
6
|
module Corpus
|
@@ -51,8 +52,8 @@ module Corpus
|
|
51
52
|
start = Time.now
|
52
53
|
paths = Pathname.glob(repo_path.join('**/*.rb')).sort_by(&:size).reverse
|
53
54
|
options = {
|
54
|
-
finish:
|
55
|
-
start:
|
55
|
+
finish: method(:finish),
|
56
|
+
start: method(:start),
|
56
57
|
in_processes: parallel_processes
|
57
58
|
}
|
58
59
|
total = Parallel.map(paths, options) do |path|
|
@@ -135,9 +136,8 @@ module Corpus
|
|
135
136
|
# @api private
|
136
137
|
#
|
137
138
|
def parallel_processes
|
138
|
-
|
139
|
-
|
140
|
-
CIRCLE_CI_CONTAINER_PROCESSES
|
139
|
+
if ENV['CI']
|
140
|
+
Mutant::Config::DEFAULT.jobs
|
141
141
|
else
|
142
142
|
Parallel.processor_count
|
143
143
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module RbBug
|
4
|
+
extend FFI::Library
|
5
|
+
ffi_lib 'ruby'
|
6
|
+
attach_function :rb_bug, [:string, :varargs], :void
|
7
|
+
|
8
|
+
# Call the test bug
|
9
|
+
#
|
10
|
+
# @return [undefined]
|
11
|
+
#
|
12
|
+
# @api private
|
13
|
+
#
|
14
|
+
def self.call
|
15
|
+
rb_bug('%s', :string, 'test bug')
|
16
|
+
end
|
17
|
+
|
18
|
+
end # RbBug
|
@@ -128,7 +128,7 @@ Environment:
|
|
128
128
|
--zombie Run mutant zombified
|
129
129
|
-I, --include DIRECTORY Add DIRECTORY to $LOAD_PATH
|
130
130
|
-r, --require NAME Require file with NAME
|
131
|
-
-j, --jobs NUMBER Number of kill
|
131
|
+
-j, --jobs NUMBER Number of kill jobs. Defaults to number of processors.
|
132
132
|
|
133
133
|
Options:
|
134
134
|
--score COVERAGE Fail unless COVERAGE is not reached exactly
|
@@ -178,7 +178,7 @@ Options:
|
|
178
178
|
it_should_behave_like 'a cli parser'
|
179
179
|
|
180
180
|
it 'configures expected coverage' do
|
181
|
-
expect(subject.config.
|
181
|
+
expect(subject.config.jobs).to eql(0)
|
182
182
|
end
|
183
183
|
end
|
184
184
|
|
@@ -16,7 +16,13 @@ RSpec.describe Mutant::Expression::Methods do
|
|
16
16
|
it { should be(object.syntax.length) }
|
17
17
|
end
|
18
18
|
|
19
|
-
context 'when other is
|
19
|
+
context 'when other is matched' do
|
20
|
+
let(:other) { described_class.parse('TestApp::Literal#foo') }
|
21
|
+
|
22
|
+
it { should be(object.syntax.length) }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when other is an not matched expression' do
|
20
26
|
let(:other) { described_class.parse('Foo*') }
|
21
27
|
|
22
28
|
it { should be(0) }
|
@@ -39,9 +39,29 @@ RSpec.describe Mutant::Isolation::Fork do
|
|
39
39
|
expect(object.call { :foo }).to be(:foo)
|
40
40
|
end
|
41
41
|
|
42
|
-
it 'wraps
|
43
|
-
expect { object.call { fail
|
42
|
+
it 'wraps exceptions' do
|
43
|
+
expect { object.call { fail } }.to raise_error(Mutant::Isolation::Error)
|
44
44
|
end
|
45
45
|
|
46
|
+
it 'wraps exceptions caused by crashing ruby' do
|
47
|
+
expect do
|
48
|
+
object.call do
|
49
|
+
fail RbBug.call
|
50
|
+
end
|
51
|
+
end.to raise_error(Mutant::Isolation::Error)
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'redirects $stderr of children to /dev/null' do
|
55
|
+
begin
|
56
|
+
Tempfile.open('mutant-test') do |file|
|
57
|
+
$stderr = file
|
58
|
+
object.call { $stderr.puts('test') }
|
59
|
+
file.rewind
|
60
|
+
expect(file.read).to eql('')
|
61
|
+
end
|
62
|
+
ensure
|
63
|
+
$stderr = STDERR
|
64
|
+
end
|
65
|
+
end
|
46
66
|
end
|
47
67
|
end
|
@@ -43,14 +43,14 @@ RSpec.describe Mutant::Matcher::Method::Instance do
|
|
43
43
|
|
44
44
|
context 'when method is defined once' do
|
45
45
|
let(:scope) { base::DefinedOnce }
|
46
|
-
let(:method_line) {
|
46
|
+
let(:method_line) { 10 }
|
47
47
|
|
48
48
|
it_should_behave_like 'a method matcher'
|
49
49
|
end
|
50
50
|
|
51
51
|
context 'when method is defined once with a memoizer' do
|
52
52
|
let(:scope) { base::WithMemoizer }
|
53
|
-
let(:method_line) {
|
53
|
+
let(:method_line) { 15 }
|
54
54
|
|
55
55
|
it_should_behave_like 'a method matcher'
|
56
56
|
end
|
@@ -58,7 +58,7 @@ RSpec.describe Mutant::Matcher::Method::Instance do
|
|
58
58
|
context 'when method is defined multiple times' do
|
59
59
|
context 'on different lines' do
|
60
60
|
let(:scope) { base::DefinedMultipleTimes::DifferentLines }
|
61
|
-
let(:method_line) {
|
61
|
+
let(:method_line) { 24 }
|
62
62
|
let(:method_arity) { 1 }
|
63
63
|
|
64
64
|
it_should_behave_like 'a method matcher'
|
@@ -66,7 +66,7 @@ RSpec.describe Mutant::Matcher::Method::Instance do
|
|
66
66
|
|
67
67
|
context 'on the same line' do
|
68
68
|
let(:scope) { base::DefinedMultipleTimes::SameLineSameScope }
|
69
|
-
let(:method_line) {
|
69
|
+
let(:method_line) { 29 }
|
70
70
|
let(:method_arity) { 1 }
|
71
71
|
|
72
72
|
it_should_behave_like 'a method matcher'
|
@@ -74,7 +74,7 @@ RSpec.describe Mutant::Matcher::Method::Instance do
|
|
74
74
|
|
75
75
|
context 'on the same line with different scope' do
|
76
76
|
let(:scope) { base::DefinedMultipleTimes::SameLineDifferentScope }
|
77
|
-
let(:method_line) {
|
77
|
+
let(:method_line) { 33 }
|
78
78
|
let(:method_arity) { 1 }
|
79
79
|
|
80
80
|
it_should_behave_like 'a method matcher'
|
@@ -23,7 +23,7 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#each' do
|
|
23
23
|
|
24
24
|
context 'when also defined on lvar' do
|
25
25
|
let(:scope) { base::AlsoDefinedOnLvar }
|
26
|
-
let(:method_line) {
|
26
|
+
let(:method_line) { 66 }
|
27
27
|
|
28
28
|
it_should_behave_like 'a method matcher'
|
29
29
|
|
@@ -37,7 +37,7 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#each' do
|
|
37
37
|
|
38
38
|
context 'when defined on self' do
|
39
39
|
let(:scope) { base::DefinedOnSelf }
|
40
|
-
let(:method_line) {
|
40
|
+
let(:method_line) { 61 }
|
41
41
|
|
42
42
|
it_should_behave_like 'a method matcher'
|
43
43
|
end
|
@@ -46,13 +46,13 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#each' do
|
|
46
46
|
|
47
47
|
context 'inside namespace' do
|
48
48
|
let(:scope) { base::DefinedOnConstant::InsideNamespace }
|
49
|
-
let(:method_line) {
|
49
|
+
let(:method_line) { 71 }
|
50
50
|
|
51
51
|
it_should_behave_like 'a method matcher'
|
52
52
|
end
|
53
53
|
|
54
54
|
context 'outside namespace' do
|
55
|
-
let(:method_line) {
|
55
|
+
let(:method_line) { 78 }
|
56
56
|
let(:scope) { base::DefinedOnConstant::OutsideNamespace }
|
57
57
|
|
58
58
|
it_should_behave_like 'a method matcher'
|
@@ -62,7 +62,7 @@ RSpec.describe Mutant::Matcher::Method::Singleton, '#each' do
|
|
62
62
|
context 'when defined multiple times in the same line' do
|
63
63
|
context 'with method on different scope' do
|
64
64
|
let(:scope) { base::DefinedMultipleTimes::SameLine::DifferentScope }
|
65
|
-
let(:method_line) {
|
65
|
+
let(:method_line) { 97 }
|
66
66
|
let(:method_arity) { 1 }
|
67
67
|
|
68
68
|
it_should_behave_like 'a method matcher'
|
@@ -33,7 +33,6 @@ RSpec.describe Mutant::Reporter::CLI do
|
|
33
33
|
|
34
34
|
let(:result) do
|
35
35
|
Mutant::Result::Env.new(
|
36
|
-
done: true,
|
37
36
|
env: env,
|
38
37
|
runtime: 1.1,
|
39
38
|
subject_results: subject_results
|
@@ -51,7 +50,7 @@ RSpec.describe Mutant::Reporter::CLI do
|
|
51
50
|
)
|
52
51
|
end
|
53
52
|
|
54
|
-
let(:config) { Mutant::Config::DEFAULT.update(
|
53
|
+
let(:config) { Mutant::Config::DEFAULT.update(jobs: 1) }
|
55
54
|
let(:mutation_class) { Mutant::Mutation::Evil }
|
56
55
|
let(:matchable_scopes) { double('Matchable Scopes', length: 10) }
|
57
56
|
|
@@ -199,7 +198,7 @@ RSpec.describe Mutant::Reporter::CLI do
|
|
199
198
|
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
200
199
|
Integration: null
|
201
200
|
Expect Coverage: 100.00%
|
202
|
-
|
201
|
+
Jobs: 1
|
203
202
|
Includes: []
|
204
203
|
Requires: []
|
205
204
|
REPORT
|
@@ -257,7 +256,7 @@ RSpec.describe Mutant::Reporter::CLI do
|
|
257
256
|
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
258
257
|
Integration: null
|
259
258
|
Expect Coverage: 100.00%
|
260
|
-
|
259
|
+
Jobs: 1
|
261
260
|
Includes: []
|
262
261
|
Requires: []
|
263
262
|
Available Subjects: 1
|
@@ -286,7 +285,7 @@ RSpec.describe Mutant::Reporter::CLI do
|
|
286
285
|
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
287
286
|
Integration: null
|
288
287
|
Expect Coverage: 100.00%
|
289
|
-
|
288
|
+
Jobs: 1
|
290
289
|
Includes: []
|
291
290
|
Requires: []
|
292
291
|
Available Subjects: 1
|
@@ -323,7 +322,7 @@ RSpec.describe Mutant::Reporter::CLI do
|
|
323
322
|
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
324
323
|
Integration: null
|
325
324
|
Expect Coverage: 100.00%
|
326
|
-
|
325
|
+
Jobs: 1
|
327
326
|
Includes: []
|
328
327
|
Requires: []
|
329
328
|
Available Subjects: 1
|
@@ -350,7 +349,7 @@ RSpec.describe Mutant::Reporter::CLI do
|
|
350
349
|
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
351
350
|
Integration: null
|
352
351
|
Expect Coverage: 100.00%
|
353
|
-
|
352
|
+
Jobs: 1
|
354
353
|
Includes: []
|
355
354
|
Requires: []
|
356
355
|
Available Subjects: 1
|
@@ -385,7 +384,7 @@ RSpec.describe Mutant::Reporter::CLI do
|
|
385
384
|
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
386
385
|
Integration: null
|
387
386
|
Expect Coverage: 100.00%
|
388
|
-
|
387
|
+
Jobs: 1
|
389
388
|
Includes: []
|
390
389
|
Requires: []
|
391
390
|
Available Subjects: 1
|
@@ -418,7 +417,7 @@ RSpec.describe Mutant::Reporter::CLI do
|
|
418
417
|
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
419
418
|
Integration: null
|
420
419
|
Expect Coverage: 100.00%
|
421
|
-
|
420
|
+
Jobs: 1
|
422
421
|
Includes: []
|
423
422
|
Requires: []
|
424
423
|
Available Subjects: 1
|
@@ -451,7 +450,7 @@ RSpec.describe Mutant::Reporter::CLI do
|
|
451
450
|
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
452
451
|
Integration: null
|
453
452
|
Expect Coverage: 100.00%
|
454
|
-
|
453
|
+
Jobs: 1
|
455
454
|
Includes: []
|
456
455
|
Requires: []
|
457
456
|
Available Subjects: 1
|
@@ -492,7 +491,7 @@ RSpec.describe Mutant::Reporter::CLI do
|
|
492
491
|
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
493
492
|
Integration: null
|
494
493
|
Expect Coverage: 100.00%
|
495
|
-
|
494
|
+
Jobs: 1
|
496
495
|
Includes: []
|
497
496
|
Requires: []
|
498
497
|
Available Subjects: 1
|
@@ -527,7 +526,7 @@ RSpec.describe Mutant::Reporter::CLI do
|
|
527
526
|
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
528
527
|
Integration: null
|
529
528
|
Expect Coverage: 100.00%
|
530
|
-
|
529
|
+
Jobs: 1
|
531
530
|
Includes: []
|
532
531
|
Requires: []
|
533
532
|
Available Subjects: 1
|
@@ -548,14 +547,14 @@ RSpec.describe Mutant::Reporter::CLI do
|
|
548
547
|
let(:subjects) { [] }
|
549
548
|
let(:subject_results) { [] }
|
550
549
|
|
551
|
-
let(:config) { Mutant::Config::DEFAULT.update(
|
550
|
+
let(:config) { Mutant::Config::DEFAULT.update(jobs: 1, includes: %w[include-dir], requires: %w[require-name]) }
|
552
551
|
|
553
552
|
it_reports(<<-REPORT)
|
554
553
|
Mutant configuration:
|
555
554
|
Matcher: #<Mutant::Matcher::Config match_expressions=[] subject_ignores=[] subject_selects=[]>
|
556
555
|
Integration: null
|
557
556
|
Expect Coverage: 100.00%
|
558
|
-
|
557
|
+
Jobs: 1
|
559
558
|
Includes: ["include-dir"]
|
560
559
|
Requires: ["require-name"]
|
561
560
|
Available Subjects: 0
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mutant::Runner::Collector do
|
4
|
+
let(:object) { described_class.new(env) }
|
5
|
+
|
6
|
+
before do
|
7
|
+
allow(Time).to receive(:now).and_return(Time.now)
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:env) do
|
11
|
+
double(
|
12
|
+
'env',
|
13
|
+
subjects: [mutation_a.subject]
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
let(:mutation_a) do
|
18
|
+
double(
|
19
|
+
'mutation a',
|
20
|
+
subject: double('subject', identification: 'A')
|
21
|
+
)
|
22
|
+
end
|
23
|
+
|
24
|
+
let(:mutation_a_result) do
|
25
|
+
double(
|
26
|
+
'mutation a result',
|
27
|
+
index: 0,
|
28
|
+
runtime: 0.0,
|
29
|
+
mutation: mutation_a
|
30
|
+
)
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:subject_a_result) do
|
34
|
+
Mutant::Result::Subject.new(
|
35
|
+
subject: mutation_a.subject,
|
36
|
+
runtime: 0.0,
|
37
|
+
mutation_results: [mutation_a_result]
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
let(:active_subject_result) do
|
42
|
+
subject_a_result.update(mutation_results: [])
|
43
|
+
end
|
44
|
+
|
45
|
+
let(:active_subject_results) do
|
46
|
+
[active_subject_result]
|
47
|
+
end
|
48
|
+
|
49
|
+
describe '.new' do
|
50
|
+
it 'initializes instance variables' do
|
51
|
+
expect(object.instance_variables).to include(:@last_mutation_result)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '#start' do
|
56
|
+
subject { object.start(mutation_a) }
|
57
|
+
|
58
|
+
it 'tracs the mutation as active' do
|
59
|
+
expect { subject }.to change { object.active_subject_results }.from([]).to(active_subject_results)
|
60
|
+
end
|
61
|
+
|
62
|
+
it_should_behave_like 'a command method'
|
63
|
+
end
|
64
|
+
|
65
|
+
describe '#finish' do
|
66
|
+
subject { object.finish(mutation_a_result) }
|
67
|
+
|
68
|
+
before do
|
69
|
+
object.start(mutation_a)
|
70
|
+
end
|
71
|
+
|
72
|
+
it 'removes the tracking of mutation as active' do
|
73
|
+
expect { subject }.to change { object.active_subject_results }.from(active_subject_results).to([])
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'sets last mutation result' do
|
77
|
+
expect { subject }.to change { object.last_mutation_result }.from(nil).to(mutation_a_result)
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'aggregates results in #result' do
|
81
|
+
subject
|
82
|
+
expect(object.result).to eql(
|
83
|
+
Mutant::Result::Env.new(
|
84
|
+
env: object.env,
|
85
|
+
runtime: 0.0,
|
86
|
+
subject_results: [subject_a_result]
|
87
|
+
)
|
88
|
+
)
|
89
|
+
end
|
90
|
+
|
91
|
+
it_should_behave_like 'a command method'
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#last_mutation_result' do
|
95
|
+
subject { object.last_mutation_result }
|
96
|
+
|
97
|
+
context 'when empty' do
|
98
|
+
it { should be(nil) }
|
99
|
+
end
|
100
|
+
|
101
|
+
context 'with partial state' do
|
102
|
+
before do
|
103
|
+
object.start(mutation_a)
|
104
|
+
end
|
105
|
+
|
106
|
+
it { should be(nil) }
|
107
|
+
end
|
108
|
+
|
109
|
+
context 'with full state' do
|
110
|
+
before do
|
111
|
+
object.start(mutation_a)
|
112
|
+
object.finish(mutation_a_result)
|
113
|
+
end
|
114
|
+
|
115
|
+
it { should be(mutation_a_result) }
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
describe '#active_subject_results' do
|
120
|
+
subject { object.active_subject_results }
|
121
|
+
|
122
|
+
context 'when empty' do
|
123
|
+
it { should eql([]) }
|
124
|
+
end
|
125
|
+
|
126
|
+
context 'on partial state' do
|
127
|
+
let(:mutation_b) do
|
128
|
+
double(
|
129
|
+
'mutation b',
|
130
|
+
subject: double(
|
131
|
+
'subject',
|
132
|
+
identification: 'B'
|
133
|
+
)
|
134
|
+
)
|
135
|
+
end
|
136
|
+
|
137
|
+
let(:mutation_b_result) do
|
138
|
+
double(
|
139
|
+
'mutation b result',
|
140
|
+
index: 0,
|
141
|
+
runtime: 0.0,
|
142
|
+
mutation: mutation_b
|
143
|
+
)
|
144
|
+
end
|
145
|
+
|
146
|
+
let(:subject_b_result) do
|
147
|
+
Mutant::Result::Subject.new(
|
148
|
+
subject: mutation_b.subject,
|
149
|
+
runtime: 0.0,
|
150
|
+
mutation_results: [mutation_b_result]
|
151
|
+
)
|
152
|
+
end
|
153
|
+
|
154
|
+
let(:active_subject_results) { [subject_a_result, subject_b_result] }
|
155
|
+
|
156
|
+
before do
|
157
|
+
object.start(mutation_b)
|
158
|
+
object.start(mutation_a)
|
159
|
+
end
|
160
|
+
|
161
|
+
it { should eql(active_subject_results.map { |result| result.update(mutation_results: []) }) }
|
162
|
+
end
|
163
|
+
|
164
|
+
context 'on full state' do
|
165
|
+
before do
|
166
|
+
object.start(mutation_a)
|
167
|
+
object.finish(mutation_a_result)
|
168
|
+
end
|
169
|
+
|
170
|
+
it { should eql([]) }
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe '#result' do
|
175
|
+
subject { object.result }
|
176
|
+
|
177
|
+
context 'when empty' do
|
178
|
+
it { should eql(Mutant::Result::Env.new(env: object.env, runtime: 0.0, subject_results: [active_subject_result])) }
|
179
|
+
end
|
180
|
+
|
181
|
+
context 'on partial state' do
|
182
|
+
before do
|
183
|
+
object.start(mutation_a)
|
184
|
+
end
|
185
|
+
|
186
|
+
it { should eql(Mutant::Result::Env.new(env: object.env, runtime: 0.0, subject_results: [active_subject_result])) }
|
187
|
+
end
|
188
|
+
|
189
|
+
context 'on full state' do
|
190
|
+
before do
|
191
|
+
object.start(mutation_a)
|
192
|
+
object.finish(mutation_a_result)
|
193
|
+
end
|
194
|
+
|
195
|
+
it { should eql(Mutant::Result::Env.new(env: object.env, runtime: 0.0, subject_results: [subject_a_result])) }
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|