1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
This commit is contained in:
Benoit Daloze 2019-05-28 22:41:48 +02:00
parent d070523e7b
commit a66bc2c011
41 changed files with 699 additions and 639 deletions

View file

@ -188,7 +188,7 @@ variables from the implementor spec: `@method` and `@object`, which the implemen
Here's an example of a snippet of a shared spec and two specs which integrates it: Here's an example of a snippet of a shared spec and two specs which integrates it:
``` ruby ```ruby
# core/hash/shared/key.rb # core/hash/shared/key.rb
describe :hash_key_p, shared: true do describe :hash_key_p, shared: true do
it "returns true if the key's matching value was false" do it "returns true if the key's matching value was false" do
@ -216,7 +216,7 @@ Sometimes, shared specs require more context from the implementor class than a s
this by passing a lambda as the method, which will have the scope of the implementor. Here's an example of this by passing a lambda as the method, which will have the scope of the implementor. Here's an example of
how this is used currently: how this is used currently:
``` ruby ```ruby
describe :kernel_sprintf, shared: true do describe :kernel_sprintf, shared: true do
it "raises TypeError exception if cannot convert to Integer" do it "raises TypeError exception if cannot convert to Integer" do
-> { @method.call("%b", Object.new) }.should raise_error(TypeError) -> { @method.call("%b", Object.new) }.should raise_error(TypeError)

View file

@ -49,6 +49,10 @@ describe :enumerable_find, shared: true do
@empty.send(@method, fail_proc) {|e| true}.should == "yay" @empty.send(@method, fail_proc) {|e| true}.should == "yay"
end end
it "ignores the ifnone argument when nil" do
@numerous.send(@method, nil) {|e| false }.should == nil
end
it "passes through the values yielded by #each_with_index" do it "passes through the values yielded by #each_with_index" do
[:a, :b].each_with_index.send(@method) { |x, i| ScratchPad << [x, i]; nil } [:a, :b].each_with_index.send(@method) { |x, i| ScratchPad << [x, i]; nil }
ScratchPad.recorded.should == [[:a, 0], [:b, 1]] ScratchPad.recorded.should == [[:a, 0], [:b, 1]]

View file

@ -65,4 +65,19 @@ describe "Exception#backtrace" do
e.backtrace[0].should == "backtrace first" e.backtrace[0].should == "backtrace first"
end end
end end
it "returns the same array after duping" do
begin
raise
rescue RuntimeError => err
bt = err.backtrace
err.dup.backtrace.should equal(bt)
new_bt = ['hi']
err.set_backtrace new_bt
err.backtrace.should == new_bt
err.dup.backtrace.should equal(new_bt)
end
end
end end

View file

@ -41,4 +41,16 @@ describe "Exception#cause" do
e.cause.should equal(cause) e.cause.should equal(cause)
} }
end end
it "is not set to the exception itself when it is re-raised" do
-> {
begin
raise RuntimeError
rescue RuntimeError => e
raise e
end
}.should raise_error(RuntimeError) { |e|
e.cause.should == nil
}
end
end end

View file

@ -225,6 +225,8 @@ platform_is_not :windows do
user = ENV.delete("USER") user = ENV.delete("USER")
begin begin
Etc.getlogin != nil Etc.getlogin != nil
rescue
false
ensure ensure
ENV["USER"] = user ENV["USER"] = user
end end

View file

@ -54,7 +54,7 @@ describe "Hash.[]" do
end end
ruby_version_is "2.7" do ruby_version_is "2.7" do
it "ignores elements that are not arrays" do it "raises for elements that are not arrays" do
-> { -> {
Hash[[:a]].should == {} Hash[[:a]].should == {}
}.should raise_error(ArgumentError) }.should raise_error(ArgumentError)

View file

@ -11,6 +11,14 @@ describe "Hash#hash" do
{ 0=>2, 11=>1 }.hash.should == { 11=>1, 0=>2 }.hash { 0=>2, 11=>1 }.hash.should == { 11=>1, 0=>2 }.hash
end end
it "returns a value in which element values do not cancel each other out" do
{ a: 2, b: 2 }.hash.should_not == { a: 7, b: 7 }.hash
end
it "returns a value in which element keys and values do not cancel each other out" do
{ :a => :a }.hash.should_not == { :b => :b }.hash
end
it "generates a hash for recursive hash structures" do it "generates a hash for recursive hash structures" do
h = {} h = {}
h[:a] = h h[:a] = h

View file

@ -63,6 +63,24 @@ describe "Hash#merge" do
merge_pairs.should == each_pairs merge_pairs.should == each_pairs
end end
it "preserves the order of merged elements" do
h1 = { 1 => 2, 3 => 4, 5 => 6 }
h2 = { 1 => 7 }
merge_pairs = []
h1.merge(h2).each_pair { |k, v| merge_pairs << [k, v] }
merge_pairs.should == [[1,7], [3, 4], [5, 6]]
end
it "preserves the order of merged elements for large hashes" do
h1 = {}
h2 = {}
merge_pairs = []
expected_pairs = []
(1..100).each { |x| h1[x] = x; h2[101 - x] = x; expected_pairs << [x, 101 - x] }
h1.merge(h2).each_pair { |k, v| merge_pairs << [k, v] }
merge_pairs.should == expected_pairs
end
ruby_version_is "2.6" do ruby_version_is "2.6" do
it "accepts multiple hashes" do it "accepts multiple hashes" do
result = { a: 1 }.merge({ b: 2 }, { c: 3 }, { d: 4 }) result = { a: 1 }.merge({ b: 2 }, { c: 3 }, { d: 4 })

View file

@ -57,7 +57,7 @@ describe "Kernel#autoload" do
end end
describe "when Object is frozen" do describe "when Object is frozen" do
it "raises a FrozenError before defining the constant" do it "raises a #{frozen_error_class} before defining the constant" do
ruby_exe(fixture(__FILE__, "autoload_frozen.rb")).should == "#{frozen_error_class} - nil" ruby_exe(fixture(__FILE__, "autoload_frozen.rb")).should == "#{frozen_error_class} - nil"
end end
end end

View file

@ -449,14 +449,13 @@ describe "Marshal.dump" do
zone = ":\tzoneI\"\bAST\x06:\x06EF" # Last is 'F' (US-ASCII) zone = ":\tzoneI\"\bAST\x06:\x06EF" # Last is 'F' (US-ASCII)
[ "#{base}#{offset}#{zone}", "#{base}#{zone}#{offset}" ].should include(dump) [ "#{base}#{offset}#{zone}", "#{base}#{zone}#{offset}" ].should include(dump)
end end
it "dumps the zone, but not the offset if zone is UTC" do
dump = Marshal.dump(@utc)
zone = ":\tzoneI\"\bUTC\x06:\x06EF" # Last is 'F' (US-ASCII)
dump.should == "\x04\bIu:\tTime\r#{@utc_dump}\x06#{zone}"
end
end end
it "dumps the zone, but not the offset if zone is UTC" do
dump = Marshal.dump(@utc)
zone = ":\tzoneI\"\bUTC\x06:\x06EF" # Last is 'F' (US-ASCII)
dump.should == "\x04\bIu:\tTime\r#{@utc_dump}\x06#{zone}"
end
end end
describe "with an Exception" do describe "with an Exception" do

View file

@ -15,13 +15,13 @@ describe "Module#name" do
it "is not nil for a nested module created with the module keyword" do it "is not nil for a nested module created with the module keyword" do
m = Module.new m = Module.new
module m::N; end module m::N; end
m::N.name.should =~ /#<Module:0x[0-9a-f]+>::N/ m::N.name.should =~ /\A#<Module:0x[0-9a-f]+>::N\z/
end end
it "changes when the module is reachable through a constant path" do it "changes when the module is reachable through a constant path" do
m = Module.new m = Module.new
module m::N; end module m::N; end
m::N.name.should =~ /#<Module:0x[0-9a-f]+>::N/ m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
ModuleSpecs::Anonymous::WasAnnon = m::N ModuleSpecs::Anonymous::WasAnnon = m::N
m::N.name.should == "ModuleSpecs::Anonymous::WasAnnon" m::N.name.should == "ModuleSpecs::Anonymous::WasAnnon"
end end
@ -42,7 +42,7 @@ describe "Module#name" do
module m::Child; end module m::Child; end
child = m::Child child = m::Child
m.send(:remove_const, :Child) m.send(:remove_const, :Child)
child.name.should =~ /#<Module:0x[0-9a-f]+>::Child/ child.name.should =~ /\A#<Module:0x\h+>::Child\z/
end end
it "is set when opened with the module keyword" do it "is set when opened with the module keyword" do

