rspec-core 3.2.3 → 3.3.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/Changelog.md +75 -0
- data/README.md +137 -20
- data/lib/rspec/autorun.rb +1 -0
- data/lib/rspec/core.rb +8 -16
- data/lib/rspec/core/backtrace_formatter.rb +1 -3
- data/lib/rspec/core/bisect/coordinator.rb +66 -0
- data/lib/rspec/core/bisect/example_minimizer.rb +130 -0
- data/lib/rspec/core/bisect/runner.rb +139 -0
- data/lib/rspec/core/bisect/server.rb +61 -0
- data/lib/rspec/core/bisect/subset_enumerator.rb +39 -0
- data/lib/rspec/core/configuration.rb +134 -5
- data/lib/rspec/core/configuration_options.rb +21 -10
- data/lib/rspec/core/example.rb +84 -50
- data/lib/rspec/core/example_group.rb +46 -18
- data/lib/rspec/core/example_status_persister.rb +235 -0
- data/lib/rspec/core/filter_manager.rb +43 -28
- data/lib/rspec/core/flat_map.rb +2 -0
- data/lib/rspec/core/formatters.rb +30 -20
- data/lib/rspec/core/formatters/base_text_formatter.rb +1 -0
- data/lib/rspec/core/formatters/bisect_formatter.rb +68 -0
- data/lib/rspec/core/formatters/bisect_progress_formatter.rb +115 -0
- data/lib/rspec/core/formatters/deprecation_formatter.rb +0 -1
- data/lib/rspec/core/formatters/documentation_formatter.rb +0 -4
- data/lib/rspec/core/formatters/exception_presenter.rb +389 -0
- data/lib/rspec/core/formatters/fallback_message_formatter.rb +28 -0
- data/lib/rspec/core/formatters/helpers.rb +22 -2
- data/lib/rspec/core/formatters/html_formatter.rb +1 -4
- data/lib/rspec/core/formatters/html_printer.rb +2 -6
- data/lib/rspec/core/formatters/json_formatter.rb +6 -4
- data/lib/rspec/core/formatters/snippet_extractor.rb +12 -7
- data/lib/rspec/core/hooks.rb +8 -2
- data/lib/rspec/core/memoized_helpers.rb +77 -17
- data/lib/rspec/core/metadata.rb +24 -10
- data/lib/rspec/core/metadata_filter.rb +16 -3
- data/lib/rspec/core/mutex.rb +63 -0
- data/lib/rspec/core/notifications.rb +84 -189
- data/lib/rspec/core/option_parser.rb +105 -32
- data/lib/rspec/core/ordering.rb +28 -25
- data/lib/rspec/core/profiler.rb +32 -0
- data/lib/rspec/core/project_initializer/spec/spec_helper.rb +6 -1
- data/lib/rspec/core/rake_task.rb +6 -20
- data/lib/rspec/core/reentrant_mutex.rb +52 -0
- data/lib/rspec/core/reporter.rb +65 -17
- data/lib/rspec/core/runner.rb +38 -14
- data/lib/rspec/core/set.rb +49 -0
- data/lib/rspec/core/shared_example_group.rb +3 -1
- data/lib/rspec/core/shell_escape.rb +49 -0
- data/lib/rspec/core/version.rb +1 -1
- data/lib/rspec/core/world.rb +31 -20
- metadata +35 -7
- metadata.gz.sig +0 -0
- data/lib/rspec/core/backport_random.rb +0 -339
data/lib/rspec/core/runner.rb
CHANGED
@@ -17,20 +17,23 @@ module RSpec
|
|
17
17
|
return
|
18
18
|
end
|
19
19
|
|
20
|
-
at_exit
|
21
|
-
# Don't bother running any specs and just let the program terminate
|
22
|
-
# if we got here due to an unrescued exception (anything other than
|
23
|
-
# SystemExit, which is raised when somebody calls Kernel#exit).
|
24
|
-
next unless $!.nil? || $!.is_a?(SystemExit)
|
25
|
-
|
26
|
-
# We got here because either the end of the program was reached or
|
27
|
-
# somebody called Kernel#exit. Run the specs and then override any
|
28
|
-
# existing exit status with RSpec's exit status if any specs failed.
|
29
|
-
invoke
|
30
|
-
end
|
20
|
+
at_exit { perform_at_exit }
|
31
21
|
@installed_at_exit = true
|
32
22
|
end
|
33
23
|
|
24
|
+
# @private
|
25
|
+
def self.perform_at_exit
|
26
|
+
# Don't bother running any specs and just let the program terminate
|
27
|
+
# if we got here due to an unrescued exception (anything other than
|
28
|
+
# SystemExit, which is raised when somebody calls Kernel#exit).
|
29
|
+
return unless $!.nil? || $!.is_a?(SystemExit)
|
30
|
+
|
31
|
+
# We got here because either the end of the program was reached or
|
32
|
+
# somebody called Kernel#exit. Run the specs and then override any
|
33
|
+
# existing exit status with RSpec's exit status if any specs failed.
|
34
|
+
invoke
|
35
|
+
end
|
36
|
+
|
34
37
|
# Runs the suite of specs and exits the process with an appropriate exit
|
35
38
|
# code.
|
36
39
|
def self.invoke
|
@@ -83,7 +86,9 @@ module RSpec
|
|
83
86
|
# @param out [IO] output stream
|
84
87
|
def run(err, out)
|
85
88
|
setup(err, out)
|
86
|
-
run_specs(@world.ordered_example_groups)
|
89
|
+
run_specs(@world.ordered_example_groups).tap do
|
90
|
+
persist_example_statuses
|
91
|
+
end
|
87
92
|
end
|
88
93
|
|
89
94
|
# Wires together the various configuration objects and state holders.
|
@@ -112,6 +117,19 @@ module RSpec
|
|
112
117
|
end
|
113
118
|
end
|
114
119
|
|
120
|
+
private
|
121
|
+
|
122
|
+
def persist_example_statuses
|
123
|
+
return unless (path = @configuration.example_status_persistence_file_path)
|
124
|
+
|
125
|
+
ExampleStatusPersister.persist(@world.all_examples, path)
|
126
|
+
rescue SystemCallError => e
|
127
|
+
RSpec.warning "Could not write example statuses to #{path} (configured as " \
|
128
|
+
"`config.example_status_persistence_file_path`) due to a " \
|
129
|
+
"system error: #{e.inspect}. Please check that the config " \
|
130
|
+
"option is set to an accessible, valid file path", :call_site => nil
|
131
|
+
end
|
132
|
+
|
115
133
|
# @private
|
116
134
|
def self.disable_autorun!
|
117
135
|
@autorun_disabled = true
|
@@ -144,8 +162,14 @@ module RSpec
|
|
144
162
|
|
145
163
|
# @private
|
146
164
|
def self.trap_interrupt
|
147
|
-
trap('INT')
|
148
|
-
|
165
|
+
trap('INT') { handle_interrupt }
|
166
|
+
end
|
167
|
+
|
168
|
+
# @private
|
169
|
+
def self.handle_interrupt
|
170
|
+
if RSpec.world.wants_to_quit
|
171
|
+
exit!(1)
|
172
|
+
else
|
149
173
|
RSpec.world.wants_to_quit = true
|
150
174
|
STDERR.puts "\nRSpec is shutting down and will print the summary report... Interrupt again to force quit."
|
151
175
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Core
|
3
|
+
# @private
|
4
|
+
#
|
5
|
+
# We use this to replace `::Set` so we can have the advantage of
|
6
|
+
# constant time key lookups for unique arrays but without the
|
7
|
+
# potential to pollute a developers environment with an extra
|
8
|
+
# piece of the stdlib. This helps to prevent false positive
|
9
|
+
# builds.
|
10
|
+
#
|
11
|
+
class Set
|
12
|
+
include Enumerable
|
13
|
+
|
14
|
+
def initialize(array=[])
|
15
|
+
@values = {}
|
16
|
+
merge(array)
|
17
|
+
end
|
18
|
+
|
19
|
+
def empty?
|
20
|
+
@values.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
def <<(key)
|
24
|
+
@values[key] = true
|
25
|
+
self
|
26
|
+
end
|
27
|
+
|
28
|
+
def delete(key)
|
29
|
+
@values.delete(key)
|
30
|
+
end
|
31
|
+
|
32
|
+
def each(&block)
|
33
|
+
@values.keys.each(&block)
|
34
|
+
self
|
35
|
+
end
|
36
|
+
|
37
|
+
def include?(key)
|
38
|
+
@values.key?(key)
|
39
|
+
end
|
40
|
+
|
41
|
+
def merge(values)
|
42
|
+
values.each do |key|
|
43
|
+
@values[key] = true
|
44
|
+
end
|
45
|
+
self
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -80,7 +80,7 @@ module RSpec
|
|
80
80
|
# @see ExampleGroup.include_context
|
81
81
|
def shared_examples(name, *args, &block)
|
82
82
|
top_level = self == ExampleGroup
|
83
|
-
if top_level && RSpec.
|
83
|
+
if top_level && RSpec::Support.thread_local_data[:in_example_group]
|
84
84
|
raise "Creating isolated shared examples from within a context is " \
|
85
85
|
"not allowed. Remove `RSpec.` prefix or move this to a " \
|
86
86
|
"top-level scope."
|
@@ -195,10 +195,12 @@ module RSpec
|
|
195
195
|
if Proc.method_defined?(:source_location)
|
196
196
|
def ensure_block_has_source_location(_block); end
|
197
197
|
else # for 1.8.7
|
198
|
+
# :nocov:
|
198
199
|
def ensure_block_has_source_location(block)
|
199
200
|
source_location = yield.split(':')
|
200
201
|
block.extend Module.new { define_method(:source_location) { source_location } }
|
201
202
|
end
|
203
|
+
# :nocov:
|
202
204
|
end
|
203
205
|
end
|
204
206
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Core
|
3
|
+
# @private
|
4
|
+
# Deals with the fact that `shellwords` only works on POSIX systems.
|
5
|
+
module ShellEscape
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def quote(argument)
|
9
|
+
"'#{argument.gsub("'", "\\\\'")}'"
|
10
|
+
end
|
11
|
+
|
12
|
+
if RSpec::Support::OS.windows?
|
13
|
+
# :nocov:
|
14
|
+
alias escape quote
|
15
|
+
# :nocov:
|
16
|
+
else
|
17
|
+
require 'shellwords'
|
18
|
+
|
19
|
+
def escape(shell_command)
|
20
|
+
shell_command.shellescape
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Known shells that require quoting: zsh, csh, tcsh.
|
25
|
+
#
|
26
|
+
# Feel free to add other shells to this list that are known to
|
27
|
+
# allow `rspec ./some_spec.rb[1:1]` syntax without quoting the id.
|
28
|
+
#
|
29
|
+
# @private
|
30
|
+
SHELLS_ALLOWING_UNQUOTED_IDS = %w[ bash ksh fish ]
|
31
|
+
|
32
|
+
def conditionally_quote(id)
|
33
|
+
return id if shell_allows_unquoted_ids?
|
34
|
+
quote(id)
|
35
|
+
end
|
36
|
+
|
37
|
+
def shell_allows_unquoted_ids?
|
38
|
+
# Note: ENV['SHELL'] isn't necessarily the shell the user is currently running.
|
39
|
+
# According to http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html:
|
40
|
+
# "This variable shall represent a pathname of the user's preferred command language interpreter."
|
41
|
+
#
|
42
|
+
# It's the best we can easily do, though. We err on the side of safety (quoting
|
43
|
+
# the id when not actually needed) so it's not a big deal if the user is actually
|
44
|
+
# using a different shell.
|
45
|
+
SHELLS_ALLOWING_UNQUOTED_IDS.include?(ENV['SHELL'].to_s.split('/').last)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/rspec/core/version.rb
CHANGED
data/lib/rspec/core/world.rb
CHANGED
@@ -13,22 +13,12 @@ module RSpec
|
|
13
13
|
def initialize(configuration=RSpec.configuration)
|
14
14
|
@configuration = configuration
|
15
15
|
@example_groups = []
|
16
|
+
@example_group_counts_by_spec_file = Hash.new(0)
|
16
17
|
@filtered_examples = Hash.new do |hash, group|
|
17
|
-
hash[group] =
|
18
|
-
examples = group.examples.dup
|
19
|
-
examples = filter_manager.prune(examples)
|
20
|
-
examples.uniq!
|
21
|
-
examples
|
22
|
-
end
|
18
|
+
hash[group] = filter_manager.prune(group.examples)
|
23
19
|
end
|
24
20
|
end
|
25
21
|
|
26
|
-
# @private
|
27
|
-
# Used internally to clear remaining groups when fail_fast is set.
|
28
|
-
def clear_remaining_example_groups
|
29
|
-
example_groups.clear
|
30
|
-
end
|
31
|
-
|
32
22
|
# @api private
|
33
23
|
#
|
34
24
|
# Apply ordering strategy from configuration to example groups.
|
@@ -55,9 +45,15 @@ module RSpec
|
|
55
45
|
# Register an example group.
|
56
46
|
def register(example_group)
|
57
47
|
example_groups << example_group
|
48
|
+
@example_group_counts_by_spec_file[example_group.metadata[:file_path]] += 1
|
58
49
|
example_group
|
59
50
|
end
|
60
51
|
|
52
|
+
# @private
|
53
|
+
def num_example_groups_defined_in(file)
|
54
|
+
@example_group_counts_by_spec_file[file]
|
55
|
+
end
|
56
|
+
|
61
57
|
# @private
|
62
58
|
def shared_example_group_registry
|
63
59
|
@shared_example_group_registry ||= SharedExampleGroup::Registry.new
|
@@ -81,6 +77,16 @@ module RSpec
|
|
81
77
|
inject(0) { |a, e| a + e.filtered_examples.size }
|
82
78
|
end
|
83
79
|
|
80
|
+
# @private
|
81
|
+
def all_example_groups
|
82
|
+
FlatMap.flat_map(example_groups) { |g| g.descendants }
|
83
|
+
end
|
84
|
+
|
85
|
+
# @private
|
86
|
+
def all_examples
|
87
|
+
FlatMap.flat_map(all_example_groups) { |g| g.examples }
|
88
|
+
end
|
89
|
+
|
84
90
|
# @api private
|
85
91
|
#
|
86
92
|
# Find line number of previous declaration.
|
@@ -99,6 +105,7 @@ module RSpec
|
|
99
105
|
#
|
100
106
|
# Notify reporter of filters.
|
101
107
|
def announce_filters
|
108
|
+
fail_if_config_and_cli_options_invalid
|
102
109
|
filter_announcements = []
|
103
110
|
|
104
111
|
announce_inclusion_filter filter_announcements
|
@@ -112,7 +119,7 @@ module RSpec
|
|
112
119
|
end
|
113
120
|
end
|
114
121
|
|
115
|
-
if @configuration.run_all_when_everything_filtered? && example_count.zero?
|
122
|
+
if @configuration.run_all_when_everything_filtered? && example_count.zero? && !@configuration.only_failures?
|
116
123
|
reporter.message("#{everything_filtered_message}; ignoring #{inclusion_filter.description}")
|
117
124
|
filtered_examples.clear
|
118
125
|
inclusion_filter.clear
|
@@ -123,13 +130,7 @@ module RSpec
|
|
123
130
|
example_groups.clear
|
124
131
|
if filter_manager.empty?
|
125
132
|
reporter.message("No examples found.")
|
126
|
-
elsif exclusion_filter.empty?
|
127
|
-
message = everything_filtered_message
|
128
|
-
if @configuration.run_all_when_everything_filtered?
|
129
|
-
message << "; ignoring #{inclusion_filter.description}"
|
130
|
-
end
|
131
|
-
reporter.message(message)
|
132
|
-
elsif inclusion_filter.empty?
|
133
|
+
elsif exclusion_filter.empty? || inclusion_filter.empty?
|
133
134
|
reporter.message(everything_filtered_message)
|
134
135
|
end
|
135
136
|
end
|
@@ -162,6 +163,16 @@ module RSpec
|
|
162
163
|
def declaration_line_numbers
|
163
164
|
@declaration_line_numbers ||= FlatMap.flat_map(example_groups, &:declaration_line_numbers)
|
164
165
|
end
|
166
|
+
|
167
|
+
def fail_if_config_and_cli_options_invalid
|
168
|
+
return unless @configuration.only_failures_but_not_configured?
|
169
|
+
|
170
|
+
reporter.abort_with(
|
171
|
+
"\nTo use `--only-failures`, you must first set " \
|
172
|
+
"`config.example_status_persistence_file_path`.",
|
173
|
+
1 # exit code
|
174
|
+
)
|
175
|
+
end
|
165
176
|
end
|
166
177
|
end
|
167
178
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rspec-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Steven Baker
|
@@ -46,7 +46,7 @@ cert_chain:
|
|
46
46
|
ZsVDj6a7lH3cNqtWXZxrb2wO38qV5AkYj8SQK7Hj3/Yui9myUX3crr+PdetazSqQ
|
47
47
|
F3MdtaDehhjC
|
48
48
|
-----END CERTIFICATE-----
|
49
|
-
date: 2015-
|
49
|
+
date: 2015-06-12 00:00:00.000000000 Z
|
50
50
|
dependencies:
|
51
51
|
- !ruby/object:Gem::Dependency
|
52
52
|
name: rspec-support
|
@@ -54,14 +54,14 @@ dependencies:
|
|
54
54
|
requirements:
|
55
55
|
- - "~>"
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version: 3.
|
57
|
+
version: 3.3.0
|
58
58
|
type: :runtime
|
59
59
|
prerelease: false
|
60
60
|
version_requirements: !ruby/object:Gem::Requirement
|
61
61
|
requirements:
|
62
62
|
- - "~>"
|
63
63
|
- !ruby/object:Gem::Version
|
64
|
-
version: 3.
|
64
|
+
version: 3.3.0
|
65
65
|
- !ruby/object:Gem::Dependency
|
66
66
|
name: rake
|
67
67
|
requirement: !ruby/object:Gem::Requirement
|
@@ -188,6 +188,20 @@ dependencies:
|
|
188
188
|
- - "~>"
|
189
189
|
- !ruby/object:Gem::Version
|
190
190
|
version: 0.9.0
|
191
|
+
- !ruby/object:Gem::Dependency
|
192
|
+
name: thread_order
|
193
|
+
requirement: !ruby/object:Gem::Requirement
|
194
|
+
requirements:
|
195
|
+
- - "~>"
|
196
|
+
- !ruby/object:Gem::Version
|
197
|
+
version: 1.1.0
|
198
|
+
type: :development
|
199
|
+
prerelease: false
|
200
|
+
version_requirements: !ruby/object:Gem::Requirement
|
201
|
+
requirements:
|
202
|
+
- - "~>"
|
203
|
+
- !ruby/object:Gem::Version
|
204
|
+
version: 1.1.0
|
191
205
|
description: BDD for Ruby. RSpec runner and example groups.
|
192
206
|
email: rspec@googlegroups.com
|
193
207
|
executables:
|
@@ -203,22 +217,31 @@ files:
|
|
203
217
|
- exe/rspec
|
204
218
|
- lib/rspec/autorun.rb
|
205
219
|
- lib/rspec/core.rb
|
206
|
-
- lib/rspec/core/backport_random.rb
|
207
220
|
- lib/rspec/core/backtrace_formatter.rb
|
221
|
+
- lib/rspec/core/bisect/coordinator.rb
|
222
|
+
- lib/rspec/core/bisect/example_minimizer.rb
|
223
|
+
- lib/rspec/core/bisect/runner.rb
|
224
|
+
- lib/rspec/core/bisect/server.rb
|
225
|
+
- lib/rspec/core/bisect/subset_enumerator.rb
|
208
226
|
- lib/rspec/core/configuration.rb
|
209
227
|
- lib/rspec/core/configuration_options.rb
|
210
228
|
- lib/rspec/core/drb.rb
|
211
229
|
- lib/rspec/core/dsl.rb
|
212
230
|
- lib/rspec/core/example.rb
|
213
231
|
- lib/rspec/core/example_group.rb
|
232
|
+
- lib/rspec/core/example_status_persister.rb
|
214
233
|
- lib/rspec/core/filter_manager.rb
|
215
234
|
- lib/rspec/core/flat_map.rb
|
216
235
|
- lib/rspec/core/formatters.rb
|
217
236
|
- lib/rspec/core/formatters/base_formatter.rb
|
218
237
|
- lib/rspec/core/formatters/base_text_formatter.rb
|
238
|
+
- lib/rspec/core/formatters/bisect_formatter.rb
|
239
|
+
- lib/rspec/core/formatters/bisect_progress_formatter.rb
|
219
240
|
- lib/rspec/core/formatters/console_codes.rb
|
220
241
|
- lib/rspec/core/formatters/deprecation_formatter.rb
|
221
242
|
- lib/rspec/core/formatters/documentation_formatter.rb
|
243
|
+
- lib/rspec/core/formatters/exception_presenter.rb
|
244
|
+
- lib/rspec/core/formatters/fallback_message_formatter.rb
|
222
245
|
- lib/rspec/core/formatters/helpers.rb
|
223
246
|
- lib/rspec/core/formatters/html_formatter.rb
|
224
247
|
- lib/rspec/core/formatters/html_printer.rb
|
@@ -237,20 +260,25 @@ files:
|
|
237
260
|
- lib/rspec/core/mocking_adapters/null.rb
|
238
261
|
- lib/rspec/core/mocking_adapters/rr.rb
|
239
262
|
- lib/rspec/core/mocking_adapters/rspec.rb
|
263
|
+
- lib/rspec/core/mutex.rb
|
240
264
|
- lib/rspec/core/notifications.rb
|
241
265
|
- lib/rspec/core/option_parser.rb
|
242
266
|
- lib/rspec/core/ordering.rb
|
243
267
|
- lib/rspec/core/pending.rb
|
268
|
+
- lib/rspec/core/profiler.rb
|
244
269
|
- lib/rspec/core/project_initializer.rb
|
245
270
|
- lib/rspec/core/project_initializer/.rspec
|
246
271
|
- lib/rspec/core/project_initializer/spec/spec_helper.rb
|
247
272
|
- lib/rspec/core/rake_task.rb
|
273
|
+
- lib/rspec/core/reentrant_mutex.rb
|
248
274
|
- lib/rspec/core/reporter.rb
|
249
275
|
- lib/rspec/core/ruby_project.rb
|
250
276
|
- lib/rspec/core/runner.rb
|
251
277
|
- lib/rspec/core/sandbox.rb
|
278
|
+
- lib/rspec/core/set.rb
|
252
279
|
- lib/rspec/core/shared_context.rb
|
253
280
|
- lib/rspec/core/shared_example_group.rb
|
281
|
+
- lib/rspec/core/shell_escape.rb
|
254
282
|
- lib/rspec/core/test_unit_assertions_adapter.rb
|
255
283
|
- lib/rspec/core/version.rb
|
256
284
|
- lib/rspec/core/warnings.rb
|
@@ -275,10 +303,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
275
303
|
- !ruby/object:Gem::Version
|
276
304
|
version: '0'
|
277
305
|
requirements: []
|
278
|
-
rubyforge_project:
|
306
|
+
rubyforge_project:
|
279
307
|
rubygems_version: 2.2.2
|
280
308
|
signing_key:
|
281
309
|
specification_version: 4
|
282
|
-
summary: rspec-core-3.
|
310
|
+
summary: rspec-core-3.3.0
|
283
311
|
test_files: []
|
284
312
|
has_rdoc:
|
metadata.gz.sig
CHANGED
Binary file
|
@@ -1,339 +0,0 @@
|
|
1
|
-
module RSpec
|
2
|
-
module Core
|
3
|
-
# @private
|
4
|
-
#
|
5
|
-
# Methods used internally by the backports.
|
6
|
-
#
|
7
|
-
# This code was (mostly) ported from the backports gem found at
|
8
|
-
# https://github.com/marcandre/backports which is subject to this license:
|
9
|
-
#
|
10
|
-
# =========================================================================
|
11
|
-
#
|
12
|
-
# Copyright (c) 2009 Marc-Andre Lafortune
|
13
|
-
#
|
14
|
-
# Permission is hereby granted, free of charge, to any person obtaining
|
15
|
-
# a copy of this software and associated documentation files (the
|
16
|
-
# "Software"), to deal in the Software without restriction, including
|
17
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
18
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
19
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
20
|
-
# the following conditions:
|
21
|
-
#
|
22
|
-
# The above copyright notice and this permission notice shall be
|
23
|
-
# included in all copies or substantial portions of the Software.
|
24
|
-
#
|
25
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
26
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
27
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
28
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
29
|
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
30
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
31
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
32
|
-
#
|
33
|
-
# =========================================================================
|
34
|
-
#
|
35
|
-
# The goal is to provide a random number generator in Ruby versions that do
|
36
|
-
# not have one. This was added to support localization of random spec
|
37
|
-
# ordering.
|
38
|
-
#
|
39
|
-
# These were in multiple files in backports, but merged into one here.
|
40
|
-
module Backports
|
41
|
-
# Helper method to coerce a value into a specific class.
|
42
|
-
# Raises a TypeError if the coercion fails or the returned value
|
43
|
-
# is not of the right class.
|
44
|
-
# (from Rubinius)
|
45
|
-
def self.coerce_to(obj, cls, meth)
|
46
|
-
return obj if obj.kind_of?(cls)
|
47
|
-
|
48
|
-
begin
|
49
|
-
ret = obj.__send__(meth)
|
50
|
-
rescue Exception => e
|
51
|
-
raise TypeError, "Coercion error: #{obj.inspect}.#{meth} => #{cls} failed:\n" \
|
52
|
-
"(#{e.message})"
|
53
|
-
end
|
54
|
-
raise TypeError, "Coercion error: obj.#{meth} did NOT return a #{cls} (was #{ret.class})" unless ret.kind_of? cls
|
55
|
-
ret
|
56
|
-
end
|
57
|
-
|
58
|
-
# @private
|
59
|
-
def self.coerce_to_int(obj)
|
60
|
-
coerce_to(obj, Integer, :to_int)
|
61
|
-
end
|
62
|
-
|
63
|
-
# Used internally to make it easy to deal with optional arguments.
|
64
|
-
# (from Rubinius)
|
65
|
-
Undefined = Object.new
|
66
|
-
|
67
|
-
# @private
|
68
|
-
class Random
|
69
|
-
# @private
|
70
|
-
# An implementation of Mersenne Twister MT19937 in Ruby.
|
71
|
-
class MT19937
|
72
|
-
STATE_SIZE = 624
|
73
|
-
LAST_STATE = STATE_SIZE - 1
|
74
|
-
PAD_32_BITS = 0xffffffff
|
75
|
-
|
76
|
-
# See seed=
|
77
|
-
def initialize(seed)
|
78
|
-
self.seed = seed
|
79
|
-
end
|
80
|
-
|
81
|
-
LAST_31_BITS = 0x7fffffff
|
82
|
-
OFFSET = 397
|
83
|
-
|
84
|
-
# Generates a completely new state out of the previous one.
|
85
|
-
def next_state
|
86
|
-
STATE_SIZE.times do |i|
|
87
|
-
mix = @state[i] & 0x80000000 | @state[i+1 - STATE_SIZE] & 0x7fffffff
|
88
|
-
@state[i] = @state[i+OFFSET - STATE_SIZE] ^ (mix >> 1)
|
89
|
-
@state[i] ^= 0x9908b0df if mix.odd?
|
90
|
-
end
|
91
|
-
@last_read = -1
|
92
|
-
end
|
93
|
-
|
94
|
-
# Seed must be either an Integer (only the first 32 bits will be used)
|
95
|
-
# or an Array of Integers (of which only the first 32 bits will be
|
96
|
-
# used).
|
97
|
-
#
|
98
|
-
# No conversion or type checking is done at this level.
|
99
|
-
def seed=(seed)
|
100
|
-
case seed
|
101
|
-
when Integer
|
102
|
-
@state = Array.new(STATE_SIZE)
|
103
|
-
@state[0] = seed & PAD_32_BITS
|
104
|
-
(1..LAST_STATE).each do |i|
|
105
|
-
@state[i] = (1812433253 * (@state[i-1] ^ @state[i-1]>>30) + i)& PAD_32_BITS
|
106
|
-
end
|
107
|
-
@last_read = LAST_STATE
|
108
|
-
when Array
|
109
|
-
self.seed = 19650218
|
110
|
-
i=1
|
111
|
-
j=0
|
112
|
-
[STATE_SIZE, seed.size].max.times do
|
113
|
-
@state[i] = (@state[i] ^ (@state[i-1] ^ @state[i-1]>>30) * 1664525) + j + seed[j] & PAD_32_BITS
|
114
|
-
if (i+=1) >= STATE_SIZE
|
115
|
-
@state[0] = @state[-1]
|
116
|
-
i = 1
|
117
|
-
end
|
118
|
-
j = 0 if (j+=1) >= seed.size
|
119
|
-
end
|
120
|
-
(STATE_SIZE-1).times do
|
121
|
-
@state[i] = (@state[i] ^ (@state[i-1] ^ @state[i-1]>>30) * 1566083941) - i & PAD_32_BITS
|
122
|
-
if (i+=1) >= STATE_SIZE
|
123
|
-
@state[0] = @state[-1]
|
124
|
-
i = 1
|
125
|
-
end
|
126
|
-
end
|
127
|
-
@state[0] = 0x80000000
|
128
|
-
else
|
129
|
-
raise ArgumentError, "Seed must be an Integer or an Array"
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
# Returns a random Integer from the range 0 ... (1 << 32).
|
134
|
-
def random_32_bits
|
135
|
-
next_state if @last_read >= LAST_STATE
|
136
|
-
@last_read += 1
|
137
|
-
y = @state[@last_read]
|
138
|
-
# Tempering
|
139
|
-
y ^= (y >> 11)
|
140
|
-
y ^= (y << 7) & 0x9d2c5680
|
141
|
-
y ^= (y << 15) & 0xefc60000
|
142
|
-
y ^= (y >> 18)
|
143
|
-
end
|
144
|
-
|
145
|
-
# Supplement the MT19937 class with methods to do
|
146
|
-
# conversions the same way as MRI.
|
147
|
-
# No argument checking is done here either.
|
148
|
-
|
149
|
-
FLOAT_FACTOR = 1.0/9007199254740992.0
|
150
|
-
# Generates a random number on [0, 1) with 53-bit resolution.
|
151
|
-
def random_float
|
152
|
-
((random_32_bits >> 5) * 67108864.0 + (random_32_bits >> 6)) * FLOAT_FACTOR;
|
153
|
-
end
|
154
|
-
|
155
|
-
# Returns an integer within 0...upto.
|
156
|
-
def random_integer(upto)
|
157
|
-
n = upto - 1
|
158
|
-
nb_full_32 = 0
|
159
|
-
while n > PAD_32_BITS
|
160
|
-
n >>= 32
|
161
|
-
nb_full_32 += 1
|
162
|
-
end
|
163
|
-
mask = mask_32_bits(n)
|
164
|
-
begin
|
165
|
-
rand = random_32_bits & mask
|
166
|
-
nb_full_32.times do
|
167
|
-
rand <<= 32
|
168
|
-
rand |= random_32_bits
|
169
|
-
end
|
170
|
-
end until rand < upto
|
171
|
-
rand
|
172
|
-
end
|
173
|
-
|
174
|
-
def random_bytes(nb)
|
175
|
-
nb_32_bits = (nb + 3) / 4
|
176
|
-
random = nb_32_bits.times.map { random_32_bits }
|
177
|
-
random.pack("L" * nb_32_bits)[0, nb]
|
178
|
-
end
|
179
|
-
|
180
|
-
def state_as_bignum
|
181
|
-
b = 0
|
182
|
-
@state.each_with_index do |val, i|
|
183
|
-
b |= val << (32 * i)
|
184
|
-
end
|
185
|
-
b
|
186
|
-
end
|
187
|
-
|
188
|
-
def left # It's actually the number of words left + 1, as per MRI...
|
189
|
-
MT19937::STATE_SIZE - @last_read
|
190
|
-
end
|
191
|
-
|
192
|
-
def marshal_dump
|
193
|
-
[state_as_bignum, left]
|
194
|
-
end
|
195
|
-
|
196
|
-
def marshal_load(ary)
|
197
|
-
b, left = ary
|
198
|
-
@last_read = MT19937::STATE_SIZE - left
|
199
|
-
@state = Array.new(STATE_SIZE)
|
200
|
-
STATE_SIZE.times do |i|
|
201
|
-
@state[i] = b & PAD_32_BITS
|
202
|
-
b >>= 32
|
203
|
-
end
|
204
|
-
end
|
205
|
-
|
206
|
-
# Convert an Integer seed of arbitrary size to either a single 32 bit
|
207
|
-
# integer, or an Array of 32 bit integers.
|
208
|
-
def self.convert_seed(seed)
|
209
|
-
seed = seed.abs
|
210
|
-
long_values = []
|
211
|
-
begin
|
212
|
-
long_values << (seed & PAD_32_BITS)
|
213
|
-
seed >>= 32
|
214
|
-
end until seed == 0
|
215
|
-
|
216
|
-
# Done to allow any kind of sequence of integers.
|
217
|
-
long_values.pop if long_values[-1] == 1 && long_values.size > 1
|
218
|
-
|
219
|
-
long_values.size > 1 ? long_values : long_values.first
|
220
|
-
end
|
221
|
-
|
222
|
-
def self.[](seed)
|
223
|
-
new(convert_seed(seed))
|
224
|
-
end
|
225
|
-
|
226
|
-
private
|
227
|
-
|
228
|
-
MASK_BY = [1,2,4,8,16]
|
229
|
-
def mask_32_bits(n)
|
230
|
-
MASK_BY.each do |shift|
|
231
|
-
n |= n >> shift
|
232
|
-
end
|
233
|
-
n
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
# @private
|
238
|
-
# Implementation corresponding to the actual Random class of Ruby
|
239
|
-
# The actual random generator (mersenne twister) is in MT19937.
|
240
|
-
# Ruby specific conversions are handled in bits_and_bytes.
|
241
|
-
# The high level stuff (argument checking) is done here.
|
242
|
-
module Implementation
|
243
|
-
attr_reader :seed
|
244
|
-
|
245
|
-
def initialize(seed = 0)
|
246
|
-
super()
|
247
|
-
seed_rand seed
|
248
|
-
end
|
249
|
-
|
250
|
-
def seed_rand(new_seed = 0)
|
251
|
-
new_seed = Backports.coerce_to_int(new_seed)
|
252
|
-
@seed = nil unless defined?(@seed)
|
253
|
-
old, @seed = @seed, new_seed.nonzero? || Random.new_seed
|
254
|
-
@mt = MT19937[ @seed ]
|
255
|
-
old
|
256
|
-
end
|
257
|
-
|
258
|
-
def rand(limit = Backports::Undefined)
|
259
|
-
case limit
|
260
|
-
when Backports::Undefined
|
261
|
-
@mt.random_float
|
262
|
-
when Float
|
263
|
-
limit * @mt.random_float unless limit <= 0
|
264
|
-
when Range
|
265
|
-
_rand_range(limit)
|
266
|
-
else
|
267
|
-
limit = Backports.coerce_to_int(limit)
|
268
|
-
@mt.random_integer(limit) unless limit <= 0
|
269
|
-
end || raise(ArgumentError, "invalid argument #{limit}")
|
270
|
-
end
|
271
|
-
|
272
|
-
def bytes(nb)
|
273
|
-
nb = Backports.coerce_to_int(nb)
|
274
|
-
raise ArgumentError, "negative size" if nb < 0
|
275
|
-
@mt.random_bytes(nb)
|
276
|
-
end
|
277
|
-
|
278
|
-
def ==(other)
|
279
|
-
other.is_a?(Random) &&
|
280
|
-
seed == other.seed &&
|
281
|
-
left == other.send(:left) &&
|
282
|
-
state == other.send(:state)
|
283
|
-
end
|
284
|
-
|
285
|
-
def marshal_dump
|
286
|
-
@mt.marshal_dump << @seed
|
287
|
-
end
|
288
|
-
|
289
|
-
def marshal_load(ary)
|
290
|
-
@seed = ary.pop
|
291
|
-
@mt = MT19937.allocate
|
292
|
-
@mt.marshal_load(ary)
|
293
|
-
end
|
294
|
-
|
295
|
-
private
|
296
|
-
|
297
|
-
def state
|
298
|
-
@mt.state_as_bignum
|
299
|
-
end
|
300
|
-
|
301
|
-
def left
|
302
|
-
@mt.left
|
303
|
-
end
|
304
|
-
|
305
|
-
def _rand_range(limit)
|
306
|
-
range = limit.end - limit.begin
|
307
|
-
if (!range.is_a?(Float)) && range.respond_to?(:to_int) && range = Backports.coerce_to_int(range)
|
308
|
-
range += 1 unless limit.exclude_end?
|
309
|
-
limit.begin + @mt.random_integer(range) unless range <= 0
|
310
|
-
elsif range = Backports.coerce_to(range, Float, :to_f)
|
311
|
-
if range < 0
|
312
|
-
nil
|
313
|
-
elsif limit.exclude_end?
|
314
|
-
limit.begin + @mt.random_float * range unless range <= 0
|
315
|
-
else
|
316
|
-
# cheat a bit... this will reduce the nb of random bits
|
317
|
-
loop do
|
318
|
-
r = @mt.random_float * range * 1.0001
|
319
|
-
break limit.begin + r unless r > range
|
320
|
-
end
|
321
|
-
end
|
322
|
-
end
|
323
|
-
end
|
324
|
-
end
|
325
|
-
|
326
|
-
def self.new_seed
|
327
|
-
(2 ** 62) + Kernel.rand(2 ** 62)
|
328
|
-
end
|
329
|
-
end
|
330
|
-
|
331
|
-
class Random
|
332
|
-
include Implementation
|
333
|
-
class << self
|
334
|
-
include Implementation
|
335
|
-
end
|
336
|
-
end
|
337
|
-
end
|
338
|
-
end
|
339
|
-
end
|