rspec-benchmark 0.4.0 → 0.5.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: '090d1207708172bb738f301300654c15e9ae2e0a11acf7a256f26137042c97e4'
4
- data.tar.gz: 0464e88827f44e6cab4c2e8e269fee7a45b2885713787c2f95b7443b867caf6f
3
+ metadata.gz: 798bc5d4e03d43057fe769a612d69c7b9e94c1d6cf00cb119ff343f184c2dcc2
4
+ data.tar.gz: 437e723c5984d44d2af9e24dc2eab5a952d4be2531f86d1e5a67de6edfcd122c
5
5
  SHA512:
6
- metadata.gz: 5680d4c898961eceb9718800012180918c8e3d1607e9d8a1a51ca2dfba93493abc5b4bc8fa40e6ae7648f4bd01eba6a5cc4aacaa10ab732e897a7a0566b85907
7
- data.tar.gz: 30c9323c288c1103872607372c5d015cc4b290df030b64239a0af3e55f4f98925dbea4470178ea552b6684f70dfc15ae36bc801bb245f58e77031b2dbd99377b
6
+ metadata.gz: 48a31057edbf78fc8f535110e9a99ccc1bf7a3f7e2ce044eb99cfb3dd1322fe75ce00996acec8b5759b15e9622ef39b6b5cfa4fb678055dda0a8cfd943d1e1cf
7
+ data.tar.gz: 755534b8baf828aad86a8659bd59c123a2056a3f8b169699db0de5e19468476637f83c093fbd12a1db153c24a29039dacbecd648c67aba7df351b4f15906c492
@@ -1,5 +1,20 @@
1
1
  # Change log
2
2
 
3
+ ## [v0.5.0] - 2019-04-21
4
+
5
+ ## Added
6
+ * Add benchmark-malloc as a dependency
7
+ * Add AllocationMatcher with #perform_allocation expectation
8
+ * Add #perform_log, #perform_exp aliases
9
+ * Add threshold matcher for specifying allowed error level when asserting computational complexity
10
+ * Add #configure to allow for global configuration of options
11
+ * Add :run_in_subprocess, :disable_gc & :samples configuration options
12
+
13
+ ## Changed
14
+ * Change to require Ruby >= 2.1.0
15
+ * Change ComplexityMatcher to use threshold when verifying the assertion
16
+ * Change ComplexityMatcher#in_range to accept full range as an input
17
+
3
18
  ## [v0.4.0] - 2018-10-01
4
19
 
5
20
  ### Added
@@ -34,6 +49,7 @@
34
49
 
35
50
  Initial release
36
51
 
52
+ [v0.5.0]: https://github.com/peter-murach/rspec-benchmark/compare/v0.4.0...v0.5.0
37
53
  [v0.4.0]: https://github.com/peter-murach/rspec-benchmark/compare/v0.3.0...v0.4.0
38
54
  [v0.3.0]: https://github.com/peter-murach/rspec-benchmark/compare/v0.2.0...v0.3.0
39
55
  [v0.2.0]: https://github.com/peter-murach/rspec-benchmark/compare/v0.1.0...v0.2.0
data/README.md CHANGED
@@ -14,15 +14,19 @@
14
14
  [coverage]: https://coveralls.io/github/piotrmurach/rspec-benchmark
15
15
  [inchpages]: http://inch-ci.org/github/piotrmurach/rspec-benchmark
16
16
 
17
- > Performance testing matchers for RSpec
17
+ > Performance testing matchers for RSpec to set expectations on speed, resources usage and scalability.
18
18
 
