mutant 0.3.6 → 0.5.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/.travis.yml +1 -0
- data/Changelog.md +13 -0
- data/Gemfile +1 -1
- data/Guardfile +7 -25
- data/LICENSE +1 -1
- data/README.md +16 -10
- data/config/flay.yml +1 -1
- data/config/reek.yml +11 -11
- data/config/rubocop.yml +1 -1
- data/lib/mutant.rb +3 -10
- data/lib/mutant/cli.rb +199 -80
- data/lib/mutant/config.rb +3 -3
- data/lib/mutant/killer.rb +20 -0
- data/lib/mutant/matcher/filter.rb +3 -8
- data/lib/mutant/matcher/method/instance.rb +1 -1
- data/lib/mutant/matcher/namespace.rb +31 -2
- data/lib/mutant/matcher/null.rb +26 -0
- data/lib/mutant/mutation.rb +0 -1
- data/lib/mutant/reporter/cli/printer.rb +29 -0
- data/lib/mutant/reporter/cli/printer/config.rb +16 -116
- data/lib/mutant/runner/config.rb +47 -1
- data/lib/mutant/strategy.rb +39 -1
- data/lib/mutant/version.rb +1 -1
- data/lib/mutant/walker.rb +51 -0
- data/mutant-rspec.gemspec +24 -0
- data/mutant.gemspec +7 -3
- data/spec/integration/mutant/rspec_spec.rb +11 -6
- data/spec/integration/mutant/zombie_spec.rb +2 -2
- data/spec/shared/method_matcher_behavior.rb +6 -6
- data/spec/spec_helper.rb +2 -2
- data/spec/unit/mutant/cli_new_spec.rb +49 -34
- data/spec/unit/mutant/context/scope/root_spec.rb +1 -1
- data/spec/unit/mutant/loader/eval_spec.rb +2 -2
- data/spec/unit/mutant/matcher/chain_spec.rb +1 -1
- data/spec/unit/mutant/matcher/methods/instance_spec.rb +1 -1
- data/spec/unit/mutant/matcher/methods/singleton_spec.rb +1 -1
- data/spec/unit/mutant/matcher/namespace_spec.rb +1 -1
- data/spec/unit/mutant/mutation_spec.rb +1 -1
- data/spec/unit/mutant/{killer/rspec_spec.rb → rspec/killer_spec.rb} +2 -1
- data/spec/unit/mutant/runner/config_spec.rb +36 -21
- data/spec/unit/mutant_spec.rb +7 -9
- metadata +25 -22
- data/lib/mutant/cli/builder.rb +0 -167
- data/lib/mutant/killer/rspec.rb +0 -95
- data/lib/mutant/predicate.rb +0 -70
- data/lib/mutant/predicate/attribute.rb +0 -68
- data/lib/mutant/predicate/blacklist.rb +0 -27
- data/lib/mutant/predicate/matcher.rb +0 -38
- data/lib/mutant/predicate/whitelist.rb +0 -28
- data/lib/mutant/strategy/rspec.rb +0 -76
- data/spec/unit/mutant/cli/builder/rspec_spec.rb +0 -38
- data/spec/unit/mutant/matcher/filter_spec.rb +0 -19
- data/spec/unit/mutant/predicate_spec.rb +0 -135
data/lib/mutant/killer/rspec.rb
DELETED
@@ -1,95 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Killer
|
5
|
-
# Runner for rspec tests
|
6
|
-
class Rspec < self
|
7
|
-
|
8
|
-
private
|
9
|
-
|
10
|
-
# Run rspec test
|
11
|
-
#
|
12
|
-
# @return [true]
|
13
|
-
# when test is NOT successful
|
14
|
-
#
|
15
|
-
# @return [false]
|
16
|
-
# otherwise
|
17
|
-
#
|
18
|
-
# @api private
|
19
|
-
#
|
20
|
-
def run
|
21
|
-
mutation.insert
|
22
|
-
|
23
|
-
groups =
|
24
|
-
if mutation.is_a?(Mutation::Neutral::Noop)
|
25
|
-
[example_groups.first]
|
26
|
-
else
|
27
|
-
example_groups
|
28
|
-
end
|
29
|
-
|
30
|
-
unless groups
|
31
|
-
$stderr.puts("No rspec example groups found for: #{match_prefixes.join(', ')}")
|
32
|
-
return false
|
33
|
-
end
|
34
|
-
|
35
|
-
reporter = RSpec::Core::Reporter.new
|
36
|
-
|
37
|
-
example_groups.each do |group|
|
38
|
-
return true unless group.run(reporter)
|
39
|
-
end
|
40
|
-
|
41
|
-
false
|
42
|
-
end
|
43
|
-
|
44
|
-
# Return match prefixes
|
45
|
-
#
|
46
|
-
# @return [Enumerble<String>]
|
47
|
-
#
|
48
|
-
# @api private
|
49
|
-
#
|
50
|
-
def match_prefixes
|
51
|
-
subject.match_prefixes
|
52
|
-
end
|
53
|
-
|
54
|
-
# Return example groups
|
55
|
-
#
|
56
|
-
# @return [Array<RSpec::Example>]
|
57
|
-
#
|
58
|
-
# @api private
|
59
|
-
#
|
60
|
-
def example_groups
|
61
|
-
match_prefixes.each do |match_expression|
|
62
|
-
example_groups = find_with(match_expression)
|
63
|
-
return example_groups unless example_groups.empty?
|
64
|
-
end
|
65
|
-
|
66
|
-
nil
|
67
|
-
end
|
68
|
-
|
69
|
-
# Return example groups that match expression
|
70
|
-
#
|
71
|
-
# @param [String] match_expression
|
72
|
-
#
|
73
|
-
# @return [Enumerable<String>]
|
74
|
-
#
|
75
|
-
# @api private
|
76
|
-
#
|
77
|
-
def find_with(match_expression)
|
78
|
-
all_example_groups.select do |example_group|
|
79
|
-
example_group.description.start_with?(match_expression)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
# Return all example groups
|
84
|
-
#
|
85
|
-
# @return [Enumerable<RSpec::Example>]
|
86
|
-
#
|
87
|
-
# @api private
|
88
|
-
#
|
89
|
-
def all_example_groups
|
90
|
-
strategy.example_groups
|
91
|
-
end
|
92
|
-
|
93
|
-
end # Rspec
|
94
|
-
end # Killer
|
95
|
-
end # Mutant
|
data/lib/mutant/predicate.rb
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
# Abstract base class for predicates used to filter subjects / mutations
|
5
|
-
class Predicate
|
6
|
-
include Adamantium::Flat, AbstractType
|
7
|
-
extend DescendantsTracker
|
8
|
-
|
9
|
-
# Check for match
|
10
|
-
#
|
11
|
-
# @param [Object] object
|
12
|
-
#
|
13
|
-
# @return [true]
|
14
|
-
# if object is matched by predicate
|
15
|
-
#
|
16
|
-
# @return [false]
|
17
|
-
# otherwise
|
18
|
-
#
|
19
|
-
# @api private
|
20
|
-
#
|
21
|
-
abstract_method :match?
|
22
|
-
|
23
|
-
# Return predicate for handle
|
24
|
-
#
|
25
|
-
# @param [String] _notation
|
26
|
-
#
|
27
|
-
# @return [nil]
|
28
|
-
#
|
29
|
-
# @api private
|
30
|
-
#
|
31
|
-
def self.handle(_notation)
|
32
|
-
nil
|
33
|
-
end
|
34
|
-
|
35
|
-
# Mutation predicate matching no inputs
|
36
|
-
Mutant.singleton_subclass_instance('CONTRADICTION', self) do
|
37
|
-
|
38
|
-
# Test for match
|
39
|
-
#
|
40
|
-
# @pram [Mutation] _mutation
|
41
|
-
#
|
42
|
-
# @return [true]
|
43
|
-
#
|
44
|
-
# @api private
|
45
|
-
#
|
46
|
-
def match?(_mutation)
|
47
|
-
false
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
# Mutation predicate matching all inputs
|
53
|
-
Mutant.singleton_subclass_instance('TAUTOLOGY', self) do
|
54
|
-
|
55
|
-
# Test for match
|
56
|
-
#
|
57
|
-
# @pram [Mutation] _mutation
|
58
|
-
#
|
59
|
-
# @return [true]
|
60
|
-
#
|
61
|
-
# @api private
|
62
|
-
#
|
63
|
-
def match?(_mutation)
|
64
|
-
true
|
65
|
-
end
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
end # Filter
|
70
|
-
end # Mutant
|
@@ -1,68 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Predicate
|
5
|
-
# Base class for predicates on object attributes
|
6
|
-
class Attribute < self
|
7
|
-
include Concord.new(:attribute_name, :expectation)
|
8
|
-
|
9
|
-
private
|
10
|
-
|
11
|
-
# Return value for object
|
12
|
-
#
|
13
|
-
# @param [Object] object
|
14
|
-
#
|
15
|
-
# @return [Object]
|
16
|
-
#
|
17
|
-
# @api private
|
18
|
-
#
|
19
|
-
def value(object)
|
20
|
-
object.public_send(attribute_name)
|
21
|
-
end
|
22
|
-
|
23
|
-
# Regexp based attribute predicate
|
24
|
-
class Regexp < self
|
25
|
-
|
26
|
-
# Test for match
|
27
|
-
#
|
28
|
-
# @param [Object] object
|
29
|
-
#
|
30
|
-
# @return [true]
|
31
|
-
# if attribute value matches expectation
|
32
|
-
#
|
33
|
-
# @return [false]
|
34
|
-
# otherwise
|
35
|
-
#
|
36
|
-
# @api private
|
37
|
-
#
|
38
|
-
def match?(object)
|
39
|
-
!!(expectation =~ value(object))
|
40
|
-
end
|
41
|
-
|
42
|
-
end # Regexp
|
43
|
-
|
44
|
-
# Equality based attribute predicate
|
45
|
-
class Equality < self
|
46
|
-
|
47
|
-
PATTERN = /\Acode:(?<code>[[:xdigit:]]{1,6})\z/.freeze
|
48
|
-
|
49
|
-
# Test for match
|
50
|
-
#
|
51
|
-
# @param [Object] object
|
52
|
-
#
|
53
|
-
# @return [true]
|
54
|
-
# if attribute value matches expectation
|
55
|
-
#
|
56
|
-
# @return [false]
|
57
|
-
# otherwise
|
58
|
-
#
|
59
|
-
# @api private
|
60
|
-
#
|
61
|
-
def match?(object)
|
62
|
-
expectation.eql?(value(object))
|
63
|
-
end
|
64
|
-
|
65
|
-
end # Equality
|
66
|
-
end # Attribute
|
67
|
-
end # Filter
|
68
|
-
end # Mutant
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Predicate
|
5
|
-
# Blacklist predicate
|
6
|
-
class Blacklist < self
|
7
|
-
include Adamantium::Flat, Concord.new(:blacklist)
|
8
|
-
|
9
|
-
# Test for match
|
10
|
-
#
|
11
|
-
# @param [Object] object
|
12
|
-
#
|
13
|
-
# @return [true]
|
14
|
-
# if object matches blacklist
|
15
|
-
#
|
16
|
-
# @return [false]
|
17
|
-
# otherwise
|
18
|
-
#
|
19
|
-
# @api private
|
20
|
-
#
|
21
|
-
def match?(object)
|
22
|
-
blacklist.none? { |predicate| predicate.match?(object) }
|
23
|
-
end
|
24
|
-
|
25
|
-
end # Whitelist
|
26
|
-
end # Filter
|
27
|
-
end # Mutant
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Predicate
|
5
|
-
# Return matcher
|
6
|
-
class Matcher < self
|
7
|
-
include Concord.new(:matcher)
|
8
|
-
|
9
|
-
# Test if subject matches
|
10
|
-
#
|
11
|
-
# @param [Subject] subject
|
12
|
-
#
|
13
|
-
# @return [true]
|
14
|
-
# if subject is handled by matcher
|
15
|
-
#
|
16
|
-
# @return [false]
|
17
|
-
# otherwise
|
18
|
-
#
|
19
|
-
def match?(subject)
|
20
|
-
subjects.include?(subject)
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
# Return subjects matched by matcher
|
26
|
-
#
|
27
|
-
# @return [Set<Subject>]
|
28
|
-
#
|
29
|
-
# @api private
|
30
|
-
#
|
31
|
-
def subjects
|
32
|
-
matcher.to_a.to_set
|
33
|
-
end
|
34
|
-
memoize :subjects
|
35
|
-
|
36
|
-
end # Matcher
|
37
|
-
end # Predicate
|
38
|
-
end # Mutant
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Predicate
|
5
|
-
|
6
|
-
# Whiltelist filter
|
7
|
-
class Whitelist < self
|
8
|
-
include Adamantium::Flat, Concord.new(:whitelist)
|
9
|
-
|
10
|
-
# Test for match
|
11
|
-
#
|
12
|
-
# @param [Object] object
|
13
|
-
#
|
14
|
-
# @return [true]
|
15
|
-
# if mutation matches whitelist
|
16
|
-
#
|
17
|
-
# @return [false]
|
18
|
-
# otherwise
|
19
|
-
#
|
20
|
-
# @api private
|
21
|
-
#
|
22
|
-
def match?(object)
|
23
|
-
whitelist.any? { |filter| filter.match?(object) }
|
24
|
-
end
|
25
|
-
|
26
|
-
end # Whitelist
|
27
|
-
end # Predicate
|
28
|
-
end # Mutant
|
@@ -1,76 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
module Mutant
|
4
|
-
class Strategy
|
5
|
-
# Rspec killer strategy
|
6
|
-
class Rspec < self
|
7
|
-
include Concord.new(:level)
|
8
|
-
|
9
|
-
KILLER = Killer::Forking.new(Killer::Rspec)
|
10
|
-
|
11
|
-
# Setup rspec strategy
|
12
|
-
#
|
13
|
-
# @return [self]
|
14
|
-
#
|
15
|
-
# @api private
|
16
|
-
#
|
17
|
-
def setup
|
18
|
-
output = StringIO.new
|
19
|
-
configuration.error_stream = output
|
20
|
-
configuration.output_stream = output
|
21
|
-
options.configure(configuration)
|
22
|
-
configuration.load_spec_files
|
23
|
-
self
|
24
|
-
end
|
25
|
-
memoize :setup
|
26
|
-
|
27
|
-
# Return configuration
|
28
|
-
#
|
29
|
-
# @return [RSpec::Core::Configuration]
|
30
|
-
#
|
31
|
-
# @api private
|
32
|
-
#
|
33
|
-
def configuration
|
34
|
-
RSpec::Core::Configuration.new
|
35
|
-
end
|
36
|
-
memoize :configuration, freezer: :noop
|
37
|
-
|
38
|
-
# Return example groups
|
39
|
-
#
|
40
|
-
# @return [Enumerable<RSpec::Core::ExampleGroup>]
|
41
|
-
#
|
42
|
-
# @api private
|
43
|
-
#
|
44
|
-
def example_groups
|
45
|
-
world.example_groups
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
# Return world
|
51
|
-
#
|
52
|
-
# @return [RSpec::Core::World]
|
53
|
-
#
|
54
|
-
# @api private
|
55
|
-
#
|
56
|
-
def world
|
57
|
-
RSpec.world
|
58
|
-
end
|
59
|
-
memoize :world, freezer: :noop
|
60
|
-
|
61
|
-
# Return options
|
62
|
-
#
|
63
|
-
# @return [RSpec::Core::ConfigurationOptions]
|
64
|
-
#
|
65
|
-
# @api private
|
66
|
-
#
|
67
|
-
def options
|
68
|
-
options = RSpec::Core::ConfigurationOptions.new(%w(--fail-fast spec))
|
69
|
-
options.parse_options
|
70
|
-
options
|
71
|
-
end
|
72
|
-
memoize :options, freezer: :noop
|
73
|
-
|
74
|
-
end # Rspec
|
75
|
-
end # Strategy
|
76
|
-
end # Mutant
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require 'spec_helper'
|
4
|
-
|
5
|
-
describe Mutant::CLI::Builder::Rspec do
|
6
|
-
|
7
|
-
let(:option_parser) { OptionParser.new }
|
8
|
-
|
9
|
-
let(:cache) { Mutant::Cache.new }
|
10
|
-
let(:object) { described_class.new(cache, option_parser) }
|
11
|
-
let(:level) { double('Level') }
|
12
|
-
|
13
|
-
let(:default_strategy) do
|
14
|
-
Mutant::Strategy::Rspec.new(0)
|
15
|
-
end
|
16
|
-
|
17
|
-
let(:altered_strategy) do
|
18
|
-
Mutant::Strategy::Rspec.new(1)
|
19
|
-
end
|
20
|
-
|
21
|
-
describe 'default' do
|
22
|
-
specify do
|
23
|
-
object
|
24
|
-
option_parser.parse!(%w[--rspec])
|
25
|
-
expect(object.output).to eql(default_strategy)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe 'parsing a level' do
|
30
|
-
|
31
|
-
specify do
|
32
|
-
object
|
33
|
-
option_parser.parse!(%w[--rspec --rspec-level 1])
|
34
|
-
expect(object.output).to eql(altered_strategy)
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|