mutant 0.10.25 → 0.10.26

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mutant.rb +10 -9
  3. data/lib/mutant/ast/find_metaclass_containing.rb +1 -1
  4. data/lib/mutant/ast/regexp.rb +17 -0
  5. data/lib/mutant/ast/regexp/transformer.rb +2 -2
  6. data/lib/mutant/ast/regexp/transformer/quantifier.rb +4 -2
  7. data/lib/mutant/bootstrap.rb +1 -1
  8. data/lib/mutant/cli/command.rb +4 -0
  9. data/lib/mutant/cli/command/environment/subject.rb +0 -4
  10. data/lib/mutant/cli/command/environment/test.rb +36 -0
  11. data/lib/mutant/cli/command/root.rb +1 -1
  12. data/lib/mutant/config.rb +1 -1
  13. data/lib/mutant/context.rb +1 -1
  14. data/lib/mutant/env.rb +2 -2
  15. data/lib/mutant/expression/method.rb +4 -4
  16. data/lib/mutant/expression/methods.rb +5 -4
  17. data/lib/mutant/integration.rb +8 -2
  18. data/lib/mutant/isolation/fork.rb +4 -11
  19. data/lib/mutant/matcher.rb +1 -1
  20. data/lib/mutant/matcher/config.rb +3 -2
  21. data/lib/mutant/matcher/method.rb +8 -6
  22. data/lib/mutant/matcher/method/instance.rb +6 -2
  23. data/lib/mutant/matcher/methods.rb +2 -4
  24. data/lib/mutant/meta/example.rb +1 -1
  25. data/lib/mutant/meta/example/verification.rb +1 -1
  26. data/lib/mutant/mutation.rb +1 -1
  27. data/lib/mutant/mutator.rb +8 -1
  28. data/lib/mutant/mutator/node/argument.rb +2 -2
  29. data/lib/mutant/mutator/node/literal/regex.rb +3 -17
  30. data/lib/mutant/mutator/node/named_value/variable_assignment.rb +3 -3
  31. data/lib/mutant/mutator/node/regexp/character_type.rb +1 -1
  32. data/lib/mutant/mutator/node/regexp/named_group.rb +39 -0
  33. data/lib/mutant/mutator/node/regexp/zero_or_more.rb +2 -2
  34. data/lib/mutant/mutator/node/regopt.rb +1 -1
  35. data/lib/mutant/mutator/node/send.rb +40 -6
  36. data/lib/mutant/parallel.rb +2 -2
  37. data/lib/mutant/parallel/driver.rb +1 -1
  38. data/lib/mutant/parallel/worker.rb +1 -1
  39. data/lib/mutant/parser.rb +1 -1
  40. data/lib/mutant/pipe.rb +1 -1
  41. data/lib/mutant/procto.rb +23 -0
  42. data/lib/mutant/reporter/cli/printer.rb +10 -4
  43. data/lib/mutant/reporter/cli/printer/env.rb +2 -2
  44. data/lib/mutant/reporter/cli/printer/env_progress.rb +2 -2
  45. data/lib/mutant/selector.rb +1 -1
  46. data/lib/mutant/subject.rb +1 -1
  47. data/lib/mutant/subject/method/instance.rb +5 -42
  48. data/lib/mutant/variable.rb +322 -0
  49. data/lib/mutant/version.rb +1 -1
  50. data/lib/mutant/world.rb +1 -1
  51. metadata +8 -158
@@ -3,7 +3,7 @@
3
3
  module Mutant
4
4
  # Subject of a mutation
5
5
  class Subject
6
- include AbstractType, Adamantium::Flat, Enumerable
6
+ include AbstractType, Adamantium, Enumerable
7
7
  include Anima.new(:context, :node)
8
8
 
9
9
  # Mutations for this subject
@@ -21,59 +21,22 @@ module Mutant
21
21
  class Memoized < self
22
22
  include AST::Sexp
23
23
 
24
- FREEZER_OPTION_VALUES = {
25
- Adamantium::Freezer::Deep => :deep,
26
- Adamantium::Freezer::Flat => :flat,
27
- Adamantium::Freezer::Noop => :noop
28
- }.freeze
29
-
30
- private_constant(*constants(false))
31
-
32
24
  # Prepare subject for mutation insertion
