pbt 0.3.0 → 0.4.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: 8415f37c2819e6370e7d418cb96d8ae2467fec24cfca1e64088c925874dc0c34
4
- data.tar.gz: f6b38e54ec98fa669cc379c6c181e210d5fab02fc076a343e941aa17cb5be476
3
+ metadata.gz: 9ce157507d0afc004a4d8993baecfb14dc4f0a14d381a996c33c15a02e8c496e
4
+ data.tar.gz: 71d314990ce4ee1ae4012a9af90666931edecba089851f8e3ea686696048c154
5
5
  SHA512:
6
- metadata.gz: cf614cf7100cbbf13f197dbc2a088e43c8b01fac31eaddc8d24ce5f1da7ed14140e3c59e3cafa6b0a22eee7014965c99df444d90dc70bcfbf07862f077ebb738
7
- data.tar.gz: df70247adc89586f9ebb813427fe3efdcfd5ba93deea286dea8f5120dae92bc293f6a7f7ff2bcb2a5bdd263ed7e5108d7c358c4a96eb978e037143f02356a1db
6
+ metadata.gz: fad18a8a7075e2e4f737f4daf1b79b8aceac8c65a0a1c566d7aa3eea35f0c14b4b868a9a249039411c4951ecf7c8419f715a9e1227348425c964b5e3914ee05c
7
+ data.tar.gz: f6747cd209851c8d4b5b8dc122f1bd7ee0c4fde21c994a3de3f49365251eddbd6883aa0ddb8582bbb057e57177b8c35a08a351cac44d4ae6c663da16c7ea4b0b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.4.0] - 2024-05-06
4
+
5
+ - Allow to use RSpec::Matchers for `worker: :none, :thread, :process` also.
6
+ - Make error message short to keep focusing on failure causes.
7
+ - Fix a bug for a case when parameters cannot be passed to a test block correctly.
8
+
3
9
  ## [0.3.0] - 2024-04-21
4
10
 
5
11
  - Add experimental_ractor_rspec_integration mode. Be careful, it's quite experimental.
data/README.md CHANGED
@@ -205,7 +205,7 @@ You can configure `Pbt` by calling `Pbt.configure` before running tests.
205
205
  ```ruby
206
206
  Pbt.configure do |config|
207
207
  # Whether to print verbose output. Default is `false`.
208
- config.verbose = 100
208
+ config.verbose = false
209
209
 
210
210
  # The concurrency method to use. `:ractor`, `:thread`, `:process` and `:none` are supported. Default is `:none`.
211
211
  config.worker = :none
data/benchmark/README.md CHANGED
@@ -21,8 +21,8 @@ Interestingly, both multi-process (`worker: :process`) and multi-thread (`worker
21
21
  The following benchmarks are the results of running the benchmark suite.
22
22
 
23
23
  - macOS 14.4.1, Apple M1 Pro 10 cores (8 performance and 2 efficiency)
24
- - ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [arm64-darwin22]
25
- - pbt commit hash 6f2c1cf1ab36d5d83a89fabb22da431e3600fe25
24
+ - ruby 3.3.1 (2024-04-23 revision c56cd86388) +MN [arm64-darwin23]
25
+ - pbt commit hash ecaecceb73a171042e52dbad25074f4f7dcfd55a
26
26
 
27
27
  ---
28
28
 
@@ -32,17 +32,17 @@ This runs a script that does not do any IO or CPU bound work.
32
32
 
33
33
  ```
34
34
  ruby benchmark/success_simple.rb
35
- ruby 3.3.0 (2023-12-25 revision 5124f9ac75) +MN [arm64-darwin22]
35
+ ruby 3.3.1 (2024-04-23 revision c56cd86388) +MN [arm64-darwin23]
36
36
  Warming up --------------------------------------
37
- ractor 19.000 i/100ms
38
- process 2.000 i/100ms
39
- thread 114.000 i/100ms
40
- none 234.000 i/100ms
37
+ ractor 21.000 i/100ms
38
+ process 3.000 i/100ms
39
+ thread 111.000 i/100ms
40
+ none 172.000 i/100ms
41
41
  Calculating -------------------------------------
42
- ractor 75.7174.0%) i/s - 380.000 in 5.025954s
43
- process 1.712 (± 0.0%) i/s - 10.000 in 5.840821s
44
- thread 1.019k34.0%) i/s - 4.560k in 5.028774s
45
- none 1.616k (±24.1%) i/s - 7.722k in 5.003744s
42
+ ractor 73.7098.1%) i/s - 378.000 in 5.166176s
43
+ process 1.868 (± 0.0%) i/s - 12.000 in 6.423704s
44
+ thread 1.028k33.4%) i/s - 4.773k in 5.123614s
45
+ none 1.534k (±24.4%) i/s - 7.224k in 5.037993s
46
46
  ```
