prop_check 0.17.0 → 0.18.0

Sign up to get free protection for your applications and to get access to all the features.
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