View file

@ -190,6 +190,17 @@ describe "Proc.new without a block" do
prc.call.should == "hello" prc.call.should == "hello"
end end
it "uses the implicit block from an enclosing method when called inside a block" do
def some_method
proc do |&block|
Proc.new
end.call { "failing" }
end
prc = some_method { "hello" }
prc.call.should == "hello"
end
end end
ruby_version_is "2.7" do ruby_version_is "2.7" do

View file

@ -4,4 +4,26 @@ describe :proc_call_block_args, shared: true do
lambda {|&b| b.send(@method)}.send(@method) {1 + 1}.should == 2 lambda {|&b| b.send(@method)}.send(@method) {1 + 1}.should == 2
proc {|&b| b.send(@method)}.send(@method) {1 + 1}.should == 2 proc {|&b| b.send(@method)}.send(@method) {1 + 1}.should == 2
end end
it "yields to the block given at declaration and not to the block argument" do
proc_creator = Object.new
def proc_creator.create
Proc.new do |&b|
yield
end
end
a_proc = proc_creator.create { 7 }
a_proc.send(@method) { 3 }.should == 7
end
it "can call its block argument declared with a block argument" do
proc_creator = Object.new
def proc_creator.create(method_name)
Proc.new do |&b|
yield + b.send(method_name)
end
end
a_proc = proc_creator.create(@method) { 7 }
a_proc.call { 3 }.should == 10
end
end end

View file

@ -1,18 +1,15 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'shared/new_ascii' require_relative 'shared/new'
require_relative 'shared/new_ascii_8bit'
describe "Regexp.compile" do describe "Regexp.compile" do
it_behaves_like :regexp_new_ascii, :compile it_behaves_like :regexp_new, :compile
it_behaves_like :regexp_new_ascii_8bit, :compile
end end
describe "Regexp.compile given a String" do describe "Regexp.compile given a String" do
it_behaves_like :regexp_new_string_ascii, :compile it_behaves_like :regexp_new_string, :compile
it_behaves_like :regexp_new_string_ascii_8bit, :compile it_behaves_like :regexp_new_string_binary, :compile
end end
describe "Regexp.compile given a Regexp" do describe "Regexp.compile given a Regexp" do
it_behaves_like :regexp_new_regexp_ascii, :compile it_behaves_like :regexp_new_regexp, :compile
it_behaves_like :regexp_new_regexp_ascii_8bit, :compile
end end

View file

@ -1,20 +1,17 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'shared/new_ascii' require_relative 'shared/new'
require_relative 'shared/new_ascii_8bit'
describe "Regexp.new" do describe "Regexp.new" do
it_behaves_like :regexp_new_ascii, :new it_behaves_like :regexp_new, :new
it_behaves_like :regexp_new_ascii_8bit, :new
end end
describe "Regexp.new given a String" do describe "Regexp.new given a String" do
it_behaves_like :regexp_new_string_ascii, :new it_behaves_like :regexp_new_string, :new
it_behaves_like :regexp_new_string_ascii_8bit, :new
end end
describe "Regexp.new given a Regexp" do describe "Regexp.new given a Regexp" do
it_behaves_like :regexp_new_regexp_ascii, :new it_behaves_like :regexp_new_regexp, :new
it_behaves_like :regexp_new_regexp_ascii_8bit, :new it_behaves_like :regexp_new_string_binary, :compile
end end
describe "Regexp.new given a Fixnum" do describe "Regexp.new given a Fixnum" do

View file