19
- **RSpec::Benchmark** uses [benchmark-perf](https://github.com/piotrmurach/benchmark-perf) for measuring execution time and iterations per second and [benchmark-trend](https://github.com/piotrmurach/benchmark-trend) for asymptotic behaviour estimation.
19
+ **RSpec::Benchmark** is powered by:
20
+
21
+ * [benchmark-perf](https://github.com/piotrmurach/benchmark-perf) for measuring execution time and iterations per second.
22
+ * [benchmark-trend](https://github.com/piotrmurach/benchmark-trend) for estimating computation complexity.
23
+ * [benchmark-malloc](https://github.com/piotrmurach/benchmark-malloc) for measuring object and memory allocations.
20
24
 
21
25
  ## Why?
22
26
 
23
27
  Integration and unit tests ensure that changing code maintains expected functionality. What is not guaranteed is the code changes impact on library performance. It is easy to refactor your way out of fast to slow code.
24
28
 
25
- If you are new to performance testing you may find [Caveats](#4-caveats) section helpful.
29
+ If you are new to performance testing you may find [Caveats](#5-caveats) section helpful.
26
30
 
27
31
  ## Contents
28
32
 
@@ -31,9 +35,14 @@ If you are new to performance testing you may find [Caveats](#4-caveats) section
31
35
  * [1.2 Iterations ](#12-iterations)
32
36
  * [1.3 Comparison ](#13-comparison)
33
37
  * [1.4 Complexity](#14-complexity)
38
+ * [1.5 Allocation](#15-allocation)
34
39
  * [2. Compounding](#2-compounding)
35
- * [3. Filtering](#3-filtering)
36
- * [4. Caveats](#4-caveats)
40
+ * [3. Configuration](#3-configuration)
41
+ * [3.1 :disable_gc](#31-disable_gc)
42
+ * [3.2 :run_in_subprocess](#32-run_in_subprocess)
43
+ * [3.3 :samples](#33-samples)
44
+ * [4. Filtering](#4-filtering)
45
+ * [5. Caveats](#5-caveats)
37
46
 
38
47
  ## Installation
39
48
 
@@ -69,8 +78,9 @@ This will add the following matchers:
69
78
  * `perform_at_least` to see how many iteration per second your code can do
70
79
  * `perform_(faster|slower)_than` to compare implementations
71
80
  * `perform_(constant|linear|logarithmic|power|exponential)` to see how your code scales with time
81
+ * `perform_allocation` to limit object and memory allocations
72
82
 
73
- that will help you express expected performance benchmark for an evaluted code.
83
+ These will help you express expected performance benchmark for an evaluated code.
74
84
 
75
85
  Alternatively, you can add matchers for particular example:
76
86
 
@@ -90,7 +100,7 @@ expect {
90
100
 
91
101
  ### 1.1 Timing
92
102
 
93
- The `perform_under` matcher answers the question of how long does it take to perform a given block of code on average. The measurements are taken executing the block of code in a child process for accurent cpu times.
103
+ The `perform_under` matcher answers the question of how long does it take to perform a given block of code on average. The measurements are taken executing the block of code in a child process for accurate CPU times.
94
104
 
95
105
  ```ruby
96
106
  expect { ... }.to perform_under(0.01).sec
@@ -103,7 +113,7 @@ expect { ... }.to perform_under(10).ms
103
113
  expect { ... }.to perform_under(10000).us
104
114
  ```
105
115
 
106
- by default the above code will be sampled only once but you can change this by using the `sample` matcher like so:
116
+ By default the above code will be sampled only once but you can change this by using the `sample` matcher like so:
107
117
 
108
118
  ```ruby
109
119
  expect { ... }.to perform_under(0.01).sample(10) # repeats measurements 10 times
@@ -133,7 +143,7 @@ expect { ... }.to perform_at_least(10000).ips
133
143
 
134
144
  The `ips` part is optional but its usage clarifies the intent.
135
145
 
136
- The performance timining of this matcher can be tweaked using the `within` and `warmup` matchers. These are expressed as seconds.
146
+ The performance timing of this matcher can be tweaked using the `within` and `warmup` matchers. These are expressed as seconds.
137
147
 
138
148
  By default `within` matcher is set to `0.2` second and `warmup` matcher to `0.1` respectively. To change how long measurements are taken, for example, to double the time amount do:
139
149
 
@@ -170,7 +180,7 @@ expect { ... }.to perform_slower_than { ... }.exactly(5).times
170
180
 
171
181
  The `times` part is also optional.
172
182
 
173
- The performance timining of each matcher can be tweaked using the `within` and `warmup` matchers. These are expressed as seconds. By default `within` matcher is set to `0.2` and `warmup` matcher to `0.1` second respectively. To change these matchers values do:
183
+ The performance timing of each matcher can be tweaked using the `within` and `warmup` matchers. These are expressed as seconds. By default `within` matcher is set to `0.2` and `warmup` matcher to `0.1` second respectively. To change these matchers values do:
174
184
 
175
185
  ```ruby
176
186
  expect { ... }.to perform_faster_than.within(0.4).warmup(0.2) { ... }
@@ -180,47 +190,124 @@ The higher values for `within` and `warmup` the more accurate average readings a
180
190
 
181
191
  ### 1.4 Complexity
182
192
 
183
- The `perform_constant`, `perform_linear`, `perform_logarithmic`, `perform_power` and `perform_exponential` matchers are useful for estimating the asymptotic behaviour of a given block of code. The most basic way to use the expectations to test how your code scales is to use the matchers:
193
+ The `perform_constant`, `perform_logarithmic`, `perform_linear`, `perform_power` and `perform_exponential` matchers are useful for estimating the asymptotic behaviour of a given block of code. The most basic way to use the expectations to test how your code scales is to use the matchers:
184
194
 
185
195
  ```ruby
186
196
  expect { ... }.to perform_constant
197
+ expect { ... }.to perform_logarithmic/perform_log
187
198
  expect { ... }.to perform_linear
188
- expect { ... }.to perform_logarithmic
189
199
  expect { ... }.to perform_power
190
- expect { ... }.to perform_exponential
200
+ expect { ... }.to perform_exponential/perform_exp
191
201
  ```
192
202
 
193
- However, for the matchers to be of any use you will need to provide the range of inputs on which they will perform measurements using `in_range` matcher. Each range input together with its corresponding iteration index will be yielded as arguments to the evaluted block.
203
+ To test performance in terms of computation complexity you can follow the algorithm:
204
+
205
+ 1. Choose a method to profile.
206
+ 2. Choose workloads for the method.
207
+ 3. Describe workloads with input features.
208
+ 4. Assert the performance in terms of Big-O notation.
209
+
210
+ Often, before expectation can be set you need to setup some workloads. To create a range of inputs use the `bench_range` helper method.
194
211
 
195
212
  For example, to create a power range of inputs from `8` to `100_000` do:
196
213
 
214
+ ```ruby
215
+ sizes = bench_range(8, 100_000) # => [8, 64, 512, 4096, 32768, 100000]
216
+ ```
217
+
218
+ Then you can use the sizes to create test data, for example to check Ruby's `max` performance create array of number arrays.
219
+
220
+ ```ruby
221
+ number_arrays = sizes.map { |n| Array.new(n) { rand(n) } }
222
+ ```
223
+
224
+ Using `in_range` matcher you can inform the expectation about the inputs. Each range value together with its index will be yielded as arguments to the evaluated block.
225
+
226
+ You can either specify the range limits:
227
+
197
228
  ```ruby
198
229
  expect { |n, i|
199
- ...
230
+ number_arrays[i].max
200
231
  }.to perform_linear.in_range(8, 100_000)
201
232
  ```
202
233
 
234
+ Or use previously generated `sizes` array:
235
+
236
+ ```ruby
237
+ expect { |n, i|
238
+ number_arrays[i].max
239
+ }.to perform_linear.in_range(sizes)
240
+ ```
241
+
203
242
  This example will generate and yield input `n` and index `i` pairs `[8, 0]`, `[64, 1]`, `[512, 2]`, `[4K, 3]`, `[32K, 4]` and `[100K, 5]` respectively.
204
243
 
205
- By default the range will be generated using ratio of 8. You can change this using `ratio` matcher:
244
+ By default the range will be generated using ratio of `8`. You can change this using `ratio` matcher:
206
245
 
207
246
  ```ruby
208
247
  expect { |n, i|
209
- ...
248
+ number_arrays[i].max
210
249
  }.to perform_linear.in_range(8, 100_000).ratio(2)
211
250
  ```
212
251
 
213
- The performance of code block is measured only once per range input. You can change this value and in doing so increase stability of your performance test using the `sample` matcher. For example, to repeat measurements 100 times for each range data input do:
252
+ The performance measurements for a code block are taken only once per range input. You can increase the stability of your performance test by using the `sample` matcher. For example, to repeat measurements 100 times for each range input do:
214
253
 
215
254
  ```ruby
216
255
  expect { |n, i|
217
- ...
256
+ number_arrays[i].max
218
257
  }.to perform_linear.in_range(8, 100_000).ratio(2).sample(100).times
219
258
  ```
220
259
 
260
+ The overall quality of the performance trend is assessed using a threshold value where `0` means a poor fit and `1` a perfect fit. By default this value is configured to `0.9` as a 'good enough' threshold. To change this use `threshold` matcher:
261
+
262
+ ```ruby
263
+ expect { |n, i|
264
+ number_arrays[i].max
265
+ }.to perform_linear.in_range(8, 100_000).threshold(0.95)
266
+ ```
267
+
268
+ ### 1.5 Allocation
269
+
270
+ The `perform_allocation` matcher checks how much memory or objects have been allocated during a piece of Ruby code execution.
271
+
272
+ By default the matcher verify the number of object allocations. You can also check for memory allocation using the `bytes` matcher.
273
+
274
+ To check number of objects allocated do:
275
+
276
+ ```ruby
277
+ expect {
278
+ ["foo", "bar", "baz"].sort[1]
279
+ }.to perform_allocation(3)
280
+ ```
281
+
282
+ You can also be more granular with your object allocations and specify which object types you're interested in:
283
+
284
+ ```ruby
285
+ expect {
286
+ _a = [Object.new]
287
+ _b = {Object.new => 'foo'}
288
+ }.to perform_allocation({Array => 1, Object => 2}).objects
289
+ ```
290
+
291
+ And you can also check how many objects are left when expectation finishes to ensure that `GC` is able to collect them.
292
+
293
+ ```ruby
294
+ expect {
295
+ ["foo", "bar", "baz"].sort[1]
296
+ }.to perform_allocation(3).and_retain(3)
297
+ ```
298
+
299
+ You can also set expectations on the memory size. In this case the memory size will serve as upper limit for the expectation:
300
+
301
+ ```ruby
302
+ expect {
303
+ _a = [Object.new]
304
+ _b = {Object.new => 'foo'}
305
+ }.to perform_allocation({Array => 40, Hash => 384, Object => 80}).bytes
306
+ ```
307
+
221
308
  ## 2. Compounding
222
309
 
223
- All the matchers can be used in compound expressions via `and/or`. For example, if you wish to check if a computation performs under certain time boundry and iterates at least a given number do:
310
+ All the matchers can be used in compound expressions via `and/or`. For example, if you wish to check if a computation performs under certain time boundary and iterates at least a given number do:
224
311
 
225
312
  ```ruby
226
313
  expect {
@@ -228,7 +315,48 @@ expect {
228
315
  }.to perform_under(6).ms and perform_at_least(10000).ips
229
316
  ```
230
317
 
231
- ## 3. Filtering
318
+ ## 3. Configuration
319
+
320
+ By default the following configuration is used:
321
+
322
+ ```ruby
323
+ RSpec::Benchmark.configure do |config|
324
+ config.run_in_subprocess = false
325
+ config.disable_gc = false
326
+ end
327
+ ```
328
+
329
+ ### 3.1. `:disable_gc`
330
+
331
+ By default all tests are run with `GC` enabled. We want to measure real performance or Ruby code. However, disabling `GC` may lead to much quicker test execution. You can change this setting:
332
+
333
+ ```ruby
334
+ RSpec::Benchmark.configure do |config|
335
+ config.disable_gc = true
336
+ end
337
+ ```
338
+
339
+ ### 3.2 `:run_in_subprocess`
340
+
341
+ The `perform_under` matcher can run all the measurements in the subprocess. This will increase isolation from other processes activity. However, the `rspec-rails` gem runs all tests in transactions. Unfortunately, when running tests in child process, database connections are used from connection pool and no data can be accessed. This is only a problem when running specs in Rails. Any other Ruby project can run specs using subprocesses. To enable this behaviour do:
342
+
343
+ ```ruby
344
+ RSpec::Benchmark.configure do |config|
345
+ config.run_in_subprocess = true
346
+ end
347
+ ```
348
+
349
+ ### 3.3 `:samples`
350
+
351
+ The `perform_under` and computational complexity matchers allow to specify how many times to repeat measurements. You configure it globally for all matchers using the `:samples` option which defaults to `1`:
352
+
353
+ ```ruby
354
+ RSpec::Benchmark.configure do |config|
355
+ config.samples = 10
356
+ end
357
+ ```
358
+
359
+ ## 4. Filtering
232
360
 
233
361
  Usually performance tests are best left for CI or occasional runs that do not affect TDD/BDD cycle.
234
362
 
@@ -240,7 +368,7 @@ RSpec.config do |config|
240
368
  end
241
369
  ```
242
370
 
243
- and then in your example group do:
371
+ And then in your example group do:
244
372
 
245
373
  ```ruby
246
374
  RSpec.describe ..., :perf do
@@ -256,7 +384,7 @@ rspec --tag perf
256
384
 
257
385
  Another option is to simply isolate the performance specs in separate directory such as `spec/performance/...` and add custom rake task to run them.
258
386
 
259
- ## 4. Caveats
387
+ ## 5. Caveats
260
388
 
261
389
  When writing performance tests things to be mindful are:
262
390
 
@@ -275,6 +403,10 @@ If you have any other observations please share them!
275
403
  4. Push to the branch (`git push origin my-new-feature`)
276
404
  5. Create a new Pull Request
277
405
 
406
+ ## Code of Conduct
407
+
408
+ Everyone interacting in the Strings project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/piotrmurach/rspec-benchmark/blob/master/CODE_OF_CONDUCT.md).
409
+
278
410
  ## Copyright
279
411
 
280
- Copyright (c) 2016-2018 Piotr Murach. See LICENSE for further details.
412
+ Copyright (c) 2016 Piotr Murach. See LICENSE for further details.
@@ -1,3 +1 @@
1
- # encoding: utf-8
2
-
3
- require 'rspec/benchmark'
1
+ require_relative 'rspec/benchmark'
@@ -1,4 +1,43 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'benchmark/configuration'
3
4
  require_relative 'benchmark/matchers'
4
5
  require_relative 'benchmark/version'
6
+
7
+ module RSpec
8
+ module Benchmark
9
+ class << self
10
+ attr_writer :configuration
11
+ end
12
+
13
+ # Current configuration
14
+ #
15
+ # @return [RSpec::Benchmark::Configuration]
16
+ #
17
+ # @api public
18
+ def self.configuration
19
+ @configuration ||= Configuration.new
20
+ end
21
+
22
+ # Reset current configuration to defaults
23
+ #
24
+ # @return [RSpec::Benchmark::Configuration]
25
+ #
26
+ # @api public
27
+ def self.reset_configuration
28
+ @configuration = Configuration.new
29
+ end
30
+
31
+ # Change current configuration
32
+ #
33
+ # @example
34
+ # RSpec::Benchmark.configure do |config|
35
+ # config.run_in_subprocess = false
36
+ # end
37
+ #
38
+ # @api public
39
+ def self.configure
40
+ yield configuration
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'benchmark-malloc'
4
+
5
+ module RSpec
6
+ module Benchmark
7
+ module AllocationMatcher
8
+ # Implements the `perform_allocation` matcher
9
+ #
10
+ # @api private
11
+ class Matcher
12
+ def initialize(objects, **options)
13
+ @objects = objects
14
+ @retained_objects = nil
15
+ @warmup = options.fetch(:warmup) { 1 }
16
+ @bench = ::Benchmark::Malloc
17
+ @count_type = :objects
18
+ end
19
+
20
+ # Indicates this matcher matches against a block
21
+ #
22
+ # @return [True]
23
+ #
24
+ # @api private
25
+ def supports_block_expectations?
26
+ true
27
+ end
28
+
29
+ # @return [Boolean]
30
+ #
31
+ # @api private
32
+ def matches?(block)
33
+ @block = block
34
+ alloc_stats = @bench.run(&block)
35
+ @actual = nil
36
+ @actual_retained = nil
37
+
38
+ case @objects
39
+ when Hash
40
+ case @count_type
41
+ when :memory
42
+ @actual = alloc_stats.allocated.count_memory
43
+ else
44
+ @actual = alloc_stats.allocated.count_objects
45
+ end
46
+ @objects.all? do |name, count|
47
+ @actual[name] <= count
48
+ end
49
+ when Numeric
50
+ case @count_type
51
+ when :memory
52
+ @actual = alloc_stats.allocated.total_memory
53
+ @actual_retained = alloc_stats.retained.total_memory
54
+ else
55
+ @actual = alloc_stats.allocated.total_objects
56
+ @actual_retained = alloc_stats.retained.total_objects
57
+ end
58
+ result = @actual <= @objects
59
+ result &= @actual_retained <= @retained_objects if @retained_objects
60
+ result
61
+ else
62
+ raise ArgumentError, "'#{@objects}' is not a recognized argument"
63
+ end
64
+ end
65
+
66
+ def and_retain(objects)
67
+ @retained_objects = objects
68
+ self
69
+ end
70
+
71
+ # The time before measurements are taken
72
+ #
73
+ # @param [Numeric] value
74
+ # the time before measurements are taken
75
+ #
76
+ # @api public
77
+ def warmup(value)
78
+ @warmup = value
79
+ self
80
+ end
81
+
82
+ def objects
83
+ @count_type = :objects
84
+ self
85
+ end
86
+ alias object objects
87
+
88
+ def memory
89
+ @count_type = :memory
90
+ self
91
+ end
92
+ alias bytes memory
93
+
94
+ def failure_message
95
+ "expected block to #{description}, but #{positive_failure_reason}"
96
+ end
97
+
98
+ def failure_message_when_negated
99
+ "expected block not to #{description}, but #{negative_failure_reason}"
100
+ end
101
+
102
+ def description
103
+ desc = ["perform allocation of #{count_objects(@objects)}"]
104
+ if @retained_objects
105
+ desc << " and retain #{count_objects(@retained_objects)}"
106
+ end
107
+ desc.join
108
+ end
109
+
110
+ def count_objects(objects)
111
+ if @count_type == :memory
112
+ "#{objects_to_s(objects)} #{objects == 1 ? "byte" : "bytes"}"
113
+ else
114
+ "#{objects_to_s(objects)} #{pluralize_objects(objects)}"
115
+ end
116
+ end
117
+
118
+ def positive_failure_reason
119
+ return "was not a block" unless @block.is_a?(Proc)
120
+ "allocated #{actual}"
121
+ end
122
+
123
+ def negative_failure_reason
124
+ "allocated #{actual}"
125
+ end
126
+
127
+ def actual
128
+ if @count_type == :memory
129
+ "#{objects_to_s(@actual)} bytes"
130
+ else
131
+ desc = ["#{objects_to_s(@actual)} #{pluralize_objects(@actual)}"]
132
+ if @retained_objects
133
+ desc << " and retained #{objects_to_s(@actual_retained)}"
134
+ end
135
+ desc.join
136
+ end
137
+ end
138
+
139
+ def pluralize_objects(value)
140
+ if value.respond_to?(:to_hash)
141
+ if value.keys.size == 1 && value.values.reduce(&:+) == 1
142
+ "object"
143
+ else
144
+ "objects"
145
+ end
146
+ else
147
+ value == 1 ? "object" : "objects"
148
+ end
149
+ end
150
+
151
+ def objects_to_s(value)
152
+ if value.respond_to?(:to_hash)
153
+ value.
154
+ sort_by { |k,v| k.to_s }.
155
+ map { |key, val| "#{val} #{key}" if @objects.keys.include?(key) }.
156
+ compact.join(" and ")
157
+ else
158
+ value
159
+ end
160
+ end
161
+ end
162
+ end # AllocationMatcher
163
+ end # Benchmark
164
+ end # RSpec
@@ -11,8 +11,10 @@ module RSpec
11
11
  class Matcher
12
12
  def initialize(fit_type, **options)
13
13
  @fit_type = fit_type
14
- @threshold = options.fetch(:threshold) { 0.9 }
15
- @repeat = options.fetch(:repeat) { 1 }
14
+ @threshold = options.fetch(:threshold) {
15
+ RSpec::Benchmark.configuration.fit_quality }
16
+ @repeat = options.fetch(:repeat) {
17
+ RSpec::Benchmark.configuration.samples }
16
18
  @start = 8
17
19
  @limit = 8 << 10
18
20
  @ratio = 8
@@ -37,12 +39,30 @@ module RSpec
37
39
  def matches?(block)
38
40
  range = ::Benchmark::Trend.range(@start, @limit, ratio: @ratio)
39
41
  @trend, trends = ::Benchmark::Trend.infer_trend(range, repeat: @repeat, &block)
42
+ threshold = trends[@trend][:residual]
40
43
 
41
- @trend == @fit_type
44
+ @trend == @fit_type && threshold >= @threshold
42
45
  end
43
46
 
44
- def in_range(start, limit)
45
- @start, @limit = start, limit
47
+ # Specify range of inputs
48
+ #
49
+ # @api public
50
+ def in_range(start, limit = (not_set = true))
51
+ case start
52
+ when Array
53
+ @start, *, @limit = *start
54
+ @ratio = start[1] / start[0]
55
+ when Numeric
56
+ @start, @limit = start, limit
57
+ else
58
+ raise ArgumentError,
59
+ "Wrong range argument '#{start}', it expects an array or numeric start value."
60
+ end
61
+ self
62
+ end
63
+
64
+ def threshold(threshold)
65
+ @threshold = threshold
46
66
  self
47
67
  end
48
68
 
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RSpec
4
+ module Benchmark
5
+ class Configuration
6
+ # Isolate benchmark time measurement in child process
7
+ # By default false due to Rails loosing DB connections
8
+ #
9
+ # @api public
10
+ attr_accessor :run_in_subprocess
11
+
12
+ # GC is enabled to measure real performance
13
+ #
14
+ # @api public
15
+ attr_accessor :disable_gc
16
+
17
+ # How many times to repeat measurements
18
+ #
19
+ # @return [Integer]
20
+ #
21
+ # @api public
22
+ attr_accessor :samples
23
+
24
+ # The fit quality in computational complexity
25
+ #
26
+ # @return [Float]
27
+ #
28
+ # @api public
29
+ attr_accessor :fit_quality
30
+
31
+ # @api private
32
+ def initialize
33
+ @disable_gc = false
34
+ @samples = 1
35
+ @fit_quality = 0.9
36
+ @run_in_subprocess = false
37
+ end
38
+ end # Configuration
39
+ end # Benchmark
40
+ end # RSpec
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal
2
2
 
3
+ require_relative 'allocation_matcher'
3
4
  require_relative 'comparison_matcher'
4
5
  require_relative 'complexity_matcher'
5
6
  require_relative 'iteration_matcher'
@@ -24,6 +25,19 @@ module RSpec
24
25
  #
25
26
  # @api public
26
27
  module Matchers
28
+ # Passes if code block performs at least iterations
29
+ #
30
+ # @param [Integer] iterations
31
+ #
32
+ # @example
33
+ # expect { ... }.to perform_allocation(10000)
34
+ # expect { ... }.to perform_allocation(10000)
35
+ #
36
+ # @api public
37
+ def perform_allocation(objects, **options)
38
+ AllocationMatcher::Matcher.new(objects, options)
39
+ end
40
+
27
41
  # Passes if code block performs at least iterations
28
42
  #
29
43
  # @param [Integer] iterations
@@ -101,6 +115,7 @@ module RSpec
101
115
  def perform_logarithmic(**options)
102
116
  ComplexityMatcher::Matcher.new(:logarithmic, options)
103
117
  end
118
+ alias perform_log perform_logarithmic
104
119
 
105
120
  # Pass if code block performs linear
106
121
  #
@@ -137,6 +152,7 @@ module RSpec
137
152
  def perform_exponential(**options)
138
153
  ComplexityMatcher::Matcher.new(:exponential, options)
139
154
  end
155
+ alias perform_exp perform_exponential
140
156
 
141
157
  # Generate a geometric progression of inputs
142
158
  #
@@ -17,8 +17,11 @@ module RSpec
17
17
 
18
18
  def initialize(threshold, **options)
19
19
  @threshold = threshold
20
- @samples = options.fetch(:samples) { 1 }
20
+ @samples = options.fetch(:samples) {
21
+ RSpec::Benchmark.configuration.samples }
21
22
  @warmup = options.fetch(:warmup) { 1 }
23
+ @subprocess = options.fetch(:subprocess) {
24
+ RSpec::Benchmark.configuration.run_in_subprocess }
22
25
  @scale = threshold.to_s.split(/\./).last.size
23
26
  @block = nil
24
27
  @bench = ::Benchmark::Perf::ExecutionTime
@@ -39,7 +42,10 @@ module RSpec
39
42
  def matches?(block)
40
43
  @block = block
41
44
  return false unless block.is_a?(Proc)
42
- @average, @stddev = @bench.run(repeat: @samples, warmup: @warmup, &block)
45
+ @average, @stddev = @bench.run(repeat: @samples,
46
+ warmup: @warmup,
47
+ subprocess: @subprocess,
48
+ &block)
43
49
  @average <= @threshold
44
50
  end
45
51
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RSpec
4
4
  module Benchmark
5
- VERSION = "0.4.0"
5
+ VERSION = "0.5.0"
6
6
  end # Benchmark
7
7
  end # RSpec
@@ -6,12 +6,18 @@ Gem::Specification.new do |spec|
6
6
  spec.name = "rspec-benchmark"
7
7
  spec.version = RSpec::Benchmark::VERSION
8
8
  spec.authors = ["Piotr Murach"]
9
- spec.email = [""]
9
+ spec.email = ["me@piotrmurach.com"]
10
10
  spec.summary = %q{Performance testing matchers for RSpec}
11
- spec.description = %q{Performance testing matchers for RSpec that provide simple way to specify speed and algorithmic complexity benchmark expectations}
12
- spec.homepage = ""
11
+ spec.description = %q{Performance testing matchers for RSpec to set expectations on speed, resources usage and scalibility.}
12
+ spec.homepage = "https://github.com/piotrmurach/rspec-benchmark"
13
13
  spec.license = "MIT"
14
14
 
15
+ if spec.respond_to?(:metadata)
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = "https://github.com/piotrmurach/rspec-benchmark"
18
+ spec.metadata["changelog_uri"] = "https://github.com/piotrmurach/rspec-benchmark/blob/master/CHANGELOG.md"
19
+ end
20
+
15
21
  spec.files = Dir['{lib,spec}/**/*.rb']
16
22
  spec.files += Dir['tasks/*', 'rspec-benchmark.gemspec']
17
23
  spec.files += Dir['README.md', 'CHANGELOG.md', 'LICENSE.txt', 'Rakefile']
@@ -19,12 +25,13 @@ Gem::Specification.new do |spec|
19
25
  spec.test_files = spec.files.grep(%r{^spec/})
20
26
  spec.require_paths = ["lib"]
21
27
 
22
- spec.required_ruby_version = '>= 2.0.0'
28
+ spec.required_ruby_version = '>= 2.1.0'
23
29
 
24
- spec.add_dependency 'benchmark-perf', '~> 0.4.0'
25
- spec.add_dependency 'benchmark-trend', '~> 0.2.0'
30
+ spec.add_dependency 'benchmark-malloc', '~> 0.1.0'
31
+ spec.add_dependency 'benchmark-perf', '~> 0.5.0'
32
+ spec.add_dependency 'benchmark-trend', '~> 0.3.0'
26
33
  spec.add_dependency 'rspec', '>= 3.0.0', '< 4.0.0'
27
34
 
28
- spec.add_development_dependency 'bundler', '~> 1.16'
29
- spec.add_development_dependency 'rake', '~> 10.0'
35
+ spec.add_development_dependency 'bundler', '>= 1.5'
36
+ spec.add_development_dependency 'rake'
30
37
  end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe RSpec::Benchmark do
4
+ after(:example) do
5
+ RSpec::Benchmark.reset_configuration
6
+ end
7
+
8
+ it "defaults :run_in_subprocess option to false" do
9
+ config = RSpec::Benchmark.configuration
10
+
11
+ expect(config.run_in_subprocess).to eq(false)
12
+ end
13
+
14
+ it "defaults :disable_gc option to false" do
15
+ config = RSpec::Benchmark.configuration
16
+
17
+ expect(config.disable_gc).to eq(false)
18
+ end
19
+
20
+ it "defaults :samples option to 1" do
21
+ config = RSpec::Benchmark.configuration
22
+
23
+ expect(config.samples).to eq(1)
24
+ end
25
+
26
+ it "sets :run_in_subprocess option to true" do
27
+ RSpec::Benchmark.configure do |config|
28
+ config.run_in_subprocess = true
29
+ end
30
+
31
+ config = RSpec::Benchmark.configuration
32
+
33
+ expect(config.run_in_subprocess).to eq(true)
34
+ end
35
+
36
+ it "sets :disable_gc option to true" do
37
+ RSpec::Benchmark.configure do |config|
38
+ config.disable_gc = true
39
+ end
40
+
41
+ config = RSpec::Benchmark.configuration
42
+
43
+ expect(config.disable_gc).to eq(true)
44
+ end
45
+
46
+ it "sets :samples option to 10" do
47
+ RSpec::Benchmark.configure do |config|
48
+ config.samples = 10
49
+ end
50
+
51
+ config = RSpec::Benchmark.configuration
52
+
53
+ expect(config.samples).to eq(10)
54
+ end
55
+
56
+ it "uses the :run_in_subprocess option in timing matcher" do
57
+ RSpec::Benchmark.configure do |config|
58
+ config.run_in_subprocess = true
59
+ config.samples = 10
60
+ end
61
+
62
+ bench = [0.005, 0.00001]
63
+ allow(::Benchmark::Perf::ExecutionTime).to receive(:run).and_return(bench)
64
+
65
+ expect { 'x' * 1024 }.to perform_under(0.1)
66
+
67
+ expect(::Benchmark::Perf::ExecutionTime).to have_received(:run).with(
68
+ subprocess: true, warmup: 1, repeat: 10)
69
+ end
70
+
71
+ it "uses the :samples option in complexity matcher" do
72
+ RSpec::Benchmark.configure do |config|
73
+ config.samples = 10
74
+ end
75
+
76
+ bench = [:constant, {constant: {residual: 0.9}}]
77
+ allow(::Benchmark::Trend).to receive(:infer_trend).and_return(bench)
78
+
79
+ expect { 'x' * 1024 }.to perform_constant
80
+
81
+ expect(::Benchmark::Trend).to have_received(:infer_trend).with(
82
+ [8, 64, 512, 4096, 8192], repeat: 10)
83
+ end
84
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ RSpec.describe "#perform_allocation" do
4
+ context "expect { ... }.to perform_allocation(...)" do
5
+ it "passes if the block performs allocations" do
6
+ expect {
7
+ _a = [Object.new]
8
+ }.to perform_allocation(2)
9
+ end
10
+
11
+ it "fails if the block doesn't perform allocation(...)" do
12
+ expect {
13
+ expect {
14
+ _a = [Object.new]
15
+ }.to perform_allocation(1)
16
+ }.to raise_error(/expected block to perform allocation of \d object, but allocated \d objects/)
17
+ end
18
+ end
19
+
20
+ context "expect { ... }.not_to perform_allocation(...)" do
21
+ it "passes if the block does not perform allocation" do
22
+ expect {
23
+ ["foo", "bar", "baz"].sort[1]
24
+ }.to_not perform_allocation(2)
25
+ end
26
+
27
+ it "fails if the block performs allocation" do
28
+ expect {
29
+ expect {
30
+ _a = [Object.new]
31
+ }.to_not perform_allocation(2)
32
+ }.to raise_error(/expected block not to perform allocation of \d objects, but allocated \d objects/)
33
+ end
34
+ end
35
+
36
+ context "expect { ... }.to perform_allocation(Object => ???, ...).objects" do
37
+ it "splits object allocations by count" do
38
+ expect {
39
+ _a = [Object.new]
40
+ _b = {Object.new => 'foo'}
41
+ }.to perform_allocation({Object => 2, Array => 1}).objects
42
+ end
43
+
44
+ it "fails to split object allocations by count" do
45
+ expect {
46
+ expect {
47
+ _a = [Object.new]
48
+ _b = {Object.new => 'bar'}
49
+ }.to perform_allocation({Object => 1, Array => 1}).objects
50
+ }.to raise_error("expected block to perform allocation of 1 Array and 1 Object objects, but allocated 1 Array and 2 Object objects")
51
+ end
52
+ end
53
+
54
+ context "expect { ... }.not_to perform_allocation(Object => ???, ...).objects" do
55
+ it "passes if the split of object allocations by count is wrong" do
56
+ expect {
57
+ _a = [Object.new]
58
+ _b = {Object.new => 'foo'}
59
+ }.to_not perform_allocation({Object => 1, Array => 1}).objects
60
+ end
61
+
62
+ it "fails to split object allocations by count" do
63
+ expect {
64
+ expect {
65
+ _a = [Object.new]
66
+ _b = {Object.new => 'bar'}
67
+ }.to_not perform_allocation({Object => 2, Array => 1}).objects
68
+ }.to raise_error("expected block not to perform allocation of 1 Array and 2 Object objects, but allocated 1 Array and 2 Object objects")
69
+ end
70
+ end
71
+
72
+ context "expect { ... }.to perform_allocation(...).bytes" do
73
+ it "passes if the block performs allocations" do
74
+ expect {
75
+ _a = [Object.new]
76
+ _b = {Object.new => 'foo'}
77
+ }.to perform_allocation(600).bytes
78
+ end
79
+
80
+ it "fails if the block doesn't perform allocation" do
81
+ expect {
82
+ expect {
83
+ _a = {Object.new => 'foo'}
84
+ }.to perform_allocation(10).bytes
85
+ }.to raise_error(/expected block to perform allocation of \d+ bytes, but allocated \d+ bytes/)
86
+ end
87
+ end
88
+
89
+ context "expect { ... }.not_to perform_allocation(...).bytes" do
90
+ it "passes if the block does not perform allocation" do
91
+ expect {
92
+ _a = {Object.new => 'foo'}
93
+ }.to_not perform_allocation(10).bytes
94
+ end
95
+
96
+ it "fails if the block performs allocation" do
97
+ expect {
98
+ expect {
99
+ _a = [Object.new]
100
+ }.to_not perform_allocation(200).bytes
101
+ }.to raise_error(/expected block not to perform allocation of \d+ bytes, but allocated \d+ bytes/)
102
+ end
103
+ end
104
+
105
+ context "expect { ... }.to perform_allocation(Object => ???, ...).bytes" do
106
+ it "splits object allocations by memory size" do
107
+ expect {
108
+ _a = [Object.new]
109
+ _b = {Object.new => 'foo'}
110
+ }.to perform_allocation({Object => 80, Array => 40, Hash => 500}).bytes
111
+ end
112
+
113
+ it "fails to split object allocations by memory size" do
114
+ expect {
115
+ expect {
116
+ _a = [Object.new]
117
+ _b = {Object.new => 'bar'}
118
+ }.to perform_allocation({Object => 80, Hash => 0}).bytes
119
+ }.to raise_error(/expected block to perform allocation of \d+ Hash and \d+ Object bytes, but allocated \d+ Hash and \d+ Object bytes/)
120
+ end
121
+ end
122
+
123
+ it "fails to recognize expectation type" do
124
+ expect {
125
+ expect { Object.new }.to perform_allocation(:error)
126
+ }.to raise_error(ArgumentError, "'error' is not a recognized argument")
127
+ end
128
+ end
@@ -16,7 +16,7 @@ RSpec.describe 'RSpec::Benchmark::ComplexityMatcher', '#perform_exponential' do
16
16
  it "passes if the block performs exponential" do
17
17
  expect { |n, i|
18
18
  fibonacci(n)
19
- }.to perform_exponential.in_range(1, 15).ratio(2).sample(100)
19
+ }.to perform_exp.in_range(1, 15).ratio(2).sample(100)
20
20
  end
21
21
 
22
22
  it "fails if the block doesn't perform exponential" do
@@ -14,8 +14,9 @@ RSpec.describe 'RSpec::Benchmark::ComplexityMatcher', '#perform_linear' do
14
14
 
15
15
  it "provides a default range" do
16
16
  range = [1,2,3]
17
+ trend = [:linear, {linear: {residual: 0.95}}]
17
18
  allow(::Benchmark::Trend).to receive(:range).and_return(range)
18
- allow(::Benchmark::Trend).to receive(:infer_trend).and_return(:linear, {})
19
+ allow(::Benchmark::Trend).to receive(:infer_trend).and_return(trend)
19
20
 
20
21
  expect { |n, i| n }.to perform_linear
21
22
 
@@ -24,14 +25,21 @@ RSpec.describe 'RSpec::Benchmark::ComplexityMatcher', '#perform_linear' do
24
25
 
25
26
  it "changes default range using in_range and ratio matchers" do
26
27
  range = [1,2,3]
28
+ trend = [:linear, {linear: {residual: 0.95}}]
27
29
  allow(::Benchmark::Trend).to receive(:range).and_return(range)
28
- allow(::Benchmark::Trend).to receive(:infer_trend).and_return(:linear, {})
30
+ allow(::Benchmark::Trend).to receive(:infer_trend).and_return(trend)
29
31
 
30
32
  expect { |n, i| n }.to perform_linear.in_range(3, 33_000).ratio(2)
31
33
 
32
34
  expect(::Benchmark::Trend).to have_received(:range).with(3, 33_000, ratio: 2)
33
35
  end
34
36
 
37
+ it "fails when wrong argument for range" do
38
+ expect {
39
+ expect { |n, i| }.to perform_linear.in_range(1..10)
40
+ }.to raise_error(ArgumentError, "Wrong range argument '1..10', it expects an array or numeric start value.")
41
+ end
42
+
35
43
  context "expect { ... }.to perfom_linear" do
36
44
  it "passes if the block performs linear" do
37
45
  range = bench_range(1, 8 << 10)
@@ -39,7 +47,7 @@ RSpec.describe 'RSpec::Benchmark::ComplexityMatcher', '#perform_linear' do
39
47
 
40
48
  expect { |n, i|
41
49
  numbers[i].max
42
- }.to perform_linear.in_range(range[0], range[-1]).sample(100)
50
+ }.to perform_linear.in_range(range).sample(100).threshold(0.85)
43
51
  end
44
52
 
45
53
  it "fails if the block doesn't perform linear" do
@@ -20,7 +20,7 @@ RSpec.describe 'RSpec::Benchmark::ComplexityMatcher', '#perform_logarithmic' do
20
20
 
21
21
  expect { |n, i|
22
22
  numbers[i].bsearch { |x| x == 1 }
23
- }.to perform_logarithmic.in_range(range[0], range[-1]).ratio(2).sample(100).times
23
+ }.to perform_log.in_range(range[0], range[-1]).ratio(2).sample(100).times
24
24
  end
25
25
 
26
26
  it "fails if the block doesn't perform logarithmic" do
@@ -42,7 +42,7 @@ RSpec.describe 'RSpec::Benchmark::ComplexityMatcher', '#perform_logarithmic' do
42
42
  expect {
43
43
  expect { |n, i|
44
44
  numbers[i].bsearch { |x| x == 1 }
45
- }.not_to perform_logarithmic.in_range(range[0], range[-1]).ratio(2).sample(100).times
45
+ }.not_to perform_log.in_range(range[0], range[-1]).ratio(2).sample(100).times
46
46
  }.to raise_error("expected block not to perform logarithmic, but performed logarithmic")
47
47
  end
48
48
  end
@@ -10,8 +10,11 @@ RSpec.describe 'RSpec::Benchmark::TimingMatcher', '#perform_under' do
10
10
  it "allows to configure warmup cycles" do
11
11
  bench = [0.005, 0.00001]
12
12
  allow(::Benchmark::Perf::ExecutionTime).to receive(:run).and_return(bench)
13
+
13
14
  expect { 'x' * 1024 * 10 }.to perform_under(0.006).sec.warmup(2).times.sample(3)
14
- expect(::Benchmark::Perf::ExecutionTime).to have_received(:run).with(repeat: 3, warmup: 2)
15
+
16
+ expect(::Benchmark::Perf::ExecutionTime).to have_received(:run).with(
17
+ subprocess: false, repeat: 3, warmup: 2)
15
18
  end
16
19
 
17
20
  it "doesn't allow sample size less than 1" do
metadata CHANGED
@@ -1,43 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rspec-benchmark
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Piotr Murach
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-10-01 00:00:00.000000000 Z
11
+ date: 2019-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: benchmark-malloc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 0.1.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.1.0
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: benchmark-perf
15
29
  requirement: !ruby/object:Gem::Requirement
16
30
  requirements:
17
31
  - - "~>"
18
32
  - !ruby/object:Gem::Version
19
- version: 0.4.0
33
+ version: 0.5.0
20
34
  type: :runtime
21
35
  prerelease: false
22
36
  version_requirements: !ruby/object:Gem::Requirement
23
37
  requirements:
24
38
  - - "~>"
25
39
  - !ruby/object:Gem::Version
26
- version: 0.4.0
40
+ version: 0.5.0
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: benchmark-trend
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: 0.2.0
47
+ version: 0.3.0
34
48
  type: :runtime
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: 0.2.0
54
+ version: 0.3.0
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rspec
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -62,34 +76,34 @@ dependencies:
62
76
  name: bundler
63
77
  requirement: !ruby/object:Gem::Requirement
64
78
  requirements:
65
- - - "~>"
79
+ - - ">="
66
80
  - !ruby/object:Gem::Version
67
- version: '1.16'
81
+ version: '1.5'
68
82
  type: :development
69
83
  prerelease: false
70
84
  version_requirements: !ruby/object:Gem::Requirement
71
85
  requirements:
72
- - - "~>"
86
+ - - ">="
73
87
  - !ruby/object:Gem::Version
74
- version: '1.16'
88
+ version: '1.5'
75
89
  - !ruby/object:Gem::Dependency
76
90
  name: rake
77
91
  requirement: !ruby/object:Gem::Requirement
78
92
  requirements:
79
- - - "~>"
93
+ - - ">="
80
94
  - !ruby/object:Gem::Version
81
- version: '10.0'
95
+ version: '0'
82
96
  type: :development
83
97
  prerelease: false
84
98
  version_requirements: !ruby/object:Gem::Requirement
85
99
  requirements:
86
- - - "~>"
100
+ - - ">="
87
101
  - !ruby/object:Gem::Version
88
- version: '10.0'
89
- description: Performance testing matchers for RSpec that provide simple way to specify
90
- speed and algorithmic complexity benchmark expectations
102
+ version: '0'
103
+ description: Performance testing matchers for RSpec to set expectations on speed,
104
+ resources usage and scalibility.
91
105
  email:
92
- - ''
106
+ - me@piotrmurach.com
93
107
  executables: []
94
108
  extensions: []
95
109
  extra_rdoc_files: []
@@ -100,8 +114,10 @@ files:
100
114
  - Rakefile
101
115
  - lib/rspec-benchmark.rb
102
116
  - lib/rspec/benchmark.rb
117
+ - lib/rspec/benchmark/allocation_matcher.rb
103
118
  - lib/rspec/benchmark/comparison_matcher.rb
104
119
  - lib/rspec/benchmark/complexity_matcher.rb
120
+ - lib/rspec/benchmark/configuration.rb
105
121
  - lib/rspec/benchmark/format_time.rb
106
122
  - lib/rspec/benchmark/iteration_matcher.rb
107
123
  - lib/rspec/benchmark/matchers.rb
@@ -111,7 +127,9 @@ files:
111
127
  - spec/spec_helper.rb
112
128
  - spec/unit/comparison_matcher_spec.rb
113
129
  - spec/unit/composable_spec.rb
130
+ - spec/unit/configuration_spec.rb
114
131
  - spec/unit/format_time_spec.rb
132
+ - spec/unit/perform_allocation_spec.rb
115
133
  - spec/unit/perform_at_least_spec.rb
116
134
  - spec/unit/perform_constant_spec.rb
117
135
  - spec/unit/perform_exponential_spec.rb
@@ -121,10 +139,13 @@ files:
121
139
  - spec/unit/perform_under_spec.rb
122
140
  - tasks/coverage.rake
123
141
  - tasks/spec.rake
124
- homepage: ''
142
+ homepage: https://github.com/piotrmurach/rspec-benchmark
125
143
  licenses:
126
144
  - MIT
127
- metadata: {}
145
+ metadata:
146
+ homepage_uri: https://github.com/piotrmurach/rspec-benchmark
147
+ source_code_uri: https://github.com/piotrmurach/rspec-benchmark
148
+ changelog_uri: https://github.com/piotrmurach/rspec-benchmark/blob/master/CHANGELOG.md
128
149
  post_install_message:
129
150
  rdoc_options: []
130
151
  require_paths:
@@ -133,15 +154,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
133
154
  requirements:
134
155
  - - ">="
135
156
  - !ruby/object:Gem::Version
136
- version: 2.0.0
157
+ version: 2.1.0
137
158
  required_rubygems_version: !ruby/object:Gem::Requirement
138
159
  requirements:
139
160
  - - ">="
140
161
  - !ruby/object:Gem::Version
141
162
  version: '0'
142
163
  requirements: []
143
- rubyforge_project:
144
- rubygems_version: 2.7.3
164
+ rubygems_version: 3.0.3
145
165
  signing_key:
146
166
  specification_version: 4
147
167
  summary: Performance testing matchers for RSpec
@@ -149,7 +169,9 @@ test_files:
149
169
  - spec/spec_helper.rb
150
170
  - spec/unit/comparison_matcher_spec.rb
151
171
  - spec/unit/composable_spec.rb
172
+ - spec/unit/configuration_spec.rb
152
173
  - spec/unit/format_time_spec.rb
174
+ - spec/unit/perform_allocation_spec.rb
153
175
  - spec/unit/perform_at_least_spec.rb
154
176
  - spec/unit/perform_constant_spec.rb
155
177
  - spec/unit/perform_exponential_spec.rb