mutant 0.6.3 → 0.6.4
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 +2 -2
- data/Changelog.md +6 -0
- data/Gemfile.devtools +1 -1
- data/bin/mutant +2 -1
- data/config/flay.yml +1 -1
- data/config/reek.yml +3 -0
- data/lib/mutant.rb +5 -3
- data/lib/mutant/cli.rb +2 -2
- data/lib/mutant/config.rb +1 -1
- data/lib/mutant/diff.rb +1 -1
- data/lib/mutant/env.rb +1 -1
- data/lib/mutant/expression/methods.rb +16 -0
- data/lib/mutant/isolation.rb +16 -2
- data/lib/mutant/mutator/node/const.rb +1 -1
- data/lib/mutant/mutator/node/generic.rb +1 -1
- data/lib/mutant/mutator/registry.rb +1 -1
- data/lib/mutant/reporter/cli.rb +1 -1
- data/lib/mutant/reporter/cli/format.rb +0 -12
- data/lib/mutant/reporter/cli/printer.rb +1 -1
- data/lib/mutant/result.rb +1 -1
- data/lib/mutant/runner.rb +50 -29
- data/lib/mutant/runner/collector.rb +10 -11
- data/lib/mutant/subject.rb +1 -4
- data/lib/mutant/subject/method.rb +11 -0
- data/lib/mutant/version.rb +1 -1
- data/meta/send.rb +13 -0
- data/mutant.gemspec +2 -2
- data/spec/spec_helper.rb +2 -9
- data/spec/support/corpus.rb +5 -5
- data/spec/support/rb_bug.rb +18 -0
- data/spec/unit/mutant/cli_spec.rb +2 -2
- data/spec/unit/mutant/expression/methods_spec.rb +7 -1
- data/spec/unit/mutant/isolation_spec.rb +22 -2
- data/spec/unit/mutant/matcher/method/instance_spec.rb +5 -5
- data/spec/unit/mutant/matcher/method/singleton_spec.rb +5 -5
- data/spec/unit/mutant/reporter/cli_spec.rb +13 -14
- data/spec/unit/mutant/runner/collector_spec.rb +198 -0
- data/spec/unit/mutant/runner_spec.rb +2 -3
- data/spec/unit/mutant/subject/method/instance_spec.rb +8 -0
- data/spec/unit/mutant/subject/method/singleton_spec.rb +8 -0
- data/spec/unit/mutant/warning_filter_spec.rb +1 -1
- data/test_app/Gemfile.devtools +1 -1
- data/test_app/lib/test_app.rb +4 -0
- metadata +22 -19
- data/lib/parser_extensions.rb +0 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee4fb487c413c8106f0b826458a2914efa842775
|
4
|
+
data.tar.gz: 005c891d8fbcd19a1e4ec806ce39a2d05defcdd3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 537342f44d70f3c23696de4962157ec74b7a0383f587c6db897bf216b7e2fe7f22572e84a54e3c055434a5bb5cbd061109655f25d1e3d2418643f9ec716cb147
|
7
|
+
data.tar.gz: 77045f8132668b54c86989ff3c0fa8e75615ebd555bbba305d7da26bded1c7414d6503d0ef16a5ae52547a3fa0a92f142f01f43678762d46dccf57d1bb9e1318
|
data/.travis.yml
CHANGED
@@ -6,11 +6,11 @@ rvm:
|
|
6
6
|
- 1.9.3
|
7
7
|
- 2.0.0
|
8
8
|
- 2.1.2
|
9
|
+
- 2.1.3
|
9
10
|
- rbx-2
|
10
11
|
matrix:
|
11
12
|
allow_failures:
|
12
|
-
- rvm: 2
|
13
|
-
- rvm: rbx-2 # Travis does not take care about RBX
|
13
|
+
- rvm: rbx-2 # travis does not maintain rbx setup correctly
|
14
14
|
notifications:
|
15
15
|
irc:
|
16
16
|
channels:
|
data/Changelog.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
# v0.6.4 2014-10-xx
|
2
|
+
|
3
|
+
* Do not buffer report prints, speedup large report generation.
|
4
|
+
* Fix some cases where --fail-fast semantics stopped far to late.
|
5
|
+
* Fix crashing / stuckage from using parallel in a nested way.
|
6
|
+
|
1
7
|
# v0.6.3 2014-09-22
|
2
8
|
|
3
9
|
* Add support for rspec-3.1.
|
data/Gemfile.devtools
CHANGED
data/bin/mutant
CHANGED
data/config/flay.yml
CHANGED
data/config/reek.yml
CHANGED
@@ -64,6 +64,7 @@ NestedIterators:
|
|
64
64
|
- Mutant#self.singleton_subclass_instance
|
65
65
|
- Mutant::CLI#parse
|
66
66
|
- Mutant::Integration::Rspec#run
|
67
|
+
- Mutant::Isolation::Fork#self.call
|
67
68
|
- Mutant::Mutator::Util::Array::Element#dispatch
|
68
69
|
- Mutant::Mutator::Node::Resbody#mutate_captures
|
69
70
|
- Mutant::Mutator::Node::Arguments#emit_argument_mutations
|
@@ -95,6 +96,7 @@ TooManyMethods:
|
|
95
96
|
- Mutant::Subject
|
96
97
|
- Mutant::Mutator::Node
|
97
98
|
- Mutant::Reporter::CLI
|
99
|
+
- Mutant::Runner
|
98
100
|
- Mutant::Meta::Example::Verification
|
99
101
|
max_methods: 10
|
100
102
|
TooManyStatements:
|
@@ -102,6 +104,7 @@ TooManyStatements:
|
|
102
104
|
exclude:
|
103
105
|
- Mutant#self.singleton_subclass_instance
|
104
106
|
- Mutant::Integration::Rspec#run
|
107
|
+
- Mutant::Isolation::Fork#self.call
|
105
108
|
- Mutant::Reporter::CLI#colorized_diff
|
106
109
|
- Mutant::Reporter::CLI::Printer::EnvProgress#run
|
107
110
|
- Mutant::Reporter::CLI::Printer::Config#run
|
data/lib/mutant.rb
CHANGED
@@ -5,10 +5,8 @@ require 'ice_nine'
|
|
5
5
|
require 'abstract_type'
|
6
6
|
require 'equalizer'
|
7
7
|
require 'digest/sha1'
|
8
|
-
require 'inflecto'
|
9
8
|
require 'parser'
|
10
9
|
require 'parser/current'
|
11
|
-
require 'parser_extensions'
|
12
10
|
require 'unparser'
|
13
11
|
require 'ice_nine'
|
14
12
|
require 'diff/lcs'
|
@@ -19,6 +17,10 @@ require 'morpher'
|
|
19
17
|
require 'parallel'
|
20
18
|
require 'open3'
|
21
19
|
|
20
|
+
# This setting is done to make errors within the parallel
|
21
|
+
# reporter / execution visible in the main thread.
|
22
|
+
Thread.abort_on_exception = true
|
23
|
+
|
22
24
|
# Library namespace
|
23
25
|
module Mutant
|
24
26
|
# The frozen empty string used within mutant
|
@@ -221,7 +223,7 @@ module Mutant
|
|
221
223
|
isolation: Mutant::Isolation::Fork,
|
222
224
|
reporter: Reporter::CLI.build($stdout),
|
223
225
|
zombie: false,
|
224
|
-
|
226
|
+
jobs: Mutant.ci? ? CI_DEFAULT_PROCESSOR_COUNT : Parallel.processor_count,
|
225
227
|
expected_coverage: 100.0
|
226
228
|
)
|
227
229
|
end # Config
|
data/lib/mutant/cli.rb
CHANGED
@@ -112,8 +112,8 @@ module Mutant
|
|
112
112
|
opts.on('-r', '--require NAME', 'Require file with NAME') do |name|
|
113
113
|
add(:requires, name)
|
114
114
|
end
|
115
|
-
opts.on('-j', '--jobs NUMBER', 'Number of kill
|
116
|
-
update(
|
115
|
+
opts.on('-j', '--jobs NUMBER', 'Number of kill jobs. Defaults to number of processors.') do |number|
|
116
|
+
update(jobs: Integer(number))
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
data/lib/mutant/config.rb
CHANGED
data/lib/mutant/diff.rb
CHANGED
data/lib/mutant/env.rb
CHANGED
@@ -115,7 +115,7 @@ module Mutant
|
|
115
115
|
def expression(scope)
|
116
116
|
name = scope_name(scope) or return
|
117
117
|
|
118
|
-
unless name.
|
118
|
+
unless name.is_a?(String)
|
119
119
|
warn("#{scope.class}#name from: #{scope.inspect} did not return a String or nil. Fix your lib to support normal ruby semantics!")
|
120
120
|
return
|
121
121
|
end
|
@@ -25,6 +25,22 @@ module Mutant
|
|
25
25
|
MATCHERS.fetch(scope_symbol).new(env, scope)
|
26
26
|
end
|
27
27
|
|
28
|
+
# Return length of match
|
29
|
+
#
|
30
|
+
# @param [Expression] expression
|
31
|
+
#
|
32
|
+
# @return [Fixnum]
|
33
|
+
#
|
34
|
+
# @api private
|
35
|
+
#
|
36
|
+
def match_length(expression)
|
37
|
+
if expression.syntax.start_with?(syntax)
|
38
|
+
syntax.length
|
39
|
+
else
|
40
|
+
0
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
28
44
|
private
|
29
45
|
|
30
46
|
# Return scope name
|
data/lib/mutant/isolation.rb
CHANGED
@@ -38,8 +38,22 @@ module Mutant
|
|
38
38
|
# @api private
|
39
39
|
#
|
40
40
|
def self.call(&block)
|
41
|
-
|
42
|
-
|
41
|
+
reader, writer = IO.pipe
|
42
|
+
|
43
|
+
pid = fork do
|
44
|
+
File.open('/dev/null', 'w') do |file|
|
45
|
+
$stderr.reopen(file)
|
46
|
+
reader.close
|
47
|
+
writer.write(Marshal.dump(block.call))
|
48
|
+
writer.close
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
writer.close
|
53
|
+
result = Marshal.load(reader.read)
|
54
|
+
Process.waitpid(pid)
|
55
|
+
result
|
56
|
+
rescue => exception
|
43
57
|
fail Error, exception
|
44
58
|
end
|
45
59
|
|
@@ -19,7 +19,7 @@ module Mutant
|
|
19
19
|
emit_singletons unless parent_node && n_const?(parent_node)
|
20
20
|
emit_type(nil, *children.drop(1))
|
21
21
|
children.each_with_index do |child, index|
|
22
|
-
mutate_child(index) if child.
|
22
|
+
mutate_child(index) if child.is_a?(Parser::AST::Node)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -64,7 +64,7 @@ module Mutant
|
|
64
64
|
# @api private
|
65
65
|
#
|
66
66
|
def self.assert_valid_type(type)
|
67
|
-
unless AST::Types::ALL.include?(type) || type.
|
67
|
+
unless AST::Types::ALL.include?(type) || type.is_a?(Class)
|
68
68
|
raise InvalidTypeError, "invalid type registration: #{type}"
|
69
69
|
end
|
70
70
|
end
|
data/lib/mutant/reporter/cli.rb
CHANGED
@@ -25,18 +25,6 @@ module Mutant
|
|
25
25
|
#
|
26
26
|
abstract_method :progress
|
27
27
|
|
28
|
-
# Format result
|
29
|
-
#
|
30
|
-
# @param [Result::Env] env
|
31
|
-
#
|
32
|
-
# @return [String]
|
33
|
-
#
|
34
|
-
# @api private
|
35
|
-
#
|
36
|
-
def report(env)
|
37
|
-
format(Printer::EnvResult, env)
|
38
|
-
end
|
39
|
-
|
40
28
|
# Output abstraction to decouple tty? from buffer
|
41
29
|
class Output
|
42
30
|
include Concord.new(:tty, :buffer)
|
@@ -177,7 +177,7 @@ module Mutant
|
|
177
177
|
info 'Matcher: %s', object.matcher_config.inspect
|
178
178
|
info 'Integration: %s', object.integration.name
|
179
179
|
info 'Expect Coverage: %0.2f%%', object.expected_coverage.inspect
|
180
|
-
info '
|
180
|
+
info 'Jobs: %d', object.jobs
|
181
181
|
info 'Includes: %s', object.includes.inspect
|
182
182
|
info 'Requires: %s', object.requires.inspect
|
183
183
|
self
|
data/lib/mutant/result.rb
CHANGED
data/lib/mutant/runner.rb
CHANGED
@@ -12,19 +12,21 @@ module Mutant
|
|
12
12
|
def initialize(env)
|
13
13
|
super
|
14
14
|
|
15
|
-
@collector
|
16
|
-
@mutex
|
17
|
-
@mutations
|
15
|
+
@collector = Collector.new(env)
|
16
|
+
@mutex = Mutex.new
|
17
|
+
@mutations = env.mutations.dup
|
18
|
+
@index = 0
|
19
|
+
@continue = true
|
18
20
|
|
19
21
|
config.integration.setup
|
20
22
|
|
21
|
-
|
23
|
+
reporter.start(env)
|
22
24
|
|
23
25
|
run
|
24
26
|
|
25
|
-
@result = @collector.result
|
27
|
+
@result = @collector.result
|
26
28
|
|
27
|
-
|
29
|
+
reporter.report(result)
|
28
30
|
end
|
29
31
|
|
30
32
|
# Return result
|
@@ -45,14 +47,36 @@ module Mutant
|
|
45
47
|
#
|
46
48
|
def run
|
47
49
|
Parallel.map(
|
48
|
-
|
49
|
-
|
50
|
-
finish:
|
51
|
-
start:
|
50
|
+
method(:next),
|
51
|
+
in_threads: config.jobs,
|
52
|
+
finish: method(:finish),
|
53
|
+
start: method(:start),
|
52
54
|
&method(:run_mutation)
|
53
55
|
)
|
54
56
|
end
|
55
57
|
|
58
|
+
# Return next mutation or stop
|
59
|
+
#
|
60
|
+
# @return [Mutation]
|
61
|
+
# in case there is a next mutation
|
62
|
+
#
|
63
|
+
# @return [Parallel::Stop]
|
64
|
+
# in case there is no next mutation or runner should stop early
|
65
|
+
#
|
66
|
+
#
|
67
|
+
# @api private
|
68
|
+
def next
|
69
|
+
@mutex.synchronize do
|
70
|
+
mutation = @mutations.at(@index)
|
71
|
+
if @continue && mutation
|
72
|
+
@index += 1
|
73
|
+
mutation
|
74
|
+
else
|
75
|
+
Parallel::Stop
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
56
80
|
# Handle started mutation
|
57
81
|
#
|
58
82
|
# @param [Mutation] mutation
|
@@ -79,7 +103,7 @@ module Mutant
|
|
79
103
|
# @api private
|
80
104
|
#
|
81
105
|
def finish(mutation, index, result)
|
82
|
-
return unless result.
|
106
|
+
return unless result.is_a?(Mutant::Result::Mutation)
|
83
107
|
|
84
108
|
test_results = result.test_results.zip(mutation.subject.tests).map do |test_result, test|
|
85
109
|
test_result.update(test: test, mutation: mutation) if test_result
|
@@ -100,22 +124,9 @@ module Mutant
|
|
100
124
|
#
|
101
125
|
def process_result(result)
|
102
126
|
@collector.finish(result)
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
# Handle exit if needed
|
108
|
-
#
|
109
|
-
# @param [Result::Mutation] result
|
110
|
-
#
|
111
|
-
# @return [undefined]
|
112
|
-
#
|
113
|
-
# @api private
|
114
|
-
#
|
115
|
-
def handle_exit(result)
|
116
|
-
return if !config.fail_fast || result.success?
|
117
|
-
|
118
|
-
@mutations.clear
|
127
|
+
reporter.progress(@collector)
|
128
|
+
return unless config.fail_fast && !result.success?
|
129
|
+
@continue = false
|
119
130
|
end
|
120
131
|
|
121
132
|
# Run mutation
|
@@ -175,13 +186,23 @@ module Mutant
|
|
175
186
|
end
|
176
187
|
rescue Isolation::Error => exception
|
177
188
|
Result::Test.new(
|
178
|
-
test:
|
179
|
-
mutation:
|
189
|
+
test: test,
|
190
|
+
mutation: mutation,
|
180
191
|
runtime: Time.now - time,
|
181
192
|
output: exception.message,
|
182
193
|
passed: false
|
183
194
|
)
|
184
195
|
end
|
185
196
|
|
197
|
+
# Return reporter
|
198
|
+
#
|
199
|
+
# @return [Reporter]
|
200
|
+
#
|
201
|
+
# @api private
|
202
|
+
#
|
203
|
+
def reporter
|
204
|
+
config.reporter
|
205
|
+
end
|
206
|
+
|
186
207
|
end # Runner
|
187
208
|
end # Mutant
|
@@ -14,7 +14,7 @@ module Mutant
|
|
14
14
|
super
|
15
15
|
@start = Time.now
|
16
16
|
@aggregate = Hash.new { |hash, key| hash[key] = [] }
|
17
|
-
@
|
17
|
+
@active = Set.new
|
18
18
|
@last_mutation_result = nil
|
19
19
|
end
|
20
20
|
|
@@ -50,12 +50,11 @@ module Mutant
|
|
50
50
|
Result::Env.new(
|
51
51
|
env: env,
|
52
52
|
runtime: Time.now - @start,
|
53
|
-
subject_results: subject_results
|
54
|
-
done: false
|
53
|
+
subject_results: subject_results
|
55
54
|
)
|
56
55
|
end
|
57
56
|
|
58
|
-
#
|
57
|
+
# Register mutation start
|
59
58
|
#
|
60
59
|
# @param [Mutation] mutation
|
61
60
|
#
|
@@ -64,7 +63,7 @@ module Mutant
|
|
64
63
|
# @api private
|
65
64
|
#
|
66
65
|
def start(mutation)
|
67
|
-
@
|
66
|
+
@active << mutation
|
68
67
|
self
|
69
68
|
end
|
70
69
|
|
@@ -79,10 +78,10 @@ module Mutant
|
|
79
78
|
def finish(mutation_result)
|
80
79
|
@last_mutation_result = mutation_result
|
81
80
|
|
82
|
-
|
81
|
+
mutation = mutation_result.mutation
|
82
|
+
@active.delete(mutation)
|
83
83
|
|
84
|
-
@
|
85
|
-
@aggregate[subject] << mutation_result
|
84
|
+
@aggregate[mutation.subject] << mutation_result
|
86
85
|
|
87
86
|
self
|
88
87
|
end
|
@@ -106,9 +105,9 @@ module Mutant
|
|
106
105
|
# @api private
|
107
106
|
#
|
108
107
|
def active_subjects
|
109
|
-
@
|
110
|
-
|
111
|
-
end.
|
108
|
+
@active.each_with_object(Set.new) do |mutation, subjects|
|
109
|
+
subjects << mutation.subject
|
110
|
+
end.sort_by(&:identification)
|
112
111
|
end
|
113
112
|
|
114
113
|
# Return current subject result
|