mutant 0.7.1 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -1
- data/Changelog.md +5 -0
- data/TODO +0 -8
- data/config/flay.yml +1 -1
- data/config/reek.yml +4 -1
- data/lib/mutant.rb +1 -1
- data/lib/mutant/actor/env.rb +8 -8
- data/lib/mutant/actor/mailbox.rb +16 -31
- data/lib/mutant/actor/receiver.rb +7 -9
- data/lib/mutant/actor/sender.rb +3 -3
- data/lib/mutant/line_trace.rb +34 -0
- data/lib/mutant/reporter/cli.rb +17 -0
- data/lib/mutant/reporter/cli/format.rb +16 -17
- data/lib/mutant/reporter/cli/printer.rb +64 -17
- data/lib/mutant/reporter/trace.rb +12 -0
- data/lib/mutant/result.rb +3 -3
- data/lib/mutant/runner.rb +2 -5
- data/lib/mutant/runner/worker.rb +4 -6
- data/lib/mutant/subject.rb +23 -11
- data/lib/mutant/subject/method/instance.rb +3 -38
- data/lib/mutant/subject/method/singleton.rb +1 -1
- data/lib/mutant/version.rb +1 -1
- data/mutant.gemspec +1 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/support/fake_actor.rb +17 -11
- data/spec/support/shared_context.rb +0 -2
- data/spec/unit/mutant/actor/env_spec.rb +5 -25
- data/spec/unit/mutant/actor/mailbox_spec.rb +29 -0
- data/spec/unit/mutant/actor/receiver_spec.rb +24 -28
- data/spec/unit/mutant/actor/sender_spec.rb +9 -9
- data/spec/unit/mutant/line_trace_spec.rb +38 -0
- data/spec/unit/mutant/reporter/cli_spec.rb +154 -157
- data/spec/unit/mutant/runner/master_spec.rb +11 -11
- data/spec/unit/mutant/runner/worker_spec.rb +2 -3
- data/spec/unit/mutant/runner_spec.rb +13 -10
- data/spec/unit/mutant/subject_spec.rb +17 -2
- metadata +51 -50
- data/lib/mutant/actor/actor.rb +0 -50
- data/spec/unit/mutant/actor/actor_spec.rb +0 -35
- data/spec/unit/mutant/mailbox_spec.rb +0 -33
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90851c1c4c4d7c0f23438bae72fe95f70a680514
|
4
|
+
data.tar.gz: 7ac31c28d9329ec976bfac638a48a8fe515e3604
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ab96c53e2d7ded947c58742c06bb5934b1b0f17437fefbe9e510d9ce25a7aea422d115aa420fc0538bd23260b2fd85c20d4aa25cb84e8f82362f08d8156f28c5
|
7
|
+
data.tar.gz: db2ace76cbabbb97d18a0a32cfc75f7ad3a014424bf4b3ae52b566f38bf47fe3ff8929edcaf31776390fc52bc9c5a2d42323c6be26fc8c617067179977edeb9a
|
data/.travis.yml
CHANGED
data/Changelog.md
CHANGED
data/TODO
CHANGED
@@ -1,23 +1,15 @@
|
|
1
1
|
Code:
|
2
2
|
* Test mutant with dynamically created zombie.
|
3
|
-
* Log all warnings through reporter, so remove random $stderr.puts calls
|
4
3
|
|
5
4
|
Mutations:
|
6
5
|
* Add true masgn mutations
|
7
|
-
* Add binary operator specific mutations (YAY, finally reached this point)
|
8
6
|
* Add some kind of a "do not touch me object" that raises on all messages.
|
9
7
|
It can be used to make sure each literal value is touched.
|
10
8
|
* Replace nil or add "do not touch me object" to literal mutations.
|
11
9
|
* Mutate options on Regexp literals
|
12
10
|
* Add mutations for dynamic regexp symbol and string literals
|
13
|
-
* Mutate Block catch "def foo(&block)" and block pass "foo(&block)"
|
14
|
-
* Binary operator mutations
|
15
11
|
* Add timeout to terminate infinite loops
|
16
12
|
|
17
|
-
Example of a negative mutation:
|
18
|
-
Mutations on local variables and arguments prefixed with an underscore would be emitted as
|
19
|
-
negative mutations that must be alive.
|
20
|
-
|
21
13
|
Loader:
|
22
14
|
* Make sure loader does not change visibility of injected mutants
|
23
15
|
|
data/config/flay.yml
CHANGED
data/config/reek.yml
CHANGED
@@ -37,6 +37,7 @@ FeatureEnvy:
|
|
37
37
|
- Mutant::Runner::Master#stop_worker
|
38
38
|
- Mutant::Runner::Worker#run_mutation
|
39
39
|
- Mutant::Runner::Worker#handle
|
40
|
+
- Mutant::Subject#source_lines
|
40
41
|
IrresponsibleModule:
|
41
42
|
enabled: true
|
42
43
|
exclude: []
|
@@ -136,9 +137,11 @@ UnusedParameters:
|
|
136
137
|
UtilityFunction:
|
137
138
|
enabled: true
|
138
139
|
exclude:
|
140
|
+
- Mutant::Actor::Env#new_mailbox
|
139
141
|
- Mutant::AST::Sexp#s
|
140
142
|
- Mutant::CLI#reporter
|
141
143
|
- Mutant::Integration::Rspec#parse_example
|
142
|
-
- Mutant::Meta::Example::Verification#format_mutation
|
144
|
+
- Mutant::Meta::Example::Verification#format_mutation
|
143
145
|
- Mutant::Reporter::CLI::Format::Progressive#new_buffer
|
146
|
+
- Mutant::Reporter::CLI::Printer::StatusProgressive#object # False positive calls super
|
144
147
|
max_helper_calls: 0
|
data/lib/mutant.rb
CHANGED
@@ -104,7 +104,6 @@ require 'mutant/actor'
|
|
104
104
|
require 'mutant/actor/receiver'
|
105
105
|
require 'mutant/actor/sender'
|
106
106
|
require 'mutant/actor/mailbox'
|
107
|
-
require 'mutant/actor/actor'
|
108
107
|
require 'mutant/actor/env'
|
109
108
|
require 'mutant/cache'
|
110
109
|
require 'mutant/delegator'
|
@@ -212,6 +211,7 @@ require 'mutant/reporter/cli'
|
|
212
211
|
require 'mutant/reporter/cli/printer'
|
213
212
|
require 'mutant/reporter/cli/tput'
|
214
213
|
require 'mutant/reporter/cli/format'
|
214
|
+
require 'mutant/line_trace'
|
215
215
|
require 'mutant/zombifier'
|
216
216
|
require 'mutant/zombifier/file'
|
217
217
|
|
data/lib/mutant/actor/env.rb
CHANGED
@@ -11,23 +11,23 @@ module Mutant
|
|
11
11
|
# @api private
|
12
12
|
#
|
13
13
|
def spawn
|
14
|
-
mailbox =
|
14
|
+
mailbox = new_mailbox
|
15
15
|
|
16
|
-
|
17
|
-
yield mailbox
|
16
|
+
thread_root.new do
|
17
|
+
yield mailbox
|
18
18
|
end
|
19
19
|
|
20
|
-
mailbox.sender
|
20
|
+
mailbox.sender
|
21
21
|
end
|
22
22
|
|
23
|
-
# Return
|
23
|
+
# Return new unbound mailbox
|
24
24
|
#
|
25
|
-
# @return [
|
25
|
+
# @return [Mailbox]
|
26
26
|
#
|
27
27
|
# @api private
|
28
28
|
#
|
29
|
-
def
|
30
|
-
Mailbox.new
|
29
|
+
def new_mailbox
|
30
|
+
Mailbox.new
|
31
31
|
end
|
32
32
|
|
33
33
|
end # Env
|
data/lib/mutant/actor/mailbox.rb
CHANGED
@@ -2,50 +2,35 @@ module Mutant
|
|
2
2
|
module Actor
|
3
3
|
# Unbound mailbox
|
4
4
|
class Mailbox
|
5
|
+
include Adamantium::Flat, Concord::Public.new(:receiver, :sender)
|
5
6
|
|
6
|
-
#
|
7
|
+
# Return new mailbox
|
7
8
|
#
|
8
|
-
# @return [
|
9
|
+
# @return [Mailbox]
|
9
10
|
#
|
10
11
|
# @api private
|
11
12
|
#
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
freeze
|
17
|
-
end
|
18
|
-
|
19
|
-
# Return receiver
|
20
|
-
#
|
21
|
-
# @return [Receiver]
|
22
|
-
#
|
23
|
-
# @api private
|
24
|
-
#
|
25
|
-
attr_reader :receiver
|
13
|
+
def self.new
|
14
|
+
mutex = Mutex.new
|
15
|
+
condition_variable = ConditionVariable.new
|
16
|
+
messages = []
|
26
17
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
# @return [Actor]
|
32
|
-
#
|
33
|
-
# @api private
|
34
|
-
#
|
35
|
-
def actor(thread)
|
36
|
-
Actor.new(thread, self)
|
18
|
+
super(
|
19
|
+
Receiver.new(condition_variable, mutex, messages),
|
20
|
+
Sender.new(condition_variable, mutex, messages)
|
21
|
+
)
|
37
22
|
end
|
38
23
|
|
39
|
-
# Return
|
24
|
+
# Return binding for RPC to other actors
|
40
25
|
#
|
41
|
-
# @param [
|
26
|
+
# @param [Actor::Sender] other
|
42
27
|
#
|
43
|
-
# @return [
|
28
|
+
# @return [Binding]
|
44
29
|
#
|
45
30
|
# @api private
|
46
31
|
#
|
47
|
-
def
|
48
|
-
|
32
|
+
def bind(other)
|
33
|
+
Binding.new(self, other)
|
49
34
|
end
|
50
35
|
|
51
36
|
end # Mailbox
|
@@ -2,7 +2,7 @@ module Mutant
|
|
2
2
|
module Actor
|
3
3
|
# Receiver side of an actor
|
4
4
|
class Receiver
|
5
|
-
include Concord.new(:mutex, :
|
5
|
+
include Adamantium::Flat, Concord.new(:condition_variable, :mutex, :messages)
|
6
6
|
|
7
7
|
# Receives a message, blocking
|
8
8
|
#
|
@@ -31,14 +31,12 @@ module Mutant
|
|
31
31
|
# @api private
|
32
32
|
#
|
33
33
|
def try_blocking_receive
|
34
|
-
mutex.
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
mailbox.shift.tap do
|
41
|
-
mutex.unlock
|
34
|
+
mutex.synchronize do
|
35
|
+
if messages.empty?
|
36
|
+
condition_variable.wait(mutex)
|
37
|
+
Undefined
|
38
|
+
else
|
39
|
+
messages.shift
|
42
40
|
end
|
43
41
|
end
|
44
42
|
end
|
data/lib/mutant/actor/sender.rb
CHANGED
@@ -3,7 +3,7 @@ module Mutant
|
|
3
3
|
|
4
4
|
# Sender for messages to acting thread
|
5
5
|
class Sender
|
6
|
-
include Concord.new(:
|
6
|
+
include Adamantium::Flat, Concord.new(:condition_variable, :mutex, :messages)
|
7
7
|
|
8
8
|
# Send a message to actor
|
9
9
|
#
|
@@ -15,8 +15,8 @@ module Mutant
|
|
15
15
|
#
|
16
16
|
def call(message)
|
17
17
|
mutex.synchronize do
|
18
|
-
|
19
|
-
|
18
|
+
messages << message
|
19
|
+
condition_variable.signal
|
20
20
|
end
|
21
21
|
|
22
22
|
self
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Mutant
|
2
|
+
# Line tracer
|
3
|
+
class LineTrace
|
4
|
+
include Adamantium::Flat, Concord.new(:contents)
|
5
|
+
|
6
|
+
private_class_method :new
|
7
|
+
|
8
|
+
# Test if trace coveres file at lineno
|
9
|
+
#
|
10
|
+
# @param [String] file
|
11
|
+
# @param [Fixnum] lineno
|
12
|
+
#
|
13
|
+
# @return [Boolean]
|
14
|
+
#
|
15
|
+
def cover?(file, lineno)
|
16
|
+
contents.fetch(file) { return false }.include?(lineno)
|
17
|
+
end
|
18
|
+
|
19
|
+
# Run block
|
20
|
+
#
|
21
|
+
# @return [Traces]
|
22
|
+
#
|
23
|
+
# @api private
|
24
|
+
#
|
25
|
+
def self.call(&block)
|
26
|
+
traces = Hash.new { |hash, file| hash[file] = Set.new }
|
27
|
+
TracePoint.trace(:return, :line) do |point|
|
28
|
+
traces[point.path] << point.lineno
|
29
|
+
end.tap(&block).disable
|
30
|
+
new(IceNine.deep_freeze(traces))
|
31
|
+
end
|
32
|
+
|
33
|
+
end # LineTrace
|
34
|
+
end # Mutant
|
data/lib/mutant/reporter/cli.rb
CHANGED
@@ -51,6 +51,23 @@ module Mutant
|
|
51
51
|
self
|
52
52
|
end
|
53
53
|
|
54
|
+
# Return report delay in seconds
|
55
|
+
#
|
56
|
+
# TODO: Move this to a callback registration
|
57
|
+
#
|
58
|
+
# Reporters other than CLI that might exist in futures
|
59
|
+
# may only the final report. So providing a noop callback
|
60
|
+
# registration makes more sense than. As only CLI reporters
|
61
|
+
# exist currently I do not really care right now.
|
62
|
+
#
|
63
|
+
# @return [Float]
|
64
|
+
#
|
65
|
+
# @api private
|
66
|
+
#
|
67
|
+
def delay
|
68
|
+
format.delay
|
69
|
+
end
|
70
|
+
|
54
71
|
# Report warning
|
55
72
|
#
|
56
73
|
# @param [String] message
|
@@ -25,6 +25,16 @@ module Mutant
|
|
25
25
|
#
|
26
26
|
abstract_method :progress
|
27
27
|
|
28
|
+
# Return report delay in seconds
|
29
|
+
#
|
30
|
+
# @return [Float]
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
#
|
34
|
+
def delay
|
35
|
+
self.class::REPORT_DELAY
|
36
|
+
end
|
37
|
+
|
28
38
|
# Output abstraction to decouple tty? from buffer
|
29
39
|
class Output
|
30
40
|
include Concord.new(:tty, :buffer)
|
@@ -67,17 +77,8 @@ module Mutant
|
|
67
77
|
# Format for progressive non rewindable output
|
68
78
|
class Progressive < self
|
69
79
|
|
70
|
-
|
71
|
-
|
72
|
-
# @return [undefined]
|
73
|
-
#
|
74
|
-
# @api private
|
75
|
-
#
|
76
|
-
def initialize(*)
|
77
|
-
@seen = Set.new
|
78
|
-
|
79
|
-
super
|
80
|
-
end
|
80
|
+
REPORT_FREQUENCY = 1.0
|
81
|
+
REPORT_DELAY = 1 / REPORT_FREQUENCY
|
81
82
|
|
82
83
|
# Return start representation
|
83
84
|
#
|
@@ -96,12 +97,7 @@ module Mutant
|
|
96
97
|
# @api private
|
97
98
|
#
|
98
99
|
def progress(status)
|
99
|
-
|
100
|
-
new = current.reject(&@seen.method(:include?))
|
101
|
-
@seen = current.to_set
|
102
|
-
new.map do |mutation_result|
|
103
|
-
format(Printer::MutationProgressResult, mutation_result)
|
104
|
-
end.join(EMPTY_STRING)
|
100
|
+
format(Printer::StatusProgressive, status)
|
105
101
|
end
|
106
102
|
|
107
103
|
private
|
@@ -124,6 +120,9 @@ module Mutant
|
|
124
120
|
|
125
121
|
BUFFER_FLAGS = 'a+'.freeze
|
126
122
|
|
123
|
+
REPORT_FREQUENCY = 20.0
|
124
|
+
REPORT_DELAY = 1 / REPORT_FREQUENCY
|
125
|
+
|
127
126
|
# Format start
|
128
127
|
#
|
129
128
|
# @param [Env] env
|
@@ -147,7 +147,7 @@ module Mutant
|
|
147
147
|
#
|
148
148
|
def run
|
149
149
|
visit(EnvProgress, object.env_result)
|
150
|
-
info('Active subjects:
|
150
|
+
info('Active subjects: %d', active_subject_results.length)
|
151
151
|
visit_collection(SubjectProgress, active_subject_results)
|
152
152
|
job_status
|
153
153
|
self
|
@@ -198,12 +198,12 @@ module Mutant
|
|
198
198
|
#
|
199
199
|
def run
|
200
200
|
info 'Mutant configuration:'
|
201
|
-
info 'Matcher:
|
202
|
-
info 'Integration:
|
203
|
-
info 'Expect Coverage:
|
204
|
-
info 'Jobs:
|
205
|
-
info 'Includes:
|
206
|
-
info 'Requires:
|
201
|
+
info 'Matcher: %s', object.matcher_config.inspect
|
202
|
+
info 'Integration: %s', object.integration.name
|
203
|
+
info 'Expect Coverage: %0.2f%%', object.expected_coverage.inspect
|
204
|
+
info 'Jobs: %d', object.jobs
|
205
|
+
info 'Includes: %s', object.includes.inspect
|
206
|
+
info 'Requires: %s', object.requires.inspect
|
207
207
|
self
|
208
208
|
end
|
209
209
|
|
@@ -232,16 +232,15 @@ module Mutant
|
|
232
232
|
#
|
233
233
|
def run
|
234
234
|
visit(Config, env.config)
|
235
|
-
info '
|
236
|
-
info '
|
237
|
-
info '
|
238
|
-
info '
|
239
|
-
info '
|
240
|
-
info '
|
241
|
-
info '
|
242
|
-
|
243
|
-
status '
|
244
|
-
status 'Expected: %0.2f%%', env.config.expected_coverage
|
235
|
+
info 'Subjects: %s', amount_subjects
|
236
|
+
info 'Mutations: %s', amount_mutations
|
237
|
+
info 'Kills: %s', amount_mutations_killed
|
238
|
+
info 'Alive: %s', amount_mutations_alive
|
239
|
+
info 'Runtime: %0.2fs', runtime
|
240
|
+
info 'Killtime: %0.2fs', killtime
|
241
|
+
info 'Overhead: %0.2f%%', overhead_percent
|
242
|
+
status 'Coverage: %0.2f%%', coverage_percent
|
243
|
+
status 'Expected: %0.2f%%', env.config.expected_coverage
|
245
244
|
self
|
246
245
|
end
|
247
246
|
|
@@ -342,6 +341,54 @@ module Mutant
|
|
342
341
|
|
343
342
|
end # MutationProgressResult
|
344
343
|
|
344
|
+
# Reporter for progressive output format on scheduler Status objects
|
345
|
+
class StatusProgressive < self
|
346
|
+
|
347
|
+
FORMAT = '(%02d/%02d) %3d%% - killtime: %0.02fs runtime: %0.02fs overhead: %0.02fs'.freeze
|
348
|
+
|
349
|
+
delegate(
|
350
|
+
:coverage,
|
351
|
+
:runtime,
|
352
|
+
:amount_mutations_killed,
|
353
|
+
:amount_mutations,
|
354
|
+
:amount_mutation_results,
|
355
|
+
:killtime,
|
356
|
+
:overhead
|
357
|
+
)
|
358
|
+
|
359
|
+
# Run printer
|
360
|
+
#
|
361
|
+
# @return [self]
|
362
|
+
#
|
363
|
+
# @api private
|
364
|
+
#
|
365
|
+
def run
|
366
|
+
status(
|
367
|
+
FORMAT,
|
368
|
+
amount_mutations_killed,
|
369
|
+
amount_mutations,
|
370
|
+
coverage * 100,
|
371
|
+
killtime,
|
372
|
+
runtime,
|
373
|
+
overhead
|
374
|
+
)
|
375
|
+
|
376
|
+
self
|
377
|
+
end
|
378
|
+
|
379
|
+
private
|
380
|
+
|
381
|
+
# Return object being printed
|
382
|
+
#
|
383
|
+
# @return [Result::Env]
|
384
|
+
#
|
385
|
+
# @api private
|
386
|
+
#
|
387
|
+
def object
|
388
|
+
super().env_result
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
345
392
|
# Reporter for subject progress
|
346
393
|
class SubjectProgress < self
|
347
394
|
|