33
25
  #
34
26
  # @return [self]
35
27
  def prepare
36
- memory.delete(name)
28
+ scope
29
+ .instance_variable_get(:@memoized_methods)
30
+ .delete(name)
31
+
37
32
  super()
38
33
  end
39
34
 
40
35
  private
41
36
 
42
37
  def wrap_node(mutant)
43
- s(:begin, mutant, s(:send, nil, :memoize, s(:sym, name), *options))
38
+ s(:begin, mutant, s(:send, nil, :memoize, s(:sym, name)))
44
39
  end
45
-
46
- # The optional AST node for adamantium memoization options
47
- #
48
- # @return [Array(Parser::AST::Node), nil]
49
- def options
50
- # rubocop:disable Style/GuardClause
51
- if FREEZER_OPTION_VALUES.key?(freezer)
52
- [
53
- s(:kwargs,
54
- s(:pair,
55
- s(:sym, :freezer),
56
- s(:sym, FREEZER_OPTION_VALUES.fetch(freezer))))
57
- ]
58
- end
59
- # rubocop:enable Style/GuardClause
60
- end
61
-
62
- # The freezer used for memoization
63
- #
64
- # @return [Object]
65
- def freezer
66
- memory.fetch(name).instance_variable_get(:@freezer)
67
- end
68
- memoize :freezer, freezer: :noop
69
-
70
- # The memory used for memoization
71
- #
72
- # @return [ThreadSafe::Cache]
73
- def memory
74
- scope.__send__(:memoized_methods).instance_variable_get(:@memory)
75
- end
76
-
77
40
  end # Memoized
78
41
  end # Instance
79
42
  end # Method
