minitest-proptest 0.2.1 → 0.3.0

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 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