@ -1,6 +1,6 @@
# -*- encoding: ascii-8bit -*- # -*- encoding: ascii-8bit -*-
describe :regexp_new_ascii_8bit, shared: true do describe :regexp_new, shared: true do
it "requires one argument and creates a new regular expression object" do it "requires one argument and creates a new regular expression object" do
Regexp.send(@method, '').is_a?(Regexp).should == true Regexp.send(@method, '').is_a?(Regexp).should == true
end end
@ -24,7 +24,7 @@ describe :regexp_new_ascii_8bit, shared: true do
end end
end end
describe :regexp_new_string_ascii_8bit, shared: true do describe :regexp_new_string, shared: true do
it "uses the String argument as an unescaped literal to construct a Regexp object" do it "uses the String argument as an unescaped literal to construct a Regexp object" do
Regexp.send(@method, "^hi{2,3}fo.o$").should == /^hi{2,3}fo.o$/ Regexp.send(@method, "^hi{2,3}fo.o$").should == /^hi{2,3}fo.o$/
end end
@ -146,6 +146,10 @@ describe :regexp_new_string_ascii_8bit, shared: true do
lambda { Regexp.send(@method, "\\") }.should raise_error(RegexpError) lambda { Regexp.send(@method, "\\") }.should raise_error(RegexpError)
end end
it "does not raise a Regexp error if there is an escaped trailing backslash" do
lambda { Regexp.send(@method, "\\\\") }.should_not raise_error(RegexpError)
end
it "accepts a backspace followed by a character" do it "accepts a backspace followed by a character" do
Regexp.send(@method, "\\N").should == /#{"\x5c"+"N"}/ Regexp.send(@method, "\\N").should == /#{"\x5c"+"N"}/
end end
@ -158,14 +162,6 @@ describe :regexp_new_string_ascii_8bit, shared: true do
Regexp.send(@method, "\11").should == /#{"\x09"}/ Regexp.send(@method, "\11").should == /#{"\x09"}/
end end
it "accepts a three-digit octal value" do
Regexp.send(@method, "\315").should == /#{"\xcd"}/
end
it "interprets a digit following a three-digit octal value as a character" do
Regexp.send(@method, "\3762").should == /#{"\xfe2"}/
end
it "accepts a one-digit hexadecimal value" do it "accepts a one-digit hexadecimal value" do
Regexp.send(@method, "\x9n").should == /#{"\x09n"}/ Regexp.send(@method, "\x9n").should == /#{"\x09n"}/
end end
@ -242,118 +238,6 @@ describe :regexp_new_string_ascii_8bit, shared: true do
Regexp.send(@method, "\C-\e").should == /#{"\x1b"}/ Regexp.send(@method, "\C-\e").should == /#{"\x1b"}/
end end
it "accepts '\\c\\n'" do
Regexp.send(@method, "\C-\n").should == /#{"\x0a"}/
end
it "accepts '\\c\\t'" do
Regexp.send(@method, "\C-\t").should == /#{"\x09"}/
end
it "accepts '\\c\\r'" do
Regexp.send(@method, "\C-\r").should == /#{"\x0d"}/
end
it "accepts '\\c\\f'" do
Regexp.send(@method, "\C-\f").should == /#{"\x0c"}/
end
it "accepts '\\c\\v'" do
Regexp.send(@method, "\C-\v").should == /#{"\x0b"}/
end
it "accepts '\\c\\a'" do
Regexp.send(@method, "\C-\a").should == /#{"\x07"}/
end
it "accepts '\\c\\e'" do
Regexp.send(@method, "\C-\e").should == /#{"\x1b"}/
end
it "accepts '\\M-\\n'" do
Regexp.send(@method, "\M-\n").should == /#{"\x8a"}/
end
it "accepts '\\M-\\t'" do
Regexp.send(@method, "\M-\t").should == /#{"\x89"}/
end
it "accepts '\\M-\\r'" do
Regexp.send(@method, "\M-\r").should == /#{"\x8d"}/
end
it "accepts '\\M-\\f'" do
Regexp.send(@method, "\M-\f").should == /#{"\x8c"}/
end
it "accepts '\\M-\\v'" do
Regexp.send(@method, "\M-\v").should == /#{"\x8b"}/
end
it "accepts '\\M-\\a'" do
Regexp.send(@method, "\M-\a").should == /#{"\x87"}/
end
it "accepts '\\M-\\e'" do
Regexp.send(@method, "\M-\e").should == /#{"\x9b"}/
end
it "accepts '\\M-\\C-\\n'" do
Regexp.send(@method, "\M-\n").should == /#{"\x8a"}/
end
it "accepts '\\M-\\C-\\t'" do
Regexp.send(@method, "\M-\t").should == /#{"\x89"}/
end
it "accepts '\\M-\\C-\\r'" do
Regexp.send(@method, "\M-\r").should == /#{"\x8d"}/
end
it "accepts '\\M-\\C-\\f'" do
Regexp.send(@method, "\M-\f").should == /#{"\x8c"}/
end
it "accepts '\\M-\\C-\\v'" do
Regexp.send(@method, "\M-\v").should == /#{"\x8b"}/
end
it "accepts '\\M-\\C-\\a'" do
Regexp.send(@method, "\M-\a").should == /#{"\x87"}/
end
it "accepts '\\M-\\C-\\e'" do
Regexp.send(@method, "\M-\e").should == /#{"\x9b"}/
end
it "accepts '\\M-\\c\\n'" do
Regexp.send(@method, "\M-\n").should == /#{"\x8a"}/
end
it "accepts '\\M-\\c\\t'" do
Regexp.send(@method, "\M-\t").should == /#{"\x89"}/
end
it "accepts '\\M-\\c\\r'" do
Regexp.send(@method, "\M-\r").should == /#{"\x8d"}/
end
it "accepts '\\M-\\c\\f'" do
Regexp.send(@method, "\M-\f").should == /#{"\x8c"}/
end
it "accepts '\\M-\\c\\v'" do
Regexp.send(@method, "\M-\v").should == /#{"\x8b"}/
end
it "accepts '\\M-\\c\\a'" do
Regexp.send(@method, "\M-\a").should == /#{"\x87"}/
end
it "accepts '\\M-\\c\\e'" do
Regexp.send(@method, "\M-\e").should == /#{"\x9b"}/
end
it "accepts multiple consecutive '\\' characters" do it "accepts multiple consecutive '\\' characters" do
Regexp.send(@method, "\\\\\\N").should == /#{"\\\\\\"+"N"}/ Regexp.send(@method, "\\\\\\N").should == /#{"\\\\\\"+"N"}/
end end
@ -494,7 +378,75 @@ describe :regexp_new_string_ascii_8bit, shared: true do
end end
end end
describe :regexp_new_regexp_ascii_8bit, shared: true do describe :regexp_new_string_binary, shared: true do
describe "with escaped characters" do
it "accepts a three-digit octal value" do
Regexp.send(@method, "\315").should == /#{"\xcd"}/
end
it "interprets a digit following a three-digit octal value as a character" do
Regexp.send(@method, "\3762").should == /#{"\xfe2"}/
end
it "accepts '\\M-\\n'" do
Regexp.send(@method, "\M-\n").should == /#{"\x8a"}/
end
it "accepts '\\M-\\t'" do
Regexp.send(@method, "\M-\t").should == /#{"\x89"}/
end
it "accepts '\\M-\\r'" do
Regexp.send(@method, "\M-\r").should == /#{"\x8d"}/
end
it "accepts '\\M-\\f'" do
Regexp.send(@method, "\M-\f").should == /#{"\x8c"}/
end
it "accepts '\\M-\\v'" do
Regexp.send(@method, "\M-\v").should == /#{"\x8b"}/
end
it "accepts '\\M-\\a'" do
Regexp.send(@method, "\M-\a").should == /#{"\x87"}/
end
it "accepts '\\M-\\e'" do
Regexp.send(@method, "\M-\e").should == /#{"\x9b"}/
end
it "accepts '\\M-\\C-\\n'" do
Regexp.send(@method, "\M-\C-\n").should == /#{"\x8a"}/
end
it "accepts '\\M-\\C-\\t'" do
Regexp.send(@method, "\M-\C-\t").should == /#{"\x89"}/
end
it "accepts '\\M-\\C-\\r'" do
Regexp.send(@method, "\M-\C-\r").should == /#{"\x8d"}/
end
it "accepts '\\M-\\C-\\f'" do
Regexp.send(@method, "\M-\C-\f").should == /#{"\x8c"}/
end
it "accepts '\\M-\\C-\\v'" do
Regexp.send(@method, "\M-\C-\v").should == /#{"\x8b"}/
end
it "accepts '\\M-\\C-\\a'" do
Regexp.send(@method, "\M-\C-\a").should == /#{"\x87"}/
end
it "accepts '\\M-\\C-\\e'" do
Regexp.send(@method, "\M-\C-\e").should == /#{"\x9b"}/
end
end
end
describe :regexp_new_regexp, shared: true do
it "uses the argument as a literal to construct a Regexp object" do it "uses the argument as a literal to construct a Regexp object" do
Regexp.send(@method, /^hi{2,3}fo.o$/).should == /^hi{2,3}fo.o$/ Regexp.send(@method, /^hi{2,3}fo.o$/).should == /^hi{2,3}fo.o$/
end end

View file