47
47
 
48
48
  ### Benchmark success:cpu_bound
@@ -51,17 +51,17 @@ This runs a script that does CPU bound work.
51
51
 
52
52
  ```
53
53
  ruby benchmark/success_cpu_bound.rb
54
- ruby 3.3.0 (2023-12-25 revision 5124f9ac75) +MN [arm64-darwin22]
54
+ ruby 3.3.1 (2024-04-23 revision c56cd86388) +MN [arm64-darwin23]
55
55
  Warming up --------------------------------------
56
56
  ractor 3.000 i/100ms
57
57
  process 2.000 i/100ms
58
58
  thread 1.000 i/100ms
59
59
  none 1.000 i/100ms
60
60
  Calculating -------------------------------------
61
- ractor 35.6888.4%) i/s - 180.000 in 5.079922s
62
- process 15.3296.5%) i/s - 78.000 in 5.097040s
63
- thread 7.654 (± 0.0%) i/s - 39.000 in 5.095252s
64
- none 7.707 (± 0.0%) i/s - 39.000 in 5.060309s
61
+ ractor 39.2732.5%) i/s - 198.000 in 5.042910s
62
+ process 20.6314.8%) i/s - 104.000 in 5.068093s
63
+ thread 7.657 (± 0.0%) i/s - 39.000 in 5.096493s
64
+ none 7.765 (± 0.0%) i/s - 39.000 in 5.022829s
65
65
  ```
66
66
 
67
67
  ### Benchmark success:io_bound
@@ -70,17 +70,17 @@ This runs a script that does IO bound work.
70
70
 
71
71
  ```
72
72
  ruby benchmark/success_io_bound.rb
73
- ruby 3.3.0 (2023-12-25 revision 5124f9ac75) +MN [arm64-darwin22]
73
+ ruby 3.3.1 (2024-04-23 revision c56cd86388) +MN [arm64-darwin23]
74
74
  Warming up --------------------------------------
75
75
  ractor 11.000 i/100ms
76
76
  process 2.000 i/100ms
77
- thread 16.000 i/100ms
78
- none 21.000 i/100ms
77
+ thread 15.000 i/100ms
78
+ none 20.000 i/100ms
79
79
  Calculating -------------------------------------
80
- ractor 55.907 (± 3.6%) i/s - 286.000 in 5.122098s
81
- process 9.916 (± 0.0%) i/s - 50.000 in 5.044945s
82
- thread 131.28017.5%) i/s - 656.000 in 5.148757s
83
- none 144.364 (± 4.8%) i/s - 735.000 in 5.102093s
80
+ ractor 53.841 (± 3.7%) i/s - 275.000 in 5.114164s
81
+ process 10.077 (± 0.0%) i/s - 52.000 in 5.166346s
82
+ thread 130.75016.8%) i/s - 645.000 in 5.057727s
83
+ none 151.102 (± 4.0%) i/s - 760.000 in 5.038146s
84
84
  ```
85
85
 
86
86
  ### Benchmark failure:simple
@@ -89,15 +89,15 @@ This runs a script that fails and shrink happens.
89
89
 
90
90
  ```
91
91
  ruby benchmark/failure_simple.rb
92
- ruby 3.3.0 (2023-12-25 revision 5124f9ac75) +MN [arm64-darwin22]
92
+ ruby 3.3.1 (2024-04-23 revision c56cd86388) +MN [arm64-darwin23]
93
93
  Warming up --------------------------------------
94
94
  ractor 7.000 i/100ms
95
95
  process 1.000 i/100ms
96
96
  thread 14.000 i/100ms
97
- none 288.000 i/100ms
97
+ none 264.000 i/100ms
98
98
  Calculating -------------------------------------
99
- ractor 13.1047.6%) i/s - 70.000 in 5.358898s
100
- process 0.060 (± 0.0%) i/s - 1.000 in 16.545525s
101
- thread 111.493 (±20.6%) i/s - 532.000 in 5.012879s
102
- none 2.445k19.0%) i/s - 12.096k in 5.086548s
99
+ ractor 12.4668.0%) i/s - 63.000 in 5.080393s
100
+ process 0.059 (± 0.0%) i/s - 1.000 in 17.091278s
101
+ thread 110.228 (±20.0%) i/s - 532.000 in 5.054091s
102
+ none 2.425k23.1%) i/s - 11.616k in 5.053378s
103
103
  ```
