mutant 0.5.23 → 0.5.24
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/config/flay.yml +1 -1
- data/config/reek.yml +19 -19
- data/lib/mutant.rb +12 -39
- data/lib/mutant/ast.rb +5 -0
- data/lib/mutant/ast/meta.rb +131 -0
- data/lib/mutant/ast/named_children.rb +98 -0
- data/lib/mutant/ast/node_predicates.rb +19 -0
- data/lib/mutant/ast/nodes.rb +21 -0
- data/lib/mutant/ast/sexp.rb +34 -0
- data/lib/mutant/ast/types.rb +48 -0
- data/lib/mutant/cache.rb +3 -2
- data/lib/mutant/cli.rb +11 -151
- data/lib/mutant/config.rb +22 -2
- data/lib/mutant/context/scope.rb +11 -21
- data/lib/mutant/delegator.rb +2 -0
- data/lib/mutant/diff.rb +7 -3
- data/lib/mutant/env.rb +49 -0
- data/lib/mutant/expression.rb +36 -8
- data/lib/mutant/expression/methods.rb +62 -0
- data/lib/mutant/expression/namespace.rb +41 -28
- data/lib/mutant/{strategy.rb → integration.rb} +12 -31
- data/lib/mutant/isolation.rb +1 -1
- data/lib/mutant/matcher.rb +1 -21
- data/lib/mutant/matcher/builder.rb +142 -0
- data/lib/mutant/matcher/method.rb +3 -7
- data/lib/mutant/matcher/method/instance.rb +6 -5
- data/lib/mutant/matcher/method/singleton.rb +2 -7
- data/lib/mutant/matcher/methods.rb +11 -14
- data/lib/mutant/matcher/namespace.rb +31 -39
- data/lib/mutant/matcher/scope.rb +13 -2
- data/lib/mutant/meta.rb +0 -1
- data/lib/mutant/meta/example/dsl.rb +5 -1
- data/lib/mutant/mutator/node.rb +16 -44
- data/lib/mutant/mutator/node/or_asgn.rb +1 -1
- data/lib/mutant/mutator/node/send.rb +5 -60
- data/lib/mutant/mutator/node/super.rb +2 -5
- data/lib/mutant/mutator/registry.rb +1 -1
- data/lib/mutant/reporter.rb +10 -0
- data/lib/mutant/reporter/cli.rb +13 -0
- data/lib/mutant/reporter/cli/printer.rb +2 -0
- data/lib/mutant/reporter/cli/progress/config.rb +1 -1
- data/lib/mutant/reporter/cli/progress/noop.rb +2 -0
- data/lib/mutant/reporter/cli/registry.rb +2 -0
- data/lib/mutant/reporter/null.rb +12 -0
- data/lib/mutant/reporter/trace.rb +4 -0
- data/lib/mutant/require_highjack.rb +2 -2
- data/lib/mutant/rspec.rb +0 -0
- data/lib/mutant/runner.rb +2 -0
- data/lib/mutant/runner/config.rb +8 -8
- data/lib/mutant/runner/killer.rb +5 -0
- data/lib/mutant/runner/subject.rb +1 -1
- data/lib/mutant/subject.rb +8 -8
- data/lib/mutant/subject/method.rb +3 -2
- data/lib/mutant/subject/method/instance.rb +1 -1
- data/lib/mutant/test.rb +7 -65
- data/lib/mutant/test/report.rb +59 -0
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/warning_filter.rb +2 -0
- data/lib/mutant/zombifier.rb +3 -0
- data/lib/mutant/zombifier/file.rb +1 -1
- data/meta/or_asgn.rb +11 -0
- data/meta/send.rb +1 -1
- data/mutant-rspec.gemspec +1 -1
- data/mutant.gemspec +1 -1
- data/spec/integration/mutant/corpus_spec.rb +2 -0
- data/spec/integration/mutant/test_mutator_handles_types_spec.rb +2 -2
- data/spec/spec_helper.rb +4 -3
- data/spec/unit/mutant/cli_new_spec.rb +11 -11
- data/spec/unit/mutant/expression/methods_spec.rb +43 -0
- data/spec/unit/mutant/expression/namespace/flat_spec.rb +1 -1
- data/spec/unit/mutant/expression/namespace/recursive_spec.rb +19 -5
- data/spec/unit/mutant/{strategy_spec.rb → integration_spec.rb} +1 -1
- data/spec/unit/mutant/isolation_spec.rb +3 -1
- data/spec/unit/mutant/matcher/method/instance_spec.rb +5 -5
- data/spec/unit/mutant/matcher/method/singleton_spec.rb +8 -8
- data/spec/unit/mutant/matcher/methods/instance_spec.rb +5 -8
- data/spec/unit/mutant/matcher/methods/singleton_spec.rb +5 -5
- data/spec/unit/mutant/matcher/namespace_spec.rb +18 -23
- data/spec/unit/mutant/mutation_spec.rb +1 -1
- data/spec/unit/mutant/runner/config_spec.rb +4 -5
- data/spec/unit/mutant/runner/mutation_spec.rb +21 -21
- data/spec/unit/mutant/runner/subject_spec.rb +6 -6
- data/spec/unit/mutant/subject/method/instance_spec.rb +0 -4
- data/spec/unit/mutant/subject/method/singleton_spec.rb +0 -1
- data/spec/unit/mutant/subject_spec.rb +3 -3
- metadata +20 -6
- data/lib/mutant/node_helpers.rb +0 -52
data/lib/mutant/runner/killer.rb
CHANGED
@@ -28,6 +28,7 @@ module Mutant
|
|
28
28
|
# @return [Boolean]
|
29
29
|
#
|
30
30
|
# @api private
|
31
|
+
#
|
31
32
|
def success?
|
32
33
|
@report.success?
|
33
34
|
end
|
@@ -36,6 +37,8 @@ module Mutant
|
|
36
37
|
#
|
37
38
|
# @return [Boolean]
|
38
39
|
#
|
40
|
+
# @api private
|
41
|
+
#
|
39
42
|
def mutation_dead?
|
40
43
|
test_report = report.test_report
|
41
44
|
killer.mutation.should_fail? && test_report.failed?
|
@@ -59,6 +62,8 @@ module Mutant
|
|
59
62
|
|
60
63
|
# Run killer
|
61
64
|
#
|
65
|
+
# @return [undefined]
|
66
|
+
#
|
62
67
|
# @api private
|
63
68
|
#
|
64
69
|
def run
|
data/lib/mutant/subject.rb
CHANGED
@@ -54,7 +54,7 @@ module Mutant
|
|
54
54
|
# @api private
|
55
55
|
#
|
56
56
|
def identification
|
57
|
-
"#{
|
57
|
+
"#{expression.syntax}:#{source_path}:#{source_line}"
|
58
58
|
end
|
59
59
|
memoize :identification
|
60
60
|
|
@@ -94,22 +94,22 @@ module Mutant
|
|
94
94
|
|
95
95
|
# Return match expression
|
96
96
|
#
|
97
|
-
# @return [
|
97
|
+
# @return [Expression]
|
98
98
|
#
|
99
99
|
# @api private
|
100
100
|
#
|
101
|
-
abstract_method :
|
101
|
+
abstract_method :expression
|
102
102
|
|
103
|
-
# Return match
|
103
|
+
# Return match expressions
|
104
104
|
#
|
105
|
-
# @return [Enumerable<
|
105
|
+
# @return [Enumerable<Expression>]
|
106
106
|
#
|
107
107
|
# @api private
|
108
108
|
#
|
109
|
-
def
|
110
|
-
[
|
109
|
+
def match_expressions
|
110
|
+
[expression].concat(context.match_expressions)
|
111
111
|
end
|
112
|
-
memoize :
|
112
|
+
memoize :match_expressions
|
113
113
|
|
114
114
|
private
|
115
115
|
|
@@ -27,9 +27,10 @@ module Mutant
|
|
27
27
|
#
|
28
28
|
# @api private
|
29
29
|
#
|
30
|
-
def
|
31
|
-
"#{context.identification}#{self.class::SYMBOL}#{name}"
|
30
|
+
def expression
|
31
|
+
Expression.parse("#{context.identification}#{self.class::SYMBOL}#{name}")
|
32
32
|
end
|
33
|
+
memoize :expression
|
33
34
|
|
34
35
|
private
|
35
36
|
|
data/lib/mutant/test.rb
CHANGED
@@ -1,65 +1,7 @@
|
|
1
1
|
module Mutant
|
2
2
|
# Abstract base class for test that might kill a mutation
|
3
3
|
class Test
|
4
|
-
include
|
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
|
4
|
+
include Adamantium::Flat, Concord::Public.new(:integration, :expression)
|
63
5
|
|
64
6
|
# Return test identification
|
65
7
|
#
|
@@ -68,19 +10,19 @@ module Mutant
|
|
68
10
|
# @api private
|
69
11
|
#
|
70
12
|
def identification
|
71
|
-
"#{
|
13
|
+
"#{integration.name}:#{expression.syntax}"
|
72
14
|
end
|
73
15
|
memoize :identification
|
74
16
|
|
75
|
-
#
|
17
|
+
# Run test, return report
|
76
18
|
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
# @return [String]
|
19
|
+
# @return [Report]
|
80
20
|
#
|
81
21
|
# @api private
|
82
22
|
#
|
83
|
-
|
23
|
+
def run
|
24
|
+
integration.run(self)
|
25
|
+
end
|
84
26
|
|
85
27
|
end # Test
|
86
28
|
end # Mutant
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Mutant
|
2
|
+
class Test
|
3
|
+
# Object to report test status
|
4
|
+
class Report
|
5
|
+
include Adamantium::Flat, Anima::Update, Anima.new(
|
6
|
+
:test,
|
7
|
+
:output,
|
8
|
+
:success
|
9
|
+
)
|
10
|
+
|
11
|
+
# Test if test was successful
|
12
|
+
#
|
13
|
+
# @return [Boolean]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
#
|
17
|
+
alias_method :success?, :success
|
18
|
+
|
19
|
+
# Test if test failed
|
20
|
+
#
|
21
|
+
# @return [Boolean]
|
22
|
+
#
|
23
|
+
# @api private
|
24
|
+
#
|
25
|
+
def failed?
|
26
|
+
!success?
|
27
|
+
end
|
28
|
+
|
29
|
+
# Return marshallable data
|
30
|
+
#
|
31
|
+
# NOTE:
|
32
|
+
#
|
33
|
+
# The test is intentionally NOT part of the mashalled data.
|
34
|
+
# In rspec the example group cannot deterministically being marshalled, because
|
35
|
+
# they reference a crazy mix of IO objects, global objects etc.
|
36
|
+
#
|
37
|
+
# @return [Array]
|
38
|
+
#
|
39
|
+
# @api private
|
40
|
+
#
|
41
|
+
def marshal_dump
|
42
|
+
[@output, @success]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Load marshalled data
|
46
|
+
#
|
47
|
+
# @param [Array] arry
|
48
|
+
#
|
49
|
+
# @return [undefined]
|
50
|
+
#
|
51
|
+
# @api private
|
52
|
+
#
|
53
|
+
def marshal_load(array)
|
54
|
+
@output, @success = array
|
55
|
+
end
|
56
|
+
|
57
|
+
end # Report
|
58
|
+
end # Test
|
59
|
+
end # Mutant
|
data/lib/mutant/version.rb
CHANGED
data/lib/mutant/zombifier.rb
CHANGED
@@ -34,10 +34,13 @@ module Mutant
|
|
34
34
|
# @param [String] logical_name
|
35
35
|
# @param [Symbol] namespace
|
36
36
|
#
|
37
|
+
# @return [self]
|
38
|
+
#
|
37
39
|
# @api private
|
38
40
|
#
|
39
41
|
def self.run(logical_name, namespace)
|
40
42
|
new(namespace).run(logical_name)
|
43
|
+
self
|
41
44
|
end
|
42
45
|
|
43
46
|
# Run zombifier
|
data/meta/or_asgn.rb
CHANGED
@@ -22,3 +22,14 @@ Mutant::Meta::Example.add do
|
|
22
22
|
mutation '@a ||= -1'
|
23
23
|
mutation '@a ||= 2'
|
24
24
|
end
|
25
|
+
|
26
|
+
Mutant::Meta::Example.add do
|
27
|
+
source 'foo[:bar] ||= 1'
|
28
|
+
|
29
|
+
singleton_mutations
|
30
|
+
mutation 'foo[:bar] ||= nil'
|
31
|
+
mutation 'foo[:bar] ||= self'
|
32
|
+
mutation 'foo[:bar] ||= 0'
|
33
|
+
mutation 'foo[:bar] ||= -1'
|
34
|
+
mutation 'foo[:bar] ||= 2'
|
35
|
+
end
|
data/meta/send.rb
CHANGED
@@ -259,7 +259,7 @@ Mutant::Meta::Example.add do
|
|
259
259
|
mutation 'self[*bar]'
|
260
260
|
end
|
261
261
|
|
262
|
-
(Mutant::BINARY_METHOD_OPERATORS - [:==, :eql?]).each do |operator|
|
262
|
+
(Mutant::AST::Types::BINARY_METHOD_OPERATORS - [:==, :eql?]).each do |operator|
|
263
263
|
Mutant::Meta::Example.add do
|
264
264
|
source "true #{operator} false"
|
265
265
|
|
data/mutant-rspec.gemspec
CHANGED
@@ -13,7 +13,7 @@ Gem::Specification.new do |gem|
|
|
13
13
|
gem.license = 'MIT'
|
14
14
|
|
15
15
|
gem.require_paths = %w[lib]
|
16
|
-
gem.files = `git ls-files -- lib/mutant/rspec.rb
|
16
|
+
gem.files = `git ls-files -- lib/mutant/integration/rspec{,2,3}.rb`.split("\n")
|
17
17
|
gem.test_files = `git ls-files -- spec/{unit/mutant/rspec,integration/rspec}`.split("\n")
|
18
18
|
gem.extra_rdoc_files = %w[TODO LICENSE]
|
19
19
|
|
data/mutant.gemspec
CHANGED
@@ -14,7 +14,7 @@ Gem::Specification.new do |gem|
|
|
14
14
|
|
15
15
|
gem.require_paths = %w[lib]
|
16
16
|
|
17
|
-
mutant_rspec_files
|
17
|
+
mutant_rspec_files = `git ls-files -- lib/mutant/integration/rspec{,2,3}.rb`.split("\n")
|
18
18
|
|
19
19
|
gem.files = `git ls-files`.split("\n") - mutant_rspec_files
|
20
20
|
gem.test_files = `git ls-files -- spec/{unit,integration}`.split("\n")
|
@@ -42,6 +42,8 @@ describe 'Mutant on ruby corpus' do
|
|
42
42
|
devtools << "gem 'mutant', path: '#{relative}'\n"
|
43
43
|
devtools << "gem 'mutant-rspec', path: '#{relative}'\n"
|
44
44
|
File.write(repo_path.join('Gemfile.devtools'), devtools)
|
45
|
+
lockfile = repo_path.join('Gemfile.lock')
|
46
|
+
lockfile.delete if lockfile.exist?
|
45
47
|
Bundler.with_clean_env do
|
46
48
|
system('bundle install')
|
47
49
|
system(%W[bundle exec mutant -I lib -r #{name} --score #{expect_coverage} --use rspec #{namespace}*])
|
@@ -3,8 +3,8 @@ require 'spec_helper'
|
|
3
3
|
describe do
|
4
4
|
|
5
5
|
specify 'mutant should not crash for any node parser can generate' do
|
6
|
-
Mutant::
|
7
|
-
Mutant::Mutator::Registry.lookup(
|
6
|
+
Mutant::AST::Types::ALL.each do |type|
|
7
|
+
Mutant::Mutator::Registry.lookup(s(type))
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -30,8 +30,8 @@ $LOAD_PATH << File.join(TestApp.root, 'lib')
|
|
30
30
|
require 'test_app'
|
31
31
|
|
32
32
|
module Fixtures
|
33
|
-
|
34
|
-
end
|
33
|
+
BOOT_ENV = Mutant::Env::Boot.new(Mutant::Reporter::CLI.new(STDERR), Mutant::Cache.new)
|
34
|
+
end # Fixtures
|
35
35
|
|
36
36
|
module ParserHelper
|
37
37
|
def generate(node)
|
@@ -46,7 +46,8 @@ end
|
|
46
46
|
RSpec.configure do |config|
|
47
47
|
config.include(CompressHelper)
|
48
48
|
config.include(ParserHelper)
|
49
|
-
config.include(Mutant::
|
49
|
+
config.include(Mutant::AST::Sexp)
|
50
|
+
|
50
51
|
config.expect_with :rspec do |rspec|
|
51
52
|
rspec.syntax = :expect
|
52
53
|
end
|
@@ -11,7 +11,7 @@ end
|
|
11
11
|
shared_examples_for 'a cli parser' do
|
12
12
|
subject { cli.config }
|
13
13
|
|
14
|
-
it { expect(subject.
|
14
|
+
it { expect(subject.integration).to eql(expected_integration) }
|
15
15
|
it { expect(subject.reporter).to eql(expected_reporter) }
|
16
16
|
it { expect(subject.matcher).to eql(expected_matcher) }
|
17
17
|
end
|
@@ -25,12 +25,12 @@ describe Mutant::CLI, '.new' do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
# Defaults
|
28
|
-
let(:expected_filter)
|
29
|
-
let(:
|
30
|
-
let(:expected_reporter)
|
28
|
+
let(:expected_filter) { Morpher.evaluator(s(:true)) }
|
29
|
+
let(:expected_integration) { Mutant::Integration::Null.new }
|
30
|
+
let(:expected_reporter) { Mutant::Reporter::CLI.new($stdout) }
|
31
31
|
|
32
|
-
let(:ns) { Mutant::Matcher
|
33
|
-
let(:
|
32
|
+
let(:ns) { Mutant::Matcher }
|
33
|
+
let(:env) { Fixtures::BOOT_ENV }
|
34
34
|
|
35
35
|
let(:cli) { object.new(arguments) }
|
36
36
|
|
@@ -71,7 +71,7 @@ describe Mutant::CLI, '.new' do
|
|
71
71
|
let(:arguments) { %w[TestApp::Literal#float] }
|
72
72
|
|
73
73
|
let(:expected_matcher) do
|
74
|
-
ns::Method::Instance.new(
|
74
|
+
ns::Method::Instance.new(env, TestApp::Literal, TestApp::Literal.instance_method(:float))
|
75
75
|
end
|
76
76
|
|
77
77
|
it_should_behave_like 'a cli parser'
|
@@ -80,7 +80,7 @@ describe Mutant::CLI, '.new' do
|
|
80
80
|
context 'with debug flag' do
|
81
81
|
let(:pattern) { 'TestApp*' }
|
82
82
|
let(:arguments) { %W[--debug #{pattern}] }
|
83
|
-
let(:expected_matcher) { ns::Namespace.new(
|
83
|
+
let(:expected_matcher) { ns::Namespace.new(env, Mutant::Expression.parse(pattern)) }
|
84
84
|
|
85
85
|
it_should_behave_like 'a cli parser'
|
86
86
|
|
@@ -92,7 +92,7 @@ describe Mutant::CLI, '.new' do
|
|
92
92
|
context 'with zombie flag' do
|
93
93
|
let(:pattern) { 'TestApp*' }
|
94
94
|
let(:arguments) { %W[--zombie #{pattern}] }
|
95
|
-
let(:expected_matcher) { ns::Namespace.new(
|
95
|
+
let(:expected_matcher) { ns::Namespace.new(env, Mutant::Expression.parse(pattern)) }
|
96
96
|
|
97
97
|
it_should_behave_like 'a cli parser'
|
98
98
|
|
@@ -104,7 +104,7 @@ describe Mutant::CLI, '.new' do
|
|
104
104
|
context 'with namespace pattern' do
|
105
105
|
let(:pattern) { 'TestApp*' }
|
106
106
|
let(:arguments) { [pattern] }
|
107
|
-
let(:expected_matcher) { ns::Namespace.new(
|
107
|
+
let(:expected_matcher) { ns::Namespace.new(env, Mutant::Expression.parse(pattern)) }
|
108
108
|
|
109
109
|
it_should_behave_like 'a cli parser'
|
110
110
|
end
|
@@ -124,7 +124,7 @@ describe Mutant::CLI, '.new' do
|
|
124
124
|
|
125
125
|
let(:expected_matcher) do
|
126
126
|
matcher = ns::Method::Instance.new(
|
127
|
-
|
127
|
+
env,
|
128
128
|
TestApp::Literal, TestApp::Literal.instance_method(:float)
|
129
129
|
)
|
130
130
|
predicate = Morpher.compile(
|