prop_check 0.9.0 → 0.10.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e5aeef61ddf82569ca885327d32b9fe8fd939f2fdbef48709cb19504b5cf041
4
- data.tar.gz: d914dcac32f7a3a976661a0280c71f0a7a665411550aed9902317b04c82ee290
3
+ metadata.gz: f8f707bae1dadf800e667376a749c7d5de3f3d741d13e63118de79dfb7233fb5
4
+ data.tar.gz: e86ac3b096bff66cfa88c0a66b1fc8ea91dc8452ded41c417fb1452c33c2b1d7
5
5
  SHA512:
6
- metadata.gz: 85c5b76ac37ba8e03b2c41c04c4cc359844fa2e52d0af8893787531c23f3a54b046eb7eed13b055fed44c8983f87cbfe492d1524746624a3744300a73caf01da
7
- data.tar.gz: 9beb7ac4e605c72cc8e9b3907e727ae532c2eec4a530b6a9b7c31445135e37c8849c9f186d4571aaf38c24e28989ebe856ed2e5e873baf2ed7b740a73561dae7
6
+ metadata.gz: e0985469e34e0b353aab0fac657a073fadfe135c03029187d3f7824ebded0bfd244122aa2ae4361b5ccad3fb05ca52162e3967e9f46a6e43674e7d7626a700f7
7
+ data.tar.gz: 0b0505768ea68855beaf9c8954cb973215dd392c40975e7f581e7faa9d7570c9e4fb76402227c5b0f223f96e87f72d58decfb7dffd2744897c22db3ba0959ac6
data/.gitignore CHANGED
@@ -11,4 +11,5 @@
11
11
  .rspec_status
12
12
 
13
13
  # .gem version files
14
- *.gem
14
+ *.gem
15
+ Gemfile.lock
data/Gemfile CHANGED
@@ -3,6 +3,11 @@ source "https://rubygems.org"
3
3
  # Specify your gem's dependencies in prop_check.gemspec
4
4
  gemspec
5
5
 
6
- gem 'simplecov', require: false, group: :test
7
- gem 'doctest-rspec', require: false, group: :test
8
- gem 'awesome_print', require: true
6
+ gem "bundler", "~> 2.0"
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/README.md CHANGED
@@ -27,6 +27,7 @@ Before releasing this gem on Rubygems, the following things need to be finished:
27
27
  - [x] Look into customization of settings from e.g. command line arguments.
28
28
  - [x] Good, unicode-compliant, string generators.
29
29
  - [x] Filtering generator outputs.
30
+ - [x] Before/after/around hooks to add setup/teardown logic to be called before/after/around each time a check is run with new data.
30
31
 
31
32
  # Nice-to-haves
32
33
 
@@ -87,7 +88,8 @@ Here we check if `naive_average` indeed always returns an integer for all arrays
87
88
  def naive_average(array)
88
89
  array.sum / array.length
89
90
  end
90
-
91
+ ```
92
+ ```ruby
91
93
  # And then in a test case:
92
94
  include PropCheck::Generators
93
95
  PropCheck.forall(numbers: array(integer)) do |numbers:|
@@ -96,6 +98,19 @@ PropCheck.forall(numbers: array(integer)) do |numbers:|
96
98
  raise "Expected the average to be an integer!"
97
99
  end
98
100
  end
101
+
102
+ # Or if you e.g. are using RSpec:
103
+ describe "#naive_average" do
104
+ include PropCheck
105
+ include PropCheck::Generators
106
+
107
+ it "returns an integer for any input" do
108
+ forall(numbers: array(integer)) do |numbers:|
109
+ result = naive_average(numbers)
110
+ expect(result).to be_a(Integer)
111
+ end
112
+ end
113
+ end
99
114
  ```
100
115
 
101
116
  When running this particular example PropCheck very quickly finds out that we have made a programming mistake:
@@ -10,6 +10,7 @@ module PropCheck
10
10
  class Generator
11
11
  @@default_size = 10
12
12
  @@default_rng = Random.new
13
+ @@max_consecutive_attempts = 100
13
14
 
14
15
  ##
15
16
  # Being a special kind of Proc, a Generator wraps a block.
@@ -20,8 +21,19 @@ module PropCheck
20
21
  ##
21
22
  # Given a `size` (integer) and a random number generator state `rng`,
22
23
  # generate a LazyTree.
23
- def generate(size = @@default_size, rng = @@default_rng)
24
- @block.call(size, rng)
24
+ def generate(size = @@default_size, rng = @@default_rng, max_consecutive_attempts = @@max_consecutive_attempts)
25
+ (0..max_consecutive_attempts).each do
26
+ res = @block.call(size, rng)
27
+ next if res == :"PropCheck.filter_me"
28
+
29
+ return res
30
+ end
31
+
32
+ raise Errors::GeneratorExhaustedError, """
33
+ Exhausted #{max_consecutive_attempts} consecutive generation attempts.
34
+
35
+ Probably too few generator results were adhering to a `where` condition.
36
+ """
25
37
  end
26
38
 
27
39
  ##
@@ -88,14 +100,16 @@ module PropCheck
88
100
  def map(&proc)
89
101
  Generator.new do |size, rng|
90
102
  result = self.generate(size, rng)
91
- result.map(&proc)
103
+ result.map do |*val|
104
+ proc.call(*val)
105
+ end
92
106
  end
93
107
  end
94
108
 
95
109
  ##
96
110
  # Creates a new Generator that only produces a value when the block `condition` returns a truthy value.
97
111
  def where(&condition)
98
- self.map do |result|
112
+ self.map do |*result|
99
113
  if condition.call(*result)
100
114
  result
101
115
  else
@@ -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
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ ##
4
+ # @api private
5
+ # Contains the logic to combine potentially many before/after/around hooks
6
+ # into a single pair of procedures called `before` and `after`.
7
+ #
8
+ # _Note: This module is an implementation detail of PropCheck._
9
+ #
10
+ # These can be invoked by manually calling `#before` and `#after`.
11
+ # Important:
12
+ # - Always call first `#before` and then `#after`.
13
+ # This is required to make sure that `around` callbacks will work properly.
14
+ # - Make sure that if you call `#before`, to also call `#after`.
15
+ # It is thus highly recommended to call `#after` inside an `ensure`.
16
+ # This is to make sure that `around` callbacks indeed perform their proper cleanup.
17
+ #
18
+ # Alternatively, check out `PropCheck::Hooks::Enumerable` which allows
19
+ # wrapping the elements of an enumerable with hooks.
20
+ class PropCheck::Hooks
21
+ # attr_reader :before, :after, :around
22
+ def initialize()
23
+ @before = proc {}
24
+ @after = proc {}
25
+ @around = proc { |*args, &block| block.call(*args) }
26
+ end
27
+
28
+ def wrap_enum(enumerable)
29
+ PropCheck::Hooks::Enumerable.new(enumerable, self)
30
+ end
31
+
32
+
33
+ ##
34
+ # Wraps a block with all hooks that were configured this far.
35
+ #
36
+ # This means that whenever the block is called,
37
+ # the before/around/after hooks are called before/around/after it.
38
+ def wrap_block(&block)
39
+ proc { |*args| call(*args, &block) }
40
+ end
41
+
42
+ ##
43
+ # Wraps a block with all hooks that were configured this far,
44
+ # and immediately calls it using the given `*args`.
45
+ #
46
+ # See also #wrap_block
47
+ def call(*args, &block)
48
+ begin
49
+ @before.call()
50
+ @around.call do
51
+ block.call(*args)
52
+ end
53
+ ensure
54
+ @after.call()
55
+ end
56
+ end
57
+
58
+ ##
59
+ # Adds `hook` to the `before` proc.
60
+ # It is called after earlier-added `before` procs.
61
+ def add_before(&hook)
62
+ old_before = @before
63
+ @before = proc {
64
+ old_before.call
65
+ hook.call
66
+ }
67
+ end
68
+
69
+ ##
70
+ # Adds `hook` to the `after` proc.
71
+ # It is called before earlier-added `after` procs.
72
+ def add_after(&hook)
73
+ old_after = @after
74
+ @after = proc {
75
+ hook.call
76
+ old_after.call
77
+ }
78
+ end
79
+
80
+ ##
81
+ # Adds `hook` to the `around` proc.
82
+ # It is called _inside_ earlier-added `around` procs.
83
+ def add_around(&hook)
84
+ old_around = @around
85
+ @around = proc do |&block|
86
+ old_around.call do |*args|
87
+ hook.call(*args, &block)
88
+ end
89
+ end
90
+ end
91
+
92
+ ##
93
+ # @api private
94
+ # Wraps enumerable `inner` with a `PropCheck::Hooks` object
95
+ # such that the before/after/around hooks are called
96
+ # before/after/around each element that is fetched from `inner`.
97
+ #
98
+ # This is very helpful if you need to perform cleanup logic
99
+ # before/after/around e.g. data is generated or fetched.
100
+ #
101
+ # Note that whatever is after a `yield` in an `around` hook
102
+ # is not guaranteed to be called (for instance when a StopIteration is raised).
103
+ # Thus: make sure you use `ensure` to clean up resources.
104
+ class Enumerable
105
+ include ::Enumerable
106
+
107
+ def initialize(inner, hooks)
108
+ @inner = inner
109
+ @hooks = hooks
110
+ end
111
+
112
+ def each(&task)
113
+ return to_enum(:each) unless block_given?
114
+
115
+ enum = @inner.to_enum
116
+
117
+ wrapped_yielder = @hooks.wrap_block do
118
+ yield enum.next(&task)
119
+ end
120
+
121
+ loop(&wrapped_yielder)
122
+ end
123
+ end
124
+ end
@@ -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,9 @@ 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'
7
+ require 'prop_check/hooks'
5
8
  module PropCheck
