minitest-proptest 0.2.0 → 0.2.1

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: '0596e6f6a66614dba0199eccc4e18a5bf6b869fd0db46dff7636a8772eacb75b'
4
- data.tar.gz: a956c579c5bb355a5b687f64109917918870dd7dac1323a18a72d44e4ca623a6
3
+ metadata.gz: 61aa3a3421a7b1996cf35540600199e11d18bbf5959d96866f994be97f372bcf
4
+ data.tar.gz: f89adae15e67f595c56f274d034b18e3e325fe097865ef60f42a7d49f7509214
5
5
  SHA512:
6
- metadata.gz: d6206c7a778b9b55e0674e204afea71721eb8b6e4fe2257691cc1cefd5e76885eff08d648f9a61172806872f1abe5f1b232186fcc803e6fcc560241fd71fac8c
7
- data.tar.gz: 1ca1d04ddcdecb9f661e0af6cffc87dda30af6a9b06bb6fe406a5f27ec445a0cf3cd9ac4d9050b4a243ab40d76d066358f6cf9612181cc546a2076b76a7d9041
6
+ metadata.gz: 6c114584acb4f0d59d93958c65e665a5acde52dce3083f1a1343e8cc85962ec11f4e8e582821bf86002cb2e02cfe45d255fe653450944fdc573112168a734520
7
+ data.tar.gz: 4f23345243cb106aa1fca9e4d9a4c87c6c20e22407e2564990de246cb81c95f96a2e8138a3991121ab24a2b2bfa9bf5066a7cdc3b639f0880d6e1170bd214652
@@ -14,6 +14,10 @@ module Minitest
14
14
  def initialize(
15
15
  # The function which proves the property
16
16
  test_proc,
17
+ # The file in which our property lives
18
+ filename,
19
+ # The method containing our property
20
+ methodname,
17
21
  # Any class which provides `rand` accepting both an Integer and a Range
18
22
  # is acceptable. The default value is Ruby's standard Mersenne Twister
19
23
  # implementation.
@@ -33,6 +37,8 @@ module Minitest
33
37
  previous_failure: []
34
38
  )
35
39
  @test_proc = test_proc
40
+ @filename = filename
41
+ @methodname = methodname
36
42
  @random = random.call
37
43
  @generator = ::Minitest::Proptest::Gen.new(@random)
38
44
  @max_success = max_success
@@ -50,6 +56,7 @@ module Minitest
50
56
  @generated = []
51
57
  @arbitrary = nil
52
58
  @previous_failure = previous_failure.to_a
59
+ @local_variables = {}
53
60
  end
54
61
 
55
62
  def run!
@@ -58,21 +65,6 @@ module Minitest
58
65
  shrink!
59
66
  end
60
67
 
61
- def arbitrary(*classes)
62
- if @arbitrary
63
- @arbitrary.call(*classes)
64
- else
65
- a = @generator.for(*classes)
66
- @generated << a
67
- @status = Status.overrun unless @generated.length <= @max_size
68
- a.value
69
- end
70
- end
71
-
72
- def where(&b)
73
- @valid_test_case &= b.call
74
- end
75
-
76
68
  def explain
77
69
  prop = if @status.valid?
78
70
  'The property was proved to satsfaction across ' \
@@ -88,10 +80,20 @@ module Minitest
88
80
  elsif @status.unknown?
89
81
  'The property has not yet been tested.'
90
82
  elsif @status.interesting?
91
- 'The property has found the following counterexample after ' \
92
- "#{@valid_test_cases} valid " \
93
- "example#{@valid_test_cases == 1 ? '' : 's'}:\n" \
94
- "#{@generated.map(&:value).inspect}"
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
95
97
  elsif @status.exhausted?
96
98
  "The property was unable to generate #{@max_success} test " \
97
99
  'cases before generating ' \
@@ -112,6 +114,21 @@ module Minitest
112
114
 
113
115
  private
114
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
+
115
132
  def iterate!
116
133
  while continue_iterate? && @result.nil? && @valid_test_cases <= @max_success
117
134
  @valid_test_case = true
@@ -198,6 +215,17 @@ module Minitest
198
215
  candidates = @generated.map(&:shrink_candidates)
199
216
  old_arbitrary = @arbitrary
200
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
+
201
229
  to_test = candidates
202
230
  .map { |x| x.map { |y| [y] } }
203
231
  .reduce { |c, e| c.flat_map { |a| e.map { |b| a + b } } }
@@ -223,6 +251,7 @@ module Minitest
223
251
  @generator = ::Minitest::Proptest::Gen.new(@random)
224
252
  if to_test[run[:run]].map(&:first).reduce(&:+) < best_score
225
253
  success = begin
254
+ tracepoint.enable
226
255
  instance_eval(&@test_proc)
227
256
  rescue Minitest::Assertion
228
257
  false
@@ -232,10 +261,12 @@ module Minitest
232
261
  @status = Status.invalid
233
262
  @excption = e
234
263
  break
264
+ ensure
265
+ tracepoint.disable
235
266
  end
236
267
 
237
268
  if !success && @valid_test_case
238
- # The first hit is guaranteed to be the best scoring due to the
269
+ # The first hit is guaranteed to be the best scoring since the
239
270
  # shrink candidates are pre-sorted.
240
271
  best_generated = @generated
241
272
  break
@@ -245,12 +276,14 @@ module Minitest
245
276
  @calls += 1
246
277
  run[:run] += 1
247
278
  end
279
+
248
280
  # Clean up after we're done
249
- @generated = best_generated
250
- @result = best_generated
251
- @generator = old_generator
252
- @random = old_random
253
- @arbitrary = old_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
254
287
  end
255
288
 
256
289
  def continue_iterate?
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Minitest
4
4
  module Proptest
5
- VERSION = '0.2.0'
5
+ VERSION = '0.2.1'
6
6
  end
7
7
  end
@@ -63,6 +63,8 @@ module Minitest
63
63
 
64
64
  prop = Minitest::Proptest::Property.new(
65
65
  f,
66
+ file,
67
+ methodname,
66
68
  random: random_thunk,
67
69
  max_success: Proptest.max_success,
68
70
  max_discard_ratio: Proptest.max_discard_ratio,
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.0
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-03-21 00:00:00.000000000 Z
11
+ date: 2024-09-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest