mutant 0.3.0.beta22 → 0.3.0.rc1
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 +4 -5
- data/Gemfile.devtools +1 -1
- data/README.md +22 -50
- data/config/flay.yml +1 -1
- data/config/flog.yml +1 -1
- data/config/reek.yml +9 -2
- data/lib/mutant.rb +3 -4
- data/lib/mutant/cli.rb +41 -35
- data/lib/mutant/cli/classifier.rb +1 -1
- data/lib/mutant/config.rb +2 -1
- data/lib/mutant/context/scope.rb +14 -1
- data/lib/mutant/killer.rb +10 -0
- data/lib/mutant/killer/rspec.rb +52 -18
- data/lib/mutant/matcher/method.rb +4 -4
- data/lib/mutant/mutator/node/generic.rb +1 -1
- data/lib/mutant/mutator/node/literal/float.rb +2 -0
- data/lib/mutant/mutator/node/nthref.rb +29 -0
- data/lib/mutant/mutator/node/send.rb +17 -0
- data/lib/mutant/reporter/cli/printer/killer.rb +9 -3
- data/lib/mutant/strategy.rb +9 -9
- data/lib/mutant/strategy/rspec.rb +51 -41
- data/lib/mutant/subject.rb +16 -6
- data/lib/mutant/subject/method.rb +10 -10
- data/lib/mutant/version.rb +7 -0
- data/lib/mutant/zombifier.rb +2 -3
- data/mutant.gemspec +6 -4
- data/spec/integration/mutant/rspec_spec.rb +26 -0
- data/spec/unit/mutant/cli/class_methods/new_spec.rb +33 -8
- data/spec/unit/mutant/killer/rspec/class_methods/new_spec.rb +4 -0
- data/spec/unit/mutant/mutator/node/nthref/mutation_spec.rb +19 -0
- data/spec/unit/mutant/mutator/node/send/mutation_spec.rb +29 -0
- metadata +14 -20
- data/lib/mutant/strategy/method_expansion.rb +0 -53
- data/lib/mutant/strategy/rspec/dm2.rb +0 -24
- data/lib/mutant/strategy/rspec/dm2/lookup.rb +0 -63
- data/lib/mutant/strategy/rspec/dm2/lookup/method.rb +0 -145
- data/spec/integration/mutant/rspec_killer_spec.rb +0 -29
- data/spec/unit/mutant/strategy/method_expansion/class_methods/run_spec.rb +0 -51
- data/spec/unit/mutant/strategy/rspec/dm2/lookup/method/instance/spec_files_spec.rb +0 -73
- data/spec/unit/mutant/strategy/rspec/dm2/lookup/method/singleton/spec_files_spec.rb +0 -62
@@ -54,16 +54,16 @@ module Mutant
|
|
54
54
|
#
|
55
55
|
def skip?
|
56
56
|
location = source_location
|
57
|
-
if location.nil?
|
57
|
+
if location.nil? || BLACKLIST.match(location.first)
|
58
58
|
message = sprintf(
|
59
59
|
'%s does not have valid source location unable to emit matcher',
|
60
60
|
method.inspect
|
61
61
|
)
|
62
62
|
$stderr.puts(message)
|
63
|
-
|
63
|
+
true
|
64
|
+
else
|
65
|
+
false
|
64
66
|
end
|
65
|
-
|
66
|
-
false
|
67
67
|
end
|
68
68
|
|
69
69
|
# Return method name
|
@@ -15,7 +15,7 @@ module Mutant
|
|
15
15
|
:blockarg, :op_asgn, :and_asgn,
|
16
16
|
:regopt, :restarg, :resbody, :retry, :arg_expr,
|
17
17
|
:kwrestarg, :kwoptarg, :kwarg, :undef, :module, :empty,
|
18
|
-
:alias, :for, :xstr, :back_ref, :
|
18
|
+
:alias, :for, :xstr, :back_ref, :class,
|
19
19
|
:sclass, :match_with_lvasgn, :match_current_line, :or_asgn, :kwbegin
|
20
20
|
)
|
21
21
|
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Mutant
|
4
|
+
class Mutator
|
5
|
+
class Node
|
6
|
+
# Mutator for nth-ref nodes
|
7
|
+
class NthRef < self
|
8
|
+
|
9
|
+
handle :nth_ref
|
10
|
+
|
11
|
+
children :number
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# Perform dispatch
|
16
|
+
#
|
17
|
+
# @return [undefined]
|
18
|
+
#
|
19
|
+
# @api private
|
20
|
+
#
|
21
|
+
def dispatch
|
22
|
+
emit_number(number - 1)
|
23
|
+
emit_number(number + 1)
|
24
|
+
end
|
25
|
+
|
26
|
+
end # NthRef
|
27
|
+
end # Node
|
28
|
+
end # Mutator
|
29
|
+
end # Mutant
|
@@ -11,6 +11,11 @@ module Mutant
|
|
11
11
|
|
12
12
|
children :receiver, :selector
|
13
13
|
|
14
|
+
SELECTOR_REPLACEMENTS = {
|
15
|
+
:send => :public_send,
|
16
|
+
:gsub => :sub
|
17
|
+
}.freeze
|
18
|
+
|
14
19
|
INDEX_REFERENCE = :[]
|
15
20
|
INDEX_ASSIGN = :[]=
|
16
21
|
ASSIGN_SUFFIX = :'='
|
@@ -98,11 +103,23 @@ module Mutant
|
|
98
103
|
#
|
99
104
|
def normal_dispatch
|
100
105
|
emit_naked_receiver
|
106
|
+
emit_selector_mutations
|
101
107
|
mutate_receiver
|
102
108
|
emit_argument_propagation
|
103
109
|
mutate_arguments
|
104
110
|
end
|
105
111
|
|
112
|
+
# Emit selector mutations
|
113
|
+
#
|
114
|
+
# @return [undefined]
|
115
|
+
#
|
116
|
+
# @api private
|
117
|
+
#
|
118
|
+
def emit_selector_mutations
|
119
|
+
replacement = SELECTOR_REPLACEMENTS.fetch(selector) { return }
|
120
|
+
emit_selector(replacement)
|
121
|
+
end
|
122
|
+
|
106
123
|
# Emit naked receiver mutation
|
107
124
|
#
|
108
125
|
# @return [undefined]
|
@@ -10,6 +10,9 @@ module Mutant
|
|
10
10
|
|
11
11
|
handle(Mutant::Killer::Forked)
|
12
12
|
|
13
|
+
SUCCESS = '.'.freeze
|
14
|
+
FAILURE = 'F'.freeze
|
15
|
+
|
13
16
|
# Run printer
|
14
17
|
#
|
15
18
|
# @return [undefined]
|
@@ -18,12 +21,14 @@ module Mutant
|
|
18
21
|
#
|
19
22
|
def run
|
20
23
|
if success?
|
21
|
-
char(
|
22
|
-
|
24
|
+
char(SUCCESS, Color::GREEN)
|
25
|
+
else
|
26
|
+
char(FAILURE, Color::RED)
|
23
27
|
end
|
24
|
-
char('F', Color::RED)
|
25
28
|
end
|
26
29
|
|
30
|
+
private
|
31
|
+
|
27
32
|
# Write colorized char
|
28
33
|
#
|
29
34
|
# @param [String] char
|
@@ -37,6 +42,7 @@ module Mutant
|
|
37
42
|
output.write(colorize(color, char))
|
38
43
|
output.flush
|
39
44
|
end
|
45
|
+
|
40
46
|
end # Killer
|
41
47
|
end # Printer
|
42
48
|
end # CLI
|
data/lib/mutant/strategy.rb
CHANGED
@@ -6,24 +6,22 @@ module Mutant
|
|
6
6
|
class Strategy
|
7
7
|
include AbstractType, Adamantium::Flat
|
8
8
|
|
9
|
-
# Perform setup
|
9
|
+
# Perform strategy setup
|
10
10
|
#
|
11
11
|
# @return [self]
|
12
12
|
#
|
13
13
|
# @api private
|
14
14
|
#
|
15
|
-
def
|
16
|
-
self
|
15
|
+
def setup
|
17
16
|
end
|
18
17
|
|
19
|
-
# Perform teardown
|
18
|
+
# Perform strategy teardown
|
20
19
|
#
|
21
20
|
# @return [self]
|
22
21
|
#
|
23
22
|
# @api private
|
24
23
|
#
|
25
|
-
def
|
26
|
-
self
|
24
|
+
def teardown
|
27
25
|
end
|
28
26
|
|
29
27
|
# Kill mutation
|
@@ -34,18 +32,20 @@ module Mutant
|
|
34
32
|
#
|
35
33
|
# @api private
|
36
34
|
#
|
37
|
-
def
|
35
|
+
def kill(mutation)
|
38
36
|
killer.new(self, mutation)
|
39
37
|
end
|
40
38
|
|
39
|
+
private
|
40
|
+
|
41
41
|
# Return killer
|
42
42
|
#
|
43
43
|
# @return [Class:Killer]
|
44
44
|
#
|
45
45
|
# @api private
|
46
46
|
#
|
47
|
-
def
|
48
|
-
self::KILLER
|
47
|
+
def killer
|
48
|
+
self.class::KILLER
|
49
49
|
end
|
50
50
|
|
51
51
|
end # Strategy
|
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
module Mutant
|
4
4
|
class Strategy
|
5
|
-
|
6
|
-
# Rspec strategy base class
|
5
|
+
# Rspec killer strategy
|
7
6
|
class Rspec < self
|
7
|
+
include Equalizer.new
|
8
8
|
|
9
9
|
KILLER = Killer::Forking.new(Killer::Rspec)
|
10
10
|
|
@@ -14,52 +14,62 @@ module Mutant
|
|
14
14
|
#
|
15
15
|
# @api private
|
16
16
|
#
|
17
|
-
def
|
18
|
-
|
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
|
19
23
|
self
|
20
24
|
end
|
25
|
+
memoize :setup
|
21
26
|
|
22
|
-
#
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
Dir['spec/unit/**/*_spec.rb']
|
33
|
-
end
|
34
|
-
end # Unit
|
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
|
35
37
|
|
36
|
-
#
|
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
|
38
47
|
|
39
|
-
|
40
|
-
#
|
41
|
-
# @return [Mutation]
|
42
|
-
#
|
43
|
-
# @api private
|
44
|
-
#
|
45
|
-
def self.spec_files(_mutation)
|
46
|
-
Dir['spec/integration/**/*_spec.rb']
|
47
|
-
end
|
48
|
-
end # Integration
|
48
|
+
private
|
49
49
|
|
50
|
-
#
|
51
|
-
|
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
|
52
60
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
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
|
63
73
|
|
64
74
|
end # Rspec
|
65
75
|
end # Strategy
|
data/lib/mutant/subject.rb
CHANGED
@@ -46,7 +46,7 @@ module Mutant
|
|
46
46
|
# @api private
|
47
47
|
#
|
48
48
|
def identification
|
49
|
-
"#{
|
49
|
+
"#{match_expression}:#{source_path}:#{source_line}"
|
50
50
|
end
|
51
51
|
memoize :identification
|
52
52
|
|
@@ -84,16 +84,26 @@ module Mutant
|
|
84
84
|
end
|
85
85
|
memoize :original_root
|
86
86
|
|
87
|
-
|
88
|
-
|
89
|
-
# Return subtype identifier
|
87
|
+
# Return match expression
|
90
88
|
#
|
91
89
|
# @return [String]
|
92
90
|
#
|
93
91
|
# @api private
|
94
92
|
#
|
95
|
-
abstract_method :
|
96
|
-
|
93
|
+
abstract_method :match_expression
|
94
|
+
|
95
|
+
# Return match prefixes
|
96
|
+
#
|
97
|
+
# @return [Enumerable<String>]
|
98
|
+
#
|
99
|
+
# @api private
|
100
|
+
#
|
101
|
+
def match_prefixes
|
102
|
+
[match_expression].concat(context.match_prefixes)
|
103
|
+
end
|
104
|
+
memoize :match_prefixes
|
105
|
+
|
106
|
+
private
|
97
107
|
|
98
108
|
# Return neutral mutation
|
99
109
|
#
|
@@ -27,6 +27,16 @@ module Mutant
|
|
27
27
|
node.children[self.class::NAME_INDEX]
|
28
28
|
end
|
29
29
|
|
30
|
+
# Return match expression
|
31
|
+
#
|
32
|
+
# @return [String]
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
#
|
36
|
+
def match_expression
|
37
|
+
"#{context.identification}#{self.class::SYMBOL}#{name}"
|
38
|
+
end
|
39
|
+
|
30
40
|
private
|
31
41
|
|
32
42
|
# Return mutations
|
@@ -54,16 +64,6 @@ module Mutant
|
|
54
64
|
context.scope
|
55
65
|
end
|
56
66
|
|
57
|
-
# Return subtype identifier
|
58
|
-
#
|
59
|
-
# @return [String]
|
60
|
-
#
|
61
|
-
# @api private
|
62
|
-
#
|
63
|
-
def subtype
|
64
|
-
"#{context.identification}#{self.class::SYMBOL}#{name}"
|
65
|
-
end
|
66
|
-
|
67
67
|
end # Method
|
68
68
|
end # Subject
|
69
69
|
end # Mutant
|
data/lib/mutant/zombifier.rb
CHANGED
@@ -151,13 +151,12 @@ module Mutant
|
|
151
151
|
|
152
152
|
$LOAD_PATH.each do |path|
|
153
153
|
path = Pathname.new(path).join(file_name)
|
154
|
-
if path.
|
155
|
-
$stderr.puts "Loading #{path}"
|
154
|
+
if path.file?
|
156
155
|
return new(path)
|
157
156
|
end
|
158
157
|
end
|
159
158
|
|
160
|
-
$stderr.puts "Cannot find #{file_name} in $LOAD_PATH"
|
159
|
+
$stderr.puts "Cannot find file #{file_name} in $LOAD_PATH"
|
161
160
|
nil
|
162
161
|
end
|
163
162
|
|
data/mutant.gemspec
CHANGED
@@ -1,8 +1,10 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
+
#
|
3
|
+
require File.expand_path('../lib/mutant/version', __FILE__)
|
2
4
|
|
3
5
|
Gem::Specification.new do |gem|
|
4
6
|
gem.name = 'mutant'
|
5
|
-
gem.version =
|
7
|
+
gem.version = Mutant::VERSION.dup
|
6
8
|
gem.authors = ['Markus Schirp']
|
7
9
|
gem.email = ['mbj@schirp-dso.com']
|
8
10
|
gem.description = 'Mutation testing for ruby'
|
@@ -16,15 +18,15 @@ Gem::Specification.new do |gem|
|
|
16
18
|
gem.extra_rdoc_files = %w[TODO LICENSE]
|
17
19
|
gem.executables = %w[mutant]
|
18
20
|
|
19
|
-
gem.add_runtime_dependency('parser', '~> 2.0.0.
|
20
|
-
gem.add_runtime_dependency('unparser', '~> 0.0.
|
21
|
+
gem.add_runtime_dependency('parser', '~> 2.0.0.pre6')
|
22
|
+
gem.add_runtime_dependency('unparser', '~> 0.0.14')
|
21
23
|
gem.add_runtime_dependency('ice_nine', '~> 0.8.0')
|
22
24
|
gem.add_runtime_dependency('descendants_tracker', '~> 0.0.1')
|
23
25
|
gem.add_runtime_dependency('adamantium', '~> 0.0.10')
|
24
26
|
gem.add_runtime_dependency('equalizer', '~> 0.0.5')
|
25
27
|
gem.add_runtime_dependency('inflecto', '~> 0.0.2')
|
26
28
|
gem.add_runtime_dependency('anima', '~> 0.0.6')
|
27
|
-
gem.add_runtime_dependency('concord', '~> 0.1.
|
29
|
+
gem.add_runtime_dependency('concord', '~> 0.1.3')
|
28
30
|
gem.add_runtime_dependency('rspec', '~> 2.14.1')
|
29
31
|
|
30
32
|
gem.add_development_dependency('bundler', '~> 1.3', '>= 1.3.5')
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
describe Mutant, 'rspec integration' do
|
6
|
+
|
7
|
+
around do |example|
|
8
|
+
Dir.chdir(TestApp.root) do
|
9
|
+
example.run
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
specify 'it allows to kill mutations' do
|
14
|
+
Kernel.system('bundle exec mutant --rspec ::TestApp::Literal#string').should be(true)
|
15
|
+
end
|
16
|
+
|
17
|
+
pending 'fails to kill mutations when they are not covered' do
|
18
|
+
cli = 'bundle exec mutant --rspec ::TestApp::Literal#uncovered_string'
|
19
|
+
Kernel.system(cli).should be(false)
|
20
|
+
end
|
21
|
+
|
22
|
+
pending 'fails when some mutations when are not covered' do
|
23
|
+
cli = 'bundle exec mutant --rspec ::TestApp::Literal'
|
24
|
+
Kernel.system(cli).should be(false)
|
25
|
+
end
|
26
|
+
end
|