6
9
  ##
7
10
  # Run properties
@@ -67,6 +70,7 @@ module PropCheck
67
70
  @kwbindings = kwbindings
68
71
  @condition = proc { true }
69
72
  @config = self.class.configuration
73
+ @hooks = PropCheck::Hooks.new
70
74
  end
71
75
 
72
76
  ##
@@ -103,13 +107,51 @@ module PropCheck
103
107
  # Only filter if you have few inputs to reject. Otherwise, improve your generators.
104
108
  def where(&condition)
105
109
  original_condition = @condition.dup
106
- @condition = proc do |**kwargs|
107
- original_condition.call(**kwargs) && condition.call(**kwargs)
110
+ @condition = proc do |*args|
111
+ original_condition.call(*args) && condition.call(*args)
108
112
  end
109
113
 
110
114
  self
111
115
  end
112
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.
122
+ def before(&hook)
123
+ @hooks.add_before(&hook)
124
+ self
125
+ end
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.
132
+ def after(&hook)
133
+ @hooks.add_after(&hook)
134
+ self
135
+ end
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.
150
+ def around(&hook)
151
+ @hooks.add_around(&hook)
152
+ self
153
+ end
154
+
113
155
  ##
114
156
  # Checks the property (after settings have been altered using the other instance methods in this class.)
115
157
  def check(&block)
@@ -127,7 +169,7 @@ module PropCheck
127
169
  n_successful = 0
128
170
 
129
171
  # Loop stops at first exception
130
- attempts_enumerator(binding_generator).each do |generator_result|
172
+ attempts_enum(binding_generator).each do |generator_result|
131
173
  n_runs += 1
132
174
  check_attempt(generator_result, n_successful, &block)
133
175
  n_successful += 1
@@ -182,10 +224,15 @@ module PropCheck
182
224
  raise e, output_string, e.backtrace
183
225
  end
184
226
 
185
- private def attempts_enumerator(binding_generator)
227
+ private def attempts_enum(binding_generator)
228
+ @hooks
229
+ .wrap_enum(raw_attempts_enum(binding_generator))
230
+ .lazy
231
+ .take(@config.n_runs)
232
+ end
186
233
 
234
+ private def raw_attempts_enum(binding_generator)
187
235
  rng = Random::DEFAULT
188
- n_runs = 0
189
236
  size = 1
190
237
  (0...@config.max_generate_attempts)
191
238
  .lazy
@@ -193,93 +240,23 @@ module PropCheck
193
240
  .reject { |val| val.root.any? { |elem| elem == :"_PropCheck.filter_me" }}
194
241
  .select { |val| @condition.call(*val.root) }
195
242
  .map do |result|
196
- n_runs += 1
197
243
  size += 1
198
244
 
199
245
  result
200
246
  end
201
- .take_while { n_runs <= @config.n_runs }
202
247
  end
203
248
 
204
249
  private def show_problem_output(problem, generator_results, n_successful, &block)
205
250
  output = @config.verbose ? STDOUT : StringIO.new
206
- output = pre_output(output, n_successful, generator_results.root, problem)
251
+ output = PropCheck::Property::OutputFormatter.pre_output(output, n_successful, generator_results.root, problem)
207
252
  shrunken_result, shrunken_exception, n_shrink_steps = shrink(generator_results, output, &block)
208
- 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)
209
254
 
210
255
  [output, shrunken_result, shrunken_exception, n_shrink_steps]
211
256
  end
212
257
 
213
- private def pre_output(output, n_successful, generated_root, problem)
214
- output.puts ""
215
- output.puts "(after #{n_successful} successful property test runs)"
216
- output.puts "Failed on: "
217
- output.puts "`#{print_roots(generated_root)}`"
218
- output.puts ""
219
- output.puts "Exception message:\n---\n#{problem}"
220
- output.puts "---"
221
- output.puts ""
222
-
223
- output
224
- end
225
-
226
- private def post_output(output, n_shrink_steps, shrunken_result, shrunken_exception)
227
- if n_shrink_steps == 0
228
- output.puts '(shrinking impossible)'
229
- else
230
- output.puts ''
231
- output.puts "Shrunken input (after #{n_shrink_steps} shrink steps):"
232
- output.puts "`#{print_roots(shrunken_result)}`"
233
- output.puts ""
234
- output.puts "Shrunken exception:\n---\n#{shrunken_exception}"
235
- output.puts "---"
236
- output.puts ""
237
- end
238
- output
239
- end
240
-
241
- private def print_roots(lazy_tree_val)
242
- if lazy_tree_val.is_a?(Array) && lazy_tree_val.length == 1 && lazy_tree_val[0].is_a?(Hash)
243
- lazy_tree_val[0].ai
244
- else
245
- lazy_tree_val.ai
246
- end
247
- end
248
-
249
258
  private def shrink(bindings_tree, io, &block)
250
- io.puts 'Shrinking...' if @config.verbose
251
- problem_child = bindings_tree
252
- siblings = problem_child.children.lazy
253
- parent_siblings = nil
254
- problem_exception = nil
255
- shrink_steps = 0
256
- (0..@config.max_shrink_steps).each do
257
- begin
258
- sibling = siblings.next
259
- rescue StopIteration
260
- break if parent_siblings.nil?
261
-
262
- siblings = parent_siblings.lazy
263
- parent_siblings = nil
264
- next
265
- end
266
-
267
- shrink_steps += 1
268
- io.print '.' if @config.verbose
269
-
270
- begin
271
- block.call(*sibling.root)
272
- rescue Exception => e
273
- problem_child = sibling
274
- parent_siblings = siblings
275
- siblings = problem_child.children.lazy
276
- problem_exception = e
277
- end
278
- end
279
-
280
- io.puts "(Note: Exceeded #{@config.max_shrink_steps} shrinking steps, the maximum.)" if shrink_steps >= @config.max_shrink_steps
281
-
282
- [problem_child.root, problem_exception, shrink_steps]
259
+ PropCheck::Property::Shrinker.call(bindings_tree, io, @hooks, @config, &block)
283
260
  end
