minitest-proptest 0.1.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/minitest/proptest/gen/value_generator.rb +1 -1
- data/lib/minitest/proptest/gen.rb +109 -35
- data/lib/minitest/proptest/property.rb +121 -33
- data/lib/minitest/proptest/status.rb +13 -0
- data/lib/minitest/proptest/version.rb +1 -1
- data/lib/minitest/proptest_plugin.rb +6 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61aa3a3421a7b1996cf35540600199e11d18bbf5959d96866f994be97f372bcf
|
4
|
+
data.tar.gz: f89adae15e67f595c56f274d034b18e3e325fe097865ef60f42a7d49f7509214
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c114584acb4f0d59d93958c65e665a5acde52dce3083f1a1343e8cc85962ec11f4e8e582821bf86002cb2e02cfe45d255fe653450944fdc573112168a734520
|
7
|
+
data.tar.gz: 4f23345243cb106aa1fca9e4d9a4c87c6c20e22407e2564990de246cb81c95f96a2e8138a3991121ab24a2b2bfa9bf5066a7cdc3b639f0880d6e1170bd214652
|
@@ -19,8 +19,8 @@ module Minitest
|
|
19
19
|
end
|
20
20
|
|
21
21
|
def self.with_append(bound_min, bound_max, &f)
|
22
|
-
define_singleton_method(:bound_max) { bound_max }
|
23
22
|
define_singleton_method(:bound_min) { bound_min }
|
23
|
+
define_singleton_method(:bound_max) { bound_max }
|
24
24
|
define_method(:append) do |other|
|
25
25
|
@value = f.call(value, other.value)
|
26
26
|
self
|
@@ -119,28 +119,60 @@ module Minitest
|
|
119
119
|
|
120
120
|
until y == 0
|
121
121
|
candidates << (x - y)
|
122
|
-
candidates << y
|
123
|
-
# Prevent negative integral from preventing termination
|
122
|
+
candidates << y if y.abs < x.abs
|
124
123
|
y = (y / 2.0).to_i
|
125
124
|
end
|
126
125
|
|
127
126
|
candidates
|
128
|
-
|
129
|
-
|
127
|
+
end
|
128
|
+
|
129
|
+
score_float = ->(f) do
|
130
|
+
if f.nan? || f.infinite?
|
131
|
+
0
|
132
|
+
else
|
133
|
+
f.abs.ceil
|
134
|
+
end
|
130
135
|
end
|
131
136
|
|
132
137
|
float_shrink = ->(x) do
|
138
|
+
return [] if x.nan? || x.infinite? || x.zero?
|
139
|
+
|
133
140
|
candidates = [Float::NAN, Float::INFINITY]
|
134
141
|
y = x
|
135
142
|
|
136
|
-
until y
|
143
|
+
until y.zero? || y.to_f.infinite? || y.to_f.nan?
|
137
144
|
candidates << (x - y)
|
138
145
|
y = (y / 2.0).to_i
|
139
146
|
end
|
140
147
|
|
141
|
-
|
142
|
-
|
143
|
-
|
148
|
+
score = score_float.call(x)
|
149
|
+
candidates.reduce([]) do |cs, c|
|
150
|
+
cs + (score_float.call(c) < score ? [c.to_f] : [])
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
score_complex = ->(c) do
|
155
|
+
r = if c.real.to_f.nan? || c.real.to_f.infinite?
|
156
|
+
0
|
157
|
+
else
|
158
|
+
c.real.abs.ceil
|
159
|
+
end
|
160
|
+
i = if c.imaginary.to_f.nan? || c.imaginary.to_f.infinite?
|
161
|
+
0
|
162
|
+
else
|
163
|
+
c.imaginary.abs.ceil
|
164
|
+
end
|
165
|
+
r + i
|
166
|
+
end
|
167
|
+
|
168
|
+
complex_shrink = ->(x) do
|
169
|
+
rs = float_shrink.call(x.real)
|
170
|
+
is = float_shrink.call(x.imaginary)
|
171
|
+
|
172
|
+
score = score_complex.call(x)
|
173
|
+
rs.flat_map { |real| is.map { |imag| Complex(real, imag) } }
|
174
|
+
.reject { |c| score_complex.call(c) >= score }
|
175
|
+
.uniq
|
144
176
|
end
|
145
177
|
|
146
178
|
# List shrink adapted from QuickCheck
|
@@ -196,6 +228,34 @@ module Minitest
|
|
196
228
|
end
|
197
229
|
end
|
198
230
|
|
231
|
+
range_shrink = ->(f, r) do
|
232
|
+
xs = f.call(r.first)
|
233
|
+
ys = f.call(r.last)
|
234
|
+
|
235
|
+
xs.flat_map { |x| ys.map { |y| x <= y ? (x..y) : (y..x) } }
|
236
|
+
end
|
237
|
+
|
238
|
+
score_rational = ->(r) do
|
239
|
+
(r.numerator * r.denominator).abs
|
240
|
+
end
|
241
|
+
|
242
|
+
rational_shrink = ->(r) do
|
243
|
+
ns = integral_shrink.call(r.numerator)
|
244
|
+
ds = integral_shrink.call(r.denominator)
|
245
|
+
|
246
|
+
score = score_rational.call(r)
|
247
|
+
ns.flat_map do |n|
|
248
|
+
ds.reduce([]) do |rs, d|
|
249
|
+
if d.zero?
|
250
|
+
rs
|
251
|
+
else
|
252
|
+
rational = Rational(n, d)
|
253
|
+
rs + (score_rational.call(rational) < score ? [rational] : [])
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
199
259
|
hash_shrink = ->(_fk, _fv, h) do
|
200
260
|
candidates = []
|
201
261
|
n = h.length
|
@@ -303,45 +363,36 @@ module Minitest
|
|
303
363
|
.unpack1('f')
|
304
364
|
end.with_shrink_function do |f|
|
305
365
|
float_shrink.call(f)
|
306
|
-
end.with_score_function
|
307
|
-
if f.nan? || f.infinite?
|
308
|
-
0
|
309
|
-
else
|
310
|
-
f.abs.ceil
|
311
|
-
end
|
312
|
-
end
|
366
|
+
end.with_score_function(&score_float)
|
313
367
|
|
314
|
-
|
315
|
-
bits = sized(0xffffffffffffffff)
|
368
|
+
float64build = ->(bits) do
|
316
369
|
(0..7)
|
317
370
|
.map { |y| ((bits & (0xff << (8 * y))) >> (8 * y)).chr }
|
318
371
|
.join
|
319
372
|
.unpack1('d')
|
373
|
+
end
|
374
|
+
|
375
|
+
generator_for(Float64) do
|
376
|
+
bits = sized(0xffffffffffffffff)
|
377
|
+
float64build.call(bits)
|
320
378
|
end.with_shrink_function do |f|
|
321
379
|
float_shrink.call(f)
|
322
|
-
end.with_score_function
|
323
|
-
if f.nan? || f.infinite?
|
324
|
-
0
|
325
|
-
else
|
326
|
-
f.abs.ceil
|
327
|
-
end
|
328
|
-
end
|
380
|
+
end.with_score_function(&score_float)
|
329
381
|
|
330
382
|
generator_for(Float) do
|
331
383
|
bits = sized(0xffffffffffffffff)
|
332
|
-
(
|
333
|
-
.map { |y| ((bits & (0xff << (8 * y))) >> (8 * y)).chr }
|
334
|
-
.join
|
335
|
-
.unpack1('d')
|
384
|
+
float64build.call(bits)
|
336
385
|
end.with_shrink_function do |f|
|
337
386
|
float_shrink.call(f)
|
338
|
-
end.with_score_function
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
end
|
387
|
+
end.with_score_function(&score_float)
|
388
|
+
|
389
|
+
generator_for(Complex) do
|
390
|
+
real = sized(0xffffffffffffffff)
|
391
|
+
imag = sized(0xffffffffffffffff)
|
392
|
+
Complex(float64build.call(real), float64build.call(imag))
|
393
|
+
end.with_shrink_function do |c|
|
394
|
+
complex_shrink.call(c)
|
395
|
+
end.with_score_function(&score_complex)
|
345
396
|
|
346
397
|
generator_for(ASCIIChar) do
|
347
398
|
sized(0x7f).chr
|
@@ -392,6 +443,29 @@ module Minitest
|
|
392
443
|
xm.merge(ym)
|
393
444
|
end.with_empty { {} }
|
394
445
|
|
446
|
+
generator_for(Range) do |x|
|
447
|
+
(x..x)
|
448
|
+
end.with_shrink_function(&range_shrink).with_score_function do |f, r|
|
449
|
+
r.to_a.reduce(1) do |c, x|
|
450
|
+
y = f.call(x).abs
|
451
|
+
c * (y > 0 ? y + 1 : 1)
|
452
|
+
end.to_i * r.to_a.length
|
453
|
+
end.with_append(2, 2) do |ra, rb|
|
454
|
+
xs = [ra.first, ra.last, rb.first, rb.last].sort
|
455
|
+
(xs.first..xs.last)
|
456
|
+
end
|
457
|
+
|
458
|
+
generator_for(Rational) do
|
459
|
+
n = sized(MAX_SIZE)
|
460
|
+
d = sized(MAX_SIZE - 1) + 1
|
461
|
+
if (n & SIGN_BIT).zero?
|
462
|
+
Rational(n, d)
|
463
|
+
else
|
464
|
+
Rational(-(((n & (MAX_SIZE ^ SIGN_BIT)) - 1) ^ (MAX_SIZE ^ SIGN_BIT)), d)
|
465
|
+
end
|
466
|
+
end.with_shrink_function(&rational_shrink)
|
467
|
+
.with_score_function(&score_rational)
|
468
|
+
|
395
469
|
generator_for(Bool) do
|
396
470
|
sized(0x1).odd?
|
397
471
|
end.with_score_function do |_|
|
@@ -4,11 +4,20 @@ module Minitest
|
|
4
4
|
module Proptest
|
5
5
|
# Property evaluation - status, scoring, shrinking
|
6
6
|
class Property
|
7
|
-
|
7
|
+
require 'minitest/assertions'
|
8
|
+
include Minitest::Assertions
|
9
|
+
|
10
|
+
attr_reader :calls, :result, :status, :trivial
|
11
|
+
|
12
|
+
attr_accessor :assertions
|
8
13
|
|
9
14
|
def initialize(
|
10
15
|
# The function which proves the property
|
11
16
|
test_proc,
|
17
|
+
# The file in which our property lives
|
18
|
+
filename,
|
19
|
+
# The method containing our property
|
20
|
+
methodname,
|
12
21
|
# Any class which provides `rand` accepting both an Integer and a Range
|
13
22
|
# is acceptable. The default value is Ruby's standard Mersenne Twister
|
14
23
|
# implementation.
|
@@ -28,6 +37,8 @@ module Minitest
|
|
28
37
|
previous_failure: []
|
29
38
|
)
|
30
39
|
@test_proc = test_proc
|
40
|
+
@filename = filename
|
41
|
+
@methodname = methodname
|
31
42
|
@random = random.call
|
32
43
|
@generator = ::Minitest::Proptest::Gen.new(@random)
|
33
44
|
@max_success = max_success
|
@@ -36,13 +47,16 @@ module Minitest
|
|
36
47
|
@max_shrinks = max_shrinks
|
37
48
|
@status = Status.unknown
|
38
49
|
@trivial = false
|
50
|
+
@valid_test_case = true
|
39
51
|
@result = nil
|
40
52
|
@exception = nil
|
41
53
|
@calls = 0
|
54
|
+
@assertions = 0
|
42
55
|
@valid_test_cases = 0
|
43
56
|
@generated = []
|
44
57
|
@arbitrary = nil
|
45
58
|
@previous_failure = previous_failure.to_a
|
59
|
+
@local_variables = {}
|
46
60
|
end
|
47
61
|
|
48
62
|
def run!
|
@@ -51,17 +65,6 @@ module Minitest
|
|
51
65
|
shrink!
|
52
66
|
end
|
53
67
|
|
54
|
-
def arbitrary(*classes)
|
55
|
-
if @arbitrary
|
56
|
-
@arbitrary.call(*classes)
|
57
|
-
else
|
58
|
-
a = @generator.for(*classes)
|
59
|
-
@generated << a
|
60
|
-
@status = Status.overrun unless @generated.length <= @max_size
|
61
|
-
a.value
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
68
|
def explain
|
66
69
|
prop = if @status.valid?
|
67
70
|
'The property was proved to satsfaction across ' \
|
@@ -77,10 +80,26 @@ module Minitest
|
|
77
80
|
elsif @status.unknown?
|
78
81
|
'The property has not yet been tested.'
|
79
82
|
elsif @status.interesting?
|
80
|
-
'
|
81
|
-
|
82
|
-
|
83
|
-
|
83
|
+
info = 'A counterexample to a property has been found after ' \
|
84
|
+
"#{@valid_test_cases} valid " \
|
85
|
+
"example#{@valid_test_cases == 1 ? '' : 's'}.\n"
|
86
|
+
var_info = if @local_variables.empty?
|
87
|
+
'Variables local to the property were unable ' \
|
88
|
+
'to be determined. This is usually a bug.'
|
89
|
+
else
|
90
|
+
"The values at the time of the failure were:\n"
|
91
|
+
end
|
92
|
+
vars = @local_variables
|
93
|
+
.map { |k, v| "\t#{k}: #{v.inspect}" }
|
94
|
+
.join("\n")
|
95
|
+
|
96
|
+
info + var_info + vars
|
97
|
+
elsif @status.exhausted?
|
98
|
+
"The property was unable to generate #{@max_success} test " \
|
99
|
+
'cases before generating ' \
|
100
|
+
"#{@max_success * @max_discard_ratio} rejected test " \
|
101
|
+
"cases. This might be a problem with the property's " \
|
102
|
+
'`where` blocks.'
|
84
103
|
end
|
85
104
|
trivial = if @trivial
|
86
105
|
"\nThe test does not appear to use any generated values " \
|
@@ -95,18 +114,47 @@ module Minitest
|
|
95
114
|
|
96
115
|
private
|
97
116
|
|
117
|
+
def arbitrary(*classes)
|
118
|
+
if @arbitrary
|
119
|
+
@arbitrary.call(*classes)
|
120
|
+
else
|
121
|
+
a = @generator.for(*classes)
|
122
|
+
@generated << a
|
123
|
+
@status = Status.overrun unless @generated.length <= @max_size
|
124
|
+
a.value
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
def where(&b)
|
129
|
+
@valid_test_case &= b.call
|
130
|
+
end
|
131
|
+
|
98
132
|
def iterate!
|
99
|
-
while continue_iterate? && @result.nil? && @valid_test_cases <= @max_success
|
133
|
+
while continue_iterate? && @result.nil? && @valid_test_cases <= @max_success
|
134
|
+
@valid_test_case = true
|
100
135
|
@generated = []
|
101
136
|
@generator = ::Minitest::Proptest::Gen.new(@random)
|
102
137
|
@calls += 1
|
103
|
-
|
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
|
104
150
|
@status = Status.valid if @status.unknown?
|
105
151
|
@valid_test_cases += 1
|
106
|
-
|
152
|
+
elsif @valid_test_case
|
107
153
|
@result = @generated
|
108
154
|
@status = Status.interesting
|
109
155
|
end
|
156
|
+
|
157
|
+
@status = Status.exhausted if @calls >= @max_success * (@max_discard_ratio + 1)
|
110
158
|
@trivial = true if @generated.empty?
|
111
159
|
end
|
112
160
|
rescue => e
|
@@ -133,9 +181,20 @@ module Minitest
|
|
133
181
|
end
|
134
182
|
|
135
183
|
@generator = ::Minitest::Proptest::Gen.new(@random)
|
136
|
-
|
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
|
137
196
|
@generated = []
|
138
|
-
|
197
|
+
elsif @valid_test_case
|
139
198
|
@result = @generated
|
140
199
|
@status = Status.interesting
|
141
200
|
end
|
@@ -156,6 +215,17 @@ module Minitest
|
|
156
215
|
candidates = @generated.map(&:shrink_candidates)
|
157
216
|
old_arbitrary = @arbitrary
|
158
217
|
|
218
|
+
local_variables = {}
|
219
|
+
tracepoint = TracePoint.new(:b_return) do |trace|
|
220
|
+
if trace.path == @filename && trace.method_id.to_s == @methodname
|
221
|
+
b = trace.binding
|
222
|
+
vs = b.local_variables
|
223
|
+
known = vs.to_h { |lv| [lv.to_s, b.local_variable_get(lv)] }
|
224
|
+
local_variables.delete_if { true }
|
225
|
+
local_variables.merge!(known)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
159
229
|
to_test = candidates
|
160
230
|
.map { |x| x.map { |y| [y] } }
|
161
231
|
.reduce { |c, e| c.flat_map { |a| e.map { |b| a + b } } }
|
@@ -174,15 +244,31 @@ module Minitest
|
|
174
244
|
end
|
175
245
|
|
176
246
|
while continue_shrink? && run[:run] < to_test.length
|
177
|
-
@generated
|
178
|
-
run[:index]
|
247
|
+
@generated = []
|
248
|
+
run[:index] = -1
|
249
|
+
@valid_test_case = true
|
179
250
|
|
180
251
|
@generator = ::Minitest::Proptest::Gen.new(@random)
|
181
252
|
if to_test[run[:run]].map(&:first).reduce(&:+) < best_score
|
182
|
-
|
183
|
-
|
184
|
-
|
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
|
185
270
|
# shrink candidates are pre-sorted.
|
271
|
+
best_generated = @generated
|
186
272
|
break
|
187
273
|
end
|
188
274
|
end
|
@@ -190,20 +276,22 @@ module Minitest
|
|
190
276
|
@calls += 1
|
191
277
|
run[:run] += 1
|
192
278
|
end
|
279
|
+
|
193
280
|
# Clean up after we're done
|
194
|
-
@generated
|
195
|
-
@result
|
196
|
-
@generator
|
197
|
-
@random
|
198
|
-
@arbitrary
|
281
|
+
@generated = best_generated
|
282
|
+
@result = best_generated
|
283
|
+
@generator = old_generator
|
284
|
+
@random = old_random
|
285
|
+
@arbitrary = old_arbitrary
|
286
|
+
@local_variables = local_variables
|
199
287
|
end
|
200
288
|
|
201
289
|
def continue_iterate?
|
202
290
|
!@trivial &&
|
203
291
|
!@status.invalid? &&
|
204
292
|
!@status.overrun? &&
|
205
|
-
|
206
|
-
@
|
293
|
+
!@status.exhausted? &&
|
294
|
+
@valid_test_cases < @max_success
|
207
295
|
end
|
208
296
|
|
209
297
|
def continue_shrink?
|
@@ -4,6 +4,10 @@ module Minitest
|
|
4
4
|
module Proptest
|
5
5
|
# Sum type representing the possible statuses of a test run.
|
6
6
|
# Invalid, Overrun, and Interesting represent different failure classes.
|
7
|
+
# Exhausted represents having generated too many invalid test cases to
|
8
|
+
# verify the property. This precipitates as a failure class (the property is
|
9
|
+
# not proved) but can be a matter of inappropriate predicates in `where`
|
10
|
+
# blocks.
|
7
11
|
# Unknown represents a lack of information about the test run (typically
|
8
12
|
# having not run to satisfaction).
|
9
13
|
# Valid represents a test which has run to satisfaction.
|
@@ -23,16 +27,21 @@ module Minitest
|
|
23
27
|
class Valid < Status
|
24
28
|
end
|
25
29
|
|
30
|
+
class Exhausted < Status
|
31
|
+
end
|
32
|
+
|
26
33
|
invalid = Invalid.new.freeze
|
27
34
|
interesting = Interesting.new.freeze
|
28
35
|
overrun = Overrun.new.freeze
|
29
36
|
unknown = Unknown.new.freeze
|
37
|
+
exhausted = Exhausted.new.freeze
|
30
38
|
valid = Valid.new.freeze
|
31
39
|
|
32
40
|
define_singleton_method(:invalid) { invalid }
|
33
41
|
define_singleton_method(:interesting) { interesting }
|
34
42
|
define_singleton_method(:overrun) { overrun }
|
35
43
|
define_singleton_method(:unknown) { unknown }
|
44
|
+
define_singleton_method(:exhausted) { exhausted }
|
36
45
|
define_singleton_method(:valid) { valid }
|
37
46
|
|
38
47
|
def invalid?
|
@@ -47,6 +56,10 @@ module Minitest
|
|
47
56
|
self.is_a?(Unknown)
|
48
57
|
end
|
49
58
|
|
59
|
+
def exhausted?
|
60
|
+
self.is_a?(Exhausted)
|
61
|
+
end
|
62
|
+
|
50
63
|
def valid?
|
51
64
|
self.is_a?(Valid)
|
52
65
|
end
|
@@ -50,8 +50,6 @@ module Minitest
|
|
50
50
|
|
51
51
|
module Assertions
|
52
52
|
def property(&f)
|
53
|
-
self.assertions += 1
|
54
|
-
|
55
53
|
random_thunk = if Proptest.instance_variable_defined?(:@_random_seed)
|
56
54
|
r = Proptest.instance_variable_get(:@_random_seed)
|
57
55
|
->() { Proptest::DEFAULT_RANDOM.call(r) }
|
@@ -65,6 +63,8 @@ module Minitest
|
|
65
63
|
|
66
64
|
prop = Minitest::Proptest::Property.new(
|
67
65
|
f,
|
66
|
+
file,
|
67
|
+
methodname,
|
68
68
|
random: random_thunk,
|
69
69
|
max_success: Proptest.max_success,
|
70
70
|
max_discard_ratio: Proptest.max_discard_ratio,
|
@@ -73,11 +73,14 @@ module Minitest
|
|
73
73
|
previous_failure: Proptest.reporter.lookup(file, classname, methodname)
|
74
74
|
)
|
75
75
|
prop.run!
|
76
|
+
self.assertions += prop.calls
|
76
77
|
|
77
78
|
if prop.status.valid? && !prop.trivial
|
78
79
|
Proptest.strike_failure(file, classname, methodname)
|
79
80
|
else
|
80
|
-
|
81
|
+
unless prop.status.exhausted? || prop.status.invalid?
|
82
|
+
Proptest.record_failure(file, classname, methodname, prop.result.map(&:value))
|
83
|
+
end
|
81
84
|
|
82
85
|
raise Minitest::Assertion, prop.explain
|
83
86
|
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.1
|
4
|
+
version: 0.2.1
|
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-
|
11
|
+
date: 2024-09-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|