@@ -4,11 +4,13 @@ require "benchmark/ips"
4
4
  # With this seed, the 4th case fails and it shrinks happens 13 times.
5
5
  seed = 17243810592888013452170775373100387856
6
6
 
7
+ def task(x) = (x > 100) ? raise : nil
8
+
7
9
  Benchmark.ips do |x|
8
10
  x.report("ractor") do
9
- Pbt.assert(worker: :ractor, seed:) do
11
+ Pbt.assert(worker: :ractor, seed:, num_runs: 100) do
10
12
  Pbt.property(Pbt.integer) do |x|
11
- raise if x > 100
13
+ task(x)
12
14
  end
13
15
  end
14
16
  rescue Pbt::PropertyFailure
@@ -16,9 +18,9 @@ Benchmark.ips do |x|
16
18
  end
17
19
 
18
20
  x.report("process") do
19
- Pbt.assert(worker: :process, seed:) do
21
+ Pbt.assert(worker: :process, seed:, num_runs: 100) do
20
22
  Pbt.property(Pbt.integer) do |x|
21
- raise if x > 100
23
+ task(x)
22
24
  end
23
25
  end
24
26
  rescue Pbt::PropertyFailure
@@ -26,9 +28,9 @@ Benchmark.ips do |x|
26
28
  end
27
29
 
28
30
  x.report("thread") do
29
- Pbt.assert(worker: :thread, seed:) do
31
+ Pbt.assert(worker: :thread, seed:, num_runs: 100) do
30
32
  Pbt.property(Pbt.integer) do |x|
31
- raise if x > 100
33
+ task(x)
32
34
  end
33
35
  end
34
36
  rescue Pbt::PropertyFailure
@@ -36,9 +38,9 @@ Benchmark.ips do |x|
36
38
  end
37
39
 
38
40
  x.report("none") do
39
- Pbt.assert(worker: :none, seed:) do
41
+ Pbt.assert(worker: :none, seed:, num_runs: 100) do
40
42
  Pbt.property(Pbt.integer) do |x|
41
- raise if x > 100
43
+ task(x)
42
44
  end
43
45
  end
44
46
  rescue Pbt::PropertyFailure
@@ -8,43 +8,43 @@ require "benchmark/ips"
8
8
  # (x=9, y=4, z=0) calls 55229 times.
9
9
  # (x=8, y=4, z=0) calls 12605 times.
10
10
  # (x=8, y=3, z=0) calls 305 times.
11
- def tarai(x, y, z)
12
- (x <= y) ? y : tarai(tarai(x - 1, y, z),
13
- tarai(y - 1, z, x),
14
- tarai(z - 1, x, y))
11
+ def task(x, y, z)
12
+ (x <= y) ? y : task(task(x - 1, y, z),
13
+ task(y - 1, z, x),
14
+ task(z - 1, x, y))
15
15
  end
16
16
 
17
17
  a, b, c = [9, 4, 0]
18
18
 
19
19
  Benchmark.ips do |x|
20
20
  x.report("ractor") do
21
- Pbt.assert(worker: :ractor) do
22
- Pbt.property(Pbt.constant(a), Pbt.constant(b), Pbt.constant(c)) do |x, y, z|
23
- tarai(x, y, z)
21
+ Pbt.assert(worker: :ractor, num_runs: 100) do
22
+ Pbt.property(Pbt.constant([a, b, c])) do |x, y, z|
23
+ task(x, y, z)
24
24
  end
25
25
  end
26
26
  end
27
27
 
28
28
  x.report("process") do
29
- Pbt.assert(worker: :process) do
30
- Pbt.property(Pbt.constant(a), Pbt.constant(b), Pbt.constant(c)) do |x, y, z|
31
- tarai(x, y, z)
29
+ Pbt.assert(worker: :process, num_runs: 100) do
30
+ Pbt.property(Pbt.constant([a, b, c])) do |x, y, z|
31
+ task(x, y, z)
32
32
  end
33
33
  end
34
34
  end
35
35
 
36
36
  x.report("thread") do
37
- Pbt.assert(worker: :thread) do
38
- Pbt.property(Pbt.constant(a), Pbt.constant(b), Pbt.constant(c)) do |x, y, z|
39
- tarai(x, y, z)
37
+ Pbt.assert(worker: :thread, num_runs: 100) do
38
+ Pbt.property(Pbt.constant([a, b, c])) do |x, y, z|
39
+ task(x, y, z)
40
40
  end
41
41
  end
42
42
  end
43
43
 
44
44
  x.report("none") do