284
261
  end
285
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.9.0"
2
+ VERSION = '0.10.4'
3
3
  end
@@ -36,7 +36,5 @@ Gem::Specification.new do |spec|
36
36
 
37
37
  spec.required_ruby_version = '>= 2.5.1'
38
38
 
39
- spec.add_development_dependency "bundler", "~> 2.0"
40
- spec.add_development_dependency "rake", "~> 12.3"
41
- spec.add_development_dependency "rspec", "~> 3.0"
39
+ spec.add_dependency 'awesome_print', '~> 1.8'
42
40
  end
metadata CHANGED
@@ -1,57 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prop_check
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.0
4
+ version: 0.10.4
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-21 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
- name: bundler
14
+ name: awesome_print
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '2.0'
20
- type: :development
19
+ version: '1.8'
20
+ type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '2.0'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '12.3'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '12.3'
41
- - !ruby/object:Gem::Dependency
42
- name: rspec
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '3.0'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '3.0'
26
+ version: '1.8'
55
27
  description: PropCheck allows you to do property-based testing, including shrinking.
56
28
  (akin to Haskell's QuickCheck, Erlang's PropEr, Elixir's StreamData). This means
57
29
  that your test are run many times with different, autogenerated inputs, and as soon
@@ -71,7 +43,6 @@ files:
71
43
  - CHANGELOG.md
72
44
  - CODE_OF_CONDUCT.md
73
45
  - Gemfile
74
- - Gemfile.lock
75
46
  - LICENSE.txt
76
47
  - README.md
77
48
  - Rakefile
@@ -82,9 +53,12 @@ files:
82
53
  - lib/prop_check/generators.rb
83
54
  - lib/prop_check/helper.rb
84
55
  - lib/prop_check/helper/lazy_append.rb
56
+ - lib/prop_check/hooks.rb
85
57
  - lib/prop_check/lazy_tree.rb
86
58
  - lib/prop_check/property.rb
87
59
  - lib/prop_check/property/configuration.rb
60
+ - lib/prop_check/property/output_formatter.rb
61
+ - lib/prop_check/property/shrinker.rb
88
62
  - lib/prop_check/version.rb
89
63
  - prop_check.gemspec
90
64
  homepage: https://github.com/Qqwy/ruby-prop_check/
@@ -1,50 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- prop_check (0.9.0)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- awesome_print (1.8.0)
10
- diff-lcs (1.3)
11
- docile (1.3.2)
12
- doctest-core (0.0.2)
13
- doctest-rspec (0.0.3)
14
- doctest-core (~> 0.0.2)
15
- rspec
16
- json (2.2.0)
17
- rake (12.3.3)
18
- rspec (3.8.0)
19
- rspec-core (~> 3.8.0)
20
- rspec-expectations (~> 3.8.0)
21
- rspec-mocks (~> 3.8.0)
22
- rspec-core (3.8.1)
23
- rspec-support (~> 3.8.0)
24
- rspec-expectations (3.8.4)
25
- diff-lcs (>= 1.2.0, < 2.0)
26
- rspec-support (~> 3.8.0)
27
- rspec-mocks (3.8.1)
28
- diff-lcs (>= 1.2.0, < 2.0)
29
- rspec-support (~> 3.8.0)
30
- rspec-support (3.8.2)
31
- simplecov (0.16.1)
32
- docile (~> 1.1)
33
- json (>= 1.8, < 3)
34
- simplecov-html (~> 0.10.0)
35
- simplecov-html (0.10.2)
36
-
37
- PLATFORMS
38
- ruby
39
-
40
- DEPENDENCIES
41
- awesome_print
42
- bundler (~> 2.0)
43
- doctest-rspec
44
- prop_check!
45
- rake (~> 12.3)
46
- rspec (~> 3.0)
47
- simplecov
48
-
49
- BUNDLED WITH
50
- 2.1.4