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