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
hookafter each time a check is run with new data. -
#around(&hook) ⇒ Object
Calls
hookaround each time a check is run with new data. -
#before(&hook) ⇒ Object
Calls
hookbefore 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 |