45
- Pbt.assert(worker: :none) do
46
- Pbt.property(Pbt.constant(a), Pbt.constant(b), Pbt.constant(c)) do |x, y, z|
47
- tarai(x, y, z)
45
+ Pbt.assert(worker: :none, num_runs: 100) do
46
+ Pbt.property(Pbt.constant([a, b, c])) do |x, y, z|
47
+ task(x, y, z)
48
48
  end
49
49
  end
50
50
  end
@@ -3,7 +3,7 @@ require "benchmark/ips"
3
3
 
4
4
  # Read file generated by https://www.lipsum.com/
5
5
  # 150 paragraphs, 13689 words, 92206 bytes.
6
- def read_file(str)
6
+ def task(str)
7
7
  File.read(File.join(__dir__, "example.txt")) + str
8
8
  end
9
9
 
@@ -11,33 +11,33 @@ seed = 17243810592888013452170775373100387856
11
11
 
12
12
  Benchmark.ips do |x|
13
13
  x.report("ractor") do
14
- Pbt.assert(worker: :ractor, seed:) do
14
+ Pbt.assert(worker: :ractor, seed:, num_runs: 100) do
15
15
  Pbt.property(Pbt.ascii_string) do |str|
16
- read_file(str)
16
+ task(str)
17
17
  end
18
18
  end
19
19
  end
20
20
 
21
21
  x.report("process") do
22
- Pbt.assert(worker: :process, seed:) do
22
+ Pbt.assert(worker: :process, seed:, num_runs: 100) do
23
23
  Pbt.property(Pbt.ascii_string) do |str|
24
- read_file(str)
24
+ task(str)
25
25
  end
26
26
  end
27
27
  end
28
28
 
29
29
  x.report("thread") do
30
- Pbt.assert(worker: :thread, seed:) do
30
+ Pbt.assert(worker: :thread, seed:, num_runs: 100) do
31
31
  Pbt.property(Pbt.ascii_string) do |str|
32
- read_file(str)
32
+ task(str)
33
33
  end
34
34
  end
35
35
  end
36
36
 
37
37
  x.report("none") do
38
- Pbt.assert(worker: :none, seed:) do
38
+ Pbt.assert(worker: :none, seed:, num_runs: 100) do
39
39
  Pbt.property(Pbt.ascii_string) do |str|
40
- read_file(str)
40
+ task(str)
41
41
  end
42
42
  end
43
43
  end
@@ -3,35 +3,37 @@ require "benchmark/ips"
3
3
 
4
4
  seed = 17243810592888013452170775373100387856
5
5
 
6
+ def task(x) = x + 1
7
+
6
8
  Benchmark.ips do |x|
7
9
  x.report("ractor") do
8
- Pbt.assert(worker: :ractor, seed:) do
10
+ Pbt.assert(worker: :ractor, seed:, num_runs: 100) do
9
11
  Pbt.property(Pbt.integer) do |x|
10
- x + 1
12
+ task(x)
11
13
  end
12
14
  end
13
15
  end
14
16
 
15
17
  x.report("process") do
16
- Pbt.assert(worker: :process, seed:) do
18
+ Pbt.assert(worker: :process, seed:, num_runs: 100) do
17
19
  Pbt.property(Pbt.integer) do |x|
18
- x + 1
20
+ task(x)
19
21
  end
20
22
  end
21
23
  end
22
24
 
23
25
  x.report("thread") do
24
- Pbt.assert(worker: :thread, seed:) do
26
+ Pbt.assert(worker: :thread, seed:, num_runs: 100) do
25
27
  Pbt.property(Pbt.integer) do |x|
26
- x + 1
28
+ task(x)
27
29
  end
28
30
  end
29
31
  end
30
32
 
31
33
  x.report("none") do
32
- Pbt.assert(worker: :none, seed:) do
34
+ Pbt.assert(worker: :none, seed:, num_runs: 100) do
33
35
  Pbt.property(Pbt.integer) do |x|
34
- x + 1
36
+ task(x)
35
37
  end
36
38
  end
37
39
  end
@@ -29,12 +29,14 @@ module Pbt
29
29
  # @param val [Object]
30
30
  # @return [Ractor]
31
31
  def run_in_ractor(val)
32
- Ractor.new(@class_name, @method_name, val) do |class_name, method_name, val|
32
+ Ractor.new(@class_name, @method_name, @predicate.parameters.size, val) do |class_name, method_name, param_size, val|
33
33
  klass = RSpecAdapter.const_get(class_name)
34
34
  if val.is_a?(Hash)
35
35
  klass.new.send(method_name, **val)
