Class: PropCheck::Property
- Inherits:
-
Object
- Object
- PropCheck::Property
- Defined in:
- lib/prop_check/property.rb,
lib/prop_check/property/configuration.rb
Overview
Create and run property-checks.
For simple usage, see ‘.forall`.
For advanced usage, call ‘PropCheck::Property.new(…)` and then configure it to your liking using e.g. `#with_config`, `#before`, `#after`, `#around` etc. Each of these methods will return a new `Property`, so earlier properties are not mutated. This allows you to re-use configuration and hooks between multiple tests.
Defined Under Namespace
Modules: OutputFormatter Classes: Configuration, Shrinker
Class Method Summary collapse
-
.configuration ⇒ Object
Returns the default configuration of the library as it is configured right now for introspection.
-
.configure {|configuration| ... } ⇒ Object
Yields the library’s configuration object for you to alter.
-
.forall(*bindings, **kwbindings, &block) ⇒ Object
Main entry-point to create (and possibly immediately run) a property-test.
Instance Method Summary collapse
-
#after(&hook) ⇒ Object
Calls ‘hook` after each time a check is run with new data.
-
#around(&hook) ⇒ Object
Calls ‘hook` around each time a check is run with new data.
-
#before(&hook) ⇒ Object
Calls ‘hook` before each time a check is run with new data.
-
#check(&block) ⇒ Object
Checks the property (after settings have been altered using the other instance methods in this class.).
-
#configuration ⇒ Object
Returns the configuration of this property for introspection.
-
#growing_exponentially(&block) ⇒ Object
Resizes all generators in this property.
-
#growing_fast(&block) ⇒ Object
Resizes all generators in this property.
-
#growing_logarithmically(&block) ⇒ Object
Resizes all generators in this property.
-
#growing_quadratically(&block) ⇒ Object
Resizes all generators in this property.
-
#growing_slowly(&block) ⇒ Object
Resizes all generators in this property.
-
#initialize(*bindings, **kwbindings) ⇒ Property
constructor
A new instance of Property.
-
#resize(&block) ⇒ Object
Resizes all generators in this property with the given function.
-
#where(&condition) ⇒ Object
filters the generator using the given ‘condition`.
- #with_bindings(*bindings, **kwbindings) ⇒ Object
-
#with_config(**config, &block) ⇒ Object
Allows you to override the configuration of this property by giving a hash with new settings.
Constructor Details
#initialize(*bindings, **kwbindings) ⇒ Property
Returns a new instance of Property.
65 66 67 68 69 70 71 |
# File 'lib/prop_check/property.rb', line 65 def initialize(*bindings, **kwbindings) @config = self.class.configuration @hooks = PropCheck::Hooks.new @gen = gen_from_bindings(bindings, kwbindings) unless bindings.empty? && kwbindings.empty? freeze end |
Class Method Details
.configuration ⇒ Object
Returns the default configuration of the library as it is configured right now for introspection.
For the configuration of a single property, check its ‘configuration` instance method. See PropCheck::Property::Configuration for more info on available settings.
54 55 56 |
# File 'lib/prop_check/property.rb', line 54 def self.configuration @configuration ||= Configuration.new end |
.configure {|configuration| ... } ⇒ Object
Yields the library’s configuration object for you to alter. See PropCheck::Property::Configuration for more info on available settings.
61 62 63 |
# File 'lib/prop_check/property.rb', line 61 def self.configure yield(configuration) end |
.forall(*bindings, **kwbindings, &block) ⇒ Object
Main entry-point to create (and possibly immediately run) a property-test.
This method accepts a list of generators and a block. The block will then be executed many times, passing the values generated by the generators as respective arguments:
“‘ include PropCheck::Generators PropCheck.forall(integer(), float()) { |x, y| … } “`
It is also possible (and recommended when having more than a few generators) to use a keyword-list of generators instead:
“‘ include PropCheck::Generators PropCheck.forall(x: integer(), y: float()) { |x:, y:| … } “`
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)
43 44 45 46 |
# File 'lib/prop_check/property.rb', line 43 def self.forall(*bindings, **kwbindings, &block) new(*bindings, **kwbindings) .check(&block) end |
Instance Method Details
#after(&hook) ⇒ Object
Calls ‘hook` after each time a check is run with new data.
This is useful to add teardown logic When called multiple times, earlier-added hooks will be called after ‘hook` is called.
215 216 217 218 219 220 |
# File 'lib/prop_check/property.rb', line 215 def after(&hook) duplicate = dup duplicate.instance_variable_set(:@hooks, @hooks.add_after(&hook)) duplicate.freeze duplicate end |
#around(&hook) ⇒ Object
Calls ‘hook` around each time a check is run with new data.
‘hook` should `yield` to the passed block.
When called multiple times, earlier-added hooks will be wrapped around ‘hook`.
Around hooks will be called after all ‘#before` hooks and before all `#after` hooks.
Note that if the block passed to ‘hook` raises an exception, it is possible for the code after `yield` not to be called. So make sure that cleanup logic is wrapped with the `ensure` keyword.
235 236 237 238 239 240 |
# File 'lib/prop_check/property.rb', line 235 def around(&hook) duplicate = dup duplicate.instance_variable_set(:@hooks, @hooks.add_around(&hook)) duplicate.freeze duplicate end |
#before(&hook) ⇒ Object
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.
203 204 205 206 207 208 |
# File 'lib/prop_check/property.rb', line 203 def before(&hook) duplicate = dup duplicate.instance_variable_set(:@hooks, @hooks.add_before(&hook)) duplicate.freeze duplicate end |
#check(&block) ⇒ Object
Checks the property (after settings have been altered using the other instance methods in this class.)
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/prop_check/property.rb', line 244 def check(&block) return self unless block_given? n_runs = 0 n_successful = 0 # Loop stops at first exception 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 |
#configuration ⇒ Object
Returns the configuration of this property for introspection.
See PropCheck::Property::Configuration for more info on available settings.
89 90 91 |
# File 'lib/prop_check/property.rb', line 89 def configuration @config end |
#growing_exponentially(&block) ⇒ Object
Resizes all generators in this property. The new size is ‘2.pow(orig_size)`
c.f. #resize
123 124 125 126 127 |
# File 'lib/prop_check/property.rb', line 123 def growing_exponentially(&block) orig_fun = @config.resize_function fun = proc { |size| 2.pow(orig_fun.call(size)) } with_config(resize_function: fun, &block) end |
#growing_fast(&block) ⇒ Object
Resizes all generators in this property. The new size is ‘2 * orig_size`
c.f. #resize
143 144 145 146 147 |
# File 'lib/prop_check/property.rb', line 143 def growing_fast(&block) orig_fun = @config.resize_function fun = proc { |size| orig_fun.call(size) * 2 } with_config(resize_function: fun, &block) end |
#growing_logarithmically(&block) ⇒ Object
Resizes all generators in this property. The new size is ‘Math.log2(orig_size)`
c.f. #resize
163 164 165 166 167 |
# File 'lib/prop_check/property.rb', line 163 def growing_logarithmically(&block) orig_fun = @config.resize_function fun = proc { |size| Math.log2(orig_fun.call(size)) } with_config(resize_function: fun, &block) end |
#growing_quadratically(&block) ⇒ Object
Resizes all generators in this property. The new size is ‘orig_size * orig_size`
c.f. #resize
133 134 135 136 137 |
# File 'lib/prop_check/property.rb', line 133 def growing_quadratically(&block) orig_fun = @config.resize_function fun = proc { |size| orig_fun.call(size).pow(2) } with_config(resize_function: fun, &block) end |
#growing_slowly(&block) ⇒ Object
Resizes all generators in this property. The new size is ‘0.5 * orig_size`
c.f. #resize
153 154 155 156 157 |
# File 'lib/prop_check/property.rb', line 153 def growing_slowly(&block) orig_fun = @config.resize_function fun = proc { |size| orig_fun.call(size) * 0.5 } with_config(resize_function: fun, &block) end |
#resize(&block) ⇒ Object
Resizes all generators in this property with the given function.
Shorthand for manually wrapping ‘PropCheck::Property::Configuration.resize_function` with the new function.
112 113 114 115 116 117 |
# File 'lib/prop_check/property.rb', line 112 def resize(&block) raise '#resize called without a block' unless block_given? orig_fun = @config.resize_function with_config(resize_function: block) end |
#where(&condition) ⇒ Object
filters the generator using the given ‘condition`. The final property checking block will only be run if the condition is truthy.
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.
186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/prop_check/property.rb', line 186 def where(&condition) unless @gen raise ArgumentError, 'No generator bindings specified! #where should be called after `#forall` or `#with_bindings`.' end duplicate = dup duplicate.instance_variable_set(:@gen, @gen.where(&condition)) duplicate.freeze duplicate end |
#with_bindings(*bindings, **kwbindings) ⇒ Object
169 170 171 172 173 174 175 176 |
# File 'lib/prop_check/property.rb', line 169 def with_bindings(*bindings, **kwbindings) raise ArgumentError, 'No bindings specified!' if bindings.empty? && kwbindings.empty? duplicate = dup duplicate.instance_variable_set(:@gen, gen_from_bindings(bindings, kwbindings)) duplicate.freeze duplicate end |
#with_config(**config, &block) ⇒ Object
Allows you to override the configuration of this property by giving a hash with new settings.
If no other changes need to occur before you want to check the property, you can immediately pass a block to this method. (so ‘forall(a: Generators.integer).with_config(verbose: true) do … end` is the same as `forall(a: Generators.integer).with_config(verbose: true).check do … end`)
100 101 102 103 104 105 106 |
# File 'lib/prop_check/property.rb', line 100 def with_config(**config, &block) duplicate = dup duplicate.instance_variable_set(:@config, @config.merge(config)) duplicate.freeze duplicate.check(&block) end |