prop_check 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e59cf670bcc8cf9720d6278e984925c50e75ca65023459174f8b511d6421fb71
4
- data.tar.gz: '088e0eb8d2d301bc3c03cc63bf68196969e8653cad37ff0b9d5d10f9b417a1ae'
3
+ metadata.gz: ba078df3937d6f069a4ed24e9aaed9617dc1eb03139be0189e51b060b11a75ba
4
+ data.tar.gz: 0fe77f31d282754df6712aafae7995e82e99d9ee86f8ad12bd060596147dafe1
5
5
  SHA512:
6
- metadata.gz: de5808bced970e0c474367bf125837ac0eefa4aa752acb31cd74e884fea858b98fb518e9fe15493c81f8238e5e0490f3cbc855eda3a9b687196ca7830daad0aa
7
- data.tar.gz: 312957d1ab0f990985f43ae7e4b0793df583ff2d3d8bb95573c11fe3e4d9c5f964d91050fe9bafb98ceb92dd6790d2ffce04257b02b0c152d75d9b4772b7423a
6
+ metadata.gz: e49791f3e5a380e822f4d86f39444a09e26828c4b1ea7c90d298c9eedcc14d8c6fdc05864439e1984b0cead4183beb1ae108bee82c7ce6dccbe11aae5efbd248
7
+ data.tar.gz: cddd15cf550e166ec93d15fa2ffdf07a68646aa6750d544b6a5cf64c9bfb44177b638e6ff1df2ce25e28105df05aa838534e6eaafadefb7688aed32dae9d3bbc
@@ -2,9 +2,9 @@ name: Ruby RSpec tests
2
2
 
3
3
  on:
4
4
  push:
5
- branches: [ master ]
5
+ branches: [ main ]
6
6
  pull_request:
7
- branches: [ master ]
7
+ branches: [ main ]
8
8
 
9
9
  permissions:
10
10
  contents: read
data/CHANGELOG.md CHANGED
@@ -1,3 +1,6 @@
1
+ - 0.18.0
2
+ - Features:
3
+ - Allows calling `PropCheck::Property#check` without a block, which will just return `self`. This is useful for writing wrapper functions that use `before/after/around/with_config` etc hooks which might themselves optionally want a block so they can be chained. (See the `forall_with_db` snippet in the README for an example)
1
4
  - 0.17.0
2
5
  - Features:
3
6
  - Recursive generation using `PropCheck::Generators.tree`.
data/README.md CHANGED
@@ -40,9 +40,9 @@ It works by generating arbitrary data matching your specification and checking t
40
40
 
41
41
  Writing these kinds of tests usually consists of deciding on guarantees that your code should have -- properties that should always hold true, regardless of wat the world throws at you. Some examples are:
42
42
 
43
- - Your code should not throw an exception, or only a particular type of exception.
43
+ - Your code should never crash.
44
44
  - If you remove an object, you can no longer see it
45
- - If you serialize and then deserializea value, you get the same value back.
45
+ - If you serialize and then deserialize a value, you get the same value back.
46
46
 
47
47
 
48
48
  ## Implemented and still missing features
@@ -107,7 +107,7 @@ PropCheck.forall(G.array(G.integer)) do |numbers|
107
107
 
108
108
  # Check that no number is smaller than the previous number
109
109
  sorted_numbers.each_cons(2) do |former, latter|
110
- raise "Elements are not sorted! #{latter} is < #{former}" if latter < former
110
+ raise "Elements are not sorted! #{latter} is < #{former}" if latter > former
111
111
  end
112
112
  end
113
113
  ```
@@ -122,32 +122,53 @@ def naive_average(array)
122
122
  array.sum / array.length
123
123
  end
124
124
  ```
125
- ```ruby
126
- # And then in a test case:
127
- G = PropCheck::Generators
128
- PropCheck.forall(numbers: G.array(G.integer)) do |numbers:|
129
- result = naive_average(numbers)
130
- unless result.is_a?(Integer) do
131
- raise "Expected the average to be an integer!"
132
- end
133
- end
134
125
 
135
- # Or if you e.g. are using RSpec:
136
- describe "#naive_average" do
137
- include PropCheck
126
+ The test case, using RSpec:
127
+ ``` ruby
128
+ require 'rspec'
129
+
130
+ RSpec.describe "#naive_average" do
138
131
  G = PropCheck::Generators
139
132
 
140
133
  it "returns an integer for any input" do
141
- forall(numbers: G.array(G.integer)) do |numbers:|
142
- result = naive_average(numbers)
134
+ PropCheck.forall(G.array(G.integer)) do |numbers|
135
+ result = naive_average(numbers)
136
+
143
137
  expect(result).to be_a(Integer)
144
138
  end
145
139
  end
146
140
  end