36
- else
36
+ elsif param_size >= 2
37
37
  klass.new.send(method_name, *val)
38
+ else
39
+ klass.new.send(method_name, val)
38
40
  end
39
41
  end
40
42
  end
@@ -114,7 +114,8 @@ module Pbt
114
114
  begin
115
115
  property.run(val)
116
116
  runner.handle_result(c)
117
- rescue => e
117
+ # Catch all exceptions including RSpec's ExpectationNotMet (It inherits Exception).
118
+ rescue Exception => e # standard:disable Lint/RescueException:
118
119
  c.exception = e
119
120
  runner.handle_result(c)
120
121
  break # Ignore the rest of the cases. Just pick up the first failure.
@@ -162,7 +163,8 @@ module Pbt
162
163
  Parallel.map_with_index(runner, in_threads: Parallel.processor_count) do |val, index|
163
164
  Case.new(val:, index:).tap do |c|
164
165
  property.run(val)
165
- rescue => e
166
+ # Catch all exceptions including RSpec's ExpectationNotMet (It inherits Exception).
167
+ rescue Exception => e # standard:disable Lint/RescueException:
166
168
  c.exception = e
167
169
  # It's possible to break this loop here by raising `Parallel::Break`.
168
170
  # But if it raises, we cannot fetch all cases' result. So this loop continues until the end.
@@ -183,7 +185,8 @@ module Pbt
183
185
  Parallel.map_with_index(runner, in_processes: Parallel.processor_count) do |val, index|
184
186
  Case.new(val:, index:).tap do |c|
185
187
  property.run(val)
186
- rescue => e
188
+ # Catch all exceptions including RSpec's ExpectationNotMet (It inherits Exception).
189
+ rescue Exception => e # standard:disable Lint/RescueException:
187
190
  c.exception = e
188
191
  # It's possible to break this loop here by raising `Parallel::Break`.
189
192
  # But if it raises, we cannot fetch all cases' result. So this loop continues until the end.
@@ -20,8 +20,6 @@ module Pbt
20
20
  message << error_backtrace
21
21
  message << if @run_details.verbose
22
22
  verbose_details
23
- else
24
- hint
25
23
  end
26
24
 
27
25
  raise PropertyFailure, message.join("\n") if message.size > 0
@@ -34,17 +32,17 @@ module Pbt
34
32
  def format_error_message
35
33
  <<~MSG.chomp
36
34
  Property failed after #{@run_details.num_runs} test(s)
37
- { seed: #{@run_details.seed} }
38
- Counterexample: #{@run_details.counterexample}
39
- Shrunk #{@run_details.num_shrinks} time(s)
40
- Got #{@run_details.error_instance.class}: #{@run_details.error_message}
35
+ seed: #{@run_details.seed}
36
+ counterexample: #{@run_details.counterexample}
37
+ Shrunk #{@run_details.num_shrinks} time(s)
38
+ Got #{@run_details.error_instance.class}: #{@run_details.error_message}
41
39
  MSG
42
40
  end
43
41
 
44
42
  def error_backtrace
45
43
  return "" if @run_details.error_instance.backtrace_locations.nil? # It can be nil.
46
44
 
47
- i = @run_details.verbose ? -1 : 10
45
+ i = @run_details.verbose ? -1 : 3
48
46
  " #{@run_details.error_instance.backtrace_locations[..i].join("\n ")}"
49
47
  end
50
48
 
@@ -89,14 +87,6 @@ module Pbt
89
87
 
90
88
  "\nExecution summary:\n#{summary_lines.join("\n")}\n"
91
89
  end
92
-
93
- # @return [String]
94
- def hint
95
- [
96
- "\nHint: Set `verbose: true` in order to check the list of all failing values encountered during the run.",
97
- "Hint: Set `seed: #{@run_details.seed}` in order to reproduce the failed test case with the same values."
98
- ].join("\n")
99
- end
100
90
  end
101
91
  end
102
92
  end
data/lib/pbt/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pbt
4
- VERSION = "0.3.0"
4
+ VERSION = "0.4.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pbt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ohbarye
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-04-21 00:00:00.000000000 Z
11
+ date: 2024-05-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description:
14
14
  email:
@@ -79,7 +79,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
79
79
  - !ruby/object:Gem::Version
80
80
  version: '0'
81
81
  requirements: []
82
- rubygems_version: 3.5.3
82
+ rubygems_version: 3.5.9
83
83
  signing_key:
84
84
  specification_version: 4
85
85
  summary: Property-Based Testing tool for Ruby, utilizing Ractor for parallelizing