@ -1,464 +0,0 @@
# -*- encoding: binary -*-
describe :regexp_new_ascii, shared: true do
it "requires one argument and creates a new regular expression object" do
Regexp.send(@method, '').is_a?(Regexp).should == true
end
it "works by default for subclasses with overridden #initialize" do
class RegexpSpecsSubclass < Regexp
def initialize(*args)
super
@args = args
end
attr_accessor :args
end
class RegexpSpecsSubclassTwo < Regexp; end
RegexpSpecsSubclass.send(@method, "hi").should be_kind_of(RegexpSpecsSubclass)
RegexpSpecsSubclass.send(@method, "hi").args.first.should == "hi"
RegexpSpecsSubclassTwo.send(@method, "hi").should be_kind_of(RegexpSpecsSubclassTwo)
end
end
describe :regexp_new_string_ascii, shared: true do
it "uses the String argument as an unescaped literal to construct a Regexp object" do
Regexp.send(@method, "^hi{2,3}fo.o$").should == /^hi{2,3}fo.o$/
end
it "raises a RegexpError when passed an incorrect regexp" do
lambda { Regexp.send(@method, "^[$", 0) }.should raise_error(RegexpError)
end
it "does not set Regexp options if only given one argument" do
r = Regexp.send(@method, 'Hi')
(r.options & Regexp::IGNORECASE).should == 0
(r.options & Regexp::MULTILINE).should == 0
not_supported_on :opal do
(r.options & Regexp::EXTENDED).should == 0
end
end
it "does not set Regexp options if second argument is nil or false" do
r = Regexp.send(@method, 'Hi', nil)
(r.options & Regexp::IGNORECASE).should == 0
(r.options & Regexp::MULTILINE).should == 0
not_supported_on :opal do
(r.options & Regexp::EXTENDED).should == 0
end
r = Regexp.send(@method, 'Hi', false)
(r.options & Regexp::IGNORECASE).should == 0
(r.options & Regexp::MULTILINE).should == 0
not_supported_on :opal do
(r.options & Regexp::EXTENDED).should == 0
end
end
it "sets options from second argument if it is one of the Fixnum option constants" do
r = Regexp.send(@method, 'Hi', Regexp::IGNORECASE)
(r.options & Regexp::IGNORECASE).should_not == 0
(r.options & Regexp::MULTILINE).should == 0
not_supported_on :opal do
(r.options & Regexp::EXTENDED).should == 0
end
r = Regexp.send(@method, 'Hi', Regexp::MULTILINE)
(r.options & Regexp::IGNORECASE).should == 0
(r.options & Regexp::MULTILINE).should_not == 0
not_supported_on :opal do
(r.options & Regexp::EXTENDED).should == 0
end
not_supported_on :opal do
r = Regexp.send(@method, 'Hi', Regexp::EXTENDED)
(r.options & Regexp::IGNORECASE).should == 0
(r.options & Regexp::MULTILINE).should == 0
(r.options & Regexp::EXTENDED).should_not == 1
end
end
it "accepts a Fixnum of two or more options ORed together as the second argument" do
r = Regexp.send(@method, 'Hi', Regexp::IGNORECASE | Regexp::EXTENDED)
(r.options & Regexp::IGNORECASE).should_not == 0
(r.options & Regexp::MULTILINE).should == 0
(r.options & Regexp::EXTENDED).should_not == 0
end
it "treats any non-Fixnum, non-nil, non-false second argument as IGNORECASE" do
r = Regexp.send(@method, 'Hi', Object.new)
(r.options & Regexp::IGNORECASE).should_not == 0
(r.options & Regexp::MULTILINE).should == 0
not_supported_on :opal do
(r.options & Regexp::EXTENDED).should == 0
end
end
it "ignores the third argument if it is 'e' or 'euc' (case-insensitive)" do
lambda {
Regexp.send(@method, 'Hi', nil, 'e').encoding.should == Encoding::US_ASCII
Regexp.send(@method, 'Hi', nil, 'euc').encoding.should == Encoding::US_ASCII
Regexp.send(@method, 'Hi', nil, 'E').encoding.should == Encoding::US_ASCII
Regexp.send(@method, 'Hi', nil, 'EUC').encoding.should == Encoding::US_ASCII
}.should complain(/encoding option is ignored/)
end
it "ignores the third argument if it is 's' or 'sjis' (case-insensitive)" do
lambda {
Regexp.send(@method, 'Hi', nil, 's').encoding.should == Encoding::US_ASCII
Regexp.send(@method, 'Hi', nil, 'sjis').encoding.should == Encoding::US_ASCII
Regexp.send(@method, 'Hi', nil, 'S').encoding.should == Encoding::US_ASCII
Regexp.send(@method, 'Hi', nil, 'SJIS').encoding.should == Encoding::US_ASCII
}.should complain(/encoding option is ignored/)
end
it "ignores the third argument if it is 'u' or 'utf8' (case-insensitive)" do
lambda {
Regexp.send(@method, 'Hi', nil, 'u').encoding.should == Encoding::US_ASCII
Regexp.send(@method, 'Hi', nil, 'utf8').encoding.should == Encoding::US_ASCII
Regexp.send(@method, 'Hi', nil, 'U').encoding.should == Encoding::US_ASCII
Regexp.send(@method, 'Hi', nil, 'UTF8').encoding.should == Encoding::US_ASCII
}.should complain(/encoding option is ignored/)
end
it "uses US_ASCII encoding if third argument is 'n' or 'none' (case insensitive) and only ascii characters" do
Regexp.send(@method, 'Hi', nil, 'n').encoding.should == Encoding::US_ASCII
Regexp.send(@method, 'Hi', nil, 'none').encoding.should == Encoding::US_ASCII
Regexp.send(@method, 'Hi', nil, 'N').encoding.should == Encoding::US_ASCII
Regexp.send(@method, 'Hi', nil, 'NONE').encoding.should == Encoding::US_ASCII
end
it "uses ASCII_8BIT encoding if third argument is 'n' or 'none' (case insensitive) and non-ascii characters" do
a = "(?:[\x8E\xA1-\xFE])"
str = "\A(?:#{a}|x*)\z"
Regexp.send(@method, str, nil, 'N').encoding.should == Encoding::ASCII_8BIT
Regexp.send(@method, str, nil, 'n').encoding.should == Encoding::ASCII_8BIT
Regexp.send(@method, str, nil, 'none').encoding.should == Encoding::ASCII_8BIT
Regexp.send(@method, str, nil, 'NONE').encoding.should == Encoding::ASCII_8BIT
end
describe "with escaped characters" do
it "raises a Regexp error if there is a trailing backslash" do
lambda { Regexp.send(@method, "\\") }.should raise_error(RegexpError)
end
it "does not raise a Regexp error if there is an escaped trailing backslash" do
lambda { Regexp.send(@method, "\\\\") }.should_not raise_error(RegexpError)
end
it "accepts a backspace followed by a character" do
Regexp.send(@method, "\\N").should == /#{"\x5c"+"N"}/
end
it "accepts a one-digit octal value" do
Regexp.send(@method, "\0").should == /#{"\x00"}/
end
it "accepts a two-digit octal value" do
Regexp.send(@method, "\11").should == /#{"\x09"}/
end
it "accepts a one-digit hexadecimal value" do
Regexp.send(@method, "\x9n").should == /#{"\x09n"}/
end
it "accepts a two-digit hexadecimal value" do
Regexp.send(@method, "\x23").should == /#{"\x23"}/
end
it "interprets a digit following a two-digit hexadecimal value as a character" do
Regexp.send(@method, "\x420").should == /#{"\x420"}/
end
it "raises a RegexpError if \\x is not followed by any hexadecimal digits" do
lambda { Regexp.send(@method, "\\" + "xn") }.should raise_error(RegexpError)
end
it "accepts an escaped string interpolation" do
Regexp.send(@method, "\#{abc}").should == /#{"\#{abc}"}/
end
it "accepts '\\n'" do
Regexp.send(@method, "\n").should == /#{"\x0a"}/
end
it "accepts '\\t'" do
Regexp.send(@method, "\t").should == /#{"\x09"}/
end
it "accepts '\\r'" do
Regexp.send(@method, "\r").should == /#{"\x0d"}/
end
it "accepts '\\f'" do
Regexp.send(@method, "\f").should == /#{"\x0c"}/
end
it "accepts '\\v'" do
Regexp.send(@method, "\v").should == /#{"\x0b"}/
end
it "accepts '\\a'" do
Regexp.send(@method, "\a").should == /#{"\x07"}/
end
it "accepts '\\e'" do
Regexp.send(@method, "\e").should == /#{"\x1b"}/
end
it "accepts '\\C-\\n'" do
Regexp.send(@method, "\C-\n").should == /#{"\x0a"}/
end
it "accepts '\\C-\\t'" do
Regexp.send(@method, "\C-\t").should == /#{"\x09"}/
end
it "accepts '\\C-\\r'" do
Regexp.send(@method, "\C-\r").should == /#{"\x0d"}/
end
it "accepts '\\C-\\f'" do
Regexp.send(@method, "\C-\f").should == /#{"\x0c"}/
end
it "accepts '\\C-\\v'" do
Regexp.send(@method, "\C-\v").should == /#{"\x0b"}/
end
it "accepts '\\C-\\a'" do
Regexp.send(@method, "\C-\a").should == /#{"\x07"}/
end
it "accepts '\\C-\\e'" do
Regexp.send(@method, "\C-\e").should == /#{"\x1b"}/
end
it "accepts '\\c\\n'" do
Regexp.send(@method, "\C-\n").should == /#{"\x0a"}/
end
it "accepts '\\c\\t'" do
Regexp.send(@method, "\C-\t").should == /#{"\x09"}/
end
it "accepts '\\c\\r'" do
Regexp.send(@method, "\C-\r").should == /#{"\x0d"}/
end
it "accepts '\\c\\f'" do
Regexp.send(@method, "\C-\f").should == /#{"\x0c"}/
end
it "accepts '\\c\\v'" do
Regexp.send(@method, "\C-\v").should == /#{"\x0b"}/
end
it "accepts '\\c\\a'" do
Regexp.send(@method, "\C-\a").should == /#{"\x07"}/
end
it "accepts '\\c\\e'" do
Regexp.send(@method, "\C-\e").should == /#{"\x1b"}/
end
it "accepts multiple consecutive '\\' characters" do
Regexp.send(@method, "\\\\\\N").should == /#{"\\\\\\"+"N"}/
end
it "accepts characters and escaped octal digits" do
Regexp.send(@method, "abc\076").should == /#{"abc\x3e"}/
end
it "accepts escaped octal digits and characters" do
Regexp.send(@method, "\076abc").should == /#{"\x3eabc"}/
end
it "accepts characters and escaped hexadecimal digits" do
Regexp.send(@method, "abc\x42").should == /#{"abc\x42"}/
end
it "accepts escaped hexadecimal digits and characters" do
Regexp.send(@method, "\x3eabc").should == /#{"\x3eabc"}/
end
it "accepts escaped hexadecimal and octal digits" do
Regexp.send(@method, "\061\x42").should == /#{"\x31\x42"}/
end
it "accepts \\u{H} for a single Unicode codepoint" do
Regexp.send(@method, "\u{f}").should == /#{"\x0f"}/
end
it "accepts \\u{HH} for a single Unicode codepoint" do
Regexp.send(@method, "\u{7f}").should == /#{"\x7f"}/
end
it "accepts \\u{HHH} for a single Unicode codepoint" do
Regexp.send(@method, "\u{07f}").should == /#{"\x7f"}/
end
it "accepts \\u{HHHH} for a single Unicode codepoint" do
Regexp.send(@method, "\u{0000}").should == /#{"\x00"}/
end
it "accepts \\u{HHHHH} for a single Unicode codepoint" do
Regexp.send(@method, "\u{00001}").should == /#{"\x01"}/
end
it "accepts \\u{HHHHHH} for a single Unicode codepoint" do
Regexp.send(@method, "\u{000000}").should == /#{"\x00"}/
end
it "accepts characters followed by \\u{HHHH}" do
Regexp.send(@method, "abc\u{3042}").should == /#{"abc\u3042"}/
end
it "accepts \\u{HHHH} followed by characters" do
Regexp.send(@method, "\u{3042}abc").should == /#{"\u3042abc"}/
end
it "accepts escaped hexadecimal digits followed by \\u{HHHH}" do
Regexp.send(@method, "\x42\u{3042}").should == /#{"\x42\u3042"}/
end
it "accepts escaped octal digits followed by \\u{HHHH}" do
Regexp.send(@method, "\056\u{3042}").should == /#{"\x2e\u3042"}/
end
it "accepts a combination of escaped octal and hexadecimal digits and \\u{HHHH}" do
Regexp.send(@method, "\056\x42\u{3042}\x52\076").should == /#{"\x2e\x42\u3042\x52\x3e"}/
end
it "accepts \\uHHHH for a single Unicode codepoint" do
Regexp.send(@method, "\u3042").should == /#{"\u3042"}/
end
it "accepts characters followed by \\uHHHH" do
Regexp.send(@method, "abc\u3042").should == /#{"abc\u3042"}/
end
it "accepts \\uHHHH followed by characters" do
Regexp.send(@method, "\u3042abc").should == /#{"\u3042abc"}/
end
it "accepts escaped hexadecimal digits followed by \\uHHHH" do
Regexp.send(@method, "\x42\u3042").should == /#{"\x42\u3042"}/
end
it "accepts escaped octal digits followed by \\uHHHH" do
Regexp.send(@method, "\056\u3042").should == /#{"\x2e\u3042"}/
end
it "accepts a combination of escaped octal and hexadecimal digits and \\uHHHH" do
Regexp.send(@method, "\056\x42\u3042\x52\076").should == /#{"\x2e\x42\u3042\x52\x3e"}/
end
it "raises a RegexpError if less than four digits are given for \\uHHHH" do
lambda { Regexp.send(@method, "\\" + "u304") }.should raise_error(RegexpError)
end
it "raises a RegexpError if the \\u{} escape is empty" do
lambda { Regexp.send(@method, "\\" + "u{}") }.should raise_error(RegexpError)
end
it "raises a RegexpError if more than six hexadecimal digits are given" do
lambda { Regexp.send(@method, "\\" + "u{0ffffff}") }.should raise_error(RegexpError)
end
it "returns a Regexp with US-ASCII encoding if only 7-bit ASCII characters are present regardless of the input String's encoding" do
Regexp.send(@method, "abc").encoding.should == Encoding::US_ASCII
end
it "returns a Regexp with source String having US-ASCII encoding if only 7-bit ASCII characters are present regardless of the input String's encoding" do
Regexp.send(@method, "abc").source.encoding.should == Encoding::US_ASCII
end
it "returns a Regexp with US-ASCII encoding if UTF-8 escape sequences using only 7-bit ASCII are present" do
Regexp.send(@method, "\u{61}").encoding.should == Encoding::US_ASCII
end
it "returns a Regexp with source String having US-ASCII encoding if UTF-8 escape sequences using only 7-bit ASCII are present" do
Regexp.send(@method, "\u{61}").source.encoding.should == Encoding::US_ASCII
end
it "returns a Regexp with UTF-8 encoding if any UTF-8 escape sequences outside 7-bit ASCII are present" do
Regexp.send(@method, "\u{ff}").encoding.should == Encoding::UTF_8
end
it "returns a Regexp with source String having UTF-8 encoding if any UTF-8 escape sequences outside 7-bit ASCII are present" do
Regexp.send(@method, "\u{ff}").source.encoding.should == Encoding::UTF_8
end
it "returns a Regexp with the input String's encoding" do
str = "\x82\xa0".force_encoding(Encoding::Shift_JIS)
Regexp.send(@method, str).encoding.should == Encoding::Shift_JIS
end
it "returns a Regexp with source String having the input String's encoding" do
str = "\x82\xa0".force_encoding(Encoding::Shift_JIS)
Regexp.send(@method, str).source.encoding.should == Encoding::Shift_JIS
end
end
end
describe :regexp_new_regexp_ascii, shared: true do
it "uses the argument as a literal to construct a Regexp object" do
Regexp.send(@method, /^hi{2,3}fo.o$/).should == /^hi{2,3}fo.o$/
end
it "preserves any options given in the Regexp literal" do
(Regexp.send(@method, /Hi/i).options & Regexp::IGNORECASE).should_not == 0
(Regexp.send(@method, /Hi/m).options & Regexp::MULTILINE).should_not == 0
not_supported_on :opal do
(Regexp.send(@method, /Hi/x).options & Regexp::EXTENDED).should_not == 0
end
not_supported_on :opal do
r = Regexp.send @method, /Hi/imx
(r.options & Regexp::IGNORECASE).should_not == 0
(r.options & Regexp::MULTILINE).should_not == 0
(r.options & Regexp::EXTENDED).should_not == 0
end
r = Regexp.send @method, /Hi/
(r.options & Regexp::IGNORECASE).should == 0
(r.options & Regexp::MULTILINE).should == 0
not_supported_on :opal do
(r.options & Regexp::EXTENDED).should == 0
end
end
it "does not honour options given as additional arguments" do
r = nil
lambda {
r = Regexp.send @method, /hi/, Regexp::IGNORECASE
}.should complain(/flags ignored/)
(r.options & Regexp::IGNORECASE).should == 0
end
not_supported_on :opal do
it "sets the encoding to UTF-8 if the Regexp literal has the 'u' option" do
Regexp.send(@method, /Hi/u).encoding.should == Encoding::UTF_8
end
it "sets the encoding to EUC-JP if the Regexp literal has the 'e' option" do
Regexp.send(@method, /Hi/e).encoding.should == Encoding::EUC_JP
end
it "sets the encoding to Windows-31J if the Regexp literal has the 's' option" do
Regexp.send(@method, /Hi/s).encoding.should == Encoding::Windows_31J
end
it "sets the encoding to US-ASCII if the Regexp literal has the 'n' option and the source String is ASCII only" do
Regexp.send(@method, /Hi/n).encoding.should == Encoding::US_ASCII
end
it "sets the encoding to source String's encoding if the Regexp literal has the 'n' option and the source String is not ASCII only" do
Regexp.send(@method, Regexp.new("\\xff", nil, 'n')).encoding.should == Encoding::ASCII_8BIT
end
end
end

