mutant 0.3.0.beta14 → 0.3.0.beta15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.devtools +9 -5
- data/config/rubocop.yml +31 -0
- data/lib/mutant/cli.rb +19 -6
- data/lib/mutant/config.rb +1 -1
- data/lib/mutant/runner.rb +99 -22
- data/lib/mutant/runner/config.rb +18 -4
- data/lib/mutant/runner/mutation.rb +4 -1
- data/lib/mutant/runner/subject.rb +3 -11
- data/lib/mutant/subject.rb +17 -27
- data/lib/mutant/subject/method.rb +7 -4
- data/mutant.gemspec +4 -3
- data/spec/spec_helper.rb +3 -0
- data/spec/unit/mutant/runner/config/subjects_spec.rb +24 -14
- data/spec/unit/mutant/runner/config/success_predicate_spec.rb +18 -23
- data/spec/unit/mutant/runner/mutation/killer_spec.rb +9 -6
- data/spec/unit/mutant/runner/subject/success_predicate_spec.rb +29 -27
- data/spec/unit/mutant/subject/mutations_spec.rb +23 -0
- data/test_app/spec/shared/method_filter_parse_behavior.rb +1 -1
- data/test_app/spec/shared/method_match_behavior.rb +3 -4
- data/test_app/spec/shared/mutator_behavior.rb +3 -3
- data/test_app/spec/spec_helper.rb +3 -3
- data/test_app/spec/unit/test_app/literal/command_spec.rb +2 -2
- metadata +10 -10
- data/spec/unit/mutant/runner/failed_predicte_spec.rb +0 -33
- data/spec/unit/mutant/subject/each_spec.rb +0 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1042e4c0fc2031a03918edcdfdfa7dfcdac388e7
|
4
|
+
data.tar.gz: b4f7f5d0b9d8e4ac9d59a147e8b25860d173145f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 85fadf546e6df77875b1d36ce8c9010037a1ed94571ec3e48b92ac73c89729d62321910872046295cbdf757ca715b88f1bf0b714ed0e9f5d443705664dc8454f
|
7
|
+
data.tar.gz: af84ddf9ba4c27c335b7c58c48a35e899bc568871ab53141db7f175ed99cdb3383c4307ee9b257fc5ef61ec15307dbfcb9ab981c5b65fcb1c489e6ffd4fc3097
|
data/Gemfile.devtools
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
group :development do
|
4
4
|
gem 'rake', '~> 10.1.0'
|
5
|
-
gem 'rspec', '~> 2.
|
5
|
+
gem 'rspec', '~> 2.14.1'
|
6
6
|
gem 'yard', '~> 0.8.6.2'
|
7
7
|
end
|
8
8
|
|
@@ -14,7 +14,7 @@ group :guard do
|
|
14
14
|
gem 'guard', '~> 1.8.1'
|
15
15
|
gem 'guard-bundler', '~> 1.0.0'
|
16
16
|
gem 'guard-rspec', '~> 3.0.2'
|
17
|
-
gem 'guard-rubocop', '~> 0.2.0'
|
17
|
+
# gem 'guard-rubocop', '~> 0.2.0'
|
18
18
|
|
19
19
|
# file system change event handling
|
20
20
|
gem 'listen', '~> 1.2.2'
|
@@ -30,13 +30,17 @@ end
|
|
30
30
|
|
31
31
|
group :metrics do
|
32
32
|
gem 'coveralls', '~> 0.6.7'
|
33
|
-
gem 'flay', '~> 2.3.
|
34
|
-
gem 'flog', '~> 4.1.
|
33
|
+
gem 'flay', '~> 2.3.1'
|
34
|
+
gem 'flog', '~> 4.1.1'
|
35
35
|
gem 'reek', '~> 1.3.1', :git => 'https://github.com/troessner/reek.git'
|
36
|
-
gem 'rubocop', '~> 0.9.1'
|
36
|
+
# gem 'rubocop', '~> 0.9.1'
|
37
37
|
gem 'simplecov', '~> 0.7.1'
|
38
38
|
gem 'yardstick', '~> 0.9.6'
|
39
39
|
|
40
|
+
platforms :ruby_19, :ruby_20 do
|
41
|
+
gem 'yard-spellcheck', '~> 0.1.5'
|
42
|
+
end
|
43
|
+
|
40
44
|
platforms :ruby_19 do
|
41
45
|
gem 'json', '~> 1.8.0'
|
42
46
|
end
|
data/config/rubocop.yml
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
AllCops:
|
2
|
+
Includes:
|
3
|
+
- '../**/*.rake'
|
4
|
+
Excludes:
|
5
|
+
- '../vendor/**'
|
6
|
+
|
7
|
+
# Avoid parameter lists longer than five parameters.
|
8
|
+
ParameterLists:
|
9
|
+
Max: 3
|
10
|
+
CountKeywordArgs: true
|
11
|
+
|
12
|
+
# Avoid more than `Max` levels of nesting.
|
13
|
+
BlockNesting:
|
14
|
+
Max: 3
|
15
|
+
|
16
|
+
# Align with the style guide.
|
17
|
+
CollectionMethods:
|
18
|
+
PreferredMethods:
|
19
|
+
collect: 'map'
|
20
|
+
inject: 'reduce'
|
21
|
+
find: 'detect'
|
22
|
+
find_all: 'select'
|
23
|
+
|
24
|
+
# Do not force public/protected/private keyword to be indented at the same
|
25
|
+
# level as the def keyword. My personal preference is to outdent these keywords
|
26
|
+
# because I think when scanning code it makes it easier to identify the
|
27
|
+
# sections of code and visually separate them. When the keyword is at the same
|
28
|
+
# level I think it sort of blends in with the def keywords and makes it harder
|
29
|
+
# to scan the code and see where the sections are.
|
30
|
+
AccessControl:
|
31
|
+
Enabled: false
|
data/lib/mutant/cli.rb
CHANGED
@@ -56,12 +56,13 @@ module Mutant
|
|
56
56
|
#
|
57
57
|
def config
|
58
58
|
Config.new(
|
59
|
-
:cache
|
60
|
-
:debug
|
61
|
-
:matcher
|
62
|
-
:filter
|
63
|
-
:
|
64
|
-
:
|
59
|
+
:cache => @cache,
|
60
|
+
:debug => debug?,
|
61
|
+
:matcher => matcher,
|
62
|
+
:filter => filter,
|
63
|
+
:fail_fast => !!@fail_fast,
|
64
|
+
:strategy => strategy,
|
65
|
+
:reporter => reporter
|
65
66
|
)
|
66
67
|
end
|
67
68
|
memoize :config
|
@@ -151,6 +152,16 @@ module Mutant
|
|
151
152
|
@filters << klass.new(filter)
|
152
153
|
end
|
153
154
|
|
155
|
+
# Set fail fast
|
156
|
+
#
|
157
|
+
# @api private
|
158
|
+
#
|
159
|
+
# @return [undefined]
|
160
|
+
#
|
161
|
+
def set_fail_fast
|
162
|
+
@fail_fast = true
|
163
|
+
end
|
164
|
+
|
154
165
|
# Set debug mode
|
155
166
|
#
|
156
167
|
# @api private
|
@@ -252,6 +263,8 @@ module Mutant
|
|
252
263
|
|
253
264
|
opts.on('--code FILTER', 'Adds a code filter') do |filter|
|
254
265
|
add_filter Mutation::Filter::Code, filter
|
266
|
+
end.on('--fail-fast', 'Fail fast') do
|
267
|
+
set_fail_fast
|
255
268
|
end.on('-d','--debug', 'Enable debugging output') do
|
256
269
|
set_debug
|
257
270
|
end.on_tail('-h', '--help', 'Show this message') do
|
data/lib/mutant/config.rb
CHANGED
data/lib/mutant/runner.rb
CHANGED
@@ -1,8 +1,57 @@
|
|
1
1
|
module Mutant
|
2
2
|
# Runner baseclass
|
3
3
|
class Runner
|
4
|
-
include Adamantium::Flat, AbstractType
|
5
|
-
|
4
|
+
include Adamantium::Flat, AbstractType
|
5
|
+
|
6
|
+
REGISTRY = {}
|
7
|
+
|
8
|
+
# Register handler
|
9
|
+
#
|
10
|
+
# @param [Class] klass
|
11
|
+
#
|
12
|
+
# @return [undefined]
|
13
|
+
#
|
14
|
+
# @api private
|
15
|
+
#
|
16
|
+
def self.register(klass)
|
17
|
+
REGISTRY[klass]=self
|
18
|
+
end
|
19
|
+
private_class_method :register
|
20
|
+
|
21
|
+
# Lookup runner
|
22
|
+
#
|
23
|
+
# @param [Class] klass
|
24
|
+
#
|
25
|
+
# @return [undefined]
|
26
|
+
#
|
27
|
+
# @api private
|
28
|
+
#
|
29
|
+
def self.lookup(klass)
|
30
|
+
current = klass
|
31
|
+
while current
|
32
|
+
handler = REGISTRY.fetch(current) do
|
33
|
+
current = current.superclass; nil
|
34
|
+
end
|
35
|
+
return handler if handler
|
36
|
+
end
|
37
|
+
|
38
|
+
raise ArgumentError, "No handler for: #{klass}"
|
39
|
+
end
|
40
|
+
private_class_method :lookup
|
41
|
+
|
42
|
+
# Run runner for object
|
43
|
+
#
|
44
|
+
# @param [Config] config
|
45
|
+
# @param [Object] object
|
46
|
+
#
|
47
|
+
# @return [Runner]
|
48
|
+
#
|
49
|
+
# @api private
|
50
|
+
#
|
51
|
+
def self.run(config, object)
|
52
|
+
handler = lookup(object.class)
|
53
|
+
handler.new(config, object)
|
54
|
+
end
|
6
55
|
|
7
56
|
# Return config
|
8
57
|
#
|
@@ -27,6 +76,18 @@ module Mutant
|
|
27
76
|
@end = Time.now
|
28
77
|
end
|
29
78
|
|
79
|
+
# Test if runner should stop
|
80
|
+
#
|
81
|
+
# @return [true]
|
82
|
+
# if runner should stop
|
83
|
+
#
|
84
|
+
# @return [false]
|
85
|
+
# otherwise
|
86
|
+
#
|
87
|
+
def stop?
|
88
|
+
!!@stop
|
89
|
+
end
|
90
|
+
|
30
91
|
# Return runtime
|
31
92
|
#
|
32
93
|
# @return [Float]
|
@@ -34,22 +95,17 @@ module Mutant
|
|
34
95
|
# @api private
|
35
96
|
#
|
36
97
|
def runtime
|
37
|
-
@end - @start
|
98
|
+
(@end || Time.now) - @start
|
38
99
|
end
|
39
|
-
memoize :runtime
|
40
100
|
|
41
|
-
#
|
42
|
-
#
|
43
|
-
# @return [true]
|
44
|
-
# if failed
|
101
|
+
# Return reporter
|
45
102
|
#
|
46
|
-
# @return [
|
47
|
-
# otherwise
|
103
|
+
# @return [Reporter]
|
48
104
|
#
|
49
105
|
# @api private
|
50
106
|
#
|
51
|
-
def
|
52
|
-
|
107
|
+
def reporter
|
108
|
+
config.reporter
|
53
109
|
end
|
54
110
|
|
55
111
|
# Test if runner is successful
|
@@ -64,16 +120,6 @@ module Mutant
|
|
64
120
|
#
|
65
121
|
abstract_method :success?
|
66
122
|
|
67
|
-
# Return reporter
|
68
|
-
#
|
69
|
-
# @return [Reporter]
|
70
|
-
#
|
71
|
-
# @api private
|
72
|
-
#
|
73
|
-
def reporter
|
74
|
-
config.reporter
|
75
|
-
end
|
76
|
-
|
77
123
|
private
|
78
124
|
|
79
125
|
# Perform operation
|
@@ -96,5 +142,36 @@ module Mutant
|
|
96
142
|
reporter.report(object)
|
97
143
|
end
|
98
144
|
|
145
|
+
# Perform dispatch
|
146
|
+
#
|
147
|
+
# @return [Enumerable<Runner>]
|
148
|
+
#
|
149
|
+
# @api private
|
150
|
+
#
|
151
|
+
def dispatch(input)
|
152
|
+
collection = []
|
153
|
+
input.each do |object|
|
154
|
+
runner = visit(object)
|
155
|
+
collection << runner
|
156
|
+
if runner.stop?
|
157
|
+
@stop = true
|
158
|
+
break
|
159
|
+
end
|
160
|
+
end
|
161
|
+
collection
|
162
|
+
end
|
163
|
+
|
164
|
+
# Visit object
|
165
|
+
#
|
166
|
+
# @param [Object] object
|
167
|
+
#
|
168
|
+
# @return [undefined]
|
169
|
+
#
|
170
|
+
# @api private
|
171
|
+
#
|
172
|
+
def visit(object)
|
173
|
+
Runner.run(config, object)
|
174
|
+
end
|
175
|
+
|
99
176
|
end # Runner
|
100
177
|
end # Mutant
|
data/lib/mutant/runner/config.rb
CHANGED
@@ -3,6 +3,22 @@ module Mutant
|
|
3
3
|
# Runner for object config
|
4
4
|
class Config < self
|
5
5
|
|
6
|
+
register Mutant::Config
|
7
|
+
|
8
|
+
# Run runner for object
|
9
|
+
#
|
10
|
+
# @param [Config] config
|
11
|
+
# @param [Object] object
|
12
|
+
#
|
13
|
+
# @return [Runner]
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
#
|
17
|
+
def self.run(config)
|
18
|
+
handler = lookup(config.class)
|
19
|
+
handler.new(config)
|
20
|
+
end
|
21
|
+
|
6
22
|
# Return subject runners
|
7
23
|
#
|
8
24
|
# @return [Enumerable<Runner::Subject>]
|
@@ -18,7 +34,7 @@ module Mutant
|
|
18
34
|
# @api private
|
19
35
|
#
|
20
36
|
def failed_subjects
|
21
|
-
subjects.
|
37
|
+
subjects.reject(&:success?)
|
22
38
|
end
|
23
39
|
memoize :failed_subjects
|
24
40
|
|
@@ -58,9 +74,7 @@ module Mutant
|
|
58
74
|
def run_subjects
|
59
75
|
strategy = self.strategy
|
60
76
|
strategy.setup
|
61
|
-
@subjects = config.subjects
|
62
|
-
Subject.run(config, subject)
|
63
|
-
end
|
77
|
+
@subjects = dispatch(config.subjects)
|
64
78
|
strategy.teardown
|
65
79
|
end
|
66
80
|
|
@@ -4,6 +4,8 @@ module Mutant
|
|
4
4
|
class Mutation < self
|
5
5
|
include Concord::Public.new(:config, :mutation)
|
6
6
|
|
7
|
+
register Mutant::Mutation
|
8
|
+
|
7
9
|
# Return killer instance
|
8
10
|
#
|
9
11
|
# @return [Killer]
|
@@ -50,7 +52,8 @@ module Mutant
|
|
50
52
|
#
|
51
53
|
def run
|
52
54
|
@killer = config.strategy.kill(mutation)
|
53
|
-
report(
|
55
|
+
report(killer)
|
56
|
+
@stop = config.fail_fast && !killer.success?
|
54
57
|
end
|
55
58
|
|
56
59
|
end # Mutation
|
@@ -4,13 +4,7 @@ module Mutant
|
|
4
4
|
class Subject < self
|
5
5
|
include Concord::Public.new(:config, :subject)
|
6
6
|
|
7
|
-
|
8
|
-
#
|
9
|
-
# @return [Subject]
|
10
|
-
#
|
11
|
-
# @api private
|
12
|
-
#
|
13
|
-
attr_reader :subject
|
7
|
+
register Mutant::Subject
|
14
8
|
|
15
9
|
# Initialize object
|
16
10
|
#
|
@@ -41,7 +35,7 @@ module Mutant
|
|
41
35
|
# @api private
|
42
36
|
#
|
43
37
|
def failed_mutations
|
44
|
-
mutations.
|
38
|
+
mutations.reject(&:success?)
|
45
39
|
end
|
46
40
|
memoize :failed_mutations
|
47
41
|
|
@@ -70,9 +64,7 @@ module Mutant
|
|
70
64
|
def run
|
71
65
|
subject = self.subject
|
72
66
|
report(subject)
|
73
|
-
@mutations = subject.
|
74
|
-
Mutation.run(config, mutation)
|
75
|
-
end
|
67
|
+
@mutations = dispatch(subject.mutations)
|
76
68
|
report(self)
|
77
69
|
end
|
78
70
|
|
data/lib/mutant/subject.rb
CHANGED
@@ -3,38 +3,18 @@ module Mutant
|
|
3
3
|
class Subject
|
4
4
|
include AbstractType, Adamantium::Flat, Enumerable, Concord::Public.new(:context, :node)
|
5
5
|
|
6
|
-
#
|
6
|
+
# Return mutations
|
7
7
|
#
|
8
|
-
# @return [
|
9
|
-
# returns self if block given
|
10
|
-
#
|
11
|
-
# @return [Enumerator<Mutation>]
|
12
|
-
# returns eumerator if no block given
|
13
|
-
#
|
14
|
-
# @api private
|
15
|
-
#
|
16
|
-
def each
|
17
|
-
return to_enum unless block_given?
|
18
|
-
|
19
|
-
yield noop_mutation
|
20
|
-
|
21
|
-
mutations.each do |mutation|
|
22
|
-
yield mutation
|
23
|
-
end
|
24
|
-
|
25
|
-
self
|
26
|
-
end
|
27
|
-
|
28
|
-
# Return noop mutation
|
29
|
-
#
|
30
|
-
# @return [Mutation::Noop]
|
8
|
+
# @return [Enumerable<Mutation>]
|
31
9
|
#
|
32
10
|
# @api private
|
33
11
|
#
|
34
|
-
def
|
35
|
-
|
12
|
+
def mutations
|
13
|
+
mutations = []
|
14
|
+
generate_mutations(mutations)
|
15
|
+
mutations
|
36
16
|
end
|
37
|
-
memoize :
|
17
|
+
memoize :mutations
|
38
18
|
|
39
19
|
# Return source path
|
40
20
|
#
|
@@ -122,5 +102,15 @@ module Mutant
|
|
122
102
|
Mutation::Neutral::Noop.new(self, node)
|
123
103
|
end
|
124
104
|
|
105
|
+
# Generate mutations
|
106
|
+
#
|
107
|
+
# @param [#<<] emitter
|
108
|
+
#
|
109
|
+
# @return [undefined]
|
110
|
+
#
|
111
|
+
# @api private
|
112
|
+
#
|
113
|
+
abstract_method :generate_mutations
|
114
|
+
|
125
115
|
end # Subject
|
126
116
|
end # Mutant
|
@@ -29,13 +29,16 @@ module Mutant
|
|
29
29
|
|
30
30
|
# Return mutations
|
31
31
|
#
|
32
|
-
# @
|
32
|
+
# @param [#<<] emitter
|
33
|
+
#
|
34
|
+
# @return [undefined]
|
33
35
|
#
|
34
36
|
# @api private
|
35
37
|
#
|
36
|
-
def
|
37
|
-
|
38
|
-
|
38
|
+
def generate_mutations(emitter)
|
39
|
+
emitter << noop_mutation
|
40
|
+
Mutator.each(node) do |mutant|
|
41
|
+
emitter << Mutation::Evil.new(self, mutant)
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
data/mutant.gemspec
CHANGED
@@ -2,13 +2,14 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |gem|
|
4
4
|
gem.name = 'mutant'
|
5
|
-
gem.version = '0.3.0.
|
5
|
+
gem.version = '0.3.0.beta15'
|
6
6
|
gem.authors = [ 'Markus Schirp' ]
|
7
7
|
gem.email = [ 'mbj@schirp-dso.com' ]
|
8
8
|
|
9
9
|
gem.description = 'Mutation testing for ruby'
|
10
10
|
gem.summary = 'Mutation testing tool for ruby under MRI and Rubinius'
|
11
11
|
gem.homepage = 'https://github.com/mbj/mutant'
|
12
|
+
gem.license = 'MIT'
|
12
13
|
|
13
14
|
gem.require_paths = [ 'lib' ]
|
14
15
|
gem.files = `git ls-files`.split("\n")
|
@@ -16,7 +17,7 @@ Gem::Specification.new do |gem|
|
|
16
17
|
gem.extra_rdoc_files = %w[TODO LICENSE]
|
17
18
|
gem.executables = [ 'mutant', 'zombie' ]
|
18
19
|
|
19
|
-
gem.add_runtime_dependency('parser', '~> 2.0.pre2')
|
20
|
+
gem.add_runtime_dependency('parser', '~> 2.0.0.pre2')
|
20
21
|
gem.add_runtime_dependency('unparser', '~> 0.0.8')
|
21
22
|
gem.add_runtime_dependency('ice_nine', '~> 0.8.0')
|
22
23
|
gem.add_runtime_dependency('descendants_tracker', '~> 0.0.1')
|
@@ -25,5 +26,5 @@ Gem::Specification.new do |gem|
|
|
25
26
|
gem.add_runtime_dependency('inflecto', '~> 0.0.2')
|
26
27
|
gem.add_runtime_dependency('anima', '~> 0.0.6')
|
27
28
|
gem.add_runtime_dependency('concord', '~> 0.1.1')
|
28
|
-
gem.add_runtime_dependency('rspec', '~> 2.
|
29
|
+
gem.add_runtime_dependency('rspec', '~> 2.14.1')
|
29
30
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -8,31 +8,41 @@ describe Mutant::Runner::Config, '#subjects' do
|
|
8
8
|
let(:config) do
|
9
9
|
double(
|
10
10
|
'Config',
|
11
|
-
:
|
11
|
+
:class => Mutant::Config,
|
12
|
+
:subjects => [subject_a, subject_b],
|
12
13
|
:strategy => strategy,
|
13
14
|
:reporter => reporter
|
14
15
|
)
|
15
16
|
end
|
16
17
|
|
17
|
-
let(:reporter)
|
18
|
-
let(:strategy)
|
19
|
-
let(:
|
20
|
-
let(:
|
21
|
-
|
22
|
-
|
23
|
-
include Concord::Public.new(:config, :mutation)
|
24
|
-
|
25
|
-
def self.run(*args); new(*args); end
|
26
|
-
end
|
18
|
+
let(:reporter) { double('Reporter') }
|
19
|
+
let(:strategy) { double('Strategy') }
|
20
|
+
let(:subject_a) { double('Subject A') }
|
21
|
+
let(:subject_b) { double('Subject B') }
|
22
|
+
let(:runner_a) { double('Runner A', :stop? => stop_a) }
|
23
|
+
let(:runner_b) { double('Runner B', :stop? => stop_b) }
|
27
24
|
|
28
25
|
before do
|
29
26
|
strategy.stub(:setup)
|
30
27
|
strategy.stub(:teardown)
|
31
28
|
reporter.stub(:report => reporter)
|
32
|
-
|
29
|
+
Mutant::Runner.stub(:run).with(config, subject_a).and_return(runner_a)
|
30
|
+
Mutant::Runner.stub(:run).with(config, subject_b).and_return(runner_b)
|
33
31
|
end
|
34
32
|
|
35
|
-
|
33
|
+
context 'without earily stop' do
|
34
|
+
let(:stop_a) { false }
|
35
|
+
let(:stop_b) { false }
|
36
|
+
it { should eql([runner_a, runner_b]) }
|
37
|
+
it_should_behave_like 'an idempotent method'
|
38
|
+
end
|
39
|
+
|
40
|
+
|
41
|
+
context 'with earily stop' do
|
42
|
+
let(:stop_a) { true }
|
43
|
+
let(:stop_b) { false }
|
44
|
+
it { should eql([runner_a]) }
|
45
|
+
it_should_behave_like 'an idempotent method'
|
46
|
+
end
|
36
47
|
|
37
|
-
it_should_behave_like 'an idempotent method'
|
38
48
|
end
|
@@ -3,50 +3,45 @@ require 'spec_helper'
|
|
3
3
|
describe Mutant::Runner::Config, '#success?' do
|
4
4
|
subject { object.success? }
|
5
5
|
|
6
|
-
let(:object) { described_class.
|
6
|
+
let(:object) { described_class.new(config) }
|
7
7
|
|
8
8
|
let(:config) do
|
9
9
|
double(
|
10
10
|
'Config',
|
11
11
|
:reporter => reporter,
|
12
12
|
:strategy => strategy,
|
13
|
-
:subjects =>
|
13
|
+
:subjects => [subject_a, subject_b]
|
14
14
|
)
|
15
15
|
end
|
16
16
|
|
17
|
-
let(:reporter) { double('Reporter')
|
18
|
-
let(:strategy) { double('Strategy')
|
19
|
-
let(:
|
20
|
-
let(:
|
21
|
-
let(:
|
22
|
-
|
23
|
-
class DummySubjectRunner
|
24
|
-
include Concord::Public.new(:config, :subject)
|
25
|
-
|
26
|
-
def self.run(*args)
|
27
|
-
new(*args)
|
28
|
-
end
|
29
|
-
|
30
|
-
def failed?
|
31
|
-
@subject.fails?
|
32
|
-
end
|
33
|
-
end
|
17
|
+
let(:reporter) { double('Reporter') }
|
18
|
+
let(:strategy) { double('Strategy') }
|
19
|
+
let(:subject_a) { double('Subject A') }
|
20
|
+
let(:subject_b) { double('Subject B') }
|
21
|
+
let(:runner_a) { double('Runner A', :stop? => stop_a, :success? => success_a) }
|
22
|
+
let(:runner_b) { double('Runner B', :stop? => stop_b, :success? => success_b) }
|
34
23
|
|
35
24
|
before do
|
36
|
-
stub_const('Mutant::Runner::Subject', DummySubjectRunner)
|
37
25
|
reporter.stub(:report => reporter)
|
38
26
|
strategy.stub(:setup)
|
39
27
|
strategy.stub(:teardown)
|
28
|
+
Mutant::Runner.stub(:run).with(config, subject_a).and_return(runner_a)
|
29
|
+
Mutant::Runner.stub(:run).with(config, subject_b).and_return(runner_b)
|
40
30
|
end
|
41
31
|
|
42
32
|
context 'without failed subjects' do
|
33
|
+
let(:stop_a) { false }
|
34
|
+
let(:stop_b) { false }
|
35
|
+
let(:success_a) { true }
|
36
|
+
let(:success_b) { true }
|
43
37
|
it { should be(true) }
|
44
38
|
end
|
45
39
|
|
46
40
|
context 'with failing subjects' do
|
47
|
-
|
48
|
-
|
49
|
-
|
41
|
+
let(:stop_a) { false }
|
42
|
+
let(:stop_b) { false }
|
43
|
+
let(:success_a) { false }
|
44
|
+
let(:success_b) { true }
|
50
45
|
|
51
46
|
it { should be(false) }
|
52
47
|
end
|
@@ -6,15 +6,18 @@ describe Mutant::Runner::Mutation, '#killer' do
|
|
6
6
|
let(:config) do
|
7
7
|
double(
|
8
8
|
'Config',
|
9
|
-
:
|
10
|
-
:
|
9
|
+
:fail_fast => fail_fast,
|
10
|
+
:reporter => reporter,
|
11
|
+
:strategy => strategy
|
11
12
|
)
|
12
13
|
end
|
13
14
|
|
14
|
-
let(:reporter)
|
15
|
-
let(:mutation)
|
16
|
-
let(:strategy)
|
17
|
-
let(:killer)
|
15
|
+
let(:reporter) { double('Reporter') }
|
16
|
+
let(:mutation) { double('Mutation', :class => Mutant::Mutation) }
|
17
|
+
let(:strategy) { double('Strategy') }
|
18
|
+
let(:killer) { double('Killer', :success? => success) }
|
19
|
+
let(:fail_fast) { false }
|
20
|
+
let(:success) { false }
|
18
21
|
|
19
22
|
subject { object.killer }
|
20
23
|
|
@@ -3,47 +3,49 @@ require 'spec_helper'
|
|
3
3
|
describe Mutant::Runner::Subject, '#success?' do
|
4
4
|
subject { object.success? }
|
5
5
|
|
6
|
-
let(:object) { described_class.
|
6
|
+
let(:object) { described_class.new(config, mutation_subject) }
|
7
|
+
|
8
|
+
let(:mutation_subject) {
|
9
|
+
double(
|
10
|
+
'Subject',
|
11
|
+
:class => Mutant::Subject,
|
12
|
+
:mutations => [mutation_a, mutation_b]
|
13
|
+
)
|
14
|
+
}
|
7
15
|
|
8
16
|
let(:reporter) { double('Reporter') }
|
9
|
-
let(:mutation_subject) { double('Subject', :map => mutations) }
|
10
17
|
let(:config) { double('Config', :reporter => reporter) }
|
11
|
-
let(:mutation_a) { double('Mutation A'
|
12
|
-
let(:mutation_b) { double('Mutation B'
|
13
|
-
|
18
|
+
let(:mutation_a) { double('Mutation A') }
|
19
|
+
let(:mutation_b) { double('Mutation B') }
|
20
|
+
|
21
|
+
let(:runner_a) { double('Runner A', :success? => success_a, :stop? => stop_a) }
|
22
|
+
let(:runner_b) { double('Runner B', :success? => success_b, :stop? => stop_b) }
|
14
23
|
|
15
24
|
before do
|
16
25
|
reporter.stub(:report => reporter)
|
26
|
+
Mutant::Runner.stub(:run).with(config, mutation_a).and_return(runner_a)
|
27
|
+
Mutant::Runner.stub(:run).with(config, mutation_b).and_return(runner_b)
|
17
28
|
end
|
18
29
|
|
19
|
-
|
20
|
-
|
30
|
+
context 'with failing mutations' do
|
31
|
+
let(:stop_a) { false }
|
32
|
+
let(:stop_b) { false }
|
33
|
+
let(:success_a) { false }
|
34
|
+
let(:success_b) { true }
|
21
35
|
|
22
|
-
|
23
|
-
new(*args)
|
24
|
-
end
|
36
|
+
it { should be(false) }
|
25
37
|
|
26
|
-
|
27
|
-
@mutation.failed?
|
28
|
-
end
|
38
|
+
it_should_behave_like 'an idempotent method'
|
29
39
|
end
|
30
40
|
|
31
|
-
|
32
|
-
|
33
|
-
|
41
|
+
context 'without failing mutations' do
|
42
|
+
let(:stop_a) { false }
|
43
|
+
let(:stop_b) { false }
|
44
|
+
let(:success_a) { true }
|
45
|
+
let(:success_b) { true }
|
34
46
|
|
35
|
-
context 'without evil failed mutations' do
|
36
47
|
it { should be(true) }
|
37
|
-
end
|
38
|
-
|
39
|
-
context 'with failing noop mutation' do
|
40
|
-
end
|
41
48
|
|
42
|
-
|
43
|
-
before do
|
44
|
-
mutation_a.stub(:failed? => true)
|
45
|
-
end
|
46
|
-
|
47
|
-
it { should be(false) }
|
49
|
+
it_should_behave_like 'an idempotent method'
|
48
50
|
end
|
49
51
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mutant::Subject, '#mutations' do
|
4
|
+
subject { object.mutations }
|
5
|
+
|
6
|
+
let(:class_under_test) do
|
7
|
+
mutation_a, mutation_b = self.mutation_a, self.mutation_b
|
8
|
+
Class.new(described_class) do
|
9
|
+
define_method(:generate_mutations) do |emitter|
|
10
|
+
emitter << mutation_a
|
11
|
+
emitter << mutation_b
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
let(:object) { class_under_test.new(context, node) }
|
17
|
+
let(:node) { double('Node') }
|
18
|
+
let(:context) { double('Context') }
|
19
|
+
let(:mutation_a) { double('Mutation A') }
|
20
|
+
let(:mutation_b) { double('Mutation B') }
|
21
|
+
|
22
|
+
it { should eql([mutation_a, mutation_b]) }
|
23
|
+
end
|
@@ -8,10 +8,9 @@ shared_examples_for 'a method match' do
|
|
8
8
|
let(:method_arity) { values.fetch(:method_arity) }
|
9
9
|
let(:scope) { values.fetch(:scope) }
|
10
10
|
let(:node_class) { values.fetch(:node_class) }
|
11
|
-
|
12
|
-
let(:
|
13
|
-
let(:
|
14
|
-
let(:mutation_subject) { subject.first }
|
11
|
+
let(:node) { mutation_subject.node }
|
12
|
+
let(:context) { mutation_subject.context }
|
13
|
+
let(:mutation_subject) { subject.first }
|
15
14
|
|
16
15
|
it 'should return one subject' do
|
17
16
|
subject.size.should be(1)
|
@@ -1,11 +1,11 @@
|
|
1
1
|
shared_examples_for 'a mutator' do
|
2
2
|
subject { object.each(node) { |item| yields << item } }
|
3
3
|
|
4
|
-
let(:yields)
|
5
|
-
let(:object)
|
4
|
+
let(:yields) { [] }
|
5
|
+
let(:object) { described_class }
|
6
6
|
|
7
7
|
unless instance_methods.map(&:to_s).include?('node')
|
8
|
-
let(:node)
|
8
|
+
let(:node) { source.to_ast }
|
9
9
|
end
|
10
10
|
|
11
11
|
it_should_behave_like 'a command method'
|
@@ -1,9 +1,9 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require 'test_app'
|
3
|
-
require 'rspec'
|
4
2
|
|
5
|
-
|
3
|
+
$LOAD_PATH << File.join(File.dirname(__FILE__), '../lib')
|
6
4
|
|
5
|
+
require 'test_app'
|
6
|
+
require 'rspec'
|
7
7
|
|
8
8
|
# require spec support files and shared behavior
|
9
9
|
Dir[File.expand_path('../{support,shared}/**/*.rb', __FILE__)].each { |f| require f }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mutant
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.0.
|
4
|
+
version: 0.3.0.beta15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Markus Schirp
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 2.0.pre2
|
19
|
+
version: 2.0.0.pre2
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ~>
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 2.0.pre2
|
26
|
+
version: 2.0.0.pre2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: unparser
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -142,14 +142,14 @@ dependencies:
|
|
142
142
|
requirements:
|
143
143
|
- - ~>
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version: 2.
|
145
|
+
version: 2.14.1
|
146
146
|
type: :runtime
|
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: 2.
|
152
|
+
version: 2.14.1
|
153
153
|
description: Mutation testing for ruby
|
154
154
|
email:
|
155
155
|
- mbj@schirp-dso.com
|
@@ -180,6 +180,7 @@ files:
|
|
180
180
|
- config/flog.yml
|
181
181
|
- config/mutant.yml
|
182
182
|
- config/reek.yml
|
183
|
+
- config/rubocop.yml
|
183
184
|
- config/yardstick.yml
|
184
185
|
- lib/mutant.rb
|
185
186
|
- lib/mutant/cache.rb
|
@@ -340,14 +341,13 @@ files:
|
|
340
341
|
- spec/unit/mutant/mutator/self_spec.rb
|
341
342
|
- spec/unit/mutant/runner/config/subjects_spec.rb
|
342
343
|
- spec/unit/mutant/runner/config/success_predicate_spec.rb
|
343
|
-
- spec/unit/mutant/runner/failed_predicte_spec.rb
|
344
344
|
- spec/unit/mutant/runner/mutation/killer_spec.rb
|
345
345
|
- spec/unit/mutant/runner/subject/success_predicate_spec.rb
|
346
346
|
- spec/unit/mutant/strategy/method_expansion/class_methods/run_spec.rb
|
347
347
|
- spec/unit/mutant/strategy/rspec/dm2/lookup/method/instance/spec_files_spec.rb
|
348
348
|
- spec/unit/mutant/strategy/rspec/dm2/lookup/method/singleton/spec_files_spec.rb
|
349
349
|
- spec/unit/mutant/subject/context_spec.rb
|
350
|
-
- spec/unit/mutant/subject/
|
350
|
+
- spec/unit/mutant/subject/mutations_spec.rb
|
351
351
|
- spec/unit/mutant/subject/node_spec.rb
|
352
352
|
- test_app/.rspec
|
353
353
|
- test_app/lib/test_app.rb
|
@@ -364,7 +364,8 @@ files:
|
|
364
364
|
- test_app/spec/unit/test_app/literal/command_spec.rb
|
365
365
|
- test_app/spec/unit/test_app/literal/string_spec.rb
|
366
366
|
homepage: https://github.com/mbj/mutant
|
367
|
-
licenses:
|
367
|
+
licenses:
|
368
|
+
- MIT
|
368
369
|
metadata: {}
|
369
370
|
post_install_message:
|
370
371
|
rdoc_options: []
|
@@ -447,13 +448,12 @@ test_files:
|
|
447
448
|
- spec/unit/mutant/mutator/self_spec.rb
|
448
449
|
- spec/unit/mutant/runner/config/subjects_spec.rb
|
449
450
|
- spec/unit/mutant/runner/config/success_predicate_spec.rb
|
450
|
-
- spec/unit/mutant/runner/failed_predicte_spec.rb
|
451
451
|
- spec/unit/mutant/runner/mutation/killer_spec.rb
|
452
452
|
- spec/unit/mutant/runner/subject/success_predicate_spec.rb
|
453
453
|
- spec/unit/mutant/strategy/method_expansion/class_methods/run_spec.rb
|
454
454
|
- spec/unit/mutant/strategy/rspec/dm2/lookup/method/instance/spec_files_spec.rb
|
455
455
|
- spec/unit/mutant/strategy/rspec/dm2/lookup/method/singleton/spec_files_spec.rb
|
456
456
|
- spec/unit/mutant/subject/context_spec.rb
|
457
|
-
- spec/unit/mutant/subject/
|
457
|
+
- spec/unit/mutant/subject/mutations_spec.rb
|
458
458
|
- spec/unit/mutant/subject/node_spec.rb
|
459
459
|
has_rdoc:
|
@@ -1,33 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Mutant::Runner, '#failed?' do
|
4
|
-
subject { object.failed? }
|
5
|
-
|
6
|
-
let(:object) { class_under_test.run(config) }
|
7
|
-
|
8
|
-
let(:config) { double('Config') }
|
9
|
-
let(:class_under_test) do
|
10
|
-
success = self.success
|
11
|
-
|
12
|
-
Class.new(described_class) do
|
13
|
-
define_method :success? do
|
14
|
-
success
|
15
|
-
end
|
16
|
-
|
17
|
-
define_method :run do
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
context 'when runner is successful' do
|
23
|
-
let(:success) { true }
|
24
|
-
|
25
|
-
it { should be(false) }
|
26
|
-
end
|
27
|
-
|
28
|
-
context 'when runner is NOT successful' do
|
29
|
-
let(:success) { false }
|
30
|
-
|
31
|
-
it { should be(true) }
|
32
|
-
end
|
33
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Mutant::Subject, '#each' do
|
4
|
-
subject { object.each { |item| yields << item } }
|
5
|
-
|
6
|
-
let(:class_under_test) do
|
7
|
-
mutations = [mutation_a, mutation_b]
|
8
|
-
Class.new(described_class) do
|
9
|
-
define_method(:mutations) { mutations }
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
let(:object) { class_under_test.new(context, node) }
|
14
|
-
let(:yields) { [] }
|
15
|
-
let(:node) { double('Node') }
|
16
|
-
let(:context) { double('Context') }
|
17
|
-
let(:mutant) { double('Mutant') }
|
18
|
-
let(:mutation_a) { double('Mutation A') }
|
19
|
-
let(:mutation_b) { double('Mutation B') }
|
20
|
-
|
21
|
-
it_should_behave_like 'an #each method'
|
22
|
-
|
23
|
-
let(:neutral_mutation) do
|
24
|
-
Mutant::Mutation::Neutral.new(object, node)
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'yields mutations' do
|
28
|
-
expect { subject }.to change { yields.dup }.from([])
|
29
|
-
.to([neutral_mutation, mutation_a, mutation_b])
|
30
|
-
end
|
31
|
-
end
|