minitest-proptest 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 61aa3a3421a7b1996cf35540600199e11d18bbf5959d96866f994be97f372bcf
4
- data.tar.gz: f89adae15e67f595c56f274d034b18e3e325fe097865ef60f42a7d49f7509214
3
+ metadata.gz: 236dabad0376379b518d9c29fc12f1bca0a17343c9dc85c6ff19ef94419698e8
4
+ data.tar.gz: dbe3075e50971bac885e3fcc6d3c607c9edb4a9e5bac4cc9dc1863a874ac2d5a
5
5
  SHA512:
6
- metadata.gz: 6c114584acb4f0d59d93958c65e665a5acde52dce3083f1a1343e8cc85962ec11f4e8e582821bf86002cb2e02cfe45d255fe653450944fdc573112168a734520
7
- data.tar.gz: 4f23345243cb106aa1fca9e4d9a4c87c6c20e22407e2564990de246cb81c95f96a2e8138a3991121ab24a2b2bfa9bf5066a7cdc3b639f0880d6e1170bd214652
6
+ metadata.gz: 70f655e9358ce5e198b5489e94a8cdb32d0a58b0d88393482f7faf8e911ab81a50bdc5514add06cb168f13a2c687a825725e00e59c0497937bd076ba8279bc91
7
+ data.tar.gz: 9dde2177e0f6a9458f1226abd43c5bd1b7048c3c69c6f746043fb02a4c5e9de1f5e8082bad699001f238b478528da350a63ede6d84b6058f011f9d6960217c88
@@ -98,7 +98,11 @@ module Minitest
98
98
  def shrink_candidates
99
99
  fs = @type_parameters.map { |x| x.method(:shrink_function) }
100
100
  os = score
101
- candidates = shrink_function(*fs, value)
101
+ # Ensure that the end of the shrink attempt will contain the original
102
+ # value. This is necessary to guarantee that the shrink process
103
+ # produces at least one failure for the purpose of capturing variable
104
+ # assignment.
105
+ candidates = shrink_function(*fs, value) + [value]
102
106
  candidates
103
107
  .map { |c| [force(c).score, c] }
104
108
  .reject { |(s, _)| s > os }
@@ -287,47 +287,27 @@ module Minitest
287
287
 
288
288
  generator_for(Int8) do
289
289
  r = sized(0xff)
290
- (r & 0x80).zero? ? r : -(((r & 0x7f) - 1) ^ 0x7f)
291
- end.with_shrink_function do |i|
292
- j = (i & 0x80).zero? ? i : -(((i & 0x7f) - 1) ^ 0x7f)
293
- integral_shrink.call(j)
294
- end
290
+ (r & 0x80).zero? ? r : -((r ^ 0x7f) - 0x7f)
291
+ end.with_shrink_function(&integral_shrink)
295
292
 
296
293
  generator_for(Int16) do
297
294
  r = sized(0xffff)
298
- (r & 0x8000).zero? ? r : -(((r & 0x7fff) - 1) ^ 0x7fff)
299
- end.with_shrink_function do |i|
300
- j = (i & 0x8000).zero? ? i : -(((i & 0x7fff) - 1) ^ 0x7fff)
301
- integral_shrink.call(j)
302
- end
295
+ (r & 0x8000).zero? ? r : -((r ^ 0x7fff) - 0x7fff)
296
+ end.with_shrink_function(&integral_shrink)
303
297
 
304
298
  generator_for(Int32) do
305
299
  r = sized(0xffffffff)
306
- (r & 0x80000000).zero? ? r : -(((r & 0x7fffffff) - 1) ^ 0x7fffffff)
307
- end.with_shrink_function do |i|
308
- j = if (i & 0x80000000).zero?
309
- i
310
- else
311
- -(((i & 0x7fffffff) - 1) ^ 0x7fffffff)
312
- end
313
- integral_shrink.call(j)
314
- end
300
+ (r & 0x80000000).zero? ? r : -((r ^ 0x7fffffff) - 0x7fffffff)
301
+ end.with_shrink_function(&integral_shrink)
315
302
 
316
303
  generator_for(Int64) do
317
304
  r = sized(0xffffffffffffffff)
318
305
  if (r & 0x8000000000000000).zero?
319
306
  r
320
307
  else
321
- -(((r & 0x7fffffffffffffff) - 1) ^ 0x7fffffffffffffff)
308
+ -((r ^ 0x7fffffffffffffff) - 0x7fffffffffffffff)
322
309
  end
323
- end.with_shrink_function do |i|
324
- j = if (i & 0x8000000000000000).zero?
325
- i
326
- else
327
- -(((i & 0x7fffffffffffffff) - 1) ^ 0x7fffffffffffffff)
328
- end
329
- integral_shrink.call(j)
330
- end
310
+ end.with_shrink_function(&integral_shrink)
331
311
 
332
312
  generator_for(UInt8) do
333
313
  sized(0xff)
@@ -471,6 +451,15 @@ module Minitest
471
451
  end.with_score_function do |_|
472
452
  1
473
453
  end
454
+
455
+ generator_for(Time) do
456
+ r = sized(0xffffffff)
457
+ Time.at((r & 0x80000000).zero? ? r : -((r ^ 0x7fffffff) - 0x7fffffff))
458
+ end.with_shrink_function do |t|
459
+ integral_shrink.call(t.to_i).map(&Time.method(:at))
460
+ end.with_score_function do |t|
461
+ t.to_i.abs
462
+ end
474
463
  end
475
464
  end
476
465
  end
@@ -7,6 +7,8 @@ module Minitest
7
7
  require 'minitest/assertions'
8
8
  include Minitest::Assertions
9
9
 
10
+ class InvalidProperty < StandardError; end
11
+
10
12
  attr_reader :calls, :result, :status, :trivial