View file

@ -41,6 +41,23 @@ describe 'String#-@' do
(-dynamic).should_not equal("this string is frozen".freeze) (-dynamic).should_not equal("this string is frozen".freeze)
(-dynamic).should_not equal(-"this string is frozen".freeze) (-dynamic).should_not equal(-"this string is frozen".freeze)
(-dynamic).should == "this string is frozen"
end
it "does not deduplicate tainted strings" do
dynamic = %w(this string is frozen).join(' ')
dynamic.taint
(-dynamic).should_not equal("this string is frozen".freeze)
(-dynamic).should_not equal(-"this string is frozen".freeze)
(-dynamic).should == "this string is frozen"
end
it "does not deduplicate strings with additional instance variables" do
dynamic = %w(this string is frozen).join(' ')
dynamic.instance_variable_set(:@foo, :bar)
(-dynamic).should_not equal("this string is frozen".freeze)
(-dynamic).should_not equal(-"this string is frozen".freeze)
(-dynamic).should == "this string is frozen"
end end
end end

View file

@ -19,6 +19,10 @@ describe "The yield call" do
it "ignores assignment to the explicit block argument and calls the passed block" do it "ignores assignment to the explicit block argument and calls the passed block" do
@y.ze { 42 }.should == 42 @y.ze { 42 }.should == 42
end end
it "does not pass a named block to the block being yielded to" do
@y.z() { |&block| block == nil }.should == true
end
end end
describe "taking a single argument" do describe "taking a single argument" do