147
141
  ```
148
142
 
149
- When running this particular example PropCheck very quickly finds out that we have made a programming mistake:
143
+ The test case, using MiniTest:
144
+ ``` ruby
145
+ require 'minitest/autorun'
146
+ class NaiveAverageTest < MiniTest::Unit::TestCase
147
+ G = PropCheck::Generators
148
+
149
+ def test_that_it_returns_an_integer_for_any_input()
150
+ PropCheck.forall(G.array(G.integer)) do |numbers|
151
+ result = naive_average(numbers)
152
+
153
+ assert_instance_of(Integer, result)
154
+ end
155
+ end
156
+ end
157
+ ```
150
158
 
159
+ The test case, using only vanilla Ruby:
160
+ ```ruby
161
+ # And then in a test case:
162
+ G = PropCheck::Generators
163
+
164
+ PropCheck.forall(G.array(G.integer)) do |numbers|
165
+ result = naive_average(numbers)
166
+
167
+ raise "Expected the average to be an integer!" unless result.is_a?(Integer)
168
+ end
169
+ ```
170
+
171
+ When running this particular example PropCheck very quickly finds out that we have made a programming mistake:
151
172
  ```ruby
152
173
  ZeroDivisionError:
153
174
  (after 6 successful property test runs)
@@ -270,6 +291,26 @@ although above are the most generally useful ones.
270
291
  [PropCheck::Generator documentation](https://www.rubydoc.info/github/Qqwy/ruby-prop_check/master/PropCheck/Generator)
271
292
  [PropCheck::Generators documentation](https://www.rubydoc.info/github/Qqwy/ruby-prop_check/master/PropCheck/Generators)
272
293
 
294
+
295
+ ## Usage within Rails / with a database
296
+
297
+ Using PropCheck for unit tests in a Rails, Sinatra, Hanami, etc. project is very easy.
298
+ Here are some simple recommendations for the best results:
299
+ - Tests that do not need to use the DB at all are usually 10x-100x faster. Faster tests means that you can configure PropCheck to do more test runs.
300
+ - If you do need to use the database, use the [database_cleaner](https://github.com/DatabaseCleaner/database_cleaner) gem, preferibly with the fast `:transaction` strategy if your RDBMS supports it. To make sure the DB is cleaned around each generated example, you can write the following helper:
301
+ ``` ruby
302
+ # Version of PropCheck.forall
303
+ # which ensures records persisted to the DB in one generated example
304
+ # do not affect any other
305
+ def forall_with_db(*args, **kwargs, &block)
306
+ PropCheck.forall(*args, **kwargs)
307
+ .before { DatabaseCleaner.start }
308
+ .after { DatabaseCleaner.clean }
309
+ .check(&block)
310
+ end
311
+ ```
312
+ - Other setup/cleanup should also usually happen around each generated example rather than around the whole test: Instead of using the hooks exposed by RSpec/MiniTest/etc., use the before/after/around hooks exposed by PropCheck.
313
+
273
314
  ## Development
274
315
 
275
316
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -286,7 +327,7 @@ The gem is available as open source under the terms of the [MIT License](https:/
286
327
 
287
328
  ## Code of Conduct
288
329
 
289
- Everyone interacting in the PropCheck project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/prop_check/blob/master/CODE_OF_CONDUCT.md).
330
+ Everyone interacting in the PropCheck project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/Qqwy/ruby-prop_check/blob/master/CODE_OF_CONDUCT.md).
290
331
 
291
332
  ## Attribution and Thanks
292
333
 
@@ -294,7 +335,7 @@ I want to thank the original creators of QuickCheck (Koen Claessen, John Hughes)
294
335
  I also want to greatly thank Thomasz Kowal who made me excited about property based testing [with his great talk about stateful property testing](https://www.youtube.com/watch?v=q0wZzFUYCuM),
295
336
  as well as Fred Herbert for his great book [Property-Based Testing with PropEr, Erlang and Elixir](https://propertesting.com/) which is really worth the read (regardless of what language you are using).
296
337
 
297
- The implementation and API of PropCheck takes a lot of inspiration from the following pre-existing libraries:
338
+ The implementation and API of PropCheck takes a lot of inspiration from the following projects:
298
339
 
299
340
  - Haskell's [QuickCheck](https://hackage.haskell.org/package/QuickCheck) and [Hedgehog](https://hackage.haskell.org/package/hedgehog);
300
341
  - Erlang's [PropEr](https://hex.pm/packages/proper);
@@ -116,7 +116,7 @@ module PropCheck
116
116
  # and act on it.
117
117
  #
118
118
  # >> Generators.choose(0..100).with_config.map { |int, conf| Date.jd(conf[:default_epoch].jd + int) }.call(size: 10, rng: Random.new(42), config: PropCheck::Property::Configuration.new)
119
- # => Date.new(2023, 01, 10)
119
+ # => Date.new(2023, 01, 12)
120
120
  def with_config
121
121
  Generator.new do |**kwargs|
122
122
  result = generate(**kwargs)
@@ -769,7 +769,7 @@ module PropCheck
769
769
  # DateTimes start around the given `epoch:` and deviate more when `size` increases.
770
770
  # when no epoch is set, `PropCheck::Property::Configuration.default_epoch` is used, which defaults to `DateTime.now`.
771
771
  #
772
- # >> PropCheck::Generators.datetime.sample(2, rng: Random.new(42), config: PropCheck::Property::Configuration.new)
772
+ # >> PropCheck::Generators.datetime(epoch: Date.new(2022, 11, 20)).sample(2, rng: Random.new(42), config: PropCheck::Property::Configuration.new)
773
773
  # => [DateTime.parse("2022-11-17 07:11:59.999983907 +0000"), DateTime.parse("2022-11-19 05:27:16.363618076 +0000")]
774
774
  def datetime(epoch: nil)
775
775
  datetime_from_offset(real_float, epoch: epoch)
@@ -785,7 +785,7 @@ module PropCheck
785
785
  ##
786
786
  # Variant of `#datetime` that only generates datetimes in the future (relative to `:epoch`).
787
787
  #
788
- # >> PropCheck::Generators.future_datetime.sample(2, rng: Random.new(42), config: PropCheck::Property::Configuration.new).map(&:inspect)
788
+ # >> PropCheck::Generators.future_datetime(epoch: Date.new(2022, 11, 20)).sample(2, rng: Random.new(42), config: PropCheck::Property::Configuration.new).map(&:inspect)
789
789
  # => ["#<DateTime: 2022-11-21T16:48:00+00:00 ((2459905j,60480s,16093n),+0s,2299161j)>", "#<DateTime: 2022-11-19T18:32:43+00:00 ((2459903j,66763s,636381924n),+0s,2299161j)>"]
790
790
  def future_datetime(epoch: nil)
791
791
  datetime_from_offset(real_positive_float, epoch: epoch)
@@ -794,7 +794,7 @@ module PropCheck
794
794
  ##
795
795
  # Variant of `#datetime` that only generates datetimes in the past (relative to `:epoch`).
796
796
  #
797
- # >> PropCheck::Generators.past_datetime.sample(2, rng: Random.new(42), config: PropCheck::Property::Configuration.new)
797
+ # >> PropCheck::Generators.past_datetime(epoch: Date.new(2022, 11, 20)).sample(2, rng: Random.new(42), config: PropCheck::Property::Configuration.new)
798
798
  # => [DateTime.parse("2022-11-17 07:11:59.999983907 +0000"), DateTime.parse("2022-11-19 05:27:16.363618076 +0000")]
799
799
  def past_datetime(epoch: nil)
800
800
  datetime_from_offset(real_negative_float, epoch: epoch)
@@ -805,7 +805,7 @@ module PropCheck
805
805
  # Times start around the given `epoch:` and deviate more when `size` increases.
806
806
  # when no epoch is set, `PropCheck::Property::Configuration.default_epoch` is used, which defaults to `DateTime.now`.
807
807
  #
808
- # >> PropCheck::Generators.time.sample(2, rng: Random.new(42), config: PropCheck::Property::Configuration.new)
808
+ # >> PropCheck::Generators.time(epoch: Date.new(2022, 11, 20)).sample(2, rng: Random.new(42), config: PropCheck::Property::Configuration.new)
809
809
  # => [DateTime.parse("2022-11-17 07:11:59.999983907 +0000").to_time, DateTime.parse("2022-11-19 05:27:16.363618076 +0000").to_time]
810
810
  def time(epoch: nil)
811
811
  datetime(epoch: epoch).map(&:to_time)
@@ -42,11 +42,8 @@ module PropCheck
42
42
  # of this class on before finally passing a block to it using `#check`.
43
43
  # (so `forall(Generators.integer) do |val| ... end` and forall(Generators.integer).check do |val| ... end` are the same)
44
44
  def self.forall(*bindings, **kwbindings, &block)
45
- property = new(*bindings, **kwbindings)
46
-
47
- return property.check(&block) if block_given?
48
-
49
- property
45
+ new(*bindings, **kwbindings)
46
+ .check(&block)
50
47
  end
51
48
 
52
49
  ##
@@ -106,9 +103,7 @@ module PropCheck
106
103
  duplicate.instance_variable_set(:@config, @config.merge(config))
107
104
  duplicate.freeze
108
105
 
109
- return duplicate.check(&block) if block_given?
110
-
111
- duplicate
106
+ duplicate.check(&block)
112
107
  end
113
108
 
114
109
  ##
@@ -248,6 +243,8 @@ module PropCheck
248
243
  ##
249
244
  # Checks the property (after settings have been altered using the other instance methods in this class.)
250
245
  def check(&block)
246
+ return self unless block_given?
247
+
251
248
  n_runs = 0
252
249
  n_successful = 0
253
250
 
@@ -1,3 +1,3 @@
1
1
  module PropCheck
2
- VERSION = '0.17.0'
2
+ VERSION = '0.18.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prop_check
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Qqwy/Wiebe-Marten Wijnja
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-11-20 00:00:00.000000000 Z
11
+ date: 2022-11-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: amazing_print