@@ -0,0 +1,322 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mutant
4
+ # Lightweight concurrency variables
5
+ #
6
+ # These are inspired by Haskells MVar and IVar types.
7
+ class Variable
8
+ EMPTY = Class.new do
9
+ const_set(:INSPECT, 'Variable::EMPTY')
10
+ end.new.freeze
11
+
12
+ TIMEOUT = Class.new do
13
+ const_set(:INSPECT, 'Variable::TIMEOUT')
14
+ end.new.freeze
15
+
16
+ # Result of operation that may time out
17
+ class Result
18
+ include Equalizer.new(:value)
19
+ attr_reader :value
20
+
21
+ # Initialize result
22
+ #
23
+ # @return [undefined]
24
+ def initialize(value)
25
+ @value = value
26
+ freeze
27
+ end
28
+
29
+ # Test if take resulted in a timeout
30
+ #
31
+ # @return [Boolean]
32
+ #
33
+ # @api private
34
+ def timeout?
35
+ instance_of?(Timeout)
36
+ end
37
+
38
+ # Instance returned on timeouts
39
+ class Timeout < self
40
+ INSTANCE = new(nil)
41
+
42
+ # Construct new object
43
+ #
44
+ # @return [Timeout]
45
+ def self.new
46
+ INSTANCE
47
+ end
48
+ end # Timeout
49
+
50
+ # Instance returned without timeouts
51
+ class Value < self
52
+ end # Value
53
+ end # Result
54
+
55
+ private_constant(*constants(false))
56
+
57
+ module Timer
58
+ # Monotonic elapsed time of block execution
59
+ #
60
+ # @return [Float]
61
+ def self.elapsed
62
+ start = now
63
+ yield
64
+ now - start
65
+ end
66
+
67
+ # The now monotonic time
68
+ #
69
+ # @return [Float]
70
+ def self.now
71
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
72
+ end
73
+ private_class_method :now
74
+ end # Timer
75
+
76
+ # Initialize object
77
+ #
78
+ # @param [Object] value
79
+ # the initial value
80
+ #
81
+ # @return [undefined]
82
+ def initialize(condition_variable:, mutex:, value: EMPTY)
83
+ @full = condition_variable.new
84
+ @mutex = mutex.new
85
+ @value = value
86
+ end
87
+
88
+ # Take value, block on empty
89
+ #
90
+ # @return [Object]
91
+ def take
92
+ synchronize do
93
+ wait_full
94
+ perform_take
95
+ end
96
+ end
97
+
98
+ # Take value, with timeout
99
+ #
100
+ # @param [Float] Timeout
101
+ #
102
+ # @return [Result::Timeout]
103
+ # in case take resulted in a timeout
104
+ #
105
+ # @return [Result::Value]
106
+ # in case take resulted in a value
107
+ def take_timeout(timeout)
108
+ synchronize do
109
+ if wait_timeout(@full, timeout, &method(:full?))
110
+ Result::Timeout.new
111
+ else
112
+ Result::Value.new(perform_take)
113
+ end
114
+ end
115
+ end
116
+
117
+ # Read value, block on empty
118
+ #
119
+ # @return [Object]
120
+ # the variable value
121
+ def read
122
+ synchronize do
123
+ wait_full
124
+ @value
125
+ end
126
+ end
127
+
128
+ # Try put value into the variable, non blocking
129
+ #
130
+ # @param [Object] value
131
+ #
132
+ # @return [self]
133
+ def try_put(value)
134
+ synchronize do
135
+ perform_put(value) if empty?
136
+ end
137
+
138
+ self
139
+ end
140
+
141
+ # Execute block with value, blocking
142
+ #
143
+ # @yield [Object]
144
+ #
145
+ # @return [Object]
146
+ # the blocks return value
147
+ def with
148
+ synchronize do
149
+ wait_full
150
+ yield @value
151
+ end
152
+ end
153
+
154
+ private
155
+
156
+ # Perform the put
157
+ #
158
+ # @param [Object] value
159
+ def perform_put(value)
160
+ (@value = value).tap { @full.signal }
161
+ end
162
+
163
+ # Execute block under mutex
164
+ #
165
+ # @return [self]
166
+ def synchronize(&block)
167
+ @mutex.synchronize(&block)
168
+ end
169
+
170
+ # Wait for block predicate
171
+ #
172
+ # @param [ConditionVariable] event
173
+ #
174
+ # @return [undefined]
175
+ def wait(event)
176
+ event.wait(@mutex) until yield
177
+ end
178
+
179
+ # Wait with timeout for block predicate
180
+ #
181
+ # @param [ConditionVariable] event
182
+ #
183
+ # @return [Boolean]
184
+ # if wait was terminated due a timeout
185
+ #
186
+ # @return [undefined]
187
+ # otherwise
188
+ def wait_timeout(event, timeout)
189
+ loop do
190
+ break true if timeout <= 0
191
+ break if yield
192
+ timeout -= Timer.elapsed { event.wait(@mutex, timeout) }
193
+ end
194
+ end
195
+
196
+ # Wait till mvar is full
197
+ #
198
+ # @return [undefined]
199
+ def wait_full
200
+ wait(@full, &method(:full?))
201
+ end
202
+
203
+ # Test if state is full
204
+ #
205
+ # @return [Boolean]
206
+ def full?
207
+ !empty?
208
+ end
209
+
210
+ # Test if state is empty
211
+ #
212
+ # @return [Boolean]
213
+ def empty?
214
+ @value.equal?(EMPTY)
215
+ end
216
+
217
+ # Shared variable that can be written at most once
218
+ #
219
+ # ignore :reek:InstanceVariableAssumption
220
+ class IVar < self
221
+
222
+ # Exception raised on ivar errors
223
+ class Error < RuntimeError; end
224
+
225
+ # Put value, raises if already full
226
+ #
227
+ # @param [Object] value
228
+ #
229
+ # @return [self]
230
+ #
231
+ # @raise Error
232
+ # if already full
233
+ def put(value)
234
+ synchronize do
235
+ fail Error, 'is immutable' if full?
236
+ perform_put(value)
237
+ end
238
+
239
+ self
240
+ end
241
+
242
+ # Populate and return value, use block to compute value if empty
243
+ #
244
+ # The block is guaranteed to be executed at max once.
245
+ #
246
+ # Subsequent reads are guaranteed to return the block value.
247
+ #
248
+ # @return [Object]
249
+ def populate_with
250
+ return @value if full?
251
+
252
+ synchronize do
253
+ perform_put(yield) if empty?
254
+ end
255
+
256
+ @value
257
+ end
258
+
259
+ private
260
+
261
+ # Perform take operation
262
+ #
263
+ # @return [Object]
264
+ def perform_take
265
+ @value
266
+ end
267
+ end # IVar
268
+
269
+ # Shared variable that can be written multiple times
270
+ #
271
+ # ignore :reek:InstanceVariableAssumption
272
+ class MVar < self
273
+
274
+ # Initialize object
275
+ #
276
+ # @param [Object] value
277
+ # the initial value
278
+ #
279
+ # @return [undefined]
280
+ def initialize(condition_variable:, mutex:, value: EMPTY)
281
+ super
282
+ @empty = condition_variable.new
283
+ end
284
+
285
+ # Put value, block on full
286
+ #
287
+ # @param [Object] value
288
+ #
289
+ # @return [self]
290
+ def put(value)
291
+ synchronize do
292
+ wait(@empty, &method(:empty?))
293
+ perform_put(value)
294
+ end
295
+
296
+ self
297
+ end
298
+
299
+ # Modify value, blocks if empty
300
+ #
301
+ # @return [Object]
302
+ def modify
303
+ synchronize do
304
+ wait_full
305
+ perform_put(yield(@value))
306
+ end
307
+ end
308
+
309
+ private
310
+
311
+ # Empty the variable
312
+ #
313
+ # @return [Object]
314
+ def perform_take
315
+ @value.tap do
316
+ @value = EMPTY
317
+ @empty.signal
318
+ end
319
+ end
320
+ end # MVar
321
+ end # Variable
322
+ end # Mutant
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Mutant
4
4
  # Current mutant version