View file

@ -100,6 +100,34 @@ describe "Kernel#BigDecimal" do
neg_inf.should < 0 neg_inf.should < 0
end end
describe "accepts NaN and [+-]Infinity as Float values" do
it "works without an explicit precision" do
BigDecimal(Float::NAN).nan?.should == true
pos_inf = BigDecimal(Float::INFINITY)
pos_inf.finite?.should == false
pos_inf.should > 0
pos_inf.should == BigDecimal("+Infinity")
neg_inf = BigDecimal(-Float::INFINITY)
neg_inf.finite?.should == false
neg_inf.should < 0
end
it "works with an explicit precision" do
BigDecimal(Float::NAN, Float::DIG).nan?.should == true
pos_inf = BigDecimal(Float::INFINITY, Float::DIG)
pos_inf.finite?.should == false
pos_inf.should > 0
pos_inf.should == BigDecimal("+Infinity")
neg_inf = BigDecimal(-Float::INFINITY, Float::DIG)
neg_inf.finite?.should == false
neg_inf.should < 0
end
end
it "allows for [eEdD] as exponent separator" do it "allows for [eEdD] as exponent separator" do
reference = BigDecimal("12345.67E89") reference = BigDecimal("12345.67E89")

View file

@ -0,0 +1,6 @@
require_relative '../../spec_helper'
require_relative 'shared/clone'
describe "BigDecimal#dup" do
it_behaves_like :bigdecimal_clone, :clone
end

View file

@ -0,0 +1,76 @@
require_relative '../../spec_helper'
require 'bigdecimal'
describe "BigDecimal constants" do
ruby_version_is "2.5" do
it "defines a VERSION value" do
BigDecimal.const_defined?(:VERSION).should be_true
end
end
it "has a BASE value" do
platform_is wordsize: 64 do
BigDecimal::BASE.should == 1000000000
end
platform_is wordsize: 32 do
BigDecimal::BASE.should == 10000
end
end
it "has a NaN value" do
BigDecimal::NAN.nan?.should be_true
end
it "has an INFINITY value" do
BigDecimal::INFINITY.infinite?.should == 1
end
describe "exception-related constants" do
[
[:EXCEPTION_ALL, 0xff],
[:EXCEPTION_INFINITY, 0x01],
[:EXCEPTION_NaN, 0x02],
[:EXCEPTION_UNDERFLOW, 0x04],
[:EXCEPTION_OVERFLOW, 0x01],
[:EXCEPTION_ZERODIVIDE, 0x10]
].each do |const, value|
it "has a #{const} value" do
BigDecimal.const_get(const).should == value
end
end
end
describe "rounding-related constants" do
[
[:ROUND_MODE, 0x100],
[:ROUND_UP, 1],
[:ROUND_DOWN, 2],
[:ROUND_HALF_UP, 3],
[:ROUND_HALF_DOWN, 4],
[:ROUND_CEILING, 5],
[:ROUND_FLOOR, 6],
[:ROUND_HALF_EVEN, 7]
].each do |const, value|
it "has a #{const} value" do
BigDecimal.const_get(const).should == value
end
end
end
describe "sign-related constants" do
[
[:SIGN_NaN, 0],
[:SIGN_POSITIVE_ZERO, 1],
[:SIGN_NEGATIVE_ZERO, -1],
[:SIGN_POSITIVE_FINITE, 2],
[:SIGN_NEGATIVE_FINITE, -2],
[:SIGN_POSITIVE_INFINITE, 3],
[:SIGN_NEGATIVE_INFINITE, -3]
].each do |const, value|
it "has a #{const} value" do
BigDecimal.const_get(const).should == value
end
end
end
end

View file

@ -0,0 +1,6 @@
require_relative '../../spec_helper'
require_relative 'shared/clone'
describe "BigDecimal#dup" do
it_behaves_like :bigdecimal_clone, :dup
end

View file

@ -0,0 +1,30 @@
require_relative '../../spec_helper'
require 'bigdecimal'
describe "BidDecimal#hash" do
describe "two BigDecimal objects with the same value" do
it "should have the same hash for ordinary values" do
BigDecimal('1.2920').hash.should == BigDecimal('1.2920').hash
end
it "should have the same hash for infinite values" do
BigDecimal("+Infinity").hash.should == BigDecimal("+Infinity").hash
BigDecimal("-Infinity").hash.should == BigDecimal("-Infinity").hash
end
it "should have the same hash for NaNs" do
BigDecimal("NaN").hash.should == BigDecimal("NaN").hash
end
it "should have the same hash for zero values" do
BigDecimal("+0").hash.should == BigDecimal("+0").hash
BigDecimal("-0").hash.should == BigDecimal("-0").hash
end
end
describe "two BigDecimal objects with numerically equal values" do
it "should have the same hash value" do
BigDecimal("1.2920").hash.should == BigDecimal("1.2920000").hash
end
end
end

View file

@ -14,4 +14,11 @@ describe "BigDecimal#inspect" do
it "looks like this" do it "looks like this" do
@bigdec.inspect.should == "0.12345678e4" @bigdec.inspect.should == "0.12345678e4"
end end
it "properly cases non-finite values" do
BigDecimal("NaN").inspect.should == "NaN"
BigDecimal("Infinity").inspect.should == "Infinity"
BigDecimal("+Infinity").inspect.should == "Infinity"
BigDecimal("-Infinity").inspect.should == "-Infinity"
end
end end

View file

@ -0,0 +1,24 @@
require 'bigdecimal'
describe :bigdecimal_clone, shared: true do
before :each do
@obj = BigDecimal("1.2345")
end
ruby_version_is "" ... "2.5" do
it "copies the BigDecimal's value to a newly allocated object" do
copy = @obj.public_send(@method)
copy.should_not equal(@obj)
copy.should == @obj
end
end
ruby_version_is "2.5" do
it "returns self" do
copy = @obj.public_send(@method)
copy.should equal(@obj)
end
end
end

View file

@ -0,0 +1,11 @@
require_relative '../../spec_helper'
require 'bigdecimal'
require 'bigdecimal/util'
describe "Float#to_d" do
it "returns appropriate BigDecimal zero for signed zero" do
-0.0.to_d.sign.should == -1
0.0.to_d.sign.should == 1
end
end

View file

@ -0,0 +1,30 @@
require_relative '../../spec_helper'
require 'objspace'
describe "ObjectSpace.memsize_of" do
it "returns 0 for true, false and nil" do
ObjectSpace.memsize_of(true).should == 0
ObjectSpace.memsize_of(false).should == 0
ObjectSpace.memsize_of(nil).should == 0
end
it "returns 0 for small Integers" do
ObjectSpace.memsize_of(42).should == 0
end
it "returns an Integer for an Object" do
obj = Object.new
ObjectSpace.memsize_of(obj).should be_kind_of(Integer)
ObjectSpace.memsize_of(obj).should > 0
end
it "is larger if the Object has more instance variables" do
obj = Object.new
before = ObjectSpace.memsize_of(obj)
100.times do |i|
obj.instance_variable_set(:"@foo#{i}", nil)
end
after = ObjectSpace.memsize_of(obj)
after.should > before
end
end

View file

