lib/prop_check/property.rb in prop_check-0.11.0 vs lib/prop_check/property.rb in prop_check-0.11.1
- old
+ new
@@ -33,13 +33,13 @@
#
# If you do not pass a block right away,
# a Property object is returned, which you can call the other instance methods
# of this class on before finally passing a block to it using `#check`.
# (so `forall(Generators.integer) do |val| ... end` and forall(Generators.integer).check do |val| ... end` are the same)
- def self.forall(*bindings, &block)
+ def self.forall(*bindings, **kwbindings, &block)
- property = new(*bindings)
+ property = new(*bindings, **kwbindings)
return property.check(&block) if block_given?
property
end
@@ -64,12 +64,13 @@
attr_reader :bindings, :condition
def initialize(*bindings, **kwbindings)
raise ArgumentError, 'No bindings specified!' if bindings.empty? && kwbindings.empty?
- @bindings = bindings
- @kwbindings = kwbindings
+ # @bindings = bindings
+ # @kwbindings = kwbindings
+ @gen = gen_from_bindings(bindings, kwbindings)
@condition = proc { true }
@config = self.class.configuration
@hooks = PropCheck::Hooks.new
end
@@ -104,18 +105,21 @@
# If wanted, multiple `where`-conditions can be specified on a property.
# Be aware that if you filter away too much generated inputs,
# you might encounter a GeneratorExhaustedError.
# Only filter if you have few inputs to reject. Otherwise, improve your generators.
def where(&condition)
- original_condition = @condition.dup
- @condition = proc do |*args|
- original_condition.call(*args) && condition.call(*args)
- end
+ # original_condition = @condition.dup
+ # @condition = proc do |val|
+ # call_splatted(val, &original_condition) && call_splatted(val, &condition)
+ # # original_condition.call(val) && condition.call(val)
+ # end
+ @gen = @gen.where(&condition)
self
end
+
##
# Calls `hook` before each time a check is run with new data.
#
# This is useful to add setup logic
# When called multiple times, earlier-added hooks will be called _before_ `hook` is called.
@@ -153,33 +157,42 @@
end
##
# Checks the property (after settings have been altered using the other instance methods in this class.)
def check(&block)
- gens =
- if @kwbindings != {}
- kwbinding_generator = PropCheck::Generators.fixed_hash(**@kwbindings)
- @bindings + [kwbinding_generator]
- else
- @bindings
- end
- binding_generator = PropCheck::Generators.tuple(*gens)
- # binding_generator = PropCheck::Generators.fixed_hash(**@kwbindings)
-
n_runs = 0
n_successful = 0
# Loop stops at first exception
- attempts_enum(binding_generator).each do |generator_result|
+ attempts_enum(@gen).each do |generator_result|
n_runs += 1
check_attempt(generator_result, n_successful, &block)
n_successful += 1
end
ensure_not_exhausted!(n_runs)
end
+ private def gen_from_bindings(bindings, kwbindings)
+ if bindings == [] && kwbindings != {}
+ PropCheck::Generators.fixed_hash(**kwbindings)
+ elsif bindings != [] && kwbindings == {}
+ if bindings.size == 1
+ bindings.first
+ else
+ PropCheck::Generators.tuple(*bindings)
+ end
+ else
+ raise ArgumentError,
+ 'Attempted to use both normal and keyword bindings at the same time.
+This is not supported because of the separation of positional and keyword arguments
+(the old behaviour is deprecated in Ruby 2.7 and will be removed in 3.0)
+c.f. https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-keyword-arguments-in-ruby-3-0/
+ '
+ end
+ end
+
private def ensure_not_exhausted!(n_runs)
return if n_runs >= @config.n_runs
raise_generator_exhausted!
end
@@ -194,11 +207,11 @@
Try refining your generators instead.
"""
end
private def check_attempt(generator_result, n_successful, &block)
- block.call(*generator_result.root)
+ PropCheck::Helper.call_splatted(generator_result.root, &block)
# immediately stop (without shrinnking) for when the app is asked
# to close by outside intervention
rescue SignalException, SystemExit
raise
@@ -234,12 +247,10 @@
private def raw_attempts_enum(binding_generator)
rng = Random::DEFAULT
size = 1
(0...@config.max_generate_attempts)
.lazy
- .map { binding_generator.generate(size, rng) }
- .reject { |val| val.root.any? { |elem| elem == :"_PropCheck.filter_me" }}
- .select { |val| @condition.call(*val.root) }
+ .map { binding_generator.generate(size: size, rng: rng, max_consecutive_attempts: @config.max_consecutive_attempts) }
.map do |result|
size += 1
result
end