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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: aaa23e40547bec5672e806d62c567947cd596e1c11ed2bc80fbe6912cd75a777
4
- data.tar.gz: a0263cddf3efb8ee55f29395004915c38b6e78c7fc7bbf2c1b456f344013b8da
3
+ metadata.gz: 5b0170f4c948f3ffb903842c33204d4a9d5f74dd4f1d29313a60dec638670623
4
+ data.tar.gz: 447b87275c1e379502694d96591a871a527535e290daf3cc255476965752e1d2
5
5
  SHA512:
6
- metadata.gz: b7976fb344d4c7135cd858ca86606beb97cd9e9f57c40e2bb322a3c76287de46491d4feb1dd3a65158ffef8ea98894490edc7eb9bc506d80ddb110b2f026de8d
7
- data.tar.gz: f80bffd3b08d1a1cf120a70645b548c2f70b540ae5be317b7635f7416cc4e7be94d3a1bfca10acd117166e08fd0a0c6cd8ab08bf68097182fc064519600cfb55
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
@@ -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
- 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
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
@@ -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`.
@@ -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
- using PropCheck::Helper::LazyAppend
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 = root_children.lazy_append(flattened_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 = inner_children.lazy_append(mapped_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].lazy_append(new_children)
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 = base.lazy_append(recursive)
79
+ # res = PropCheck::Helper.lazy_append(base, recursive)
82
80
 
83
81
  # return res.each(&block) if block_given?
84
82
 
@@ -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
- io.puts 'Shrinking...' if @config.verbose
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
@@ -1,3 +1,3 @@
1
1
  module PropCheck
2
- VERSION = '0.10.0'
2
+ VERSION = '0.10.1'
3
3
  end
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.0
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-07-29 00:00:00.000000000 Z
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/