@ -0,0 +1,61 @@
require_relative '../../spec_helper'
require 'objspace'
describe "ObjectSpace.reachable_objects_from" do
it "returns nil for true and false" do
ObjectSpace.reachable_objects_from(true).should == nil
ObjectSpace.reachable_objects_from(false).should == nil
end
it "returns nil for nil" do
ObjectSpace.reachable_objects_from(nil).should == nil
end
it "returns nil for small Integers" do
ObjectSpace.reachable_objects_from(42).should == nil
end
it "enumerates objects directly reachable from a given object" do
ObjectSpace.reachable_objects_from(['a', 'b', 'c']).should include(Array, 'a', 'b', 'c')
ObjectSpace.reachable_objects_from(Object.new).should == [Object]
end
it "finds an object stored in an Array" do
obj = Object.new
ary = [obj]
reachable = ObjectSpace.reachable_objects_from(ary)
reachable.should include(obj)
end
it "finds an object stored in a copy-on-write Array" do
removed = Object.new
obj = Object.new
ary = [removed, obj]
ary.shift
reachable = ObjectSpace.reachable_objects_from(ary)
reachable.should include(obj)
reachable.should_not include(removed)
end
it "finds an object stored in a Queue" do
require 'thread'
o = Object.new
q = Queue.new
q << o
reachable = ObjectSpace.reachable_objects_from(q)
reachable = reachable + reachable.flat_map { |r| ObjectSpace.reachable_objects_from(r) }
reachable.should include(o)
end
it "finds an object stored in a SizedQueue" do
require 'thread'
o = Object.new
q = SizedQueue.new(3)
q << o
reachable = ObjectSpace.reachable_objects_from(q)
reachable = reachable + reachable.flat_map { |r| ObjectSpace.reachable_objects_from(r) }
reachable.should include(o)
end
end

View file

@ -37,3 +37,67 @@ describe "BasicSocket.do_not_reverse_lookup" do
@socket.peeraddr[2].should == "127.0.0.1" @socket.peeraddr[2].should == "127.0.0.1"
end end
end end
describe :socket_do_not_reverse_lookup, shared: true do
it "inherits from BasicSocket.do_not_reverse_lookup when the socket is created" do
@socket = @method.call
reverse = BasicSocket.do_not_reverse_lookup
@socket.do_not_reverse_lookup.should == reverse
BasicSocket.do_not_reverse_lookup = !reverse
@socket.do_not_reverse_lookup.should == reverse
end
it "is true when BasicSocket.do_not_reverse_lookup is true" do
BasicSocket.do_not_reverse_lookup = true
@socket = @method.call
@socket.do_not_reverse_lookup.should == true
end
it "is false when BasicSocket.do_not_reverse_lookup is false" do
BasicSocket.do_not_reverse_lookup = false
@socket = @method.call
@socket.do_not_reverse_lookup.should == false
end
it "can be changed with #do_not_reverse_lookup=" do
@socket = @method.call
reverse = @socket.do_not_reverse_lookup
@socket.do_not_reverse_lookup = !reverse
@socket.do_not_reverse_lookup.should == !reverse
end
end
describe "BasicSocket#do_not_reverse_lookup" do
before :each do
@do_not_reverse_lookup = BasicSocket.do_not_reverse_lookup
@server = TCPServer.new('127.0.0.1', 0)
@port = @server.addr[1]
end
after :each do
@server.close unless @server.closed?
@socket.close if @socket && !@socket.closed?
BasicSocket.do_not_reverse_lookup = @do_not_reverse_lookup
end
describe "for an TCPSocket.new socket" do
it_behaves_like :socket_do_not_reverse_lookup, -> {
TCPSocket.new('127.0.0.1', @port)
}
end
describe "for an TCPServer#accept socket" do
before :each do
@client = TCPSocket.new('127.0.0.1', @port)
end
after :each do
@client.close if @client && !@client.closed?
end
it_behaves_like :socket_do_not_reverse_lookup, -> {
@server.accept
}
end
end

View file

@ -72,24 +72,11 @@ module SocketSpecs
end end
def self.loop_with_timeout(timeout = TIME_TOLERANCE) def self.loop_with_timeout(timeout = TIME_TOLERANCE)
require 'timeout' start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
loop do while yield == :retry
if Process.clock_gettime(Process::CLOCK_MONOTONIC) - time >= timeout if Process.clock_gettime(Process::CLOCK_MONOTONIC) - start >= timeout
raise TimeoutError, "Did not succeed within #{timeout} seconds" raise RuntimeError, "Did not succeed within #{timeout} seconds"
end
sleep 0.01 # necessary on OSX; don't know why
yield
end
end
def self.wait_until_success(timeout = TIME_TOLERANCE)
loop_with_timeout(timeout) do
begin
return yield
rescue
end end
end end
end end

View file

@ -31,8 +31,13 @@ describe 'Socket.tcp_server_loop' do
end end
end end
SocketSpecs.wait_until_success do SocketSpecs.loop_with_timeout do
@client.connect(Socket.sockaddr_in(@port, '127.0.0.1')) begin
@client.connect(Socket.sockaddr_in(@port, '127.0.0.1'))
rescue SystemCallError
sleep 0.01
:retry
end
end end
# At this point the connection has been set up but the thread may not yet # At this point the connection has been set up but the thread may not yet

View file

@ -35,9 +35,17 @@ describe 'Socket.udp_server_loop' do
@client.connect(Socket.sockaddr_in(@port, '127.0.0.1')) @client.connect(Socket.sockaddr_in(@port, '127.0.0.1'))
SocketSpecs.loop_with_timeout do SocketSpecs.loop_with_timeout do
SocketSpecs.wait_until_success { @client.write('hello') } begin
@client.write('hello')
break if msg rescue SystemCallError
sleep 0.01
:retry
else
unless msg
sleep 0.001
:retry
end
end
end end
msg.should == 'hello' msg.should == 'hello'

View file

@ -39,7 +39,14 @@ with_feature :unix_socket do
end end
end end
@client = SocketSpecs.wait_until_success { Socket.unix(@path) } SocketSpecs.loop_with_timeout do
begin
@client = Socket.unix(@path)
rescue SystemCallError
sleep 0.01
:retry
end
end
thread.join(2) thread.join(2)

View file

@ -49,6 +49,14 @@ describe "Tempfile.open" do
tempfile.binmode?.should be_true tempfile.binmode?.should be_true
end end
end end
it "uses a blank string for basename when passed no arguments" do
Tempfile.open() do |tempfile|
@tempfile = tempfile
tempfile.closed?.should be_false
end
@tempfile.should_not == nil
end
end end
describe "Tempfile.open when passed a block" do describe "Tempfile.open when passed a block" do

View file

