mutiny 0.1.0 → 0.2.0
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/Gemfile.lock +30 -30
- data/RELEASES.md +3 -0
- data/bin/mutiny +8 -0
- data/examples/calculator/lib/calculator/min.rb +3 -3
- data/lib/mutiny/analysis/analyser.rb +37 -0
- data/lib/mutiny/analysis/results.rb +41 -0
- data/lib/mutiny/integration/rspec/context.rb +14 -6
- data/lib/mutiny/integration/rspec/parser.rb +1 -1
- data/lib/mutiny/integration/rspec/runner.rb +17 -5
- data/lib/mutiny/integration/rspec/test.rb +9 -2
- data/lib/mutiny/integration/rspec/test_set.rb +7 -1
- data/lib/mutiny/integration/rspec.rb +7 -7
- data/lib/mutiny/integration.rb +12 -0
- data/lib/mutiny/isolation/pipe.rb +25 -0
- data/lib/mutiny/isolation/vacuum.rb +14 -0
- data/lib/mutiny/isolation.rb +42 -0
- data/lib/mutiny/mode/check.rb +1 -1
- data/lib/mutiny/mode/score.rb +49 -0
- data/lib/mutiny/mode.rb +1 -0
- data/lib/mutiny/mutants/mutant.rb +9 -8
- data/lib/mutiny/mutants/mutant_set.rb +26 -21
- data/lib/mutiny/mutants/mutation_set.rb +8 -1
- data/lib/mutiny/output/table.rb +35 -0
- data/lib/mutiny/tests/test_run.rb +11 -2
- data/lib/mutiny/tests/test_set.rb +5 -1
- data/lib/mutiny/version.rb +1 -1
- data/lib/mutiny.rb +1 -0
- data/mutiny.gemspec +4 -4
- data/spec/integration/score_spec.rb +35 -0
- data/spec/unit/isolation_spec.rb +41 -0
- data/spec/unit/mutants/mutant_set_spec.rb +8 -46
- data/spec/unit/mutants/mutant_spec.rb +17 -0
- data/spec/unit/subjects/environment_spec.rb +1 -1
- data/spec/unit/subjects/test_set_spec.rb +8 -8
- metadata +24 -10
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6284685da742cd3e372fb6969484dbef17fcb022
|
|
4
|
+
data.tar.gz: 4390a6132c28e9c9e6f705307d290ea071f0173a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a144740eaa9e502506eb0c7f07e4c95cb633b61e62b41fb932d756341c5ed920564f008f511224868f4614c782169c2effb68889a64944870e054deade9ad33c
|
|
7
|
+
data.tar.gz: d96ccc36e280c6df7182d7f8d2eb70f88f2dbf436ded930a1d81ec6009c778d8cc4a863a4c366c70ebb78dac2a7ccad70b5173482536209266e6598229e779c9
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
mutiny (0.
|
|
4
|
+
mutiny (0.2.0)
|
|
5
5
|
gli (~> 2.13.0)
|
|
6
6
|
metamorpher (~> 0.2.2)
|
|
7
7
|
parser (~> 2.2.2)
|
|
@@ -14,13 +14,13 @@ GEM
|
|
|
14
14
|
adamantium (0.2.0)
|
|
15
15
|
ice_nine (~> 0.11.0)
|
|
16
16
|
memoizable (~> 0.4.0)
|
|
17
|
-
aruba (0.
|
|
17
|
+
aruba (0.7.4)
|
|
18
18
|
childprocess (>= 0.3.6)
|
|
19
19
|
cucumber (>= 1.1.1)
|
|
20
20
|
rspec-expectations (>= 2.7.0)
|
|
21
|
-
ast (2.
|
|
22
|
-
astrolabe (1.3.
|
|
23
|
-
parser (
|
|
21
|
+
ast (2.1.0)
|
|
22
|
+
astrolabe (1.3.1)
|
|
23
|
+
parser (~> 2.2)
|
|
24
24
|
attributable (0.1.0)
|
|
25
25
|
builder (3.2.2)
|
|
26
26
|
childprocess (0.5.6)
|
|
@@ -30,54 +30,54 @@ GEM
|
|
|
30
30
|
concord (0.1.5)
|
|
31
31
|
adamantium (~> 0.2.0)
|
|
32
32
|
equalizer (~> 0.0.9)
|
|
33
|
-
cucumber (2.0.
|
|
33
|
+
cucumber (2.0.2)
|
|
34
34
|
builder (>= 2.1.2)
|
|
35
|
-
cucumber-core (~> 1.
|
|
35
|
+
cucumber-core (~> 1.2.0)
|
|
36
36
|
diff-lcs (>= 1.1.3)
|
|
37
37
|
gherkin (~> 2.12)
|
|
38
38
|
multi_json (>= 1.7.5, < 2.0)
|
|
39
39
|
multi_test (>= 0.1.2)
|
|
40
|
-
cucumber-core (1.
|
|
40
|
+
cucumber-core (1.2.0)
|
|
41
41
|
gherkin (~> 2.12.0)
|
|
42
42
|
diff-lcs (1.2.5)
|
|
43
43
|
docile (1.1.5)
|
|
44
44
|
equalizer (0.0.11)
|
|
45
|
-
ffi (1.9.
|
|
45
|
+
ffi (1.9.10)
|
|
46
46
|
gherkin (2.12.2)
|
|
47
47
|
multi_json (~> 1.3)
|
|
48
48
|
gli (2.13.1)
|
|
49
49
|
ice_nine (0.11.1)
|
|
50
|
-
json (1.8.
|
|
50
|
+
json (1.8.3)
|
|
51
51
|
memoizable (0.4.2)
|
|
52
52
|
thread_safe (~> 0.3, >= 0.3.1)
|
|
53
53
|
metamorpher (0.2.2)
|
|
54
54
|
attributable (~> 0.1.0)
|
|
55
55
|
parser (~> 2.2.2)
|
|
56
56
|
unparser (~> 0.2.4)
|
|
57
|
-
multi_json (1.11.
|
|
57
|
+
multi_json (1.11.2)
|
|
58
58
|
multi_test (0.1.2)
|
|
59
|
-
parser (2.2.2.
|
|
59
|
+
parser (2.2.2.6)
|
|
60
60
|
ast (>= 1.1, < 3.0)
|
|
61
61
|
powerpack (0.1.1)
|
|
62
62
|
procto (0.0.2)
|
|
63
63
|
rainbow (2.0.0)
|
|
64
64
|
rake (10.4.2)
|
|
65
|
-
rspec (3.
|
|
66
|
-
rspec-core (~> 3.
|
|
67
|
-
rspec-expectations (~> 3.
|
|
68
|
-
rspec-mocks (~> 3.
|
|
69
|
-
rspec-core (3.2
|
|
70
|
-
rspec-support (~> 3.
|
|
71
|
-
rspec-expectations (3.
|
|
65
|
+
rspec (3.3.0)
|
|
66
|
+
rspec-core (~> 3.3.0)
|
|
67
|
+
rspec-expectations (~> 3.3.0)
|
|
68
|
+
rspec-mocks (~> 3.3.0)
|
|
69
|
+
rspec-core (3.3.2)
|
|
70
|
+
rspec-support (~> 3.3.0)
|
|
71
|
+
rspec-expectations (3.3.1)
|
|
72
72
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
73
|
-
rspec-support (~> 3.
|
|
74
|
-
rspec-mocks (3.2
|
|
73
|
+
rspec-support (~> 3.3.0)
|
|
74
|
+
rspec-mocks (3.3.2)
|
|
75
75
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
76
|
-
rspec-support (~> 3.
|
|
77
|
-
rspec-support (3.
|
|
78
|
-
rubocop (0.
|
|
76
|
+
rspec-support (~> 3.3.0)
|
|
77
|
+
rspec-support (3.3.0)
|
|
78
|
+
rubocop (0.33.0)
|
|
79
79
|
astrolabe (~> 1.3)
|
|
80
|
-
parser (>= 2.2.2.
|
|
80
|
+
parser (>= 2.2.2.5, < 3.0)
|
|
81
81
|
powerpack (~> 0.1)
|
|
82
82
|
rainbow (>= 1.99.1, < 3.0)
|
|
83
83
|
ruby-progressbar (~> 1.4)
|
|
@@ -101,13 +101,13 @@ PLATFORMS
|
|
|
101
101
|
ruby
|
|
102
102
|
|
|
103
103
|
DEPENDENCIES
|
|
104
|
-
aruba (~> 0.
|
|
105
|
-
bundler (~> 1.10.
|
|
104
|
+
aruba (~> 0.7.0)
|
|
105
|
+
bundler (~> 1.10.3)
|
|
106
106
|
codeclimate-test-reporter (~> 0.4.6)
|
|
107
107
|
mutiny!
|
|
108
108
|
rake (~> 10.4.2)
|
|
109
|
-
rspec (~> 3.
|
|
110
|
-
rubocop (~> 0.
|
|
109
|
+
rspec (~> 3.3.0)
|
|
110
|
+
rubocop (~> 0.33.0)
|
|
111
111
|
|
|
112
112
|
BUNDLED WITH
|
|
113
|
-
1.10.
|
|
113
|
+
1.10.4
|
data/RELEASES.md
CHANGED
data/bin/mutiny
CHANGED
|
@@ -32,4 +32,12 @@ command :mutate do |c|
|
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
desc 'Calculates a mutation score for your project'
|
|
36
|
+
long_desc 'Calculates a mutation score for your project and displays a list of surviving mutants'
|
|
37
|
+
command :score do |c|
|
|
38
|
+
c.action do
|
|
39
|
+
Mutiny::Mode::Score.new(@configuration).run
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
35
43
|
exit run(ARGV)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require_relative "results"
|
|
2
|
+
|
|
3
|
+
module Mutiny
|
|
4
|
+
module Analysis
|
|
5
|
+
class Analyser
|
|
6
|
+
attr_reader :mutant_set, :integration
|
|
7
|
+
|
|
8
|
+
def initialize(mutant_set:, integration:)
|
|
9
|
+
@mutant_set = mutant_set
|
|
10
|
+
@integration = integration
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def call
|
|
14
|
+
analyse_all
|
|
15
|
+
results
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
def analyse_all
|
|
21
|
+
mutant_set.mutants.each do |mutant|
|
|
22
|
+
mutant.apply
|
|
23
|
+
test_run = integration.test(mutant.subject)
|
|
24
|
+
results.add(mutant, test_run)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def results
|
|
29
|
+
@results ||= Results.new
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def mutant_set
|
|
33
|
+
@mutant_set ||= configuration.mutator.mutants_for(environment.subjects)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Mutiny
|
|
2
|
+
module Analysis
|
|
3
|
+
class Results
|
|
4
|
+
def add(mutant, test_run)
|
|
5
|
+
mutants << mutant
|
|
6
|
+
test_runs[mutant] = test_run
|
|
7
|
+
killed << mutant if test_run.failed?
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def kill_count
|
|
11
|
+
killed.size
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def killed?(mutant)
|
|
15
|
+
killed.include?(mutant)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def survived?(mutant)
|
|
19
|
+
!killed?(mutant)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def test_run_for(mutant)
|
|
23
|
+
test_runs[mutant]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def mutants
|
|
27
|
+
@mutants ||= Mutants::MutantSet.new
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def killed
|
|
33
|
+
@killed ||= []
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_runs
|
|
37
|
+
@test_runs ||= {}
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -3,23 +3,31 @@ require "stringio"
|
|
|
3
3
|
|
|
4
4
|
module Mutiny
|
|
5
5
|
class Integration
|
|
6
|
-
class RSpec
|
|
6
|
+
class RSpec < self
|
|
7
7
|
# This code originally based on Markus Schirp's implementation of Mutant::Integration::Rspec
|
|
8
8
|
# https://github.com/mbj/mutant/blob/master/lib/mutant/integration/rspec.rb
|
|
9
9
|
class Context
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
CLI_OPTIONS = %w(spec)
|
|
10
|
+
DEFAULT_CLI_OPTIONS = %w(spec)
|
|
11
|
+
FAIL_FAST_CLI_OPTION = %w(--fail-fast)
|
|
13
12
|
|
|
14
13
|
attr_reader :runner, :world, :configuration, :output
|
|
15
14
|
|
|
16
|
-
def initialize
|
|
15
|
+
def initialize(options = {})
|
|
16
|
+
@options = options
|
|
17
17
|
@output = StringIO.new
|
|
18
18
|
@world = ::RSpec.world
|
|
19
19
|
@configuration = ::RSpec.configuration
|
|
20
|
-
@runner = ::RSpec::Core::Runner.new(::RSpec::Core::ConfigurationOptions.new(
|
|
20
|
+
@runner = ::RSpec::Core::Runner.new(::RSpec::Core::ConfigurationOptions.new(cli_options))
|
|
21
21
|
@runner.setup($stderr, @output)
|
|
22
22
|
end
|
|
23
|
+
|
|
24
|
+
def cli_options
|
|
25
|
+
if @options.fetch(:fail_fast, false)
|
|
26
|
+
DEFAULT_CLI_OPTIONS + FAIL_FAST_CLI_OPTION
|
|
27
|
+
else
|
|
28
|
+
DEFAULT_CLI_OPTIONS
|
|
29
|
+
end
|
|
30
|
+
end
|
|
23
31
|
end
|
|
24
32
|
end
|
|
25
33
|
end
|
|
@@ -3,7 +3,7 @@ require_relative "test_set"
|
|
|
3
3
|
|
|
4
4
|
module Mutiny
|
|
5
5
|
class Integration
|
|
6
|
-
class RSpec
|
|
6
|
+
class RSpec < self
|
|
7
7
|
# This code originally based on Markus Schirp's implementation of Mutant::Integration::Rspec
|
|
8
8
|
# https://github.com/mbj/mutant/blob/master/lib/mutant/integration/rspec.rb
|
|
9
9
|
class Parser
|
|
@@ -2,7 +2,7 @@ require "forwardable"
|
|
|
2
2
|
|
|
3
3
|
module Mutiny
|
|
4
4
|
class Integration
|
|
5
|
-
class RSpec
|
|
5
|
+
class RSpec < self
|
|
6
6
|
# This code originally based on Markus Schirp's implementation of Mutant::Integration::Rspec
|
|
7
7
|
# https://github.com/mbj/mutant/blob/master/lib/mutant/integration/rspec.rb
|
|
8
8
|
class Runner
|
|
@@ -23,11 +23,13 @@ module Mutiny
|
|
|
23
23
|
private
|
|
24
24
|
|
|
25
25
|
def reset
|
|
26
|
+
@passed_examples = []
|
|
26
27
|
@failed_examples = []
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
def prepare
|
|
30
31
|
filter_examples
|
|
32
|
+
configuration.reporter.register_listener(self, :example_passed)
|
|
31
33
|
configuration.reporter.register_listener(self, :example_failed)
|
|
32
34
|
end
|
|
33
35
|
|
|
@@ -35,14 +37,24 @@ module Mutiny
|
|
|
35
37
|
start = Time.now
|
|
36
38
|
runner.run_specs(world.ordered_example_groups)
|
|
37
39
|
output.rewind
|
|
40
|
+
runtime = Time.now - start
|
|
41
|
+
create_test_run(output.read, runtime)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def create_test_run(output, runtime)
|
|
38
45
|
Tests::TestRun.new(
|
|
39
|
-
tests: @test_set,
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
tests: @test_set.generalise,
|
|
47
|
+
passed_tests: @test_set.subset_for_examples(@passed_examples).generalise,
|
|
48
|
+
failed_tests: @test_set.subset_for_examples(@failed_examples).generalise,
|
|
49
|
+
output: output,
|
|
50
|
+
runtime: runtime
|
|
43
51
|
)
|
|
44
52
|
end
|
|
45
53
|
|
|
54
|
+
def example_passed(notification)
|
|
55
|
+
@passed_examples << notification.example
|
|
56
|
+
end
|
|
57
|
+
|
|
46
58
|
def example_failed(notification)
|
|
47
59
|
@failed_examples << notification.example
|
|
48
60
|
end
|
|
@@ -2,13 +2,20 @@ require_relative "../../tests"
|
|
|
2
2
|
|
|
3
3
|
module Mutiny
|
|
4
4
|
class Integration
|
|
5
|
-
class RSpec
|
|
5
|
+
class RSpec < self
|
|
6
6
|
class Test < Tests::Test
|
|
7
|
-
attr_reader :example
|
|
7
|
+
attr_reader :example, :rest
|
|
8
8
|
|
|
9
9
|
def initialize(example:, **rest)
|
|
10
10
|
super(rest)
|
|
11
11
|
@example = example
|
|
12
|
+
@rest = rest
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Converts to a Mutiny::Tests::Test, which is independent of
|
|
16
|
+
# any specific testing framework
|
|
17
|
+
def generalise
|
|
18
|
+
Mutiny::Tests::Test.new(@rest)
|
|
12
19
|
end
|
|
13
20
|
end
|
|
14
21
|
end
|
|
@@ -2,7 +2,7 @@ require_relative "../../tests"
|
|
|
2
2
|
|
|
3
3
|
module Mutiny
|
|
4
4
|
class Integration
|
|
5
|
-
class RSpec
|
|
5
|
+
class RSpec < self
|
|
6
6
|
class TestSet < Tests::TestSet
|
|
7
7
|
def examples
|
|
8
8
|
@tests.map(&:example)
|
|
@@ -11,6 +11,12 @@ module Mutiny
|
|
|
11
11
|
def subset_for_examples(examples)
|
|
12
12
|
subset { |test| examples.include?(test.example) }
|
|
13
13
|
end
|
|
14
|
+
|
|
15
|
+
# Converts to a Mutiny::Tests::TestSet, which is independent of
|
|
16
|
+
# any specific testing framework
|
|
17
|
+
def generalise
|
|
18
|
+
Mutiny::Tests::TestSet.new(tests.map(&:generalise))
|
|
19
|
+
end
|
|
14
20
|
end
|
|
15
21
|
end
|
|
16
22
|
end
|
|
@@ -6,19 +6,19 @@ module Mutiny
|
|
|
6
6
|
class Integration
|
|
7
7
|
# This code originally based on Markus Schirp's implementation of Mutant::Integration::Rspec
|
|
8
8
|
# https://github.com/mbj/mutant/blob/master/lib/mutant/integration/rspec.rb
|
|
9
|
-
class RSpec
|
|
10
|
-
def tests
|
|
11
|
-
Parser.new(context).call
|
|
9
|
+
class RSpec < self
|
|
10
|
+
def tests(options = {})
|
|
11
|
+
Parser.new(context(options)).call
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
-
def run(test_set)
|
|
15
|
-
Runner.new(test_set, context).call
|
|
14
|
+
def run(test_set, options = {})
|
|
15
|
+
Runner.new(test_set, context(options)).call
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
private
|
|
19
19
|
|
|
20
|
-
def context
|
|
21
|
-
|
|
20
|
+
def context(options = {})
|
|
21
|
+
Context.new(options)
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
24
|
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Mutiny
|
|
2
|
+
class Isolation
|
|
3
|
+
# An inter-process communication mechanism for sending and receiving
|
|
4
|
+
# (marshalled) data over an IO pipe
|
|
5
|
+
Pipe = Struct.new(:reader, :writer) do
|
|
6
|
+
def self.with(&block)
|
|
7
|
+
IO.pipe(binmode: true) do |reader, writer|
|
|
8
|
+
writer.binmode
|
|
9
|
+
block.call(Pipe.new(reader, writer))
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def receive
|
|
14
|
+
writer.close
|
|
15
|
+
Marshal.load(reader.read)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def send(data)
|
|
19
|
+
reader.close
|
|
20
|
+
writer.write(Marshal.dump(data))
|
|
21
|
+
writer.close
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Mutiny
|
|
2
|
+
class Isolation
|
|
3
|
+
# A mechanism for temporarily silencing a stream by redirecting
|
|
4
|
+
# the output to the OS's null device (e.g., /dev/null)
|
|
5
|
+
class Vacuum
|
|
6
|
+
def self.silence(stream, &block)
|
|
7
|
+
File.open(File::NULL, File::WRONLY) do |file|
|
|
8
|
+
stream.reopen(file)
|
|
9
|
+
block.call
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
require_relative 'isolation/pipe'
|
|
2
|
+
require_relative 'isolation/vacuum'
|
|
3
|
+
|
|
4
|
+
module Mutiny
|
|
5
|
+
# This code originally based on Markus Schirp's implementation of Mutant::Isolation::Fork
|
|
6
|
+
# https://github.com/mbj/mutant/blob/master/lib/mutant/isolation.rb
|
|
7
|
+
class Isolation
|
|
8
|
+
# Runs the given block, isolating the global state so that changes cannot
|
|
9
|
+
# leak out to the caller's runtime
|
|
10
|
+
def self.call(&block)
|
|
11
|
+
new(block).run_in_isolation
|
|
12
|
+
rescue => exception
|
|
13
|
+
raise Error, exception
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
attr_reader :isolated_code
|
|
17
|
+
|
|
18
|
+
def initialize(isolated_code)
|
|
19
|
+
@isolated_code = isolated_code
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def run_in_isolation
|
|
23
|
+
Pipe.with do |comms|
|
|
24
|
+
begin
|
|
25
|
+
pid = Process.fork { run_and_send_result_via(comms) }
|
|
26
|
+
comms.receive # wait to receive the result form the child process
|
|
27
|
+
ensure
|
|
28
|
+
Process.waitpid(pid) if pid
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def run_and_send_result_via(comms)
|
|
34
|
+
Vacuum.silence($stderr) do
|
|
35
|
+
result = isolated_code.call
|
|
36
|
+
comms.send(result) # send the result to the parent process over the pipes
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
Error = Class.new(RuntimeError)
|
|
41
|
+
end
|
|
42
|
+
end
|
data/lib/mutiny/mode/check.rb
CHANGED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require_relative "../analysis/analyser"
|
|
2
|
+
require_relative "../output/table"
|
|
3
|
+
|
|
4
|
+
module Mutiny
|
|
5
|
+
class Mode
|
|
6
|
+
class Score < self
|
|
7
|
+
def run
|
|
8
|
+
report "Scoring..."
|
|
9
|
+
report "#{mutant_set.size} mutants, #{results.kill_count} killed"
|
|
10
|
+
report ""
|
|
11
|
+
report summary
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def summary
|
|
17
|
+
Output::Table.new.tap do |summary|
|
|
18
|
+
summary.add_row(summary_header)
|
|
19
|
+
summary.add_rows(results.mutants.ordered.map { |m| summarise(m) })
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def summary_header
|
|
24
|
+
["Mutant", "Status", "# Tests", "Time"]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def summarise(mutant)
|
|
28
|
+
identifier = mutant.identifier
|
|
29
|
+
status = results.survived?(mutant) ? "survived" : "killed"
|
|
30
|
+
executed_count = results.test_run_for(mutant).executed_count
|
|
31
|
+
total_count = results.test_run_for(mutant).tests.size
|
|
32
|
+
runtime = results.test_run_for(mutant).runtime
|
|
33
|
+
[identifier, status, "#{executed_count} (of #{total_count})", runtime]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def results
|
|
37
|
+
@results ||= analyser.call
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def analyser
|
|
41
|
+
Analysis::Analyser.new(mutant_set: mutant_set, integration: configuration.integration)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def mutant_set
|
|
45
|
+
@mutant_set ||= configuration.mutator.mutants_for(environment.subjects)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
data/lib/mutiny/mode.rb
CHANGED
|
@@ -5,21 +5,22 @@ module Mutiny
|
|
|
5
5
|
class Mutant
|
|
6
6
|
attr_reader :subject, :code
|
|
7
7
|
|
|
8
|
-
def initialize(subject
|
|
8
|
+
def initialize(subject: nil, code:)
|
|
9
9
|
@subject = subject
|
|
10
10
|
@code = code
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
def apply
|
|
14
|
+
# Evaluate the mutanted code, overidding any existing version.
|
|
15
|
+
# We evaluate in the context of TOPLEVEL_BINDING as we want
|
|
16
|
+
# the unit to be evaluated in its usual namespace.
|
|
17
|
+
# rubocop:disable Eval
|
|
18
|
+
eval(code, TOPLEVEL_BINDING)
|
|
19
|
+
# rubocop:enable Eval
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
def eql?(other)
|
|
22
|
-
|
|
23
|
+
other.subject == subject && other.code == code
|
|
23
24
|
end
|
|
24
25
|
|
|
25
26
|
alias_method "==", "eql?"
|
|
@@ -3,39 +3,44 @@ require_relative "mutant"
|
|
|
3
3
|
module Mutiny
|
|
4
4
|
module Mutants
|
|
5
5
|
class MutantSet
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
def add(subject, mutated_code)
|
|
11
|
-
mutants = mutated_code.map { |code| create_mutant(subject, code) }
|
|
12
|
-
@mutants_by_subject[subject] = @mutants_by_subject[subject] + mutants
|
|
13
|
-
end
|
|
6
|
+
extend Forwardable
|
|
7
|
+
def_delegators :mutants, :size, :<<, :concat
|
|
14
8
|
|
|
15
|
-
def
|
|
16
|
-
mutants
|
|
9
|
+
def mutants
|
|
10
|
+
@mutants ||= []
|
|
17
11
|
end
|
|
18
12
|
|
|
19
13
|
def group_by_subject
|
|
20
|
-
|
|
14
|
+
mutants.group_by(&:subject).dup
|
|
21
15
|
end
|
|
22
16
|
|
|
23
|
-
def
|
|
24
|
-
group_by_subject.
|
|
25
|
-
mutants.
|
|
17
|
+
def ordered
|
|
18
|
+
group_by_subject.flat_map do |_, mutants|
|
|
19
|
+
mutants.map.with_index do |mutant, index|
|
|
20
|
+
OrderedMutant.new(mutant, index)
|
|
21
|
+
end
|
|
26
22
|
end
|
|
27
23
|
end
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
def create_mutant(subject, code)
|
|
32
|
-
Mutant.new(subject: subject, code: code)
|
|
25
|
+
def store(mutant_directory = ".mutants")
|
|
26
|
+
ordered.each { |m| m.store(mutant_directory) }
|
|
33
27
|
end
|
|
34
28
|
|
|
35
|
-
|
|
29
|
+
class OrderedMutant < SimpleDelegator
|
|
30
|
+
def initialize(mutant, number)
|
|
31
|
+
super(mutant)
|
|
32
|
+
@number = number
|
|
33
|
+
end
|
|
36
34
|
|
|
37
|
-
|
|
38
|
-
|
|
35
|
+
def identifier
|
|
36
|
+
subject.relative_path.sub(/\.rb$/, ".#{@number}.rb")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def store(directory)
|
|
40
|
+
path = File.join(directory, identifier)
|
|
41
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
42
|
+
File.open(path, 'w') { |f| f.write(code) }
|
|
43
|
+
end
|
|
39
44
|
end
|
|
40
45
|
end
|
|
41
46
|
end
|
|
@@ -14,11 +14,18 @@ module Mutiny
|
|
|
14
14
|
MutantSet.new.tap do |mutants|
|
|
15
15
|
@mutations.each do |mutation|
|
|
16
16
|
subjects.each do |subject|
|
|
17
|
-
|
|
17
|
+
mutated_codes = mutation.mutate_file(subject.path)
|
|
18
|
+
mutants.concat(create_mutants(subject, mutated_codes))
|
|
18
19
|
end
|
|
19
20
|
end
|
|
20
21
|
end
|
|
21
22
|
end
|
|
23
|
+
|
|
24
|
+
private
|
|
25
|
+
|
|
26
|
+
def create_mutants(subject, mutated_codes)
|
|
27
|
+
mutated_codes.map { |code| Mutant.new(subject: subject, code: code) }
|
|
28
|
+
end
|
|
22
29
|
end
|
|
23
30
|
end
|
|
24
31
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
module Mutiny
|
|
2
|
+
module Output
|
|
3
|
+
class Table
|
|
4
|
+
def initialize
|
|
5
|
+
@rows = []
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def add_rows(rows)
|
|
9
|
+
rows.each { |r| add_row(r) }
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def add_row(cells)
|
|
13
|
+
@rows << cells
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_s
|
|
17
|
+
@rows.map { |r| row_to_s(r) }.join("\n")
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def row_to_s(cells)
|
|
21
|
+
"| " +
|
|
22
|
+
cells.each_with_index.map { |cell, index| cell_to_s(cell, index) }.join(" | ") +
|
|
23
|
+
" |"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def cell_to_s(cell, column_index)
|
|
27
|
+
cell.to_s.ljust(width_for_column(column_index))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def width_for_column(index)
|
|
31
|
+
@rows.map { |r| r[index].to_s.size }.max
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -1,18 +1,27 @@
|
|
|
1
1
|
module Mutiny
|
|
2
2
|
module Tests
|
|
3
3
|
class TestRun
|
|
4
|
-
attr_reader :tests, :failed_tests, :output, :runtime
|
|
4
|
+
attr_reader :tests, :passed_tests, :failed_tests, :output, :runtime
|
|
5
5
|
|
|
6
|
-
def initialize(tests:, failed_tests:, output:, runtime:)
|
|
6
|
+
def initialize(tests:, passed_tests:, failed_tests:, output:, runtime:)
|
|
7
7
|
@tests = tests
|
|
8
|
+
@passed_tests = passed_tests
|
|
8
9
|
@failed_tests = failed_tests
|
|
9
10
|
@output = output
|
|
10
11
|
@runtime = runtime
|
|
11
12
|
end
|
|
12
13
|
|
|
14
|
+
def executed_count
|
|
15
|
+
passed_tests.size + failed_tests.size
|
|
16
|
+
end
|
|
17
|
+
|
|
13
18
|
def passed?
|
|
14
19
|
failed_tests.empty?
|
|
15
20
|
end
|
|
21
|
+
|
|
22
|
+
def failed?
|
|
23
|
+
!passed?
|
|
24
|
+
end
|
|
16
25
|
end
|
|
17
26
|
end
|
|
18
27
|
end
|
|
@@ -18,10 +18,14 @@ module Mutiny
|
|
|
18
18
|
tests.map(&:location)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def
|
|
21
|
+
def for_all(subject_set)
|
|
22
22
|
subset { |test| subject_set.names.include?(test.expression) }
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
def for(subject)
|
|
26
|
+
subset { |test| subject.name == test.expression }
|
|
27
|
+
end
|
|
28
|
+
|
|
25
29
|
def subset(&block)
|
|
26
30
|
self.class.new(tests.select(&block))
|
|
27
31
|
end
|
data/lib/mutiny/version.rb
CHANGED
data/lib/mutiny.rb
CHANGED
data/mutiny.gemspec
CHANGED
|
@@ -23,10 +23,10 @@ Gem::Specification.new do |spec|
|
|
|
23
23
|
spec.add_runtime_dependency "gli", "~> 2.13.0"
|
|
24
24
|
spec.add_runtime_dependency "metamorpher", "~> 0.2.2"
|
|
25
25
|
|
|
26
|
-
spec.add_development_dependency "bundler", "~> 1.10.
|
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.10.3"
|
|
27
27
|
spec.add_development_dependency "rake", "~> 10.4.2"
|
|
28
|
-
spec.add_development_dependency "rspec", "~> 3.
|
|
29
|
-
spec.add_development_dependency "aruba", "~> 0.
|
|
28
|
+
spec.add_development_dependency "rspec", "~> 3.3.0"
|
|
29
|
+
spec.add_development_dependency "aruba", "~> 0.7.0"
|
|
30
30
|
spec.add_development_dependency "codeclimate-test-reporter", "~> 0.4.6"
|
|
31
|
-
spec.add_development_dependency "rubocop", "~> 0.
|
|
31
|
+
spec.add_development_dependency "rubocop", "~> 0.33.0"
|
|
32
32
|
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
describe "Using Mutiny to generate mutants" do
|
|
2
|
+
before(:each) do
|
|
3
|
+
cd "calculator"
|
|
4
|
+
run "bundle exec mutiny mutate"
|
|
5
|
+
run "bundle exec mutiny score"
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
it "should report a mutation score" do
|
|
9
|
+
expected_output = "Scoring...\n" \
|
|
10
|
+
"14 mutants, 12 killed\n"
|
|
11
|
+
|
|
12
|
+
expect(all_output).to include(expected_output)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "should report status of mutants" do
|
|
16
|
+
expect(all_output).to include("calculator/min.0.rb | killed")
|
|
17
|
+
expect(all_output).to include("calculator/min.1.rb | killed")
|
|
18
|
+
expect(all_output).to include("calculator/min.2.rb | survived")
|
|
19
|
+
expect(all_output).to include("calculator/min.3.rb | killed")
|
|
20
|
+
expect(all_output).to include("calculator/min.4.rb | killed")
|
|
21
|
+
expect(all_output).to include("calculator/min.5.rb | killed")
|
|
22
|
+
expect(all_output).to include("calculator/min.6.rb | killed")
|
|
23
|
+
expect(all_output).to include("calculator/max.0.rb | killed")
|
|
24
|
+
expect(all_output).to include("calculator/max.1.rb | killed")
|
|
25
|
+
expect(all_output).to include("calculator/max.2.rb | killed")
|
|
26
|
+
expect(all_output).to include("calculator/max.3.rb | killed")
|
|
27
|
+
expect(all_output).to include("calculator/max.4.rb | killed")
|
|
28
|
+
expect(all_output).to include("calculator/max.5.rb | killed")
|
|
29
|
+
expect(all_output).to include("calculator/max.6.rb | survived")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should fail fast (not execute all tests for some killed mutants)" do
|
|
33
|
+
expect(all_output).to include("2 (of 3)")
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require "mutiny/isolation"
|
|
2
|
+
|
|
3
|
+
module Mutiny
|
|
4
|
+
# This code originally based on Markus Schirp's implementation of Mutant::Isolation::Fork
|
|
5
|
+
# https://github.com/mbj/mutant/blob/master/spec/unit/mutant/isolation_spec.rb
|
|
6
|
+
describe Isolation do
|
|
7
|
+
subject { described_class }
|
|
8
|
+
|
|
9
|
+
before do
|
|
10
|
+
@initial = 1
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
describe '.run' do
|
|
14
|
+
it 'does isolate side effects' do
|
|
15
|
+
subject.call { @initial = 2 }
|
|
16
|
+
expect(@initial).to be(1)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'return block value' do
|
|
20
|
+
expect(subject.call { :foo }).to be(:foo)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it 'wraps exceptions' do
|
|
24
|
+
expect { subject.call { fail } }.to raise_error(Isolation::Error, 'marshal data too short')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it 'redirects $stderr of children to /dev/null' do
|
|
28
|
+
begin
|
|
29
|
+
Tempfile.open('mutiny-test') do |file|
|
|
30
|
+
$stderr = file
|
|
31
|
+
subject.call { $stderr.puts('test') }
|
|
32
|
+
file.rewind
|
|
33
|
+
expect(file.read).to eql('')
|
|
34
|
+
end
|
|
35
|
+
ensure
|
|
36
|
+
$stderr = STDERR
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -1,56 +1,18 @@
|
|
|
1
1
|
module Mutiny
|
|
2
2
|
module Mutants
|
|
3
|
-
class ObservableMutantSet < MutantSet
|
|
4
|
-
def create_mutant(subject, code)
|
|
5
|
-
MutantSpy.new(subject: subject, code: code)
|
|
6
|
-
end
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
class MutantSpy < Mutant
|
|
10
|
-
attr_reader :directory, :index
|
|
11
|
-
|
|
12
|
-
def store(directory, index)
|
|
13
|
-
@directory = directory
|
|
14
|
-
@index = index
|
|
15
|
-
end
|
|
16
|
-
end
|
|
17
|
-
|
|
18
3
|
describe MutantSet do
|
|
19
|
-
subject(:mutant_set) {
|
|
4
|
+
subject(:mutant_set) { MutantSet.new }
|
|
5
|
+
let(:m1) { Mutant.new(subject: :min, code: :min_mutant_1) }
|
|
6
|
+
let(:m2) { Mutant.new(subject: :min, code: :min_mutant_2) }
|
|
7
|
+
let(:m3) { Mutant.new(subject: :max, code: :max_mutant_1) }
|
|
8
|
+
let(:m4) { Mutant.new(subject: :min, code: :min_mutant_3) }
|
|
20
9
|
|
|
21
10
|
before(:each) do
|
|
22
|
-
mutant_set
|
|
23
|
-
mutant_set.add(:max, [:max_mutant_1])
|
|
24
|
-
mutant_set.add(:min, [:min_mutant_3])
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
it "groups mutants by subject" do
|
|
28
|
-
groups = mutant_set.group_by_subject.to_a
|
|
29
|
-
first = groups.first
|
|
30
|
-
second = groups.last
|
|
31
|
-
|
|
32
|
-
expect(first).to eq(mutants_for(:min, :min_mutant_1, :min_mutant_2, :min_mutant_3))
|
|
33
|
-
expect(second).to eq(mutants_for(:max, :max_mutant_1))
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
it "counts mutants" do
|
|
37
|
-
expect(mutant_set.size).to eq(4)
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
it "stores by delegating to mutants" do
|
|
41
|
-
mutant_set.store(:mutant_dir)
|
|
42
|
-
|
|
43
|
-
mutant_set.group_by_subject.each do |_, mutants|
|
|
44
|
-
mutants.each_with_index do |mutant, index|
|
|
45
|
-
expect(mutant.directory).to eq(:mutant_dir)
|
|
46
|
-
expect(mutant.index).to eq(index)
|
|
47
|
-
end
|
|
48
|
-
end
|
|
11
|
+
mutant_set << m1 << m2 << m3 << m4
|
|
49
12
|
end
|
|
50
13
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
[subject, mutants]
|
|
14
|
+
it "orders mutants by subject and index" do
|
|
15
|
+
expect(mutant_set.ordered).to eq([m1, m2, m4, m3])
|
|
54
16
|
end
|
|
55
17
|
end
|
|
56
18
|
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Mutiny
|
|
2
|
+
module Mutants
|
|
3
|
+
describe Mutant do
|
|
4
|
+
subject(:mutant) { Mutant.new(code: "class Hello; def run; 'Goodbye'; end; end") }
|
|
5
|
+
|
|
6
|
+
it "overrides existing code when applied" do
|
|
7
|
+
expect { mutant.apply }.to change { Hello.new.run }.from("Hello").to("Goodbye")
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
class Hello
|
|
14
|
+
def run
|
|
15
|
+
"Hello"
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -35,31 +35,31 @@ module Mutiny
|
|
|
35
35
|
|
|
36
36
|
context "for" do
|
|
37
37
|
it "should return only those tests (whose expression) matches a subject" do
|
|
38
|
-
|
|
38
|
+
subjects = subject_set_for("Max", "Min")
|
|
39
39
|
test_set = test_set_for("Subtract", "Min", "Add")
|
|
40
40
|
|
|
41
|
-
expect(test_set.
|
|
41
|
+
expect(test_set.for_all(subjects)).to eq(test_set.subset { |t| t.expression == "Min" })
|
|
42
42
|
end
|
|
43
43
|
|
|
44
44
|
it "should return multiple tests for a single subject" do
|
|
45
|
-
|
|
45
|
+
subjects = subject_set_for("Min")
|
|
46
46
|
test_set = test_set_for("Min", "Max", "Min", "Max", "Min")
|
|
47
47
|
|
|
48
|
-
expect(test_set.
|
|
48
|
+
expect(test_set.for_all(subjects)).to eq(test_set.subset { |t| t.expression == "Min" })
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
it "should return no tests when there are no tests" do
|
|
52
|
-
|
|
52
|
+
subjects = subject_set_for("Max", "Min")
|
|
53
53
|
test_set = TestSet.empty
|
|
54
54
|
|
|
55
|
-
expect(test_set.
|
|
55
|
+
expect(test_set.for_all(subjects)).to eq(TestSet.empty)
|
|
56
56
|
end
|
|
57
57
|
|
|
58
58
|
it "should return no tests when there are no relevant subjects" do
|
|
59
|
-
|
|
59
|
+
subjects = subject_set_for("Max", "Min")
|
|
60
60
|
test_set = test_set_for("Subtract", "Add")
|
|
61
61
|
|
|
62
|
-
expect(test_set.
|
|
62
|
+
expect(test_set.for_all(subjects)).to eq(TestSet.empty)
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def subject_set_for(*names)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mutiny
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Louis Rose
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-
|
|
11
|
+
date: 2015-08-14 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: parser
|
|
@@ -72,14 +72,14 @@ dependencies:
|
|
|
72
72
|
requirements:
|
|
73
73
|
- - "~>"
|
|
74
74
|
- !ruby/object:Gem::Version
|
|
75
|
-
version: 1.10.
|
|
75
|
+
version: 1.10.3
|
|
76
76
|
type: :development
|
|
77
77
|
prerelease: false
|
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
79
79
|
requirements:
|
|
80
80
|
- - "~>"
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
|
-
version: 1.10.
|
|
82
|
+
version: 1.10.3
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
84
|
name: rake
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -100,28 +100,28 @@ dependencies:
|
|
|
100
100
|
requirements:
|
|
101
101
|
- - "~>"
|
|
102
102
|
- !ruby/object:Gem::Version
|
|
103
|
-
version: 3.
|
|
103
|
+
version: 3.3.0
|
|
104
104
|
type: :development
|
|
105
105
|
prerelease: false
|
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
|
107
107
|
requirements:
|
|
108
108
|
- - "~>"
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
|
-
version: 3.
|
|
110
|
+
version: 3.3.0
|
|
111
111
|
- !ruby/object:Gem::Dependency
|
|
112
112
|
name: aruba
|
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
|
114
114
|
requirements:
|
|
115
115
|
- - "~>"
|
|
116
116
|
- !ruby/object:Gem::Version
|
|
117
|
-
version: 0.
|
|
117
|
+
version: 0.7.0
|
|
118
118
|
type: :development
|
|
119
119
|
prerelease: false
|
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
|
121
121
|
requirements:
|
|
122
122
|
- - "~>"
|
|
123
123
|
- !ruby/object:Gem::Version
|
|
124
|
-
version: 0.
|
|
124
|
+
version: 0.7.0
|
|
125
125
|
- !ruby/object:Gem::Dependency
|
|
126
126
|
name: codeclimate-test-reporter
|
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -142,14 +142,14 @@ dependencies:
|
|
|
142
142
|
requirements:
|
|
143
143
|
- - "~>"
|
|
144
144
|
- !ruby/object:Gem::Version
|
|
145
|
-
version: 0.
|
|
145
|
+
version: 0.33.0
|
|
146
146
|
type: :development
|
|
147
147
|
prerelease: false
|
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
|
149
149
|
requirements:
|
|
150
150
|
- - "~>"
|
|
151
151
|
- !ruby/object:Gem::Version
|
|
152
|
-
version: 0.
|
|
152
|
+
version: 0.33.0
|
|
153
153
|
description: A tiny and experimental mutation testing framework for exploring research
|
|
154
154
|
ideas.
|
|
155
155
|
email:
|
|
@@ -189,16 +189,23 @@ files:
|
|
|
189
189
|
- examples/untested_calculator/lib/calculator/max.rb
|
|
190
190
|
- examples/untested_calculator/spec/spec_helper.rb
|
|
191
191
|
- lib/mutiny.rb
|
|
192
|
+
- lib/mutiny/analysis/analyser.rb
|
|
193
|
+
- lib/mutiny/analysis/results.rb
|
|
192
194
|
- lib/mutiny/configuration.rb
|
|
195
|
+
- lib/mutiny/integration.rb
|
|
193
196
|
- lib/mutiny/integration/rspec.rb
|
|
194
197
|
- lib/mutiny/integration/rspec/context.rb
|
|
195
198
|
- lib/mutiny/integration/rspec/parser.rb
|
|
196
199
|
- lib/mutiny/integration/rspec/runner.rb
|
|
197
200
|
- lib/mutiny/integration/rspec/test.rb
|
|
198
201
|
- lib/mutiny/integration/rspec/test_set.rb
|
|
202
|
+
- lib/mutiny/isolation.rb
|
|
203
|
+
- lib/mutiny/isolation/pipe.rb
|
|
204
|
+
- lib/mutiny/isolation/vacuum.rb
|
|
199
205
|
- lib/mutiny/mode.rb
|
|
200
206
|
- lib/mutiny/mode/check.rb
|
|
201
207
|
- lib/mutiny/mode/mutate.rb
|
|
208
|
+
- lib/mutiny/mode/score.rb
|
|
202
209
|
- lib/mutiny/mutants/mutant.rb
|
|
203
210
|
- lib/mutiny/mutants/mutant_set.rb
|
|
204
211
|
- lib/mutiny/mutants/mutation.rb
|
|
@@ -218,6 +225,7 @@ files:
|
|
|
218
225
|
- lib/mutiny/mutants/mutation/method/unary_arithmetic_operator_insertion.rb
|
|
219
226
|
- lib/mutiny/mutants/mutation_set.rb
|
|
220
227
|
- lib/mutiny/mutants/ruby.rb
|
|
228
|
+
- lib/mutiny/output/table.rb
|
|
221
229
|
- lib/mutiny/pattern.rb
|
|
222
230
|
- lib/mutiny/reporter/stdout.rb
|
|
223
231
|
- lib/mutiny/subjects.rb
|
|
@@ -233,13 +241,16 @@ files:
|
|
|
233
241
|
- mutiny.gemspec
|
|
234
242
|
- spec/integration/check_spec.rb
|
|
235
243
|
- spec/integration/mutate_spec.rb
|
|
244
|
+
- spec/integration/score_spec.rb
|
|
236
245
|
- spec/spec_helper.rb
|
|
237
246
|
- spec/support/aruba.rb
|
|
238
247
|
- spec/support/in_example_project.rb
|
|
239
248
|
- spec/support/shared_examples/shared_examples_for_an_operator_replacement_mutation.rb
|
|
240
249
|
- spec/unit/integration/rspec/parser_spec.rb
|
|
241
250
|
- spec/unit/integration/rspec/runner_spec.rb
|
|
251
|
+
- spec/unit/isolation_spec.rb
|
|
242
252
|
- spec/unit/mutants/mutant_set_spec.rb
|
|
253
|
+
- spec/unit/mutants/mutant_spec.rb
|
|
243
254
|
- spec/unit/mutants/mutations/method/binary_operator_replacement_spec.rb
|
|
244
255
|
- spec/unit/mutants/mutations/method/conditional_operator_deletion_spec.rb
|
|
245
256
|
- spec/unit/mutants/mutations/method/conditional_operator_insertion_spec.rb
|
|
@@ -284,13 +295,16 @@ summary: A tiny mutation testing framework for Ruby
|
|
|
284
295
|
test_files:
|
|
285
296
|
- spec/integration/check_spec.rb
|
|
286
297
|
- spec/integration/mutate_spec.rb
|
|
298
|
+
- spec/integration/score_spec.rb
|
|
287
299
|
- spec/spec_helper.rb
|
|
288
300
|
- spec/support/aruba.rb
|
|
289
301
|
- spec/support/in_example_project.rb
|
|
290
302
|
- spec/support/shared_examples/shared_examples_for_an_operator_replacement_mutation.rb
|
|
291
303
|
- spec/unit/integration/rspec/parser_spec.rb
|
|
292
304
|
- spec/unit/integration/rspec/runner_spec.rb
|
|
305
|
+
- spec/unit/isolation_spec.rb
|
|
293
306
|
- spec/unit/mutants/mutant_set_spec.rb
|
|
307
|
+
- spec/unit/mutants/mutant_spec.rb
|
|
294
308
|
- spec/unit/mutants/mutations/method/binary_operator_replacement_spec.rb
|
|
295
309
|
- spec/unit/mutants/mutations/method/conditional_operator_deletion_spec.rb
|
|
296
310
|
- spec/unit/mutants/mutations/method/conditional_operator_insertion_spec.rb
|