sspec-mirror-test 3.8.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 +7 -0
- data/Changelog.md +242 -0
- data/LICENSE.md +23 -0
- data/README.md +40 -0
- data/lib/rspec/support.rb +149 -0
- data/lib/rspec/support/caller_filter.rb +83 -0
- data/lib/rspec/support/comparable_version.rb +46 -0
- data/lib/rspec/support/differ.rb +215 -0
- data/lib/rspec/support/directory_maker.rb +63 -0
- data/lib/rspec/support/encoded_string.rb +165 -0
- data/lib/rspec/support/fuzzy_matcher.rb +48 -0
- data/lib/rspec/support/hunk_generator.rb +47 -0
- data/lib/rspec/support/matcher_definition.rb +42 -0
- data/lib/rspec/support/method_signature_verifier.rb +426 -0
- data/lib/rspec/support/mutex.rb +73 -0
- data/lib/rspec/support/object_formatter.rb +275 -0
- data/lib/rspec/support/recursive_const_methods.rb +76 -0
- data/lib/rspec/support/reentrant_mutex.rb +53 -0
- data/lib/rspec/support/ruby_features.rb +176 -0
- data/lib/rspec/support/source.rb +75 -0
- data/lib/rspec/support/source/location.rb +21 -0
- data/lib/rspec/support/source/node.rb +110 -0
- data/lib/rspec/support/source/token.rb +87 -0
- data/lib/rspec/support/spec.rb +81 -0
- data/lib/rspec/support/spec/deprecation_helpers.rb +64 -0
- data/lib/rspec/support/spec/formatting_support.rb +9 -0
- data/lib/rspec/support/spec/in_sub_process.rb +69 -0
- data/lib/rspec/support/spec/library_wide_checks.rb +150 -0
- data/lib/rspec/support/spec/shell_out.rb +84 -0
- data/lib/rspec/support/spec/stderr_splitter.rb +63 -0
- data/lib/rspec/support/spec/string_matcher.rb +46 -0
- data/lib/rspec/support/spec/with_isolated_directory.rb +13 -0
- data/lib/rspec/support/spec/with_isolated_stderr.rb +13 -0
- data/lib/rspec/support/version.rb +7 -0
- data/lib/rspec/support/warnings.rb +39 -0
- metadata +115 -0
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'rspec/support'
|
2
|
+
require 'rspec/support/spec/in_sub_process'
|
3
|
+
|
4
|
+
RSpec::Support.require_rspec_support "spec/deprecation_helpers"
|
5
|
+
RSpec::Support.require_rspec_support "spec/with_isolated_stderr"
|
6
|
+
RSpec::Support.require_rspec_support "spec/stderr_splitter"
|
7
|
+
RSpec::Support.require_rspec_support "spec/formatting_support"
|
8
|
+
RSpec::Support.require_rspec_support "spec/with_isolated_directory"
|
9
|
+
RSpec::Support.require_rspec_support "ruby_features"
|
10
|
+
|
11
|
+
warning_preventer = $stderr = RSpec::Support::StdErrSplitter.new($stderr)
|
12
|
+
|
13
|
+
RSpec.configure do |c|
|
14
|
+
c.include RSpecHelpers
|
15
|
+
c.include RSpec::Support::WithIsolatedStdErr
|
16
|
+
c.include RSpec::Support::FormattingSupport
|
17
|
+
c.include RSpec::Support::InSubProcess
|
18
|
+
|
19
|
+
unless defined?(Debugger) # debugger causes warnings when used
|
20
|
+
c.before do
|
21
|
+
warning_preventer.reset!
|
22
|
+
end
|
23
|
+
|
24
|
+
c.after do
|
25
|
+
warning_preventer.verify_no_warnings!
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
if c.files_to_run.one?
|
30
|
+
c.full_backtrace = true
|
31
|
+
c.default_formatter = 'doc'
|
32
|
+
end
|
33
|
+
|
34
|
+
c.filter_run_when_matching :focus
|
35
|
+
|
36
|
+
c.example_status_persistence_file_path = "./spec/examples.txt"
|
37
|
+
|
38
|
+
c.define_derived_metadata :failing_on_appveyor do |meta|
|
39
|
+
meta[:pending] ||= "This spec fails on AppVeyor and needs someone to fix it."
|
40
|
+
end if ENV['APPVEYOR']
|
41
|
+
end
|
42
|
+
|
43
|
+
module RSpec
|
44
|
+
module Support
|
45
|
+
module Spec
|
46
|
+
def self.setup_simplecov(&block)
|
47
|
+
# Simplecov emits some ruby warnings when loaded, so silence them.
|
48
|
+
old_verbose, $VERBOSE = $VERBOSE, false
|
49
|
+
|
50
|
+
return if ENV['NO_COVERAGE'] || RUBY_VERSION < '1.9.3'
|
51
|
+
return if RUBY_ENGINE != 'ruby' || RSpec::Support::OS.windows?
|
52
|
+
|
53
|
+
# Don't load it when we're running a single isolated
|
54
|
+
# test file rather than the whole suite.
|
55
|
+
return if RSpec.configuration.files_to_run.one?
|
56
|
+
|
57
|
+
require 'simplecov'
|
58
|
+
start_simplecov(&block)
|
59
|
+
rescue LoadError
|
60
|
+
warn "Simplecov could not be loaded"
|
61
|
+
ensure
|
62
|
+
$VERBOSE = old_verbose
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.start_simplecov(&block)
|
66
|
+
SimpleCov.start do
|
67
|
+
add_filter "./bundle/"
|
68
|
+
add_filter "./tmp/"
|
69
|
+
add_filter do |source_file|
|
70
|
+
# Filter out `spec` directory except when it is under `lib`
|
71
|
+
# (as is the case in rspec-support)
|
72
|
+
source_file.filename.include?('/spec/') && !source_file.filename.include?('/lib/')
|
73
|
+
end
|
74
|
+
|
75
|
+
instance_eval(&block) if block
|
76
|
+
end
|
77
|
+
end
|
78
|
+
private_class_method :start_simplecov
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module RSpecHelpers
|
2
|
+
def expect_no_deprecation
|
3
|
+
expect(RSpec.configuration.reporter).not_to receive(:deprecation)
|
4
|
+
end
|
5
|
+
|
6
|
+
def expect_deprecation_with_call_site(file, line, snippet=//)
|
7
|
+
expect(RSpec.configuration.reporter).to receive(:deprecation) do |options|
|
8
|
+
expect(options[:call_site]).to include([file, line].join(':'))
|
9
|
+
expect(options[:deprecated]).to match(snippet)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def expect_deprecation_without_call_site(snippet=//)
|
14
|
+
expect(RSpec.configuration.reporter).to receive(:deprecation) do |options|
|
15
|
+
expect(options[:call_site]).to eq nil
|
16
|
+
expect(options[:deprecated]).to match(snippet)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def expect_warn_deprecation_with_call_site(file, line, snippet=//)
|
21
|
+
expect(RSpec.configuration.reporter).to receive(:deprecation) do |options|
|
22
|
+
message = options[:message]
|
23
|
+
expect(message).to match(snippet)
|
24
|
+
expect(message).to include([file, line].join(':'))
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def expect_warn_deprecation(snippet=//)
|
29
|
+
expect(RSpec.configuration.reporter).to receive(:deprecation) do |options|
|
30
|
+
message = options[:message]
|
31
|
+
expect(message).to match(snippet)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def allow_deprecation
|
36
|
+
allow(RSpec.configuration.reporter).to receive(:deprecation)
|
37
|
+
end
|
38
|
+
|
39
|
+
def expect_no_deprecations
|
40
|
+
expect(RSpec.configuration.reporter).not_to receive(:deprecation)
|
41
|
+
end
|
42
|
+
|
43
|
+
def expect_warning_without_call_site(expected=//)
|
44
|
+
expect(::Kernel).to receive(:warn) do |message|
|
45
|
+
expect(message).to match expected
|
46
|
+
expect(message).to_not match(/Called from/)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def expect_warning_with_call_site(file, line, expected=//)
|
51
|
+
expect(::Kernel).to receive(:warn) do |message|
|
52
|
+
expect(message).to match expected
|
53
|
+
expect(message).to match(/Called from #{file}:#{line}/)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def expect_no_warnings
|
58
|
+
expect(::Kernel).not_to receive(:warn)
|
59
|
+
end
|
60
|
+
|
61
|
+
def allow_warning
|
62
|
+
allow(::Kernel).to receive(:warn)
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module RSpec
|
2
|
+
module Support
|
3
|
+
module InSubProcess
|
4
|
+
if Process.respond_to?(:fork) && !(Ruby.jruby? && RUBY_VERSION == '1.8.7')
|
5
|
+
|
6
|
+
UnmarshableObject = Struct.new(:error)
|
7
|
+
|
8
|
+
# Useful as a way to isolate a global change to a subprocess.
|
9
|
+
|
10
|
+
# rubocop:disable MethodLength
|
11
|
+
def in_sub_process(prevent_warnings=true)
|
12
|
+
exception_reader, exception_writer = IO.pipe
|
13
|
+
result_reader, result_writer = IO.pipe
|
14
|
+
|
15
|
+
pid = Process.fork do
|
16
|
+
warning_preventer = $stderr = RSpec::Support::StdErrSplitter.new($stderr)
|
17
|
+
|
18
|
+
begin
|
19
|
+
result = yield
|
20
|
+
warning_preventer.verify_no_warnings! if prevent_warnings
|
21
|
+
# rubocop:disable Lint/HandleExceptions
|
22
|
+
rescue Support::AllExceptionsExceptOnesWeMustNotRescue => exception
|
23
|
+
# rubocop:enable Lint/HandleExceptions
|
24
|
+
end
|
25
|
+
|
26
|
+
exception_writer.write marshal_dump_with_unmarshable_object_handling(exception)
|
27
|
+
exception_reader.close
|
28
|
+
exception_writer.close
|
29
|
+
|
30
|
+
result_writer.write marshal_dump_with_unmarshable_object_handling(result)
|
31
|
+
result_reader.close
|
32
|
+
result_writer.close
|
33
|
+
|
34
|
+
exit! # prevent at_exit hooks from running (e.g. minitest)
|
35
|
+
end
|
36
|
+
|
37
|
+
exception_writer.close
|
38
|
+
result_writer.close
|
39
|
+
Process.waitpid(pid)
|
40
|
+
|
41
|
+
exception = Marshal.load(exception_reader.read)
|
42
|
+
exception_reader.close
|
43
|
+
raise exception if exception
|
44
|
+
|
45
|
+
result = Marshal.load(result_reader.read)
|
46
|
+
result_reader.close
|
47
|
+
result
|
48
|
+
end
|
49
|
+
# rubocop:enable MethodLength
|
50
|
+
alias :in_sub_process_if_possible :in_sub_process
|
51
|
+
|
52
|
+
def marshal_dump_with_unmarshable_object_handling(object)
|
53
|
+
Marshal.dump(object)
|
54
|
+
rescue TypeError => error
|
55
|
+
Marshal.dump(UnmarshableObject.new(error))
|
56
|
+
end
|
57
|
+
else
|
58
|
+
def in_sub_process(*)
|
59
|
+
skip "This spec requires forking to work properly, " \
|
60
|
+
"and your platform does not support forking"
|
61
|
+
end
|
62
|
+
|
63
|
+
def in_sub_process_if_possible(*)
|
64
|
+
yield
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'rspec/support/spec/shell_out'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Support
|
5
|
+
module WhitespaceChecks
|
6
|
+
# This malformed whitespace detection logic has been borrowed from bundler:
|
7
|
+
# https://github.com/bundler/bundler/blob/v1.8.0/spec/quality_spec.rb
|
8
|
+
def check_for_tab_characters(filename)
|
9
|
+
failing_lines = []
|
10
|
+
File.readlines(filename).each_with_index do |line, number|
|
11
|
+
failing_lines << number + 1 if line =~ /\t/
|
12
|
+
end
|
13
|
+
|
14
|
+
return if failing_lines.empty?
|
15
|
+
"#{filename} has tab characters on lines #{failing_lines.join(', ')}"
|
16
|
+
end
|
17
|
+
|
18
|
+
def check_for_extra_spaces(filename)
|
19
|
+
failing_lines = []
|
20
|
+
File.readlines(filename).each_with_index do |line, number|
|
21
|
+
next if line =~ /^\s+#.*\s+\n$/
|
22
|
+
failing_lines << number + 1 if line =~ /\s+\n$/
|
23
|
+
end
|
24
|
+
|
25
|
+
return if failing_lines.empty?
|
26
|
+
"#{filename} has spaces on the EOL on lines #{failing_lines.join(', ')}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
RSpec.shared_examples_for "library wide checks" do |lib, options|
|
33
|
+
consider_a_test_env_file = options.fetch(:consider_a_test_env_file, /MATCHES NOTHING/)
|
34
|
+
allowed_loaded_feature_regexps = options.fetch(:allowed_loaded_feature_regexps, [])
|
35
|
+
preamble_for_lib = options[:preamble_for_lib]
|
36
|
+
preamble_for_spec = "require 'rspec/core'; require 'spec_helper'"
|
37
|
+
skip_spec_files = options.fetch(:skip_spec_files, /MATCHES NOTHING/)
|
38
|
+
|
39
|
+
include RSpec::Support::ShellOut
|
40
|
+
include RSpec::Support::WhitespaceChecks
|
41
|
+
|
42
|
+
define_method :files_to_require_for do |sub_dir|
|
43
|
+
slash = File::SEPARATOR
|
44
|
+
lib_path_re = /#{slash + lib}[^#{slash}]*#{slash}lib/
|
45
|
+
load_path = $LOAD_PATH.grep(lib_path_re).first
|
46
|
+
directory = load_path.sub(/lib$/, sub_dir)
|
47
|
+
files = Dir["#{directory}/**/*.rb"]
|
48
|
+
extract_regex = /#{Regexp.escape(directory) + File::SEPARATOR}(.+)\.rb$/
|
49
|
+
|
50
|
+
# We sort to ensure the files are loaded in a consistent order, regardless
|
51
|
+
# of OS. Otherwise, it could load in a different order on Travis than
|
52
|
+
# locally, and potentially trigger a "circular require considered harmful"
|
53
|
+
# warning or similar.
|
54
|
+
files.sort.map { |file| file[extract_regex, 1] }
|
55
|
+
end
|
56
|
+
|
57
|
+
def command_from(code_lines)
|
58
|
+
code_lines.join("\n")
|
59
|
+
end
|
60
|
+
|
61
|
+
def load_all_files(files, preamble, postamble=nil)
|
62
|
+
requires = files.map { |f| "require '#{f}'" }
|
63
|
+
command = command_from(Array(preamble) + requires + Array(postamble))
|
64
|
+
|
65
|
+
stdout, stderr, status = with_env 'NO_COVERAGE' => '1' do
|
66
|
+
options = %w[ -w ]
|
67
|
+
options << "--disable=gem" if RUBY_VERSION.to_f >= 1.9 && RSpec::Support::Ruby.mri?
|
68
|
+
run_ruby_with_current_load_path(command, *options)
|
69
|
+
end
|
70
|
+
|
71
|
+
[stdout, strip_known_warnings(stderr), status.exitstatus]
|
72
|
+
end
|
73
|
+
|
74
|
+
define_method :load_all_lib_files do
|
75
|
+
files = all_lib_files - lib_test_env_files
|
76
|
+
preamble = ['orig_loaded_features = $".dup', preamble_for_lib]
|
77
|
+
postamble = ['puts(($" - orig_loaded_features).join("\n"))']
|
78
|
+
|
79
|
+
@loaded_feature_lines, stderr, exitstatus = load_all_files(files, preamble, postamble)
|
80
|
+
["", stderr, exitstatus]
|
81
|
+
end
|
82
|
+
|
83
|
+
define_method :load_all_spec_files do
|
84
|
+
files = files_to_require_for("spec") + lib_test_env_files
|
85
|
+
files = files.reject { |f| f =~ skip_spec_files }
|
86
|
+
load_all_files(files, preamble_for_spec)
|
87
|
+
end
|
88
|
+
|
89
|
+
attr_reader :all_lib_files, :lib_test_env_files,
|
90
|
+
:lib_file_results, :spec_file_results
|
91
|
+
|
92
|
+
before(:context) do
|
93
|
+
@all_lib_files = files_to_require_for("lib")
|
94
|
+
@lib_test_env_files = all_lib_files.grep(consider_a_test_env_file)
|
95
|
+
|
96
|
+
@lib_file_results, @spec_file_results = [
|
97
|
+
# Load them in parallel so it's faster...
|
98
|
+
Thread.new { load_all_lib_files },
|
99
|
+
Thread.new { load_all_spec_files }
|
100
|
+
].map(&:join).map(&:value)
|
101
|
+
end
|
102
|
+
|
103
|
+
def have_successful_no_warnings_output
|
104
|
+
eq ["", "", 0]
|
105
|
+
end
|
106
|
+
|
107
|
+
it "issues no warnings when loaded", :slow do
|
108
|
+
expect(lib_file_results).to have_successful_no_warnings_output
|
109
|
+
end
|
110
|
+
|
111
|
+
it "issues no warnings when the spec files are loaded", :slow do
|
112
|
+
expect(spec_file_results).to have_successful_no_warnings_output
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'only loads a known set of stdlibs so gem authors are forced ' \
|
116
|
+
'to load libs they use to have passing specs', :slow do
|
117
|
+
loaded_features = @loaded_feature_lines.split("\n")
|
118
|
+
if RUBY_VERSION == '1.8.7'
|
119
|
+
# On 1.8.7, $" returns the relative require path if that was used
|
120
|
+
# to require the file. LIB_REGEX will not match the relative version
|
121
|
+
# since it has a `/lib` prefix. Here we deal with this by expanding
|
122
|
+
# relative files relative to the $LOAD_PATH dir (lib).
|
123
|
+
Dir.chdir("lib") { loaded_features.map! { |f| File.expand_path(f) } }
|
124
|
+
end
|
125
|
+
|
126
|
+
loaded_features.reject! { |feature| RSpec::CallerFilter::LIB_REGEX =~ feature }
|
127
|
+
loaded_features.reject! { |feature| allowed_loaded_feature_regexps.any? { |r| r =~ feature } }
|
128
|
+
|
129
|
+
expect(loaded_features).to eq([])
|
130
|
+
end
|
131
|
+
|
132
|
+
RSpec::Matchers.define :be_well_formed do
|
133
|
+
match do |actual|
|
134
|
+
actual.empty?
|
135
|
+
end
|
136
|
+
|
137
|
+
failure_message do |actual|
|
138
|
+
actual.join("\n")
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
it "has no malformed whitespace", :slow do
|
143
|
+
error_messages = []
|
144
|
+
`git ls-files -z`.split("\x0").each do |filename|
|
145
|
+
error_messages << check_for_tab_characters(filename)
|
146
|
+
error_messages << check_for_extra_spaces(filename)
|
147
|
+
end
|
148
|
+
expect(error_messages.compact).to be_well_formed
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'open3'
|
2
|
+
require 'rake/file_utils'
|
3
|
+
require 'shellwords'
|
4
|
+
|
5
|
+
module RSpec
|
6
|
+
module Support
|
7
|
+
module ShellOut
|
8
|
+
def with_env(vars)
|
9
|
+
original = ENV.to_hash
|
10
|
+
vars.each { |k, v| ENV[k] = v }
|
11
|
+
|
12
|
+
begin
|
13
|
+
yield
|
14
|
+
ensure
|
15
|
+
ENV.replace(original)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
if Open3.respond_to?(:capture3) # 1.9+
|
20
|
+
def shell_out(*command)
|
21
|
+
stdout, stderr, status = Open3.capture3(*command)
|
22
|
+
return stdout, filter(stderr), status
|
23
|
+
end
|
24
|
+
else # 1.8.7
|
25
|
+
# popen3 doesn't provide the exit status so we fake it out.
|
26
|
+
FakeProcessStatus = Struct.new(:exitstatus)
|
27
|
+
|
28
|
+
def shell_out(*command)
|
29
|
+
stdout = stderr = nil
|
30
|
+
|
31
|
+
Open3.popen3(*command) do |_in, out, err|
|
32
|
+
stdout = out.read
|
33
|
+
stderr = err.read
|
34
|
+
end
|
35
|
+
|
36
|
+
status = FakeProcessStatus.new(0)
|
37
|
+
return stdout, filter(stderr), status
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def run_ruby_with_current_load_path(ruby_command, *flags)
|
42
|
+
command = [
|
43
|
+
FileUtils::RUBY,
|
44
|
+
"-I#{$LOAD_PATH.map(&:shellescape).join(File::PATH_SEPARATOR)}",
|
45
|
+
"-e", ruby_command, *flags
|
46
|
+
]
|
47
|
+
|
48
|
+
# Unset these env vars because `ruby -w` will issue warnings whenever
|
49
|
+
# they are set to non-default values.
|
50
|
+
with_env 'RUBY_GC_HEAP_FREE_SLOTS' => nil, 'RUBY_GC_MALLOC_LIMIT' => nil,
|
51
|
+
'RUBY_FREE_MIN' => nil do
|
52
|
+
shell_out(*command)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def strip_known_warnings(input)
|
57
|
+
input.split("\n").reject do |l|
|
58
|
+
# Ignore bundler warning.
|
59
|
+
l =~ %r{bundler/source/rubygems} ||
|
60
|
+
# Ignore bundler + rubygems warning.
|
61
|
+
l =~ %r{site_ruby/\d\.\d\.\d/rubygems} ||
|
62
|
+
# This is required for windows for some reason
|
63
|
+
l =~ %r{lib/bundler/rubygems} ||
|
64
|
+
# This is a JRuby file that generates warnings on 9.0.3.0
|
65
|
+
l =~ %r{lib/ruby/stdlib/jar}
|
66
|
+
end.join("\n")
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
if Ruby.jruby?
|
72
|
+
def filter(output)
|
73
|
+
output.each_line.reject do |line|
|
74
|
+
line.include?("lib/ruby/shared/rubygems/defaults/jruby")
|
75
|
+
end.join($/)
|
76
|
+
end
|
77
|
+
else
|
78
|
+
def filter(output)
|
79
|
+
output
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|