pbt 0.3.0 → 0.4.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: 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