зеркало из https://github.com/github/ruby.git
Update to ruby/spec@07164da
This commit is contained in:
Родитель
7429841ab6
Коммит
126fd5f15c
|
@ -152,6 +152,7 @@ RegexpSpecsSubclassTwo
|
|||
Reline
|
||||
RescueInClassExample
|
||||
Resolv
|
||||
Ripper
|
||||
SHA1Constants
|
||||
SHA256Constants
|
||||
SHA384Constants
|
||||
|
|
|
@ -92,6 +92,7 @@ Lint/UnreachableCode:
|
|||
Exclude:
|
||||
- 'core/enumerator/lazy/fixtures/classes.rb'
|
||||
- 'core/kernel/catch_spec.rb'
|
||||
- 'core/kernel/raise_spec.rb'
|
||||
- 'core/kernel/throw_spec.rb'
|
||||
- 'language/break_spec.rb'
|
||||
- 'language/fixtures/break.rb'
|
||||
|
|
|
@ -59,6 +59,7 @@ Lint/InheritException:
|
|||
- 'core/enumerator/lazy/fixtures/classes.rb'
|
||||
- 'core/exception/fixtures/common.rb'
|
||||
- 'core/module/fixtures/autoload_ex1.rb'
|
||||
- 'shared/kernel/raise.rb'
|
||||
|
||||
# Offense count: 72
|
||||
# Cop supports --auto-correct.
|
||||
|
@ -115,6 +116,7 @@ Lint/RescueException:
|
|||
- 'core/exception/cause_spec.rb'
|
||||
- 'core/exception/no_method_error_spec.rb'
|
||||
- 'core/kernel/fixtures/autoload_frozen.rb'
|
||||
- 'core/kernel/raise_spec.rb'
|
||||
- 'core/module/autoload_spec.rb'
|
||||
- 'core/mutex/sleep_spec.rb'
|
||||
- 'core/thread/abort_on_exception_spec.rb'
|
||||
|
|
|
@ -136,11 +136,11 @@ Here is a list of the most commonly-used guards:
|
|||
#### Version guards
|
||||
|
||||
```ruby
|
||||
ruby_version_is ""..."2.6 do
|
||||
ruby_version_is ""..."2.6" do
|
||||
# Specs for RUBY_VERSION < 2.6
|
||||
end
|
||||
|
||||
ruby_version_is "2.6 do
|
||||
ruby_version_is "2.6" do
|
||||
# Specs for RUBY_VERSION >= 2.6
|
||||
end
|
||||
```
|
||||
|
|
|
@ -7,7 +7,22 @@ describe "The -r command line option" do
|
|||
end
|
||||
|
||||
it "requires the specified file" do
|
||||
result = ruby_exe(@script, options: "-r #{@test_file}")
|
||||
result.should include(@test_file + ".rb")
|
||||
out = ruby_exe(@script, options: "-r #{@test_file}")
|
||||
out.should include("REQUIRED")
|
||||
out.should include(@test_file + ".rb")
|
||||
end
|
||||
|
||||
it "requires the file before parsing the main script" do
|
||||
out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), options: "-r #{@test_file}", args: "2>&1")
|
||||
$?.should_not.success?
|
||||
out.should include("REQUIRED")
|
||||
out.should include("syntax error")
|
||||
end
|
||||
|
||||
it "does not require the file if the main script file does not exist" do
|
||||
out = `#{ruby_exe.to_a.join(' ')} -r #{@test_file} #{fixture(__FILE__, "does_not_exist.rb")} 2>&1`
|
||||
$?.should_not.success?
|
||||
out.should_not.include?("REQUIRED")
|
||||
out.should.include?("No such file or directory")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1 +1 @@
|
|||
"test file"
|
||||
puts "REQUIRED"
|
||||
|
|
|
@ -207,8 +207,9 @@ describe "Array#fill with (filler, index, length)" do
|
|||
|
||||
not_supported_on :opal do
|
||||
it "raises an ArgumentError or RangeError for too-large sizes" do
|
||||
error_types = [RangeError, ArgumentError]
|
||||
arr = [1, 2, 3]
|
||||
-> { arr.fill(10, 1, fixnum_max) }.should raise_error(ArgumentError)
|
||||
-> { arr.fill(10, 1, fixnum_max) }.should raise_error { |err| error_types.should include(err.class) }
|
||||
-> { arr.fill(10, 1, bignum_value) }.should raise_error(RangeError)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -43,7 +43,7 @@ describe "Exception#backtrace" do
|
|||
# This regexp is deliberately imprecise to account for the need to abstract out
|
||||
# the paths of the included mspec files and the desire to avoid specifying in any
|
||||
# detail what the in `...' portion looks like.
|
||||
line.should =~ /^[^ ]+\:\d+(:in `[^`]+')?$/
|
||||
line.should =~ /^.+:\d+:in `[^`]+'$/
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -5,6 +5,13 @@ describe "Kernel#__dir__" do
|
|||
__dir__.should == File.realpath(File.dirname(__FILE__))
|
||||
end
|
||||
|
||||
it "returns the expanded path of the directory when used in the main script" do
|
||||
fixtures_dir = File.dirname(fixture(__FILE__, '__dir__.rb'))
|
||||
Dir.chdir(fixtures_dir) do
|
||||
ruby_exe("__dir__.rb").should == "__dir__.rb\n#{fixtures_dir}\n"
|
||||
end
|
||||
end
|
||||
|
||||
context "when used in eval with a given filename" do
|
||||
it "returns File.dirname(filename)" do
|
||||
eval("__dir__", nil, "foo.rb").should == "."
|
||||
|
|
|
@ -23,7 +23,7 @@ describe "Kernel.at_exit" do
|
|||
it "gives access to the last raised exception" do
|
||||
code = <<-EOC
|
||||
at_exit do
|
||||
puts "The exception matches: \#{$! == $exception}"
|
||||
puts "The exception matches: \#{$! == $exception} (message=\#{$!.message})"
|
||||
end
|
||||
|
||||
begin
|
||||
|
@ -33,10 +33,35 @@ describe "Kernel.at_exit" do
|
|||
end
|
||||
EOC
|
||||
|
||||
result = ruby_exe(code, args: "2>&1", escape: true)
|
||||
result.should =~ /The exception matches: true/
|
||||
result = ruby_exe(code, args: "2>&1")
|
||||
result.lines.should.include?("The exception matches: true (message=foo)\n")
|
||||
end
|
||||
|
||||
it "both exceptions in at_exit and in the main script are printed" do
|
||||
result = ruby_exe('at_exit { raise "at_exit_error" }; raise "main_script_error"', args: "2>&1")
|
||||
result.should.include?('at_exit_error (RuntimeError)')
|
||||
result.should.include?('main_script_error (RuntimeError)')
|
||||
end
|
||||
|
||||
it "decides the exit status if both at_exit and the main script raise SystemExit" do
|
||||
ruby_exe('at_exit { exit 43 }; exit 42', args: "2>&1")
|
||||
$?.exitstatus.should == 43
|
||||
end
|
||||
|
||||
it "runs all at_exit even if some raise exceptions" do
|
||||
code = 'at_exit { STDERR.puts "last" }; at_exit { exit 43 }; at_exit { STDERR.puts "first" }; exit 42'
|
||||
result = ruby_exe(code, args: "2>&1")
|
||||
result.should == "first\nlast\n"
|
||||
$?.exitstatus.should == 43
|
||||
end
|
||||
|
||||
it "runs at_exit handlers even if the main script fails to parse" do
|
||||
script = fixture(__FILE__, "at_exit.rb")
|
||||
result = ruby_exe('{', options: "-r#{script}", args: "2>&1")
|
||||
$?.should_not.success?
|
||||
result.should.include?("at_exit ran\n")
|
||||
result.should.include?("syntax error")
|
||||
end
|
||||
end
|
||||
|
||||
describe "Kernel#at_exit" do
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
puts __FILE__
|
||||
puts __dir__
|
|
@ -0,0 +1,3 @@
|
|||
at_exit do
|
||||
STDERR.puts "at_exit ran"
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
warn 'warn-require-warning', uplevel: 1
|
|
@ -0,0 +1,2 @@
|
|||
# Use a different line than just 1
|
||||
require "#{__dir__}/warn_require"
|
|
@ -6,6 +6,27 @@ describe "Kernel#raise" do
|
|||
it "is a private method" do
|
||||
Kernel.should have_private_instance_method(:raise)
|
||||
end
|
||||
|
||||
it "re-raises the previously rescued exception if no exception is specified" do
|
||||
ScratchPad.record nil
|
||||
|
||||
-> do
|
||||
begin
|
||||
raise Exception, "outer"
|
||||
ScratchPad.record :no_abort
|
||||
rescue Exception
|
||||
begin
|
||||
raise StandardError, "inner"
|
||||
rescue StandardError
|
||||
end
|
||||
|
||||
raise
|
||||
ScratchPad.record :no_reraise
|
||||
end
|
||||
end.should raise_error(Exception, "outer")
|
||||
|
||||
ScratchPad.recorded.should be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "Kernel#raise" do
|
||||
|
|
|
@ -101,6 +101,19 @@ describe "Kernel#warn" do
|
|||
-> { w.f4("foo", 3) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f3_call_lineno}: warning: foo|)
|
||||
end
|
||||
|
||||
# Test both explicitly without and with RubyGems as RubyGems overrides Kernel#warn
|
||||
it "shows the caller of #require and not #require itself without RubyGems" do
|
||||
file = fixture(__FILE__ , "warn_require_caller.rb")
|
||||
ruby_exe(file, options: "--disable-gems", args: "2>&1").should == "#{file}:2: warning: warn-require-warning\n"
|
||||
end
|
||||
|
||||
ruby_version_is "2.6" do
|
||||
it "shows the caller of #require and not #require itself with RubyGems loaded" do
|
||||
file = fixture(__FILE__ , "warn_require_caller.rb")
|
||||
ruby_exe(file, options: "-rrubygems", args: "2>&1").should == "#{file}:2: warning: warn-require-warning\n"
|
||||
end
|
||||
end
|
||||
|
||||
it "converts first arg using to_s" do
|
||||
w = KernelSpecs::WarnInNestedCall.new
|
||||
|
||||
|
|
|
@ -3,6 +3,10 @@ module ModuleSpecs
|
|||
def foo; "foo" end
|
||||
end
|
||||
|
||||
class ClassWithSuperFoo
|
||||
def foo; [:C] end
|
||||
end
|
||||
|
||||
module PrependedModule
|
||||
def foo; "foo from prepended module"; end
|
||||
end
|
||||
|
@ -11,7 +15,11 @@ module ModuleSpecs
|
|||
def foo; "foo from included module"; end
|
||||
end
|
||||
|
||||
def self.build_refined_class
|
||||
def self.build_refined_class(for_super: false)
|
||||
if for_super
|
||||
Class.new(ClassWithSuperFoo)
|
||||
else
|
||||
Class.new(ClassWithFoo)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -731,16 +731,67 @@ describe "Module#refine" do
|
|||
result.should == "foo"
|
||||
end
|
||||
|
||||
it "looks in the refined class from included module" do
|
||||
refined_class = ModuleSpecs.build_refined_class(for_super: true)
|
||||
|
||||
a = Module.new do
|
||||
def foo
|
||||
[:A] + super
|
||||
end
|
||||
end
|
||||
|
||||
refinement = Module.new do
|
||||
refine refined_class do
|
||||
include a
|
||||
end
|
||||
end
|
||||
|
||||
result = nil
|
||||
Module.new do
|
||||
using refinement
|
||||
|
||||
result = refined_class.new.foo
|
||||
end
|
||||
|
||||
result.should == [:A, :C]
|
||||
end
|
||||
|
||||
it "looks in the refined ancestors from included module" do
|
||||
refined_class = ModuleSpecs.build_refined_class(for_super: true)
|
||||
subclass = Class.new(refined_class)
|
||||
|
||||
a = Module.new do
|
||||
def foo
|
||||
[:A] + super
|
||||
end
|
||||
end
|
||||
|
||||
refinement = Module.new do
|
||||
refine refined_class do
|
||||
include a
|
||||
end
|
||||
end
|
||||
|
||||
result = nil
|
||||
Module.new do
|
||||
using refinement
|
||||
|
||||
result = subclass.new.foo
|
||||
end
|
||||
|
||||
result.should == [:A, :C]
|
||||
end
|
||||
|
||||
# super in a method of a refinement invokes the method in the refined
|
||||
# class even if there is another refinement which has been activated
|
||||
# in the same context.
|
||||
it "looks in the refined class even if there is another active refinement" do
|
||||
refined_class = ModuleSpecs.build_refined_class
|
||||
it "looks in the refined class first if called from refined method" do
|
||||
refined_class = ModuleSpecs.build_refined_class(for_super: true)
|
||||
|
||||
refinement = Module.new do
|
||||
refine refined_class do
|
||||
def foo
|
||||
"foo from refinement"
|
||||
[:R1]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -748,7 +799,7 @@ describe "Module#refine" do
|
|||
refinement_with_super = Module.new do
|
||||
refine refined_class do
|
||||
def foo
|
||||
super
|
||||
[:R2] + super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -760,7 +811,246 @@ describe "Module#refine" do
|
|||
result = refined_class.new.foo
|
||||
end
|
||||
|
||||
result.should == "foo"
|
||||
result.should == [:R2, :C]
|
||||
end
|
||||
|
||||
it "looks only in the refined class even if there is another active refinement" do
|
||||
refined_class = ModuleSpecs.build_refined_class(for_super: true)
|
||||
|
||||
refinement = Module.new do
|
||||
refine refined_class do
|
||||
def bar
|
||||
"you cannot see me from super because I belong to another active R"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
refinement_with_super = Module.new do
|
||||
refine refined_class do
|
||||
def bar
|
||||
super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Module.new do
|
||||
using refinement
|
||||
using refinement_with_super
|
||||
-> {
|
||||
refined_class.new.bar
|
||||
}.should raise_error(NoMethodError)
|
||||
end
|
||||
end
|
||||
|
||||
it "does't have access to active refinements for C from included module" do
|
||||
refined_class = ModuleSpecs.build_refined_class
|
||||
|
||||
a = Module.new do
|
||||
def foo
|
||||
super + bar
|
||||
end
|
||||
end
|
||||
|
||||
refinement = Module.new do
|
||||
refine refined_class do
|
||||
include a
|
||||
|
||||
def bar
|
||||
"bar is not seen from A methods"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Module.new do
|
||||
using refinement
|
||||
-> {
|
||||
refined_class.new.foo
|
||||
}.should raise_error(NameError) { |e| e.name.should == :bar }
|
||||
end
|
||||
end
|
||||
|
||||
it "does't have access to other active refinements from included module" do
|
||||
refined_class = ModuleSpecs.build_refined_class
|
||||
|
||||
refinement_integer = Module.new do
|
||||
refine Integer do
|
||||
def bar
|
||||
"bar is not seen from A methods"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
a = Module.new do
|
||||
def foo
|
||||
super + 1.bar
|
||||
end
|
||||
end
|
||||
|
||||
refinement = Module.new do
|
||||
refine refined_class do
|
||||
include a
|
||||
end
|
||||
end
|
||||
|
||||
Module.new do
|
||||
using refinement
|
||||
using refinement_integer
|
||||
-> {
|
||||
refined_class.new.foo
|
||||
}.should raise_error(NameError) { |e| e.name.should == :bar }
|
||||
end
|
||||
end
|
||||
|
||||
# https://bugs.ruby-lang.org/issues/16977
|
||||
it "looks in the another active refinement if super called from included modules" do
|
||||
refined_class = ModuleSpecs.build_refined_class(for_super: true)
|
||||
|
||||
a = Module.new do
|
||||
def foo
|
||||
[:A] + super
|
||||
end
|
||||
end
|
||||
|
||||
b = Module.new do
|
||||
def foo
|
||||
[:B] + super
|
||||
end
|
||||
end
|
||||
|
||||
refinement_a = Module.new do
|
||||
refine refined_class do
|
||||
include a
|
||||
end
|
||||
end
|
||||
|
||||
refinement_b = Module.new do
|
||||
refine refined_class do
|
||||
include b
|
||||
end
|
||||
end
|
||||
|
||||
result = nil
|
||||
Module.new do
|
||||
using refinement_a
|
||||
using refinement_b
|
||||
result = refined_class.new.foo
|
||||
end
|
||||
|
||||
result.should == [:B, :A, :C]
|
||||
end
|
||||
|
||||
it "looks in the current active refinement from included modules" do
|
||||
refined_class = ModuleSpecs.build_refined_class(for_super: true)
|
||||
|
||||
a = Module.new do
|
||||
def foo
|
||||
[:A] + super
|
||||
end
|
||||
end
|
||||
|
||||
b = Module.new do
|
||||
def foo
|
||||
[:B] + super
|
||||
end
|
||||
end
|
||||
|
||||
refinement = Module.new do
|
||||
refine refined_class do
|
||||
def foo
|
||||
[:LAST] + super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
refinement_a_b = Module.new do
|
||||
refine refined_class do
|
||||
include a
|
||||
include b
|
||||
end
|
||||
end
|
||||
|
||||
result = nil
|
||||
Module.new do
|
||||
using refinement
|
||||
using refinement_a_b
|
||||
result = refined_class.new.foo
|
||||
end
|
||||
|
||||
result.should == [:B, :A, :LAST, :C]
|
||||
end
|
||||
|
||||
ruby_version_is ""..."2.8" do
|
||||
it "looks in the lexical scope refinements before other active refinements" do
|
||||
refined_class = ModuleSpecs.build_refined_class(for_super: true)
|
||||
|
||||
refinement_local = Module.new do
|
||||
refine refined_class do
|
||||
def foo
|
||||
[:LOCAL] + super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
a = Module.new do
|
||||
using refinement_local
|
||||
|
||||
def foo
|
||||
[:A] + super
|
||||
end
|
||||
end
|
||||
|
||||
refinement = Module.new do
|
||||
refine refined_class do
|
||||
include a
|
||||
end
|
||||
end
|
||||
|
||||
result = nil
|
||||
Module.new do
|
||||
using refinement
|
||||
result = refined_class.new.foo
|
||||
end
|
||||
|
||||
result.should == [:A, :LOCAL, :C]
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is "2.8" do
|
||||
# https://bugs.ruby-lang.org/issues/17007
|
||||
it "does not look in the lexical scope refinements before other active refinements" do
|
||||
refined_class = ModuleSpecs.build_refined_class(for_super: true)
|
||||
|
||||
refinement_local = Module.new do
|
||||
refine refined_class do
|
||||
def foo
|
||||
[:LOCAL] + super
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
a = Module.new do
|
||||
using refinement_local
|
||||
|
||||
def foo
|
||||
[:A] + super
|
||||
end
|
||||
end
|
||||
|
||||
refinement = Module.new do
|
||||
refine refined_class do
|
||||
include a
|
||||
end
|
||||
end
|
||||
|
||||
result = nil
|
||||
Module.new do
|
||||
using refinement
|
||||
result = refined_class.new.foo
|
||||
end
|
||||
|
||||
result.should == [:A, :C]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -426,14 +426,72 @@ describe "String#split with Regexp" do
|
|||
end
|
||||
|
||||
ruby_version_is "2.6" do
|
||||
it "yields each split substrings if a block is given" do
|
||||
context "when a block is given" do
|
||||
it "yields each split substring with default pattern" do
|
||||
a = []
|
||||
returned_object = "chunky bacon".split(" ") { |str| a << str.capitalize }
|
||||
returned_object = "chunky bacon".split { |str| a << str.capitalize }
|
||||
|
||||
returned_object.should == "chunky bacon"
|
||||
a.should == ["Chunky", "Bacon"]
|
||||
end
|
||||
|
||||
it "yields the string when limit is 1" do
|
||||
a = []
|
||||
returned_object = "chunky bacon".split("", 1) { |str| a << str.capitalize }
|
||||
|
||||
returned_object.should == "chunky bacon"
|
||||
a.should == ["Chunky bacon"]
|
||||
end
|
||||
|
||||
it "yields each split letter" do
|
||||
a = []
|
||||
returned_object = "chunky".split("", 0) { |str| a << str.capitalize }
|
||||
|
||||
returned_object.should == "chunky"
|
||||
a.should == %w(C H U N K Y)
|
||||
end
|
||||
|
||||
it "yields each split substring with a pattern" do
|
||||
a = []
|
||||
returned_object = "chunky-bacon".split("-", 0) { |str| a << str.capitalize }
|
||||
|
||||
returned_object.should == "chunky-bacon"
|
||||
a.should == ["Chunky", "Bacon"]
|
||||
end
|
||||
|
||||
it "yields each split substring with empty regexp pattern" do
|
||||
a = []
|
||||
returned_object = "chunky".split(//) { |str| a << str.capitalize }
|
||||
|
||||
returned_object.should == "chunky"
|
||||
a.should == %w(C H U N K Y)
|
||||
end
|
||||
|
||||
it "yields each split substring with empty regexp pattern and limit" do
|
||||
a = []
|
||||
returned_object = "chunky".split(//, 3) { |str| a << str.capitalize }
|
||||
|
||||
returned_object.should == "chunky"
|
||||
a.should == %w(C H Unky)
|
||||
end
|
||||
|
||||
it "yields each split substring with a regexp pattern" do
|
||||
a = []
|
||||
returned_object = "chunky:bacon".split(/:/) { |str| a << str.capitalize }
|
||||
|
||||
returned_object.should == "chunky:bacon"
|
||||
a.should == ["Chunky", "Bacon"]
|
||||
end
|
||||
|
||||
it "returns a string as is (and doesn't call block) if it is empty" do
|
||||
a = []
|
||||
returned_object = "".split { |str| a << str.capitalize }
|
||||
|
||||
returned_object.should == ""
|
||||
a.should == []
|
||||
end
|
||||
end
|
||||
|
||||
describe "for a String subclass" do
|
||||
it "yields instances of the same subclass" do
|
||||
a = []
|
||||
|
|
|
@ -10,6 +10,13 @@ describe 'Thread::Backtrace::Location#absolute_path' do
|
|||
@frame.absolute_path.should == File.realpath(__FILE__)
|
||||
end
|
||||
|
||||
it 'returns an absolute path when using a relative main script path' do
|
||||
script = fixture(__FILE__, 'absolute_path_main.rb')
|
||||
Dir.chdir(File.dirname(script)) do
|
||||
ruby_exe('absolute_path_main.rb').should == "absolute_path_main.rb\n#{script}\n"
|
||||
end
|
||||
end
|
||||
|
||||
context "when used in eval with a given filename" do
|
||||
it "returns filename" do
|
||||
code = "caller_locations(0)[0].absolute_path"
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
puts __FILE__
|
||||
puts caller_locations(0)[0].absolute_path
|
|
@ -10,4 +10,14 @@ describe 'Thread::Backtrace::Location#lineno' do
|
|||
it 'returns the absolute path of the call frame' do
|
||||
@frame.lineno.should == @line
|
||||
end
|
||||
|
||||
it 'should be the same line number as in #to_s, including for core methods' do
|
||||
# Get the caller_locations from a call made into a core library method
|
||||
locations = [:non_empty].map { caller_locations }[0]
|
||||
|
||||
locations.each do |location|
|
||||
line_number = location.to_s[/:(\d+):/, 1]
|
||||
location.lineno.should == Integer(line_number)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -87,6 +87,18 @@ describe 'Thread::Backtrace::Location#path' do
|
|||
end
|
||||
end
|
||||
|
||||
it 'should be the same path as in #to_s, including for core methods' do
|
||||
# Get the caller_locations from a call made into a core library method
|
||||
locations = [:non_empty].map { caller_locations }[0]
|
||||
|
||||
locations.each do |location|
|
||||
filename = location.to_s[/^(.+):\d+:/, 1]
|
||||
path = location.path
|
||||
|
||||
path.should == filename
|
||||
end
|
||||
end
|
||||
|
||||
context "canonicalization" do
|
||||
platform_is_not :windows do
|
||||
before :each do
|
||||
|
|
|
@ -203,6 +203,6 @@ describe "Thread#raise on same thread" do
|
|||
Thread.current.raise
|
||||
end
|
||||
end
|
||||
-> { t.value }.should raise_error(RuntimeError)
|
||||
-> { t.value }.should raise_error(RuntimeError, '')
|
||||
end
|
||||
end
|
||||
|
|
|
@ -362,4 +362,22 @@ describe "Executing break from within a block" do
|
|||
bt2.three
|
||||
ScratchPad.recorded.should == [:two_ensure, :three_post, :three_ensure]
|
||||
end
|
||||
|
||||
it "works when passing through a super call" do
|
||||
cls1 = Class.new { def foo; yield; end }
|
||||
cls2 = Class.new(cls1) { def foo; super { break 1 }; end }
|
||||
|
||||
-> do
|
||||
cls2.new.foo.should == 1
|
||||
end.should_not raise_error
|
||||
end
|
||||
|
||||
it "raises LocalJumpError when converted into a proc during a a super call" do
|
||||
cls1 = Class.new { def foo(&b); b; end }
|
||||
cls2 = Class.new(cls1) { def foo; super { break 1 }.call; end }
|
||||
|
||||
-> do
|
||||
cls2.new.foo
|
||||
end.should raise_error(LocalJumpError)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -42,7 +42,7 @@ ruby_version_is "2.7" do
|
|||
end
|
||||
end
|
||||
|
||||
it "warns when numbered parameter is overriten with local variable" do
|
||||
it "warns when numbered parameter is overwritten with local variable" do
|
||||
-> {
|
||||
eval("_1 = 0")
|
||||
}.should complain(/warning: `_1' is reserved for numbered parameter; consider another name/)
|
||||
|
@ -59,7 +59,7 @@ ruby_version_is "2.7" do
|
|||
}.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
|
||||
end
|
||||
|
||||
it "errors when numbered parameter is overriten with local variable" do
|
||||
it "errors when numbered parameter is overwritten with local variable" do
|
||||
-> {
|
||||
eval("_1 = 0")
|
||||
}.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
|
||||
|
|
|
@ -8,6 +8,11 @@ describe "BigDecimal#to_s" do
|
|||
@bigneg_str = "-3.1415926535897932384626433832795028841971693993"
|
||||
@bigdec = BigDecimal(@bigdec_str)
|
||||
@bigneg = BigDecimal(@bigneg_str)
|
||||
@internal = Encoding.default_internal
|
||||
end
|
||||
|
||||
after :each do
|
||||
Encoding.default_internal = @internal
|
||||
end
|
||||
|
||||
it "return type is of class String" do
|
||||
|
@ -78,4 +83,15 @@ describe "BigDecimal#to_s" do
|
|||
end
|
||||
end
|
||||
|
||||
ruby_version_is "2.8" do
|
||||
it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do
|
||||
Encoding.default_internal = nil
|
||||
BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII)
|
||||
end
|
||||
|
||||
it "returns a String in US-ASCII encoding when Encoding.default_internal is not nil" do
|
||||
Encoding.default_internal = Encoding::IBM437
|
||||
BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
require_relative '../../../spec_helper'
|
||||
require 'digest'
|
||||
require_relative '../md5/shared/constants'
|
||||
|
||||
describe "Digest::Instance#new" do
|
||||
it "returns a copy of the digest instance" do
|
||||
digest = Digest::MD5.new
|
||||
copy = digest.new
|
||||
copy.should_not.equal?(digest)
|
||||
end
|
||||
|
||||
it "calls reset" do
|
||||
digest = Digest::MD5.new
|
||||
digest << "test"
|
||||
digest.hexdigest.should != MD5Constants::BlankHexdigest
|
||||
copy = digest.new
|
||||
copy.hexdigest.should == MD5Constants::BlankHexdigest
|
||||
end
|
||||
end
|
|
@ -0,0 +1,23 @@
|
|||
require_relative '../../spec_helper'
|
||||
require 'ripper'
|
||||
|
||||
describe "Ripper.lex" do
|
||||
it "lexes a simple method declaration" do
|
||||
expected = [
|
||||
[[1, 0], :on_kw, "def", 'FNAME'],
|
||||
[[1, 3], :on_sp, " ", 'FNAME'],
|
||||
[[1, 4], :on_ident, "m", 'ENDFN'],
|
||||
[[1, 5], :on_lparen, "(", 'BEG|LABEL'],
|
||||
[[1, 6], :on_ident, "a", 'ARG'],
|
||||
[[1, 7], :on_rparen, ")", 'ENDFN'],
|
||||
[[1, 8], :on_sp, " ", 'BEG'],
|
||||
[[1, 9], :on_kw, "nil", 'END'],
|
||||
[[1, 12], :on_sp, " ", 'END'],
|
||||
[[1, 13], :on_kw, "end", 'END']
|
||||
]
|
||||
lexed = Ripper.lex("def m(a) nil end")
|
||||
lexed.map { |e|
|
||||
e[0...-1] + [e[-1].to_s.split('|').map { |s| s.sub(/^EXPR_/, '') }.join('|')]
|
||||
}.should == expected
|
||||
end
|
||||
end
|
|
@ -0,0 +1,13 @@
|
|||
require_relative '../../spec_helper'
|
||||
require 'ripper'
|
||||
|
||||
describe "Ripper.sexp" do
|
||||
it "returns an s-expression for a method declaration" do
|
||||
expected = [:program,
|
||||
[[:def,
|
||||
[:@ident, "hello", [1, 4]],
|
||||
[:params, nil, nil, nil, nil, nil, nil, nil],
|
||||
[:bodystmt, [[:@int, "42", [1, 11]]], nil, nil, nil]]]]
|
||||
Ripper.sexp("def hello; 42; end").should == expected
|
||||
end
|
||||
end
|
|
@ -58,6 +58,15 @@ describe "C-API Encoding function" do
|
|||
end
|
||||
end
|
||||
|
||||
describe "rb_enc_codelen" do
|
||||
it "returns the correct length for the given codepoint" do
|
||||
@s.rb_enc_codelen(0x24, Encoding::UTF_8).should == 1
|
||||
@s.rb_enc_codelen(0xA2, Encoding::UTF_8).should == 2
|
||||
@s.rb_enc_codelen(0x20AC, Encoding::UTF_8).should == 3
|
||||
@s.rb_enc_codelen(0x24B62, Encoding::UTF_8).should == 4
|
||||
end
|
||||
end
|
||||
|
||||
describe "rb_enc_find" do
|
||||
it "returns the encoding of an Encoding" do
|
||||
@s.rb_enc_find("UTF-8").should == "UTF-8"
|
||||
|
@ -130,6 +139,18 @@ describe "C-API Encoding function" do
|
|||
end
|
||||
end
|
||||
|
||||
describe "rb_enc_mbcput" do
|
||||
it "writes the correct bytes to the buffer" do
|
||||
@s.rb_enc_mbcput(0x24, Encoding::UTF_8).should == "$"
|
||||
@s.rb_enc_mbcput(0xA2, Encoding::UTF_8).should == "¢"
|
||||
@s.rb_enc_mbcput(0x20AC, Encoding::UTF_8).should == "€"
|
||||
@s.rb_enc_mbcput(0x24B62, Encoding::UTF_8).should == "𤭢"
|
||||
|
||||
@s.rb_enc_mbcput(0x24, Encoding::UTF_16BE).bytes.should == [0, 0x24]
|
||||
@s.rb_enc_mbcput(0x24B62, Encoding::UTF_16LE).bytes.should == [82, 216, 98, 223]
|
||||
end
|
||||
end
|
||||
|
||||
describe "rb_usascii_encoding" do
|
||||
it "returns the encoding for Encoding::US_ASCII" do
|
||||
@s.rb_usascii_encoding.should == "US-ASCII"
|
||||
|
@ -610,4 +631,21 @@ describe "C-API Encoding function" do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "ONIGENC_MBC_CASE_FOLD" do
|
||||
it "returns the correct case fold for the given string" do
|
||||
@s.ONIGENC_MBC_CASE_FOLD("lower").should == ["l", 1]
|
||||
@s.ONIGENC_MBC_CASE_FOLD("Upper").should == ["u", 1]
|
||||
end
|
||||
|
||||
it "works with other encodings" do
|
||||
@s.ONIGENC_MBC_CASE_FOLD("lower".force_encoding("binary")).should == ["l", 1]
|
||||
@s.ONIGENC_MBC_CASE_FOLD("Upper".force_encoding("binary")).should == ["u", 1]
|
||||
@s.ONIGENC_MBC_CASE_FOLD("É").should == ["é", 2]
|
||||
|
||||
str, length = @s.ONIGENC_MBC_CASE_FOLD('$'.encode(Encoding::UTF_16BE))
|
||||
length.should == 2
|
||||
str.bytes.should == [0, 0x24]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -127,6 +127,18 @@ static VALUE encoding_spec_rb_enc_mbc_to_codepoint(VALUE self, VALUE str, VALUE
|
|||
return INT2FIX(rb_enc_mbc_to_codepoint(p, e, rb_enc_get(str)));
|
||||
}
|
||||
|
||||
static VALUE encoding_spec_rb_enc_mbcput(VALUE self, VALUE code, VALUE encoding) {
|
||||
unsigned int c = FIX2UINT(code);
|
||||
rb_encoding *enc = rb_to_encoding(encoding);
|
||||
char buf[ONIGENC_CODE_TO_MBC_MAXLEN];
|
||||
memset(buf, '\1', sizeof(buf));
|
||||
int len = rb_enc_mbcput(c, buf, enc);
|
||||
if (buf[len] != '\1') {
|
||||
rb_raise(rb_eRuntimeError, "should not change bytes after len");
|
||||
}
|
||||
return rb_enc_str_new(buf, len, enc);
|
||||
}
|
||||
|
||||
static VALUE encoding_spec_rb_enc_from_encoding(VALUE self, VALUE name) {
|
||||
return rb_enc_from_encoding(rb_enc_find(RSTRING_PTR(name)));
|
||||
}
|
||||
|
@ -266,6 +278,28 @@ static VALUE encoding_spec_rb_uv_to_utf8(VALUE self, VALUE buf, VALUE num) {
|
|||
return INT2NUM(rb_uv_to_utf8(RSTRING_PTR(buf), NUM2INT(num)));
|
||||
}
|
||||
|
||||
static VALUE encoding_spec_ONIGENC_MBC_CASE_FOLD(VALUE self, VALUE str) {
|
||||
char *beg = RSTRING_PTR(str);
|
||||
char *beg_initial = beg;
|
||||
char *end = beg + 2;
|
||||
OnigUChar fold[ONIGENC_GET_CASE_FOLD_CODES_MAX_NUM];
|
||||
memset(fold, '\1', sizeof(fold));
|
||||
rb_encoding *enc = rb_enc_get(str);
|
||||
int r = ONIGENC_MBC_CASE_FOLD(enc, ONIGENC_CASE_FOLD, &beg, (const OnigUChar *)end, fold);
|
||||
if (r > 0 && fold[r] != '\1') {
|
||||
rb_raise(rb_eRuntimeError, "should not change bytes after len");
|
||||
}
|
||||
VALUE str_result = r <= 0 ? Qnil : rb_enc_str_new((char *)fold, r, enc);
|
||||
long bytes_used = beg - beg_initial;
|
||||
return rb_ary_new3(2, str_result, INT2FIX(bytes_used));
|
||||
}
|
||||
|
||||
static VALUE encoding_spec_rb_enc_codelen(VALUE self, VALUE code, VALUE encoding) {
|
||||
unsigned int c = FIX2UINT(code);
|
||||
rb_encoding *enc = rb_to_encoding(encoding);
|
||||
return INT2FIX(rb_enc_codelen(c, enc));
|
||||
}
|
||||
|
||||
void Init_encoding_spec(void) {
|
||||
VALUE cls;
|
||||
native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*));
|
||||
|
@ -299,12 +333,14 @@ void Init_encoding_spec(void) {
|
|||
rb_define_method(cls, "rb_enc_associate_index", encoding_spec_rb_enc_associate_index, 2);
|
||||
rb_define_method(cls, "rb_enc_compatible", encoding_spec_rb_enc_compatible, 2);
|
||||
rb_define_method(cls, "rb_enc_copy", encoding_spec_rb_enc_copy, 2);
|
||||
rb_define_method(cls, "rb_enc_codelen", encoding_spec_rb_enc_codelen, 2);
|
||||
rb_define_method(cls, "rb_enc_find", encoding_spec_rb_enc_find, 1);
|
||||
rb_define_method(cls, "rb_enc_find_index", encoding_spec_rb_enc_find_index, 1);
|
||||
rb_define_method(cls, "rb_enc_isalnum", encoding_spec_rb_enc_isalnum, 2);
|
||||
rb_define_method(cls, "rb_enc_isspace", encoding_spec_rb_enc_isspace, 2);
|
||||
rb_define_method(cls, "rb_enc_from_index", encoding_spec_rb_enc_from_index, 1);
|
||||
rb_define_method(cls, "rb_enc_mbc_to_codepoint", encoding_spec_rb_enc_mbc_to_codepoint, 2);
|
||||
rb_define_method(cls, "rb_enc_mbcput", encoding_spec_rb_enc_mbcput, 2);
|
||||
rb_define_method(cls, "rb_enc_from_encoding", encoding_spec_rb_enc_from_encoding, 1);
|
||||
rb_define_method(cls, "rb_enc_get", encoding_spec_rb_enc_get, 1);
|
||||
rb_define_method(cls, "rb_enc_precise_mbclen", encoding_spec_rb_enc_precise_mbclen, 2);
|
||||
|
@ -326,6 +362,7 @@ void Init_encoding_spec(void) {
|
|||
rb_define_method(cls, "rb_enc_codepoint_len", encoding_spec_rb_enc_codepoint_len, 1);
|
||||
rb_define_method(cls, "rb_enc_str_asciionly_p", encoding_spec_rb_enc_str_asciionly_p, 1);
|
||||
rb_define_method(cls, "rb_uv_to_utf8", encoding_spec_rb_uv_to_utf8, 2);
|
||||
rb_define_method(cls, "ONIGENC_MBC_CASE_FOLD", encoding_spec_ONIGENC_MBC_CASE_FOLD, 1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -148,6 +148,18 @@ VALUE sws_typed_change_struct(VALUE self, VALUE obj, VALUE new_val) {
|
|||
return Qnil;
|
||||
}
|
||||
|
||||
VALUE sws_typed_rb_check_typeddata_same_type(VALUE self, VALUE obj) {
|
||||
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
VALUE sws_typed_rb_check_typeddata_same_type_parent(VALUE self, VALUE obj) {
|
||||
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_parent_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
VALUE sws_typed_rb_check_typeddata_different_type(VALUE self, VALUE obj) {
|
||||
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_other_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
|
||||
}
|
||||
|
||||
void Init_typed_data_spec(void) {
|
||||
VALUE cls = rb_define_class("CApiAllocTypedSpecs", rb_cObject);
|
||||
rb_define_alloc_func(cls, sdaf_alloc_typed_func);
|
||||
|
@ -160,6 +172,9 @@ void Init_typed_data_spec(void) {
|
|||
rb_define_method(cls, "typed_get_struct_rdata", sws_typed_get_struct_rdata, 1);
|
||||
rb_define_method(cls, "typed_get_struct_data_ptr", sws_typed_get_struct_data_ptr, 1);
|
||||
rb_define_method(cls, "typed_change_struct", sws_typed_change_struct, 2);
|
||||
rb_define_method(cls, "rb_check_typeddata_same_type", sws_typed_rb_check_typeddata_same_type, 1);
|
||||
rb_define_method(cls, "rb_check_typeddata_same_type_parent", sws_typed_rb_check_typeddata_same_type_parent, 1);
|
||||
rb_define_method(cls, "rb_check_typeddata_different_type", sws_typed_rb_check_typeddata_different_type, 1);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
@ -831,6 +831,7 @@ describe "CApiObject" do
|
|||
|
||||
it "returns nil if the instance variable has not been initialized and is not a valid Ruby name" do
|
||||
@o.rb_ivar_get(@test, :bar).should == nil
|
||||
@o.rb_ivar_get(@test, :mesg).should == nil
|
||||
end
|
||||
|
||||
it 'returns the instance variable when it is not a valid Ruby name' do
|
||||
|
@ -866,6 +867,7 @@ describe "CApiObject" do
|
|||
|
||||
it "does not throw an error if the instance variable is not a valid Ruby name" do
|
||||
@o.rb_ivar_defined(@test, :bar).should == false
|
||||
@o.rb_ivar_defined(@test, :mesg).should == false
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -76,6 +76,7 @@ def compile_extension(name)
|
|||
$ruby = ENV.values_at('RUBY_EXE', 'RUBY_FLAGS').join(' ')
|
||||
# MRI magic to consider building non-bundled extensions
|
||||
$extout = nil
|
||||
$warnflags << ' -Wno-declaration-after-statement'
|
||||
create_makefile(#{ext.inspect})
|
||||
RUBY
|
||||
output = ruby_exe("extconf.rb")
|
||||
|
|
|
@ -57,4 +57,21 @@ describe "CApiWrappedTypedStruct" do
|
|||
@s.typed_get_struct_data_ptr(a).should == 1024
|
||||
end
|
||||
end
|
||||
|
||||
describe "rb_check_typeddata" do
|
||||
it "returns data pointer when the struct has the given type" do
|
||||
a = @s.typed_wrap_struct(1024)
|
||||
@s.rb_check_typeddata_same_type(a).should == true
|
||||
end
|
||||
|
||||
it "returns data pointer when the parent struct has the given type" do
|
||||
a = @s.typed_wrap_struct(1024)
|
||||
@s.rb_check_typeddata_same_type_parent(a).should == true
|
||||
end
|
||||
|
||||
it "raises an error for different types" do
|
||||
a = @s.typed_wrap_struct(1024)
|
||||
-> { @s.rb_check_typeddata_different_type(a) }.should raise_error(TypeError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,6 +25,14 @@ describe :kernel_raise, shared: true do
|
|||
-> { @object.raise("a bad thing") }.should raise_error(RuntimeError)
|
||||
end
|
||||
|
||||
it "passes no arguments to the constructor when given only an exception class" do
|
||||
klass = Class.new(Exception) do
|
||||
def initialize
|
||||
end
|
||||
end
|
||||
-> { @object.raise(klass) }.should raise_error(klass) { |e| e.message.should == klass.to_s }
|
||||
end
|
||||
|
||||
it "raises a TypeError when passed a non-Exception object" do
|
||||
-> { @object.raise(Object.new) }.should raise_error(TypeError)
|
||||
end
|
||||
|
@ -41,25 +49,6 @@ describe :kernel_raise, shared: true do
|
|||
-> { @object.raise(nil) }.should raise_error(TypeError)
|
||||
end
|
||||
|
||||
it "re-raises the previously rescued exception if no exception is specified" do
|
||||
-> do
|
||||
begin
|
||||
@object.raise Exception, "outer"
|
||||
ScratchPad.record :no_abort
|
||||
rescue
|
||||
begin
|
||||
@object.raise StandardError, "inner"
|
||||
rescue
|
||||
end
|
||||
|
||||
@object.raise
|
||||
ScratchPad.record :no_reraise
|
||||
end
|
||||
end.should raise_error(Exception, "outer")
|
||||
|
||||
ScratchPad.recorded.should be_nil
|
||||
end
|
||||
|
||||
it "re-raises a previously rescued exception without overwriting the backtrace" do
|
||||
begin
|
||||
initial_raise_line = __LINE__; @object.raise 'raised'
|
||||
|
|
|
@ -91,4 +91,24 @@ describe :process_exit!, shared: true do
|
|||
out.should == ""
|
||||
$?.exitstatus.should == 21
|
||||
end
|
||||
|
||||
it "skips at_exit handlers" do
|
||||
out = ruby_exe("at_exit { STDERR.puts 'at_exit' }; #{@object}.send(:exit!, 21)", args: '2>&1')
|
||||
out.should == ""
|
||||
$?.exitstatus.should == 21
|
||||
end
|
||||
|
||||
it "overrides the original exception and exit status when called from #at_exit" do
|
||||
code = <<-RUBY
|
||||
at_exit do
|
||||
STDERR.puts 'in at_exit'
|
||||
STDERR.puts "$! is \#{$!.class}:\#{$!.message}"
|
||||
#{@object}.send(:exit!, 21)
|
||||
end
|
||||
raise 'original error'
|
||||
RUBY
|
||||
out = ruby_exe(code, args: '2>&1')
|
||||
out.should == "in at_exit\n$! is RuntimeError:original error\n"
|
||||
$?.exitstatus.should == 21
|
||||
end
|
||||
end
|
||||
|
|
Загрузка…
Ссылка в новой задаче