prop_check 0.15.0 → 0.16.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/run_tests.yaml +31 -0
- data/CHANGELOG.md +4 -0
- data/README.md +26 -21
- data/lib/prop_check/generators.rb +0 -1
- data/lib/prop_check/helper.rb +0 -5
- data/lib/prop_check/property/configuration.rb +6 -1
- data/lib/prop_check/property.rb +63 -1
- data/lib/prop_check/version.rb +1 -1
- metadata +3 -4
- data/.travis.yml +0 -18
- data/lib/prop_check/helper/lazy_append.rb +0 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 912a84633a6ab5b7f209555be0086e4dcafd371f337b289113003edf765fb668
|
4
|
+
data.tar.gz: 92146dcaf693c20f4cb3021178e881495de8b63f3819c254aea186a3780891c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 192ed9c6887dc19f29fc3d8aba9278eeb0fd389aab9fae546c940e2831833ea8064ea53e1e903c599d7d7ec2a8fe5bdc04a2c3122c2374a2d1d933b2184a2ab0
|
7
|
+
data.tar.gz: 63005af74e5f0d1757930f64ce031f5cc922e34b4e876cdaebbbf139280e9e923d134440f20ab63129c4fd1647d1e524b07b6ed3800828b29d22ad7e2cc5e394
|
@@ -0,0 +1,31 @@
|
|
1
|
+
name: Ruby RSpec tests
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master ]
|
8
|
+
|
9
|
+
permissions:
|
10
|
+
contents: read
|
11
|
+
|
12
|
+
jobs:
|
13
|
+
test:
|
14
|
+
|
15
|
+
runs-on: ubuntu-latest
|
16
|
+
strategy:
|
17
|
+
matrix:
|
18
|
+
ruby-version: ['2.5', '2.6', '2.7', '3.0']
|
19
|
+
|
20
|
+
steps:
|
21
|
+
- uses: actions/checkout@v3
|
22
|
+
- name: Set up Ruby
|
23
|
+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
24
|
+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
25
|
+
# uses: ruby/setup-ruby@v1
|
26
|
+
uses: ruby/setup-ruby@0a29871fe2b0200a17a4497bae54fe5df0d973aa # v1.115.3
|
27
|
+
with:
|
28
|
+
ruby-version: ${{ matrix.ruby-version }}
|
29
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
30
|
+
- name: Run tests
|
31
|
+
run: bundle exec rake
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
- 0.16.0
|
2
|
+
- Features:
|
3
|
+
- New option in `PropCheck::Property::Configuration` to resize all generators at once.
|
4
|
+
- Wrapper functions to modify this easily in `PropCheck::Property` called `#resize`, `#grow_fast`, `#grow_slowly`, `#grow_exponentially`, `#grow_quadratically`, `#grow_logarithmically`.
|
1
5
|
- 0.15.0
|
2
6
|
- Features:
|
3
7
|
- Generators for `Date`, `Time` and `DateTime`.
|
data/README.md
CHANGED
@@ -3,9 +3,9 @@
|
|
3
3
|
PropCheck allows you to do Property Testing in Ruby.
|
4
4
|
|
5
5
|
[![Gem](https://img.shields.io/gem/v/prop_check.svg)](https://rubygems.org/gems/prop_check)
|
6
|
-
[![
|
6
|
+
[![Ruby RSpec tests build status](https://github.com/Qqwy/ruby-prop_check/actions/workflows/run_tests.yaml/badge.svg)](https://github.com/Qqwy/ruby-prop_check/actions/workflows/run_tests.yaml)
|
7
7
|
[![Maintainability](https://api.codeclimate.com/v1/badges/71897f5e6193a5124a53/maintainability)](https://codeclimate.com/github/Qqwy/ruby-prop_check/maintainability)
|
8
|
-
[![RubyDoc](https://img.shields.io/badge/%F0%9F%93%9ARubyDoc-documentation-informational.svg)](https://www.rubydoc.info/github/Qqwy/ruby-prop_check/master/
|
8
|
+
[![RubyDoc](https://img.shields.io/badge/%F0%9F%93%9ARubyDoc-documentation-informational.svg)](https://www.rubydoc.info/github/Qqwy/ruby-prop_check/master/)
|
9
9
|
|
10
10
|
It features:
|
11
11
|
|
@@ -61,11 +61,11 @@ Before releasing v1.0, we want to finish the following:
|
|
61
61
|
- [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.
|
62
62
|
- [x] Possibility to resize generators.
|
63
63
|
- [x] `#instance` generator to allow the easy creation of generators for custom datatypes.
|
64
|
-
- [ ] A usage guide.
|
65
|
-
- [ ] A simple way to create recursive generators
|
66
64
|
- [x] Builtin generation of `Set`s
|
67
65
|
- [x] Builtin generation of `Date`s, `Time`s and `DateTime`s.
|
68
|
-
- [
|
66
|
+
- [x] Configuration option to resize all generators given to a particular Property instance.
|
67
|
+
- [ ] A simple way to create recursive generators
|
68
|
+
- [ ] A usage guide.
|
69
69
|
|
70
70
|
## Nice-to-haves
|
71
71
|
|
@@ -100,9 +100,9 @@ The value(s) generated from the generator(s) passed to the `forall` will be give
|
|
100
100
|
Raise an exception from the block if there is a problem. If there is no problem, just return normally.
|
101
101
|
|
102
102
|
```ruby
|
103
|
-
|
103
|
+
G = PropCheck::Generators
|
104
104
|
# testing that Enumerable#sort sorts in ascending order
|
105
|
-
PropCheck.forall(array(integer)) do |numbers|
|
105
|
+
PropCheck.forall(G.array(G.integer)) do |numbers|
|
106
106
|
sorted_numbers = numbers.sort
|
107
107
|
|
108
108
|
# Check that no number is smaller than the previous number
|
@@ -124,8 +124,8 @@ end
|
|
124
124
|
```
|
125
125
|
```ruby
|
126
126
|
# And then in a test case:
|
127
|
-
|
128
|
-
PropCheck.forall(numbers: array(integer)) do |numbers:|
|
127
|
+
G = PropCheck::Generators
|
128
|
+
PropCheck.forall(numbers: G.array(G.integer)) do |numbers:|
|
129
129
|
result = naive_average(numbers)
|
130
130
|
unless result.is_a?(Integer) do
|
131
131
|
raise "Expected the average to be an integer!"
|
@@ -135,10 +135,10 @@ end
|
|
135
135
|
# Or if you e.g. are using RSpec:
|
136
136
|
describe "#naive_average" do
|
137
137
|
include PropCheck
|
138
|
-
|
138
|
+
G = PropCheck::Generators
|
139
139
|
|
140
140
|
it "returns an integer for any input" do
|
141
|
-
forall(numbers: array(integer)) do |numbers:|
|
141
|
+
forall(numbers: G.array(G.integer)) do |numbers:|
|
142
142
|
result = naive_average(numbers)
|
143
143
|
expect(result).to be_a(Integer)
|
144
144
|
end
|
@@ -208,11 +208,12 @@ It contains generators for:
|
|
208
208
|
- (any, only real-valued) floats,
|
209
209
|
- (any, printable only, alphanumeric only, etc) strings and symbols
|
210
210
|
- fixed-size arrays and hashes
|
211
|
-
- as well as varying-size arrays and
|
211
|
+
- as well as varying-size arrays, hashes and sets.
|
212
|
+
- dates, times, datetimes.
|
212
213
|
- and many more!
|
213
214
|
|
214
|
-
It is common to
|
215
|
-
|
215
|
+
It is common and recommended to set up a module alias by using `G = PropCheck::Generators` in e.g. your testing-suite files to be able to refer to all of them.
|
216
|
+
_(Earlier versions of the library recommended including the module instead. But this will make it very simple to accidentally shadow a generator with a local variable named `float` or `array` and similar.)_
|
216
217
|
|
217
218
|
### Writing Custom Generators
|
218
219
|
|
@@ -228,33 +229,37 @@ Always returns the given value. No shrinking.
|
|
228
229
|
|
229
230
|
Allows you to take the result of one generator and transform it into something else.
|
230
231
|
|
231
|
-
>>
|
232
|
-
=> "S"
|
232
|
+
>> G.choose(32..128).map(&:chr).sample(1, size: 10, Random.new(42))
|
233
|
+
=> ["S"]
|
233
234
|
|
234
235
|
#### Generator#bind
|
235
236
|
|
236
237
|
Allows you to create one or another generator conditionally on the output of another generator.
|
237
238
|
|
238
|
-
>>
|
239
|
-
=> [2, 79]
|
239
|
+
>> G.integer.bind { |a| G.integer.bind { |b| G.constant([a , b]) } }.sample(1, size: 100, rng: Random.new(42)
|
240
|
+
=> [[2, 79]]
|
241
|
+
|
242
|
+
This is an advanced feature. Often, you can use a combination of `Generators.tuple` and `Generator#map` instead:
|
240
243
|
|
244
|
+
>> G.tuple(integer, integer).sample(1, size: 100, rng: Random.new(42)
|
245
|
+
=> [[2, 79]]
|
241
246
|
|
242
247
|
#### Generators.one_of
|
243
248
|
|
244
249
|
Useful if you want to be able to generate a value to be one of multiple possibilities:
|
245
250
|
|
246
251
|
|
247
|
-
>>
|
252
|
+
>> G.one_of(G.constant(true), G.constant(false)).sample(5, size: 10, rng: Random.new(42))
|
248
253
|
=> [true, false, true, true, true]
|
249
254
|
|
250
|
-
(
|
255
|
+
(Note that for this example, you can also use `G.boolean`. The example happens to show how it is implemented under the hood.)
|
251
256
|
|
252
257
|
#### Generators.frequency
|
253
258
|
|
254
259
|
If `one_of` does not give you enough flexibility because you want some results to be more common than others,
|
255
260
|
you can use `Generators.frequency` which takes a hash of (integer_frequency => generator) keypairs.
|
256
261
|
|
257
|
-
>>
|
262
|
+
>> G.frequency(5 => G.integer, 1 => G.printable_ascii_char).sample(size: 10, rng: Random.new(42))
|
258
263
|
=> [4, -3, 10, 8, 0, -7, 10, 1, "E", 10]
|
259
264
|
|
260
265
|
#### Others
|
data/lib/prop_check/helper.rb
CHANGED
@@ -18,6 +18,9 @@ module PropCheck
|
|
18
18
|
# - `default_epoch:` The 'base' value to use for date/time generators like
|
19
19
|
# `PropCheck::Generators#date` `PropCheck::Generators#future_date` `PropCheck::Generators#time`, etc.
|
20
20
|
# (Default: `DateTime.now`)
|
21
|
+
# - `resize_function` A proc that can be used to resize _all_ generators.
|
22
|
+
# Takes the current size as integer and should return a new integer.
|
23
|
+
# (Default: `proc { |size| size }`)
|
21
24
|
Configuration = Struct.new(
|
22
25
|
:verbose,
|
23
26
|
:n_runs,
|
@@ -25,6 +28,7 @@ module PropCheck
|
|
25
28
|
:max_shrink_steps,
|
26
29
|
:max_consecutive_attempts,
|
27
30
|
:default_epoch,
|
31
|
+
:resize_function,
|
28
32
|
keyword_init: true
|
29
33
|
) do
|
30
34
|
def initialize(
|
@@ -33,7 +37,8 @@ module PropCheck
|
|
33
37
|
max_generate_attempts: 10_000,
|
34
38
|
max_shrink_steps: 10_000,
|
35
39
|
max_consecutive_attempts: 30,
|
36
|
-
default_epoch: DateTime.now
|
40
|
+
default_epoch: DateTime.now,
|
41
|
+
resize_function: proc { |size| size }
|
37
42
|
)
|
38
43
|
super
|
39
44
|
end
|
data/lib/prop_check/property.rb
CHANGED
@@ -111,6 +111,67 @@ module PropCheck
|
|
111
111
|
duplicate
|
112
112
|
end
|
113
113
|
|
114
|
+
##
|
115
|
+
# Resizes all generators in this property with the given function.
|
116
|
+
#
|
117
|
+
# Shorthand for manually wrapping `PropCheck::Property::Configuration.resize_function` with the new function.
|
118
|
+
def resize(&block)
|
119
|
+
raise '#resize called without a block' unless block_given?
|
120
|
+
|
121
|
+
orig_fun = @config.resize_function
|
122
|
+
with_config(resize_function: block)
|
123
|
+
end
|
124
|
+
|
125
|
+
##
|
126
|
+
# Resizes all generators in this property. The new size is `2.pow(orig_size)`
|
127
|
+
#
|
128
|
+
# c.f. #resize
|
129
|
+
def growing_exponentially(&block)
|
130
|
+
orig_fun = @config.resize_function
|
131
|
+
fun = proc { |size| 2.pow(orig_fun.call(size)) }
|
132
|
+
with_config(resize_function: fun, &block)
|
133
|
+
end
|
134
|
+
|
135
|
+
##
|
136
|
+
# Resizes all generators in this property. The new size is `orig_size * orig_size`
|
137
|
+
#
|
138
|
+
# c.f. #resize
|
139
|
+
def growing_quadratically(&block)
|
140
|
+
orig_fun = @config.resize_function
|
141
|
+
fun = proc { |size| orig_fun.call(size).pow(2) }
|
142
|
+
with_config(resize_function: fun, &block)
|
143
|
+
end
|
144
|
+
|
145
|
+
##
|
146
|
+
# Resizes all generators in this property. The new size is `2 * orig_size`
|
147
|
+
#
|
148
|
+
# c.f. #resize
|
149
|
+
def growing_fast(&block)
|
150
|
+
orig_fun = @config.resize_function
|
151
|
+
fun = proc { |size| orig_fun.call(size) * 2 }
|
152
|
+
with_config(resize_function: fun, &block)
|
153
|
+
end
|
154
|
+
|
155
|
+
##
|
156
|
+
# Resizes all generators in this property. The new size is `0.5 * orig_size`
|
157
|
+
#
|
158
|
+
# c.f. #resize
|
159
|
+
def growing_slowly(&block)
|
160
|
+
orig_fun = @config.resize_function
|
161
|
+
fun = proc { |size| orig_fun.call(size) * 0.5 }
|
162
|
+
with_config(resize_function: fun, &block)
|
163
|
+
end
|
164
|
+
|
165
|
+
##
|
166
|
+
# Resizes all generators in this property. The new size is `Math.log2(orig_size)`
|
167
|
+
#
|
168
|
+
# c.f. #resize
|
169
|
+
def growing_logarithmically(&block)
|
170
|
+
orig_fun = @config.resize_function
|
171
|
+
fun = proc { |size| Math.log2(orig_fun.call(size)) }
|
172
|
+
with_config(resize_function: fun, &block)
|
173
|
+
end
|
174
|
+
|
114
175
|
def with_bindings(*bindings, **kwbindings)
|
115
176
|
raise ArgumentError, 'No bindings specified!' if bindings.empty? && kwbindings.empty?
|
116
177
|
|
@@ -279,8 +340,9 @@ c.f. https://www.ruby-lang.org/en/news/2019/12/12/separation-of-positional-and-k
|
|
279
340
|
(0...@config.max_generate_attempts)
|
280
341
|
.lazy
|
281
342
|
.map do
|
343
|
+
generator_size = @config.resize_function.call(size).to_i
|
282
344
|
binding_generator.generate(
|
283
|
-
size:
|
345
|
+
size: generator_size,
|
284
346
|
rng: rng,
|
285
347
|
max_consecutive_attempts: @config.max_consecutive_attempts,
|
286
348
|
config: @config
|
data/lib/prop_check/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: prop_check
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Qqwy/Wiebe-Marten Wijnja
|
@@ -35,11 +35,11 @@ executables: []
|
|
35
35
|
extensions: []
|
36
36
|
extra_rdoc_files: []
|
37
37
|
files:
|
38
|
+
- ".github/workflows/run_tests.yaml"
|
38
39
|
- ".gitignore"
|
39
40
|
- ".rspec"
|
40
41
|
- ".rubocop.yml"
|
41
42
|
- ".tool-versions"
|
42
|
-
- ".travis.yml"
|
43
43
|
- CHANGELOG.md
|
44
44
|
- CODE_OF_CONDUCT.md
|
45
45
|
- Gemfile
|
@@ -53,7 +53,6 @@ files:
|
|
53
53
|
- lib/prop_check/generator.rb
|
54
54
|
- lib/prop_check/generators.rb
|
55
55
|
- lib/prop_check/helper.rb
|
56
|
-
- lib/prop_check/helper/lazy_append.rb
|
57
56
|
- lib/prop_check/hooks.rb
|
58
57
|
- lib/prop_check/lazy_tree.rb
|
59
58
|
- lib/prop_check/property.rb
|
@@ -84,7 +83,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
83
|
- !ruby/object:Gem::Version
|
85
84
|
version: '0'
|
86
85
|
requirements: []
|
87
|
-
rubygems_version: 3.
|
86
|
+
rubygems_version: 3.2.3
|
88
87
|
signing_key:
|
89
88
|
specification_version: 4
|
90
89
|
summary: PropCheck allows you to do property-based testing, including shrinking.
|
data/.travis.yml
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
---
|
2
|
-
sudo: false
|
3
|
-
language: ruby
|
4
|
-
cache: bundler
|
5
|
-
rvm:
|
6
|
-
- 2.6.5
|
7
|
-
before_install: gem install bundler -v 2.0.2
|
8
|
-
env:
|
9
|
-
global:
|
10
|
-
- CC_TEST_REPORTER_ID=9d18f5b43e49eecd6c3da64d85ea9c765d3606c129289d7c8cadf6d448713311
|
11
|
-
before_script:
|
12
|
-
- curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
13
|
-
- chmod +x ./cc-test-reporter
|
14
|
-
- ./cc-test-reporter before-build
|
15
|
-
script:
|
16
|
-
- bundle exec rspec
|
17
|
-
after_script:
|
18
|
-
- ./cc-test-reporter after-build --exit-code $TRAVIS_TEST_RESULT
|
@@ -1,18 +0,0 @@
|
|
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
|