@ -96,6 +96,11 @@ VALUE hash_spec_rb_hash_lookup2(VALUE self, VALUE hash, VALUE key, VALUE def) {
return rb_hash_lookup2(hash, key, def); return rb_hash_lookup2(hash, key, def);
} }
VALUE hash_spec_rb_hash_lookup2_default_undef(VALUE self, VALUE hash, VALUE key) {
VALUE ret = rb_hash_lookup2(hash, key, Qundef);
return ret == Qundef ? Qtrue : Qfalse;
}
VALUE hash_spec_rb_hash_new(VALUE self) { VALUE hash_spec_rb_hash_new(VALUE self) {
return rb_hash_new(); return rb_hash_new();
} }
@ -127,6 +132,7 @@ void Init_hash_spec(void) {
rb_define_method(cls, "rb_hash_lookup_nil", hash_spec_rb_hash_lookup_nil, 2); rb_define_method(cls, "rb_hash_lookup_nil", hash_spec_rb_hash_lookup_nil, 2);
rb_define_method(cls, "rb_hash_lookup", hash_spec_rb_hash_lookup, 2); rb_define_method(cls, "rb_hash_lookup", hash_spec_rb_hash_lookup, 2);
rb_define_method(cls, "rb_hash_lookup2", hash_spec_rb_hash_lookup2, 3); rb_define_method(cls, "rb_hash_lookup2", hash_spec_rb_hash_lookup2, 3);
rb_define_method(cls, "rb_hash_lookup2_default_undef", hash_spec_rb_hash_lookup2_default_undef, 2);
rb_define_method(cls, "rb_hash_new", hash_spec_rb_hash_new, 0); rb_define_method(cls, "rb_hash_new", hash_spec_rb_hash_new, 0);
rb_define_method(cls, "rb_hash_size", hash_spec_rb_hash_size, 1); rb_define_method(cls, "rb_hash_size", hash_spec_rb_hash_size, 1);
rb_define_method(cls, "rb_hash_set_ifnone", hash_spec_rb_hash_set_ifnone, 2); rb_define_method(cls, "rb_hash_set_ifnone", hash_spec_rb_hash_set_ifnone, 2);

View file

@ -175,6 +175,17 @@ static VALUE kernel_spec_rb_protect_yield(VALUE self, VALUE obj, VALUE ary) {
return res; return res;
} }
static VALUE kernel_spec_rb_eval_string_protect(VALUE self, VALUE str, VALUE ary) {
int status = 0;
VALUE res = rb_eval_string_protect(RSTRING_PTR(str), &status);
rb_ary_store(ary, 0, INT2NUM(23));
rb_ary_store(ary, 1, res);
if (status) {
rb_jump_tag(status);
}
return res;
}
VALUE kernel_spec_rb_sys_fail(VALUE self, VALUE msg) { VALUE kernel_spec_rb_sys_fail(VALUE self, VALUE msg) {
errno = 1; errno = 1;
if(msg == Qnil) { if(msg == Qnil) {
@ -301,6 +312,7 @@ void Init_kernel_spec(void) {
rb_define_method(cls, "rb_rescue", kernel_spec_rb_rescue, 4); rb_define_method(cls, "rb_rescue", kernel_spec_rb_rescue, 4);
rb_define_method(cls, "rb_rescue2", kernel_spec_rb_rescue2, -1); rb_define_method(cls, "rb_rescue2", kernel_spec_rb_rescue2, -1);
rb_define_method(cls, "rb_protect_yield", kernel_spec_rb_protect_yield, 2); rb_define_method(cls, "rb_protect_yield", kernel_spec_rb_protect_yield, 2);
rb_define_method(cls, "rb_eval_string_protect", kernel_spec_rb_eval_string_protect, 2);
rb_define_method(cls, "rb_catch", kernel_spec_rb_catch, 2); rb_define_method(cls, "rb_catch", kernel_spec_rb_catch, 2);
rb_define_method(cls, "rb_catch_obj", kernel_spec_rb_catch_obj, 2); rb_define_method(cls, "rb_catch_obj", kernel_spec_rb_catch_obj, 2);
rb_define_method(cls, "rb_sys_fail", kernel_spec_rb_sys_fail, 1); rb_define_method(cls, "rb_sys_fail", kernel_spec_rb_sys_fail, 1);

View file

@ -44,6 +44,30 @@ VALUE util_spec_rb_scan_args(VALUE self, VALUE argv, VALUE fmt, VALUE expected,
return INT2NUM(result); return INT2NUM(result);
} }
static VALUE util_spec_rb_get_kwargs(VALUE self, VALUE keyword_hash, VALUE keys, VALUE required, VALUE optional) {
int req = FIX2INT(required);
int opt = FIX2INT(optional);
int len = RARRAY_LEN(keys);
int values_len = req + (opt < 0 ? -1 - opt : opt);
int i = 0;
ID *ids = malloc(sizeof(VALUE) * len);
VALUE *results = malloc(sizeof(VALUE) * values_len);
int extracted = 0;
VALUE ary = Qundef;
for (i = 0; i < len; i++) {
ids[i] = SYM2ID(rb_ary_entry(keys, i));
}
extracted = rb_get_kwargs(keyword_hash, ids, req, opt, results);
ary = rb_ary_new_from_values(extracted, results);
free(results);
free(ids);
return ary;
}
static VALUE util_spec_rb_long2int(VALUE self, VALUE n) { static VALUE util_spec_rb_long2int(VALUE self, VALUE n) {
return INT2NUM(rb_long2int(NUM2LONG(n))); return INT2NUM(rb_long2int(NUM2LONG(n)));
} }
@ -64,6 +88,7 @@ static VALUE util_spec_rb_sourceline(VALUE self) {
void Init_util_spec(void) { void Init_util_spec(void) {
VALUE cls = rb_define_class("CApiUtilSpecs", rb_cObject); VALUE cls = rb_define_class("CApiUtilSpecs", rb_cObject);
rb_define_method(cls, "rb_scan_args", util_spec_rb_scan_args, 4); rb_define_method(cls, "rb_scan_args", util_spec_rb_scan_args, 4);
rb_define_method(cls, "rb_get_kwargs", util_spec_rb_get_kwargs, 4);
rb_define_method(cls, "rb_long2int", util_spec_rb_long2int, 1); rb_define_method(cls, "rb_long2int", util_spec_rb_long2int, 1);
rb_define_method(cls, "rb_iter_break", util_spec_rb_iter_break, 0); rb_define_method(cls, "rb_iter_break", util_spec_rb_iter_break, 0);
rb_define_method(cls, "rb_sourcefile", util_spec_rb_sourcefile, 0); rb_define_method(cls, "rb_sourcefile", util_spec_rb_sourcefile, 0);

View file

@ -211,6 +211,11 @@ describe "C-API Hash function" do
@s.rb_hash_lookup2(hash, :chunky, 10).should == 10 @s.rb_hash_lookup2(hash, :chunky, 10).should == 10
end end
it "returns undefined if that is the default value specified" do
hsh = Hash.new(0)
@s.rb_hash_lookup2_default_undef(hsh, :chunky).should be_true
end
end end
end end

View file

@ -292,6 +292,22 @@ describe "C-API Kernel function" do
end end
end end
describe "rb_eval_string_protect" do
it "will evaluate the given string" do
proof = []
res = @s.rb_eval_string_protect('1 + 7', proof)
proof.should == [23, 8]
end
it "will allow cleanup code to be run when an exception is raised" do
proof = []
lambda do
@s.rb_eval_string_protect('raise RuntimeError', proof)
end.should raise_error(RuntimeError)
proof.should == [23, nil]
end
end
describe "rb_rescue" do describe "rb_rescue" do
before :each do before :each do
@proc = lambda { |x| x } @proc = lambda { |x| x }

View file

@ -154,6 +154,50 @@ describe "C-API Util function" do
end end
end end
describe "rb_get_kwargs" do
it "extracts required arguments in the order requested" do
h = { :a => 7, :b => 5 }
@o.rb_get_kwargs(h, [:b, :a], 2, 0).should == [5, 7]
h.should == {}
end
it "extracts required and optional arguments in the order requested" do
h = { :a => 7, :c => 12, :b => 5 }
@o.rb_get_kwargs(h, [:b, :a, :c], 2, 1).should == [5, 7, 12]
h.should == {}
end
it "accepts nil instead of a hash when only optional arguments are requested" do
h = nil
@o.rb_get_kwargs(h, [:b, :a, :c], 0, 3).should == []
h.should == nil
end
it "raises an error if a required argument is not in the hash" do
h = { :a => 7, :c => 12, :b => 5 }
lambda { @o.rb_get_kwargs(h, [:b, :d], 2, 0) }.should raise_error(ArgumentError, /missing keyword: d/)
h.should == {:a => 7, :c => 12}
end
it "does not raise an error for an optional argument not in the hash" do
h = { :a => 7, :b => 5 }
@o.rb_get_kwargs(h, [:b, :a, :c], 2, 1).should == [5, 7]
h.should == {}
end
it "raises an error if there are additional arguments and optional is positive" do
h = { :a => 7, :c => 12, :b => 5 }
lambda { @o.rb_get_kwargs(h, [:b, :a], 2, 0) }.should raise_error(ArgumentError, /unknown keyword: c/)
h.should == {:c => 12}
end
it "leaves additional arguments in the hash if optional is negative" do
h = { :a => 7, :c => 12, :b => 5 }
@o.rb_get_kwargs(h, [:b, :a], 2, -1).should == [5, 7]
h.should == {:c => 12}
end
end
platform_is wordsize: 64 do platform_is wordsize: 64 do
describe "rb_long2int" do describe "rb_long2int" do
it "raises a RangeError if the value is outside the range of a C int" do it "raises a RangeError if the value is outside the range of a C int" do