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 +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +1 -1
- data/benchmark/README.md +29 -29
- data/benchmark/failure_simple.rb +10 -8
- data/benchmark/success_cpu_bound.rb +16 -16
- data/benchmark/success_io_bound.rb +9 -9
- data/benchmark/success_simple.rb +10 -8
- data/lib/pbt/check/rspec_adapter/property_extension.rb +4 -2
- data/lib/pbt/check/runner_methods.rb +6 -3
- data/lib/pbt/reporter/run_details_reporter.rb +5 -15
- data/lib/pbt/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9ce157507d0afc004a4d8993baecfb14dc4f0a14d381a996c33c15a02e8c496e
|
4
|
+
data.tar.gz: 71d314990ce4ee1ae4012a9af90666931edecba089851f8e3ea686696048c154
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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 =
|
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.
|
25
|
-
- pbt commit hash
|
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.
|
35
|
+
ruby 3.3.1 (2024-04-23 revision c56cd86388) +MN [arm64-darwin23]
|
36
36
|
Warming up --------------------------------------
|
37
|
-
ractor
|
38
|
-
process
|
39
|
-
thread
|
40
|
-
none
|
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
|
43
|
-
process 1.
|
44
|
-
thread 1.
|
45
|
-
none 1.
|
42
|
+
ractor 73.709 (± 8.1%) i/s - 378.000 in 5.166176s
|
43
|
+
process 1.868 (± 0.0%) i/s - 12.000 in 6.423704s
|
44
|
+
thread 1.028k (±33.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.
|
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
|
62
|
-
process
|
63
|
-
thread 7.
|
64
|
-
none 7.
|
61
|
+
ractor 39.273 (± 2.5%) i/s - 198.000 in 5.042910s
|
62
|
+
process 20.631 (± 4.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.
|
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
|
78
|
-
none
|
77
|
+
thread 15.000 i/100ms
|
78
|
+
none 20.000 i/100ms
|
79
79
|
Calculating -------------------------------------
|
80
|
-
ractor
|
81
|
-
process
|
82
|
-
thread
|
83
|
-
none
|
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.750 (±16.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.
|
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
|
97
|
+
none 264.000 i/100ms
|
98
98
|
Calculating -------------------------------------
|
99
|
-
ractor
|
100
|
-
process 0.
|
101
|
-
thread
|
102
|
-
none 2.
|
99
|
+
ractor 12.466 (± 8.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.425k (±23.1%) i/s - 11.616k in 5.053378s
|
103
103
|
```
|
data/benchmark/failure_simple.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
12
|
-
(x <= y) ? y :
|
13
|
-
|
14
|
-
|
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
|
23
|
-
|
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
|
31
|
-
|
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
|
39
|
-
|
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
|
47
|
-
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
40
|
+
task(str)
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
data/benchmark/success_simple.rb
CHANGED
@@ -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
|
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
|
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
|
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
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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 :
|
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
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.
|
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-
|
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.
|
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
|