11
13
 
12
14
  attr_accessor :assertions
@@ -47,7 +49,6 @@ module Minitest
47
49
  @max_shrinks = max_shrinks
48
50
  @status = Status.unknown
49
51
  @trivial = false
50
- @valid_test_case = true
51
52
  @result = nil
52
53
  @exception = nil
53
54
  @calls = 0
@@ -126,40 +127,35 @@ module Minitest
126
127
  end
127
128
 
128
129
  def where(&b)
129
- @valid_test_case &= b.call
130
+ raise InvalidProperty unless b.call
130
131
  end
131
132
 
132
133
  def iterate!
133
134
  while continue_iterate? && @result.nil? && @valid_test_cases <= @max_success
134
- @valid_test_case = true
135
135
  @generated = []
136
136
  @generator = ::Minitest::Proptest::Gen.new(@random)
137
137
  @calls += 1
138
138
 
139
- success = begin
140
- instance_eval(&@test_proc)
141
- rescue Minitest::Assertion
142
- if @valid_test_case
143
- @result = @generated
144
- @status = Status.interesting
145
- end
146
- rescue => e
147
- raise e if @valid_test_case
148
- end
149
- if @valid_test_case && success
150
- @status = Status.valid if @status.unknown?
151
- @valid_test_cases += 1
152
- elsif @valid_test_case
139
+ begin
140
+ if instance_eval(&@test_proc)
141
+ @status = Status.valid if @status.unknown?
142
+ @valid_test_cases += 1
143
+ else
144
+ @result = @generated
145
+ @status = Status.interesting
146
+ end
147
+ rescue Minitest::Assertion
153
148
  @result = @generated
154
149
  @status = Status.interesting
150
+ rescue InvalidProperty
151
+ rescue => e
152
+ @status = Status.invalid
153
+ @exception = e
155
154
  end
156
155
 
157
156
  @status = Status.exhausted if @calls >= @max_success * (@max_discard_ratio + 1)
158
157
  @trivial = true if @generated.empty?
159
158
  end
160
- rescue => e
161
- @status = Status.invalid
162
- @exception = e
163
159
  end
164
160
 
165
161
  def rerun!
@@ -181,22 +177,22 @@ module Minitest
181
177
  end
182
178
 
183
179
  @generator = ::Minitest::Proptest::Gen.new(@random)
184
- success = begin
185
- instance_eval(&@test_proc)
186
- rescue Minitest::Assertion
187
- !@valid_test_case
188
- rescue => e
189
- if @valid_test_case
190
- @status = Status.invalid
191
- @exception = e
192
- false
193
- end
194
- end
195
- if success || !@valid_test_case
196
- @generated = []
197
- elsif @valid_test_case
180
+ begin
181
+ if instance_eval(&@test_proc)
182
+ @generated = []
183
+ else
184
+ @result = @generated
185
+ @status = Status.interesting
186
+ end
187
+ rescue Minitest::Assertion
198
188
  @result = @generated
199
189
  @status = Status.interesting
190
+ rescue InvalidProperty
191
+ @generated = []
192
+ rescue => e
193
+ @result = @generated
194
+ @status = Status.invalid
195
+ @exception = e
200
196
  end
201
197
 
202
198
  # Clean up after we're done
@@ -215,6 +211,12 @@ module Minitest
215
211
  candidates = @generated.map(&:shrink_candidates)
216
212
  old_arbitrary = @arbitrary
217
213
 
214
+ # Using a TracePoint to determine variable assignments at the time of
215
+ # the failure only occurs within shrink! - this is a deliberate decision
216
+ # which eliminates all time lost in iterate! to optimize for the success
217
+ # case. The tradeoff is that if all shrinking fails, one additional
218
+ # cycle (with the values which produced the original failure) will be
219
+ # required.
218
220
  local_variables = {}
219
221
  tracepoint = TracePoint.new(:b_return) do |trace|
220
222
  if trace.path == @filename && trace.method_id.to_s == @methodname
@@ -249,27 +251,28 @@ module Minitest
249
251
  @valid_test_case = true
250
252
 
251
253
  @generator = ::Minitest::Proptest::Gen.new(@random)
252
- if to_test[run[:run]].map(&:first).reduce(&:+) < best_score
253
- success = begin
254
- tracepoint.enable
255
- instance_eval(&@test_proc)
256
- rescue Minitest::Assertion
257
- false
258
- rescue => e
259
- next unless @valid_test_case
260
-
261
- @status = Status.invalid
262
- @excption = e
263
- break
264
- ensure
265
- tracepoint.disable
266
- end
267
-
268
- if !success && @valid_test_case
269
- # The first hit is guaranteed to be the best scoring since the
270
- # shrink candidates are pre-sorted.
254
+ if to_test[run[:run]].map(&:first).reduce(&:+) <= best_score
255
+ begin
256
+ tracepoint.enable
257
+ unless instance_eval(&@test_proc)
258
+ # The first hit is guaranteed to be the best scoring since the
259
+ # shrink candidates are pre-sorted.
260
+ best_generated = @generated
261
+ break
262
+ end
263
+ rescue Minitest::Assertion
271
264
  best_generated = @generated
272
265
  break
266
+ rescue InvalidProperty
267
+ # Invalid test case generated- continue
268
+ rescue => e
269
+ next unless @valid_test_case
270
+
271
+ @status = Status.invalid
272
+ @excption = e
273
+ break
274
+ ensure
275
+ tracepoint.disable
273
276
  end
274
277
  end
275
278
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Minitest
4
4
  module Proptest
5
- VERSION = '0.2.1'
5
+ VERSION = '0.3.0'
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minitest-proptest
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tina Wuest
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-09-08 00:00:00.000000000 Z
11
+ date: 2024-09-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest