prop_check 0.10.0 → 0.10.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 +4 -4
- data/Gemfile +6 -4
- data/lib/prop_check/helper.rb +8 -0
- data/lib/prop_check/helper/lazy_append.rb +18 -18
- data/lib/prop_check/hooks.rb +2 -0
- data/lib/prop_check/lazy_tree.rb +5 -7
- data/lib/prop_check/property.rb +28 -71
- data/lib/prop_check/property/output_formatter.rb +41 -0
- data/lib/prop_check/property/shrinker.rb +79 -0
- data/lib/prop_check/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5b0170f4c948f3ffb903842c33204d4a9d5f74dd4f1d29313a60dec638670623
|
4
|
+
data.tar.gz: 447b87275c1e379502694d96591a871a527535e290daf3cc255476965752e1d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 533aae467c23eb1ecc974e842e735b49f3cfdef7ae51090ef11ad86e95f90f81660a6617565df4aab6470d2c2ae9ff5978826b48ed2686a727ac53b7c065a7b1
|
7
|
+
data.tar.gz: 4d6cc50716b03427a0aba7c4617a2970cc791c524d6aa427d22a63870853118cd72c6eca469fcd1e42ce2288f42a63b7fc577b248aea47a2892f324d94377db8
|
data/Gemfile
CHANGED
@@ -4,8 +4,10 @@ source "https://rubygems.org"
|
|
4
4
|
gemspec
|
5
5
|
|
6
6
|
gem "bundler", "~> 2.0"
|
7
|
-
gem "rake", "~> 12.3", require: false, group: :test
|
8
|
-
gem "rspec", "~> 3.0", require: false, group: :test
|
9
|
-
gem "doctest-rspec", require: false, group: :test
|
10
|
-
gem "simplecov", require: false, group: :test
|
11
7
|
|
8
|
+
group :test do
|
9
|
+
gem "rake", "~> 12.3", require: false
|
10
|
+
gem "rspec", "~> 3.0", require: false
|
11
|
+
gem "doctest-rspec", require: false
|
12
|
+
gem "simplecov", require: false
|
13
|
+
end
|
data/lib/prop_check/helper.rb
CHANGED
@@ -23,5 +23,13 @@ module PropCheck
|
|
23
23
|
end
|
24
24
|
end.lazy
|
25
25
|
end
|
26
|
+
|
27
|
+
##
|
28
|
+
# allow lazy appending of two (potentially lazy) enumerators:
|
29
|
+
# >> PropCheck::Helper::LazyAppend.lazy_append([1,2,3],[4,5.6]).to_a
|
30
|
+
# => [1,2,3,4,5,6]
|
31
|
+
def lazy_append(this_enumerator, other_enumerator)
|
32
|
+
[this_enumerator, other_enumerator].lazy.flat_map(&:lazy)
|
33
|
+
end
|
26
34
|
end
|
27
35
|
end
|
@@ -1,18 +1,18 @@
|
|
1
|
-
module PropCheck
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
1
|
+
# module PropCheck
|
2
|
+
# module Helper
|
3
|
+
# ##
|
4
|
+
# # A refinement for enumerators
|
5
|
+
# # to allow lazy appending of two (potentially lazy) enumerators:
|
6
|
+
# # >> [1,2,3].lazy_append([4,5.6]).to_a
|
7
|
+
# # => [1,2,3,4,5,6]
|
8
|
+
# module LazyAppend
|
9
|
+
# refine Enumerable do
|
10
|
+
# ## >> [1,2,3].lazy_append([4,5.6]).to_a
|
11
|
+
# ## => [1,2,3,4,5,6]
|
12
|
+
# def lazy_append(other_enumerator)
|
13
|
+
# [self, other_enumerator].lazy.flat_map(&:lazy)
|
14
|
+
# end
|
15
|
+
# end
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
# end
|
data/lib/prop_check/hooks.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
##
|
4
|
+
# @api private
|
4
5
|
# Contains the logic to combine potentially many before/after/around hooks
|
5
6
|
# into a single pair of procedures called `before` and `after`.
|
6
7
|
#
|
@@ -89,6 +90,7 @@ class PropCheck::Hooks
|
|
89
90
|
end
|
90
91
|
|
91
92
|
##
|
93
|
+
# @api private
|
92
94
|
# Wraps enumerable `inner` with a `PropCheck::Hooks` object
|
93
95
|
# such that the before/after/around hooks are called
|
94
96
|
# before/after/around each element that is fetched from `inner`.
|
data/lib/prop_check/lazy_tree.rb
CHANGED
@@ -1,13 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'prop_check/helper/lazy_append'
|
4
|
-
|
5
3
|
module PropCheck
|
6
4
|
##
|
7
5
|
# A Rose tree with the root being eager,
|
8
6
|
# and the children computed lazily, on demand.
|
9
7
|
class LazyTree
|
10
|
-
|
8
|
+
require 'prop_check/helper'
|
11
9
|
|
12
10
|
attr_accessor :root, :children
|
13
11
|
def initialize(root, children = [].lazy)
|
@@ -38,7 +36,7 @@ module PropCheck
|
|
38
36
|
# root_children = root_tree.children
|
39
37
|
# flattened_children = children.map(&:flatten)
|
40
38
|
|
41
|
-
# combined_children =
|
39
|
+
# combined_children = PropCheck::Helper.lazy_append(root_children, flattened_children)
|
42
40
|
|
43
41
|
# LazyTree.new(root_root, combined_children)
|
44
42
|
# end
|
@@ -53,7 +51,7 @@ module PropCheck
|
|
53
51
|
inner_children = inner_tree.children
|
54
52
|
mapped_children = children.map { |child| child.bind(&fun) }
|
55
53
|
|
56
|
-
combined_children =
|
54
|
+
combined_children = PropCheck::Helper.lazy_append(inner_children, mapped_children)
|
57
55
|
|
58
56
|
LazyTree.new(inner_root, combined_children)
|
59
57
|
end
|
@@ -70,7 +68,7 @@ module PropCheck
|
|
70
68
|
def each(&block)
|
71
69
|
squish = lambda do |tree, list|
|
72
70
|
new_children = tree.children.reduce(list) { |acc, elem| squish.call(elem, acc) }
|
73
|
-
[tree.root]
|
71
|
+
PropCheck::Helper.lazy_append([tree.root], new_children)
|
74
72
|
end
|
75
73
|
|
76
74
|
squish
|
@@ -78,7 +76,7 @@ module PropCheck
|
|
78
76
|
|
79
77
|
# base = [root]
|
80
78
|
# recursive = children.map(&:each)
|
81
|
-
# res =
|
79
|
+
# res = PropCheck::Helper.lazy_append(base, recursive)
|
82
80
|
|
83
81
|
# return res.each(&block) if block_given?
|
84
82
|
|
data/lib/prop_check/property.rb
CHANGED
@@ -2,6 +2,8 @@ require 'stringio'
|
|
2
2
|
require "awesome_print"
|
3
3
|
|
4
4
|
require 'prop_check/property/configuration'
|
5
|
+
require 'prop_check/property/output_formatter'
|
6
|
+
require 'prop_check/property/shrinker'
|
5
7
|
require 'prop_check/hooks'
|
6
8
|
module PropCheck
|
7
9
|
##
|
@@ -112,16 +114,39 @@ module PropCheck
|
|
112
114
|
self
|
113
115
|
end
|
114
116
|
|
117
|
+
##
|
118
|
+
# Calls `hook` before each time a check is run with new data.
|
119
|
+
#
|
120
|
+
# This is useful to add setup logic
|
121
|
+
# When called multiple times, earlier-added hooks will be called _before_ `hook` is called.
|
115
122
|
def before(&hook)
|
116
123
|
@hooks.add_before(&hook)
|
117
124
|
self
|
118
125
|
end
|
119
126
|
|
127
|
+
##
|
128
|
+
# Calls `hook` after each time a check is run with new data.
|
129
|
+
#
|
130
|
+
# This is useful to add teardown logic
|
131
|
+
# When called multiple times, earlier-added hooks will be called _after_ `hook` is called.
|
120
132
|
def after(&hook)
|
121
133
|
@hooks.add_after(&hook)
|
122
134
|
self
|
123
135
|
end
|
124
136
|
|
137
|
+
##
|
138
|
+
# Calls `hook` around each time a check is run with new data.
|
139
|
+
#
|
140
|
+
# `hook` should `yield` to the passed block.
|
141
|
+
#
|
142
|
+
# When called multiple times, earlier-added hooks will be wrapped _around_ `hook`.
|
143
|
+
#
|
144
|
+
# Around hooks will be called after all `#before` hooks
|
145
|
+
# and before all `#after` hooks.
|
146
|
+
#
|
147
|
+
# Note that if the block passed to `hook` raises an exception,
|
148
|
+
# it is possible for the code after `yield` not to be called.
|
149
|
+
# So make sure that cleanup logic is wrapped with the `ensure` keyword.
|
125
150
|
def around(&hook)
|
126
151
|
@hooks.add_around(&hook)
|
127
152
|
self
|
@@ -223,83 +248,15 @@ module PropCheck
|
|
223
248
|
|
224
249
|
private def show_problem_output(problem, generator_results, n_successful, &block)
|
225
250
|
output = @config.verbose ? STDOUT : StringIO.new
|
226
|
-
output = pre_output(output, n_successful, generator_results.root, problem)
|
251
|
+
output = PropCheck::Property::OutputFormatter.pre_output(output, n_successful, generator_results.root, problem)
|
227
252
|
shrunken_result, shrunken_exception, n_shrink_steps = shrink(generator_results, output, &block)
|
228
|
-
output = post_output(output, n_shrink_steps, shrunken_result, shrunken_exception)
|
253
|
+
output = PropCheck::Property::OutputFormatter.post_output(output, n_shrink_steps, shrunken_result, shrunken_exception)
|
229
254
|
|
230
255
|
[output, shrunken_result, shrunken_exception, n_shrink_steps]
|
231
256
|
end
|
232
257
|
|
233
|
-
private def pre_output(output, n_successful, generated_root, problem)
|
234
|
-
output.puts ""
|
235
|
-
output.puts "(after #{n_successful} successful property test runs)"
|
236
|
-
output.puts "Failed on: "
|
237
|
-
output.puts "`#{print_roots(generated_root)}`"
|
238
|
-
output.puts ""
|
239
|
-
output.puts "Exception message:\n---\n#{problem}"
|
240
|
-
output.puts "---"
|
241
|
-
output.puts ""
|
242
|
-
|
243
|
-
output
|
244
|
-
end
|
245
|
-
|
246
|
-
private def post_output(output, n_shrink_steps, shrunken_result, shrunken_exception)
|
247
|
-
if n_shrink_steps == 0
|
248
|
-
output.puts '(shrinking impossible)'
|
249
|
-
else
|
250
|
-
output.puts ''
|
251
|
-
output.puts "Shrunken input (after #{n_shrink_steps} shrink steps):"
|
252
|
-
output.puts "`#{print_roots(shrunken_result)}`"
|
253
|
-
output.puts ""
|
254
|
-
output.puts "Shrunken exception:\n---\n#{shrunken_exception}"
|
255
|
-
output.puts "---"
|
256
|
-
output.puts ""
|
257
|
-
end
|
258
|
-
output
|
259
|
-
end
|
260
|
-
|
261
|
-
private def print_roots(lazy_tree_val)
|
262
|
-
if lazy_tree_val.is_a?(Array) && lazy_tree_val.length == 1 && lazy_tree_val[0].is_a?(Hash)
|
263
|
-
lazy_tree_val[0].ai
|
264
|
-
else
|
265
|
-
lazy_tree_val.ai
|
266
|
-
end
|
267
|
-
end
|
268
|
-
|
269
258
|
private def shrink(bindings_tree, io, &block)
|
270
|
-
|
271
|
-
problem_child = bindings_tree
|
272
|
-
siblings = problem_child.children.lazy
|
273
|
-
parent_siblings = nil
|
274
|
-
problem_exception = nil
|
275
|
-
shrink_steps = 0
|
276
|
-
@hooks.wrap_enum(0..@config.max_shrink_steps).lazy.each do
|
277
|
-
begin
|
278
|
-
sibling = siblings.next
|
279
|
-
rescue StopIteration
|
280
|
-
break if parent_siblings.nil?
|
281
|
-
|
282
|
-
siblings = parent_siblings.lazy
|
283
|
-
parent_siblings = nil
|
284
|
-
next
|
285
|
-
end
|
286
|
-
|
287
|
-
shrink_steps += 1
|
288
|
-
io.print '.' if @config.verbose
|
289
|
-
|
290
|
-
begin
|
291
|
-
block.call(*sibling.root)
|
292
|
-
rescue Exception => e
|
293
|
-
problem_child = sibling
|
294
|
-
parent_siblings = siblings
|
295
|
-
siblings = problem_child.children.lazy
|
296
|
-
problem_exception = e
|
297
|
-
end
|
298
|
-
end
|
299
|
-
|
300
|
-
io.puts "(Note: Exceeded #{@config.max_shrink_steps} shrinking steps, the maximum.)" if shrink_steps >= @config.max_shrink_steps
|
301
|
-
|
302
|
-
[problem_child.root, problem_exception, shrink_steps]
|
259
|
+
PropCheck::Property::Shrinker.call(bindings_tree, io, @hooks, @config, &block)
|
303
260
|
end
|
304
261
|
end
|
305
262
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
##
|
2
|
+
# @api private
|
3
|
+
module PropCheck::Property::OutputFormatter
|
4
|
+
extend self
|
5
|
+
|
6
|
+
def pre_output(output, n_successful, generated_root, problem)
|
7
|
+
output.puts ""
|
8
|
+
output.puts "(after #{n_successful} successful property test runs)"
|
9
|
+
output.puts "Failed on: "
|
10
|
+
output.puts "`#{print_roots(generated_root)}`"
|
11
|
+
output.puts ""
|
12
|
+
output.puts "Exception message:\n---\n#{problem}"
|
13
|
+
output.puts "---"
|
14
|
+
output.puts ""
|
15
|
+
|
16
|
+
output
|
17
|
+
end
|
18
|
+
|
19
|
+
def post_output(output, n_shrink_steps, shrunken_result, shrunken_exception)
|
20
|
+
if n_shrink_steps == 0
|
21
|
+
output.puts '(shrinking impossible)'
|
22
|
+
else
|
23
|
+
output.puts ''
|
24
|
+
output.puts "Shrunken input (after #{n_shrink_steps} shrink steps):"
|
25
|
+
output.puts "`#{print_roots(shrunken_result)}`"
|
26
|
+
output.puts ""
|
27
|
+
output.puts "Shrunken exception:\n---\n#{shrunken_exception}"
|
28
|
+
output.puts "---"
|
29
|
+
output.puts ""
|
30
|
+
end
|
31
|
+
output
|
32
|
+
end
|
33
|
+
|
34
|
+
def print_roots(lazy_tree_val)
|
35
|
+
if lazy_tree_val.is_a?(Array) && lazy_tree_val.length == 1 && lazy_tree_val[0].is_a?(Hash)
|
36
|
+
lazy_tree_val[0].ai
|
37
|
+
else
|
38
|
+
lazy_tree_val.ai
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
class PropCheck::Property::Shrinker
|
2
|
+
def initialize(bindings_tree, io, hooks, config)
|
3
|
+
@problem_child = bindings_tree
|
4
|
+
@io = io
|
5
|
+
@siblings = @problem_child.children.lazy
|
6
|
+
@parent_siblings = nil
|
7
|
+
@problem_exception = nil
|
8
|
+
@shrink_steps = 0
|
9
|
+
@hooks = hooks
|
10
|
+
@config = config
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.call(bindings_tree, io, hooks, config, &block)
|
14
|
+
self
|
15
|
+
.new(bindings_tree, io, hooks, config)
|
16
|
+
.call(&block)
|
17
|
+
end
|
18
|
+
|
19
|
+
def call(&block)
|
20
|
+
@io.puts 'Shrinking...' if @config.verbose
|
21
|
+
|
22
|
+
shrink(&block)
|
23
|
+
|
24
|
+
print_shrinking_exceeded_message if @shrink_steps >= @config.max_shrink_steps
|
25
|
+
|
26
|
+
[@problem_child.root, @problem_exception, @shrink_steps]
|
27
|
+
end
|
28
|
+
|
29
|
+
private def shrink(&block)
|
30
|
+
wrapped_enum.each do
|
31
|
+
instruction, sibling = safe_read_sibling
|
32
|
+
break if instruction == :break
|
33
|
+
next if instruction == :next
|
34
|
+
|
35
|
+
inc_shrink_step
|
36
|
+
|
37
|
+
safe_call_block(sibling, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private def wrapped_enum
|
42
|
+
@hooks.wrap_enum(0..@config.max_shrink_steps).lazy
|
43
|
+
end
|
44
|
+
|
45
|
+
private def inc_shrink_step
|
46
|
+
@shrink_steps += 1
|
47
|
+
@io.print '.' if @config.verbose
|
48
|
+
end
|
49
|
+
|
50
|
+
private def safe_read_sibling
|
51
|
+
begin
|
52
|
+
sibling = @siblings.next
|
53
|
+
[:continue, sibling]
|
54
|
+
rescue StopIteration
|
55
|
+
return [:break, nil] if @parent_siblings.nil?
|
56
|
+
|
57
|
+
@siblings = @parent_siblings.lazy
|
58
|
+
@parent_siblings = nil
|
59
|
+
[:next, nil]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private def safe_call_block(sibling, &block)
|
64
|
+
begin
|
65
|
+
block.call(*sibling.root)
|
66
|
+
# It is correct that we want to rescue _all_ Exceptions
|
67
|
+
# not only 'StandardError's
|
68
|
+
rescue Exception => e
|
69
|
+
@problem_child = sibling
|
70
|
+
@parent_siblings = @siblings
|
71
|
+
@siblings = @problem_child.children.lazy
|
72
|
+
@problem_exception = e
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
private def print_shrinking_exceeded_message
|
77
|
+
@io.puts "(Note: Exceeded #{@config.max_shrink_steps} shrinking steps, the maximum.)"
|
78
|
+
end
|
79
|
+
end
|
data/lib/prop_check/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prop_check
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.10.
|
4
|
+
version: 0.10.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Qqwy/Wiebe-Marten Wijnja
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-08-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: awesome_print
|
@@ -57,6 +57,8 @@ files:
|
|
57
57
|
- lib/prop_check/lazy_tree.rb
|
58
58
|
- lib/prop_check/property.rb
|
59
59
|
- lib/prop_check/property/configuration.rb
|
60
|
+
- lib/prop_check/property/output_formatter.rb
|
61
|
+
- lib/prop_check/property/shrinker.rb
|
60
62
|
- lib/prop_check/version.rb
|
61
63
|
- prop_check.gemspec
|
62
64
|
homepage: https://github.com/Qqwy/ruby-prop_check/
|