mutant 0.7.1 → 0.7.2

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -1
  3. data/Changelog.md +5 -0
  4. data/TODO +0 -8
  5. data/config/flay.yml +1 -1
  6. data/config/reek.yml +4 -1
  7. data/lib/mutant.rb +1 -1
  8. data/lib/mutant/actor/env.rb +8 -8
  9. data/lib/mutant/actor/mailbox.rb +16 -31
  10. data/lib/mutant/actor/receiver.rb +7 -9
  11. data/lib/mutant/actor/sender.rb +3 -3
  12. data/lib/mutant/line_trace.rb +34 -0
  13. data/lib/mutant/reporter/cli.rb +17 -0
  14. data/lib/mutant/reporter/cli/format.rb +16 -17
  15. data/lib/mutant/reporter/cli/printer.rb +64 -17
  16. data/lib/mutant/reporter/trace.rb +12 -0
  17. data/lib/mutant/result.rb +3 -3
  18. data/lib/mutant/runner.rb +2 -5
  19. data/lib/mutant/runner/worker.rb +4 -6
  20. data/lib/mutant/subject.rb +23 -11
  21. data/lib/mutant/subject/method/instance.rb +3 -38
  22. data/lib/mutant/subject/method/singleton.rb +1 -1
  23. data/lib/mutant/version.rb +1 -1
  24. data/mutant.gemspec +1 -1
  25. data/spec/spec_helper.rb +2 -0
  26. data/spec/support/fake_actor.rb +17 -11
  27. data/spec/support/shared_context.rb +0 -2
  28. data/spec/unit/mutant/actor/env_spec.rb +5 -25
  29. data/spec/unit/mutant/actor/mailbox_spec.rb +29 -0
  30. data/spec/unit/mutant/actor/receiver_spec.rb +24 -28
  31. data/spec/unit/mutant/actor/sender_spec.rb +9 -9
  32. data/spec/unit/mutant/line_trace_spec.rb +38 -0
  33. data/spec/unit/mutant/reporter/cli_spec.rb +154 -157
  34. data/spec/unit/mutant/runner/master_spec.rb +11 -11
  35. data/spec/unit/mutant/runner/worker_spec.rb +2 -3
  36. data/spec/unit/mutant/runner_spec.rb +13 -10
  37. data/spec/unit/mutant/subject_spec.rb +17 -2
  38. metadata +51 -50
  39. data/lib/mutant/actor/actor.rb +0 -50
  40. data/spec/unit/mutant/actor/actor_spec.rb +0 -35
  41. data/spec/unit/mutant/mailbox_spec.rb +0 -33
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 607569850361ac4088176c89f75ac7f7d732d8f0
4
- data.tar.gz: 3247e38171198bf00c53341447881cb76fa44a3f
3
+ metadata.gz: 90851c1c4c4d7c0f23438bae72fe95f70a680514
4
+ data.tar.gz: 7ac31c28d9329ec976bfac638a48a8fe515e3604
5
5
  SHA512:
6
- metadata.gz: 888a9f29aa202635ece333e17c514ca52c7a28660e0ab8cd7f4397f4f108be3a8d91477812ad48ae970f2808b1516de084f44ff02f743b21174ad2504fb4cdae
7
- data.tar.gz: 5e3faa4096046383aa51274b6f201fb3f1eb416d7f8ca8049505fcf823fd994f051c34dd159256a6926e56401f5270d859b0bad0f13b645101442bfff5e80ef6
6
+ metadata.gz: ab96c53e2d7ded947c58742c06bb5934b1b0f17437fefbe9e510d9ce25a7aea422d115aa420fc0538bd23260b2fd85c20d4aa25cb84e8f82362f08d8156f28c5
7
+ data.tar.gz: db2ace76cbabbb97d18a0a32cfc75f7ad3a014424bf4b3ae52b566f38bf47fe3ff8929edcaf31776390fc52bc9c5a2d42323c6be26fc8c617067179977edeb9a
data/.travis.yml CHANGED
@@ -3,7 +3,6 @@ script: "bundle exec rake ci"
3
3
  env:
4
4
  - TRAVIS=true
5
5
  rvm:
6
- - 1.9.3
7
6
  - 2.0.0
8
7
  - 2.1.4
9
8
  - rbx-2
data/Changelog.md CHANGED
@@ -1,3 +1,8 @@
1
+ # v0.7.2 2014-12-08
2
+
3
+ * Fix synthetic race conditon in actor implementation
4
+ * Fix progressive reporter slowdown
5
+
1
6
  # v0.7.1 2014-12-04
2
7
 
3
8
  * Fix invalid dependencies on rspec for mutant-rspec
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
@@ -1,3 +1,3 @@
1
1
  ---
2
2
  threshold: 18
3
- total_score: 1141
3
+ total_score: 1200
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 # False positive, its a utility
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
 
@@ -11,23 +11,23 @@ module Mutant
11
11
  # @api private
12
12
  #
13
13
  def spawn
14
- mailbox = Mailbox.new
14
+ mailbox = new_mailbox
15
15
 
16
- thread = thread_root.new do
17
- yield mailbox.actor(thread_root.current)
16
+ thread_root.new do
17
+ yield mailbox
18
18
  end
19
19
 
20
- mailbox.sender(thread)
20
+ mailbox.sender
21
21
  end
22
22
 
23
- # Return an private actor for current thread
23
+ # Return new unbound mailbox
24
24
  #
25
- # @return [Actor::Private]
25
+ # @return [Mailbox]
26
26
  #
27
27
  # @api private
28
28
  #
29
- def current
30
- Mailbox.new.actor(thread_root.current)
29
+ def new_mailbox
30
+ Mailbox.new
31
31
  end
32
32
 
33
33
  end # Env
@@ -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
- # Initialize new unbound mailbox
7
+ # Return new mailbox
7
8
  #
8
- # @return [undefined]
9
+ # @return [Mailbox]
9
10
  #
10
11
  # @api private
11
12
  #
12
- def initialize
13
- @mutex = Mutex.new
14
- @messages = []
15
- @receiver = Receiver.new(@mutex, @messages)
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
- # Return actor that is able to read mailbox
28
- #
29
- # @param [Thread] thread
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 sender to mailbox
24
+ # Return binding for RPC to other actors
40
25
  #
41
- # @param [Thread] thread
26
+ # @param [Actor::Sender] other
42
27
  #
43
- # @return [Sender]
28
+ # @return [Binding]
44
29
  #
45
30
  # @api private
46
31
  #
47
- def sender(thread)
48
- Sender.new(thread, @mutex, @messages)
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, :mailbox)
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.lock
35
- if mailbox.empty?
36
- mutex.unlock
37
- Thread.stop
38
- Undefined
39
- else
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
@@ -3,7 +3,7 @@ module Mutant
3
3
 
4
4
  # Sender for messages to acting thread
5
5
  class Sender
6
- include Concord.new(:thread, :mutex, :mailbox)
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
- mailbox << message
19
- thread.run
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
@@ -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
- # Initialize object
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
- current = status.env_result.subject_results.flat_map(&:mutation_results)
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: %d', active_subject_results.length)
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: %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
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 'Available Subjects: %s', amount_subjects
236
- info 'Subjects: %s', amount_subjects
237
- info 'Mutations: %s', amount_mutations
238
- info 'Kills: %s', amount_mutations_killed
239
- info 'Alive: %s', amount_mutations_alive
240
- info 'Runtime: %0.2fs', runtime
241
- info 'Killtime: %0.2fs', killtime
242
- info 'Overhead: %0.2f%%', overhead_percent
243
- status 'Coverage: %0.2f%%', coverage_percent
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