5
- VERSION = '0.10.25'
5
+ VERSION = '0.10.26'
6
6
  end # Mutant
@@ -3,7 +3,7 @@
3
3
  module Mutant
4
4
  # The outer world IO objects mutant does interact with
5
5
  class World
6
- include Adamantium::Flat, Anima.new(
6
+ include Adamantium, Anima.new(
7
7
  :condition_variable,
8
8
  :gem,
9
9
  :gem_method,
metadata CHANGED
@@ -1,85 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mutant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.25
4
+ version: 0.10.26
5
5
  platform: ruby
6
6
  authors:
7
7
  - Markus Schirp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-01-03 00:00:00.000000000 Z
11
+ date: 2021-01-16 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: abstract_type
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: 0.0.7
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: 0.0.7
27
- - !ruby/object:Gem::Dependency
28
- name: adamantium
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: 0.2.0
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: 0.2.0
41
- - !ruby/object:Gem::Dependency
42
- name: anima
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: 0.3.1
48
- type: :runtime
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: 0.3.1
55
- - !ruby/object:Gem::Dependency
56
- name: ast
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: '2.2'
62
- type: :runtime
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: '2.2'
69
- - !ruby/object:Gem::Dependency
70
- name: concord
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: 0.1.5
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - "~>"
81
- - !ruby/object:Gem::Version
82
- version: 0.1.5
83
13
  - !ruby/object:Gem::Dependency
84
14
  name: diff-lcs
85
15
  requirement: !ruby/object:Gem::Requirement
@@ -94,62 +24,6 @@ dependencies:
94
24
  - - "~>"
95
25
  - !ruby/object:Gem::Version
96
26
  version: '1.3'
97
- - !ruby/object:Gem::Dependency
98
- name: equalizer
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: 0.0.9
104
- type: :runtime
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: 0.0.9
111
- - !ruby/object:Gem::Dependency
112
- name: ice_nine
113
- requirement: !ruby/object:Gem::Requirement
114
- requirements:
115
- - - "~>"
116
- - !ruby/object:Gem::Version
117
- version: 0.11.1
118
- type: :runtime
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- requirements:
122
- - - "~>"
123
- - !ruby/object:Gem::Version
124
- version: 0.11.1
125
- - !ruby/object:Gem::Dependency
126
- name: memoizable
127
- requirement: !ruby/object:Gem::Requirement
128
- requirements:
129
- - - "~>"
130
- - !ruby/object:Gem::Version
131
- version: 0.4.2
132
- type: :runtime
133
- prerelease: false
134
- version_requirements: !ruby/object:Gem::Requirement
135
- requirements:
136
- - - "~>"
137
- - !ruby/object:Gem::Version
138
- version: 0.4.2
139
- - !ruby/object:Gem::Dependency
140
- name: mprelude
141
- requirement: !ruby/object:Gem::Requirement
142
- requirements:
143
- - - "~>"
144
- - !ruby/object:Gem::Version
145
- version: 0.1.0
146
- type: :runtime
147
- prerelease: false
148
- version_requirements: !ruby/object:Gem::Requirement
149
- requirements:
150
- - - "~>"
151
- - !ruby/object:Gem::Version
152
- version: 0.1.0
153
27
  - !ruby/object:Gem::Dependency
154
28
  name: parser
155
29
  requirement: !ruby/object:Gem::Requirement
@@ -164,20 +38,6 @@ dependencies:
164
38
  - - "~>"
165
39
  - !ruby/object:Gem::Version
166
40
  version: 3.0.0
167
- - !ruby/object:Gem::Dependency
168
- name: procto
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - "~>"
172
- - !ruby/object:Gem::Version
173
- version: 0.0.2
174
- type: :runtime
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - "~>"
179
- - !ruby/object:Gem::Version
180
- version: 0.0.2
181
41
  - !ruby/object:Gem::Dependency
182
42
  name: regexp_parser
183
43
  requirement: !ruby/object:Gem::Requirement
@@ -204,28 +64,14 @@ dependencies:
204
64
  requirements:
205
65
  - - "~>"
206
66
  - !ruby/object:Gem::Version
207
- version: 0.5.6
208
- type: :runtime
209
- prerelease: false
210
- version_requirements: !ruby/object:Gem::Requirement
211
- requirements:
212
- - - "~>"
213
- - !ruby/object:Gem::Version
214
- version: 0.5.6
215
- - !ruby/object:Gem::Dependency
216
- name: variable
217
- requirement: !ruby/object:Gem::Requirement
218
- requirements:
219
- - - "~>"
220
- - !ruby/object:Gem::Version
221
- version: 0.0.1
67
+ version: 0.6.0
222
68
  type: :runtime
223
69
  prerelease: false
224
70
  version_requirements: !ruby/object:Gem::Requirement
225
71
  requirements:
226
72
  - - "~>"
227
73
  - !ruby/object:Gem::Version
228
- version: 0.0.1
74
+ version: 0.6.0
229
75
  - !ruby/object:Gem::Dependency
230
76
  name: parallel
231
77
  requirement: !ruby/object:Gem::Requirement
@@ -337,6 +183,7 @@ files:
337
183
  - lib/mutant/cli/command/environment/run.rb
338
184
  - lib/mutant/cli/command/environment/show.rb
339
185
  - lib/mutant/cli/command/environment/subject.rb
186
+ - lib/mutant/cli/command/environment/test.rb
340
187
  - lib/mutant/cli/command/root.rb
341
188
  - lib/mutant/cli/command/subscription.rb
342
189
  - lib/mutant/config.rb
@@ -428,6 +275,7 @@ files:
428
275
  - lib/mutant/mutator/node/regexp/character_type.rb
429
276
  - lib/mutant/mutator/node/regexp/end_of_line_anchor.rb
430
277
  - lib/mutant/mutator/node/regexp/end_of_string_or_before_end_of_line_anchor.rb
278
+ - lib/mutant/mutator/node/regexp/named_group.rb
431
279
  - lib/mutant/mutator/node/regexp/zero_or_more.rb
432
280
  - lib/mutant/mutator/node/regopt.rb
433
281
  - lib/mutant/mutator/node/resbody.rb
@@ -452,6 +300,7 @@ files:
452
300
  - lib/mutant/parallel/worker.rb
453
301
  - lib/mutant/parser.rb
454
302
  - lib/mutant/pipe.rb
303
+ - lib/mutant/procto.rb
455
304
  - lib/mutant/range.rb
456
305
  - lib/mutant/registry.rb
457
306
  - lib/mutant/reporter.rb
@@ -489,6 +338,7 @@ files:
489
338
  - lib/mutant/timer.rb
490
339
  - lib/mutant/transform.rb
491
340
  - lib/mutant/util.rb
341
+ - lib/mutant/variable.rb
492
342
  - lib/mutant/version.rb
493
343
  - lib/mutant/world.rb
494
344
  - lib/mutant/zombifier.rb