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 2022-08-29 15:36:29 +02:00
parent a319d3cfdc
commit 4ee1a68776
32 changed files with 471 additions and 50 deletions

View file

@ -175,9 +175,10 @@ end
#### Guard for bug
In case there is a bug in MRI but the expected behavior is obvious.
In case there is a bug in MRI and the fix will be backported to previous versions.
If it is not backported or not likely, use `ruby_version_is` instead.
First, file a bug at https://bugs.ruby-lang.org/.
It is better to use a `ruby_version_is` guard if there was a release with the fix.
The problem is `ruby_bug` would make non-MRI implementations fail this spec while MRI itself does not pass it, so it should only be used if the bug is/will be fixed and backported.
```ruby
ruby_bug '#13669', ''...'3.2' do

View file

@ -144,10 +144,9 @@ The file `/etc/services` is required for socket specs (package `netbase` on Debi
### Socket specs from rubysl-socket
Most specs under `library/socket` were imported from [the rubysl-socket project](https://github.com/rubysl/rubysl-socket).
Most specs under `library/socket` were imported from the rubysl-socket project (which is no longer on GitHub).
The 3 copyright holders of rubysl-socket, Yorick Peterse, Chuck Remes and
Brian Shirai, [agreed to relicense those specs](https://github.com/rubysl/rubysl-socket/issues/15)
under the MIT license in ruby/spec.
Brian Shirai, agreed to relicense those specs under the MIT license in ruby/spec.
### History and RubySpec

View file

@ -82,6 +82,7 @@ module DirSpecs
special/test{1}/file[1]
special/{}/special
special/test\ +()[]{}/hello_world.erb
]
platform_is_not :windows do

View file

@ -79,6 +79,7 @@ describe "Dir.glob" do
nested/
nested/.dotsubir/
special/
special/test\ +()[]{}/
special/test{1}/
special/{}/
subdir_one/
@ -130,6 +131,7 @@ describe "Dir.glob" do
./nested/
./nested/.dotsubir/
./special/
./special/test\ +()[]{}/
./special/test{1}/
./special/{}/
./subdir_one/

View file

@ -111,6 +111,10 @@ describe :dir_glob, shared: true do
it "matches files with backslashes in their name" do
Dir.glob('special/\\\\{a,b}').should == ['special/\a']
end
it "matches directory with special characters in their name in complex patterns" do
Dir.glob("special/test +()\\[\\]\\{\\}/hello_world{.{en},}{.{html},}{+{phone},}{.{erb},}").should == ['special/test +()[]{}/hello_world.erb']
end
end
it "matches regexp special ^" do
@ -225,6 +229,7 @@ describe :dir_glob, shared: true do
dir/
nested/
special/
special/test\ +()[]{}/
special/test{1}/
special/{}/
subdir_one/

View file

@ -7,6 +7,18 @@ module IOSpecs
class SubIO < IO
end
class SubIOWithRedefinedNew < IO
def self.new(...)
ScratchPad << :redefined_new_called
super
end
def initialize(...)
ScratchPad << :call_original_initialize
super
end
end
def self.collector
Proc.new { |x| ScratchPad << x }
end

View file

@ -25,6 +25,17 @@ describe "IO.pipe" do
@r.should be_an_instance_of(IOSpecs::SubIO)
@w.should be_an_instance_of(IOSpecs::SubIO)
end
it "does not use IO.new method to create pipes and allows its overriding" do
ScratchPad.record []
# so redefined .new is not called, but original #initialize is
@r, @w = IOSpecs::SubIOWithRedefinedNew.pipe
ScratchPad.recorded.should == [:call_original_initialize, :call_original_initialize] # called 2 times - for each pipe (r and w)
@r.should be_an_instance_of(IOSpecs::SubIOWithRedefinedNew)
@w.should be_an_instance_of(IOSpecs::SubIOWithRedefinedNew)
end
end
describe "IO.pipe" do

View file

@ -293,13 +293,13 @@ describe :kernel_sprintf, shared: true do
it "raises ArgumentError if argument is a string of several characters" do
-> {
@method.call("%c", "abc")
}.should raise_error(ArgumentError)
}.should raise_error(ArgumentError, /%c requires a character/)
end
it "raises ArgumentError if argument is an empty string" do
-> {
@method.call("%c", "")
}.should raise_error(ArgumentError)
}.should raise_error(ArgumentError, /%c requires a character/)
end
end
@ -313,9 +313,56 @@ describe :kernel_sprintf, shared: true do
end
end
it "supports Unicode characters" do
@method.call("%c", 1286).should == "Ԇ"
@method.call("%c", "ش").should == "ش"
it "raises TypeError if argument is not String or Integer and cannot be converted to them" do
-> {
@method.call("%c", [])
}.should raise_error(TypeError, /no implicit conversion of Array into Integer/)
end
it "raises TypeError if argument is nil" do
-> {
@method.call("%c", nil)
}.should raise_error(TypeError, /no implicit conversion from nil to integer/)
end
it "tries to convert argument to String with to_str" do
obj = BasicObject.new
def obj.to_str
"a"
end
@method.call("%c", obj).should == "a"
end
it "tries to convert argument to Integer with to_int" do
obj = BasicObject.new
def obj.to_int
90
end
@method.call("%c", obj).should == "Z"
end
it "raises TypeError if converting to String with to_str returns non-String" do
obj = BasicObject.new
def obj.to_str
:foo
end
-> {
@method.call("%c", obj)
}.should raise_error(TypeError, /can't convert BasicObject to String/)
end
it "raises TypeError if converting to Integer with to_int returns non-Integer" do
obj = BasicObject.new
def obj.to_str
:foo
end
-> {
@method.call("%c", obj)
}.should raise_error(TypeError, /can't convert BasicObject to String/)
end
end
@ -374,11 +421,11 @@ describe :kernel_sprintf, shared: true do
@method.call("%4.6s", "abcdefg").should == "abcdef"
end
it "formats nli with width" do
it "formats nil with width" do
@method.call("%6s", nil).should == " "
end
it "formats nli with precision" do
it "formats nil with precision" do
@method.call("%.6s", nil).should == ""
end
@ -939,4 +986,8 @@ describe :kernel_sprintf, shared: true do
}
end
end
it "does not raise error when passed more arguments than needed" do
sprintf("%s %d %c", "string", 2, "c", []).should == "string 2 c"
end
end

View file

@ -1,3 +1,5 @@
# Keep encoding-related specs in a separate shared example to be able to skip them in IO/File/StringIO specs.
# It's difficult to check result's encoding in the test after writing to a file/io buffer.
describe :kernel_sprintf_encoding, shared: true do
it "can produce a string with valid encoding" do
string = @method.call("good day %{valid}", valid: "e")
@ -25,7 +27,7 @@ describe :kernel_sprintf_encoding, shared: true do
result.encoding.should equal(Encoding::UTF_8)
end
it "raises Encoding::CompatibilityError if both encodings are ASCII compatible and there ano not ASCII characters" do
it "raises Encoding::CompatibilityError if both encodings are ASCII compatible and there are not ASCII characters" do
string = "Ä %s".encode('windows-1252')
argument = "Ђ".encode('windows-1251')
@ -33,4 +35,33 @@ describe :kernel_sprintf_encoding, shared: true do
@method.call(string, argument)
}.should raise_error(Encoding::CompatibilityError)
end
describe "%c" do
it "supports Unicode characters" do
result = @method.call("%c", 1286)
result.should == "Ԇ"
result.bytes.should == [212, 134]
result = @method.call("%c", "ش")
result.should == "ش"
result.bytes.should == [216, 180]
end
it "raises error when a codepoint isn't representable in an encoding of a format string" do
format = "%c".encode("ASCII")
-> {
@method.call(format, 1286)
}.should raise_error(RangeError, /out of char range/)
end
it "uses the encoding of the format string to interpret codepoints" do
format = "%c".force_encoding("euc-jp")
result = @method.call(format, 9415601)
result.encoding.should == Encoding::EUC_JP
result.should == "é".encode(Encoding::EUC_JP)
result.bytes.should == [143, 171, 177]
end
end
end

View file

@ -13,3 +13,7 @@ end
describe "Regexp.compile given a Regexp" do
it_behaves_like :regexp_new_regexp, :compile
end
describe "Regexp.new given a non-String/Regexp" do
it_behaves_like :regexp_new_non_string_or_regexp, :compile
end

View file

@ -11,17 +11,9 @@ end
describe "Regexp.new given a Regexp" do
it_behaves_like :regexp_new_regexp, :new
it_behaves_like :regexp_new_string_binary, :compile
it_behaves_like :regexp_new_string_binary, :new
end
describe "Regexp.new given an Integer" do
it "raises a TypeError" do
-> { Regexp.new(1) }.should raise_error(TypeError)
end
end
describe "Regexp.new given a Float" do
it "raises a TypeError" do
-> { Regexp.new(1.0) }.should raise_error(TypeError)
end
describe "Regexp.new given a non-String/Regexp" do
it_behaves_like :regexp_new_non_string_or_regexp, :new
end

View file

@ -24,6 +24,32 @@ describe :regexp_new, shared: true do
end
end
describe :regexp_new_non_string_or_regexp, shared: true do
it "calls #to_str method for non-String/Regexp argument" do
obj = Object.new
def obj.to_str() "a" end
Regexp.send(@method, obj).should == /a/
end
it "raises TypeError if there is no #to_str method for non-String/Regexp argument" do
obj = Object.new
-> { Regexp.send(@method, obj) }.should raise_error(TypeError, "no implicit conversion of Object into String")
-> { Regexp.send(@method, 1) }.should raise_error(TypeError, "no implicit conversion of Integer into String")
-> { Regexp.send(@method, 1.0) }.should raise_error(TypeError, "no implicit conversion of Float into String")
-> { Regexp.send(@method, :symbol) }.should raise_error(TypeError, "no implicit conversion of Symbol into String")
-> { Regexp.send(@method, []) }.should raise_error(TypeError, "no implicit conversion of Array into String")
end
it "raises TypeError if #to_str returns non-String value" do
obj = Object.new
def obj.to_str() [] end
-> { Regexp.send(@method, obj) }.should raise_error(TypeError, /can't convert Object to String/)
end
end
describe :regexp_new_string, 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$/
@ -97,6 +123,16 @@ describe :regexp_new_string, shared: true do
(r.options & Regexp::EXTENDED).should_not == 0
end
it "does not try to convert the second argument to Integer with #to_int method call" do
ScratchPad.clear
obj = Object.new
def obj.to_int() ScratchPad.record(:called) end
Regexp.send(@method, "Hi", obj)
ScratchPad.recorded.should == nil
end
ruby_version_is ""..."3.2" do
it "treats any non-Integer, non-nil, non-false second argument as IGNORECASE" do
r = Regexp.send(@method, 'Hi', Object.new)

View file

@ -9,10 +9,10 @@ describe :time_local, shared: true do
=begin
platform_is_not :windows do
describe "timezone changes" do
it "correctly adjusts the timezone change to 'CEST' on 'Europe/Amsterdam'" do
it "correctly adjusts the timezone change to 'CET' on 'Europe/Amsterdam'" do
with_timezone("Europe/Amsterdam") do
Time.send(@method, 1940, 5, 16).to_a.should ==
[0, 40, 1, 16, 5, 1940, 4, 137, true, "CEST"]
Time.send(@method, 1970, 5, 16).to_a.should ==
[0, 0, 0, 16, 5, 1970, 6, 136, false, "CET"]
end
end
end

View file

@ -983,3 +983,77 @@ describe "Post-args" do
end
end
end
describe "Anonymous block forwarding" do
ruby_version_is "3.1" do
it "forwards blocks to other functions that formally declare anonymous blocks" do
eval <<-EOF
def b(&); c(&) end
def c(&); yield :non_null end
EOF
b { |c| c }.should == :non_null
end
it "requires the anonymous block parameter to be declared if directly passing a block" do
-> { eval "def a; b(&); end; def b; end" }.should raise_error(SyntaxError)
end
it "works when it's the only declared parameter" do
eval <<-EOF
def inner; yield end
def block_only(&); inner(&) end
EOF
block_only { 1 }.should == 1
end
it "works alongside positional parameters" do
eval <<-EOF
def inner; yield end
def pos(arg1, &); inner(&) end
EOF
pos(:a) { 1 }.should == 1
end
it "works alongside positional arguments and splatted keyword arguments" do
eval <<-EOF
def inner; yield end
def pos_kwrest(arg1, **kw, &); inner(&) end
EOF
pos_kwrest(:a, arg: 3) { 1 }.should == 1
end
it "works alongside positional arguments and disallowed keyword arguments" do
eval <<-EOF
def inner; yield end
def no_kw(arg1, **nil, &); inner(&) end
EOF
no_kw(:a) { 1 }.should == 1
end
end
ruby_version_is "3.2" do
it "works alongside explicit keyword arguments" do
eval <<-EOF
def inner; yield end
def rest_kw(*a, kwarg: 1, &); inner(&) end
def kw(kwarg: 1, &); inner(&) end
def pos_kw_kwrest(arg1, kwarg: 1, **kw, &); inner(&) end
def pos_rkw(arg1, kwarg1:, &); inner(&) end
def all(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, &); inner(&) end
def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, **kw, &); inner(&) end
EOF
rest_kw { 1 }.should == 1
kw { 1 }.should == 1
pos_kw_kwrest(:a) { 1 }.should == 1
pos_rkw(:a, kwarg1: 3) { 1 }.should == 1
all(:a, :b, :c, :d, :e, okw1: 'x', okw2: 'y') { 1 }.should == 1
all_kwrest(:a, :b, :c, :d, :e, okw1: 'x', okw2: 'y') { 1 }.should == 1
end
end
end

View file

@ -58,6 +58,24 @@ ruby_version_is "3.0" do
m(kw: 1).should == []
-> { m(kw: 1, kw2: 2) }.should raise_error(ArgumentError, 'unknown keyword: :kw2')
-> { m(kw: 1, true => false) }.should raise_error(ArgumentError, 'unknown keyword: true')
-> { m(kw: 1, a: 1, b: 2, c: 3) }.should raise_error(ArgumentError, 'unknown keywords: :a, :b, :c')
end
it "raises ArgumentError exception when required keyword argument is not passed" do
def m(a:, b:, c:)
[a, b, c]
end
-> { m(a: 1, b: 2) }.should raise_error(ArgumentError, /missing keyword: :c/)
-> { m() }.should raise_error(ArgumentError, /missing keywords: :a, :b, :c/)
end
it "raises ArgumentError for missing keyword arguments even if there are extra ones" do
def m(a:)
a
end
-> { m(b: 1) }.should raise_error(ArgumentError, /missing keyword: :a/)
end
it "handle * and ** at the same call site" do

View file

@ -571,6 +571,13 @@ describe "A method" do
end
end
evaluate <<-ruby do
def m(a:, **kw) [a, kw] end
ruby
-> { m(b: 1) }.should raise_error(ArgumentError)
end
evaluate <<-ruby do
def m(a: 1) a end
ruby

View file

@ -237,4 +237,11 @@ describe "A Proc" do
end
end
end
describe "taking |required keyword arguments, **kw| arguments" do
it "raises ArgumentError for missing required argument" do
p = proc { |a:, **kw| [a, kw] }
-> { p.call() }.should raise_error(ArgumentError)
end
end
end

View file

@ -13,4 +13,16 @@ describe "BigDecimal#to_r" do
r.denominator.should eql(1000000000000000000000000)
end
it "returns a Rational from a BigDecimal with an exponent" do
r = BigDecimal("1E2").to_r
r.numerator.should eql(100)
r.denominator.should eql(1)
end
it "returns a Rational from a negative BigDecimal with an exponent" do
r = BigDecimal("-1E2").to_r
r.numerator.should eql(-100)
r.denominator.should eql(1)
end
end

View file

@ -167,10 +167,14 @@ describe "StringIO.open when passed [Object]" do
io.should equal(ret)
end
it "sets the mode to read-write" do
it "sets the mode to read-write (r+)" do
io = StringIO.open("example")
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.new("example")
io.printf("%d", 123)
io.string.should == "123mple"
end
it "tries to convert the passed Object to a String using #to_str" do
@ -195,10 +199,14 @@ describe "StringIO.open when passed no arguments" do
io.should equal(ret)
end
it "sets the mode to read-write" do
it "sets the mode to read-write (r+)" do
io = StringIO.open
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.new("example")
io.printf("%d", 123)
io.string.should == "123mple"
end
it "uses an empty String as the StringIO backend" do

View file

@ -4,7 +4,7 @@ require_relative '../../core/kernel/shared/sprintf'
describe "StringIO#printf" do
before :each do
@io = StringIO.new('example')
@io = StringIO.new()
end
it "returns nil" do
@ -12,9 +12,9 @@ describe "StringIO#printf" do
end
it "pads self with \\000 when the current position is after the end" do
@io.pos = 10
@io.pos = 3
@io.printf("%d", 123)
@io.string.should == "example\000\000\000123"
@io.string.should == "\000\000\000123"
end
it "performs format conversion" do
@ -39,6 +39,27 @@ describe "StringIO#printf" do
end
end
describe "StringIO#printf when in read-write mode" do
before :each do
@io = StringIO.new("example", "r+")
end
it "starts from the beginning" do
@io.printf("%s", "abcdefghijk")
@io.string.should == "abcdefghijk"
end
it "does not truncate existing string" do
@io.printf("%s", "abc")
@io.string.should == "abcmple"
end
it "correctly updates self's position" do
@io.printf("%s", "abc")
@io.pos.should eql(3)
end
end
describe "StringIO#printf when in append mode" do
before :each do
@io = StringIO.new("example", "a")

View file

@ -5,10 +5,21 @@ require_relative 'shared/sysread'
describe "StringIO#read_nonblock when passed length, buffer" do
it_behaves_like :stringio_read, :read_nonblock
it "accepts :exception option" do
io = StringIO.new("example")
io.read_nonblock(3, buffer = "", exception: true)
buffer.should == "exa"
end
end
describe "StringIO#read_nonblock when passed length" do
it_behaves_like :stringio_read_length, :read_nonblock
it "accepts :exception option" do
io = StringIO.new("example")
io.read_nonblock(3, exception: true).should == "exa"
end
end
describe "StringIO#read_nonblock when passed nil" do

View file

@ -8,6 +8,12 @@ end
describe "StringIO#write_nonblock when passed [String]" do
it_behaves_like :stringio_write_string, :write_nonblock
it "accepts :exception option" do
io = StringIO.new("12345", "a")
io.write_nonblock("67890", exception: true)
io.string.should == "1234567890"
end
end
describe "StringIO#write_nonblock when self is not writable" do

View file

@ -58,6 +58,11 @@ describe "Zlib::Deflate#deflate" do
Array.new(31, 0) +
[24, 128, 0, 0, 1]).pack('C*')
end
it "has a binary encoding" do
@deflator.deflate("").encoding.should == Encoding::BINARY
@deflator.finish.encoding.should == Encoding::BINARY
end
end
describe "Zlib::Deflate#deflate" do

View file

@ -39,6 +39,13 @@ describe "Zlib::Inflate#inflate" do
@inflator.finish.should == 'uncompressed_data'
end
it "has a binary encoding" do
data = [120, 156, 99, 96, 128, 1, 0, 0, 10, 0, 1].pack('C*')
unzipped = @inflator.inflate data
@inflator.finish.encoding.should == Encoding::BINARY
unzipped.encoding.should == Encoding::BINARY
end
end
describe "Zlib::Inflate.inflate" do

View file

@ -63,6 +63,48 @@ describe "C-API Encoding function" do
end
end
describe "rb_enc_strlen" do
before :each do
@str = 'こにちわ' # Each codepoint in this string is 3 bytes in UTF-8
end
it "returns the correct string length for the encoding" do
@s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_8).should == 4
@s.rb_enc_strlen(@str, @str.bytesize, Encoding::BINARY).should == 12
end
it "returns the string length based on a fixed-width encoding's character length, even if the encoding is incompatible" do
@s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_16BE).should == 6
@s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_16LE).should == 6
@s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_32BE).should == 3
@s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_32LE).should == 3
end
it "does not consider strings to be NUL-terminated" do
s = "abc\0def"
@s.rb_enc_strlen(s, s.bytesize, Encoding::US_ASCII).should == 7
@s.rb_enc_strlen(s, s.bytesize, Encoding::UTF_8).should == 7
end
describe "handles broken strings" do
it "combines valid character and invalid character counts in UTF-8" do
# The result is 3 because `rb_enc_strlen` counts the first valid character and then adds
# the byte count for the invalid character that follows for 1 + 2.
@s.rb_enc_strlen(@str, 5, Encoding::UTF_8).should == 3
end
it "combines valid character and invalid character counts in UTF-16" do
@s.rb_enc_strlen(@str, 5, Encoding::UTF_16BE).should == 3
end
it "rounds up for fixed-width encodings" do
@s.rb_enc_strlen(@str, 7, Encoding::UTF_32BE).should == 2
@s.rb_enc_strlen(@str, 7, Encoding::UTF_32LE).should == 2
@s.rb_enc_strlen(@str, 5, Encoding::BINARY).should == 5
end
end
end
describe "rb_enc_find" do
it "returns the encoding of an Encoding" do
@s.rb_enc_find("UTF-8").should == "UTF-8"

View file

@ -301,6 +301,14 @@ static VALUE encoding_spec_rb_enc_codelen(VALUE self, VALUE code, VALUE encoding
return INT2FIX(rb_enc_codelen(c, enc));
}
static VALUE encoding_spec_rb_enc_strlen(VALUE self, VALUE str, VALUE length, VALUE encoding) {
int l = FIX2INT(length);
char *p = RSTRING_PTR(str);
char *e = p + l;
return LONG2FIX(rb_enc_strlen(p, e, rb_to_encoding(encoding)));
}
void Init_encoding_spec(void) {
VALUE cls;
native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*));
@ -335,6 +343,7 @@ void Init_encoding_spec(void) {
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_strlen", encoding_spec_rb_enc_strlen, 3);
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);

View file

@ -437,6 +437,12 @@ VALUE string_spec_RSTRING_PTR_read(VALUE self, VALUE str, VALUE path) {
return capacities;
}
VALUE string_spec_RSTRING_PTR_null_terminate(VALUE self, VALUE str, VALUE min_length) {
char* ptr = RSTRING_PTR(str);
char* end = ptr + RSTRING_LEN(str);
return rb_str_new(end, FIX2LONG(min_length));
}
VALUE string_spec_StringValue(VALUE self, VALUE str) {
return StringValue(str);
}
@ -662,6 +668,7 @@ void Init_string_spec(void) {
rb_define_method(cls, "RSTRING_PTR_after_funcall", string_spec_RSTRING_PTR_after_funcall, 2);
rb_define_method(cls, "RSTRING_PTR_after_yield", string_spec_RSTRING_PTR_after_yield, 1);
rb_define_method(cls, "RSTRING_PTR_read", string_spec_RSTRING_PTR_read, 2);
rb_define_method(cls, "RSTRING_PTR_null_terminate", string_spec_RSTRING_PTR_null_terminate, 2);
rb_define_method(cls, "StringValue", string_spec_StringValue, 1);
rb_define_method(cls, "SafeStringValue", string_spec_SafeStringValue, 1);
rb_define_method(cls, "rb_str_hash", string_spec_rb_str_hash, 1);

View file

@ -7,15 +7,18 @@ extern "C" {
#endif
VALUE util_spec_rb_scan_args(VALUE self, VALUE argv, VALUE fmt, VALUE expected, VALUE acc) {
int i, result, argc = (int)RARRAY_LEN(argv);
VALUE args[6], failed, a1, a2, a3, a4, a5, a6;
int result, argc;
VALUE a1, a2, a3, a4, a5, a6;
failed = rb_intern("failed");
a1 = a2 = a3 = a4 = a5 = a6 = failed;
argc = (int) RARRAY_LEN(argv);
VALUE* args = RARRAY_PTR(argv);
/* the line above can be replaced with this for Ruby implementations which do not support RARRAY_PTR() yet
VALUE args[6];
for(int i = 0; i < argc; i++) {
args[i] = rb_ary_entry(argv, i);
} */
for(i = 0; i < argc; i++) {
args[i] = rb_ary_entry(argv, i);
}
a1 = a2 = a3 = a4 = a5 = a6 = INT2FIX(-1);
#ifdef RB_SCAN_ARGS_KEYWORDS
if (*RSTRING_PTR(fmt) == 'k') {

View file

@ -97,6 +97,32 @@ describe "C-API String function" do
end
end
describe "rb_str_set_len on a UTF-16 String" do
before :each do
@str = "abcdefghij".force_encoding(Encoding::UTF_16BE)
# Make sure to unshare the string
@s.rb_str_modify(@str)
end
it "inserts two NULL bytes at the length" do
@s.rb_str_set_len(@str, 4).b.should == "abcd".b
@s.rb_str_set_len(@str, 8).b.should == "abcd\x00\x00gh".b
end
end
describe "rb_str_set_len on a UTF-32 String" do
before :each do
@str = "abcdefghijkl".force_encoding(Encoding::UTF_32BE)
# Make sure to unshare the string
@s.rb_str_modify(@str)
end
it "inserts four NULL bytes at the length" do
@s.rb_str_set_len(@str, 4).b.should == "abcd".b
@s.rb_str_set_len(@str, 12).b.should == "abcd\x00\x00\x00\x00ijkl".b
end
end
describe "rb_str_buf_new" do
it "returns the equivalent of an empty string" do
buf = @s.rb_str_buf_new(10, nil)
@ -592,6 +618,12 @@ describe "C-API String function" do
capacities[0].should < capacities[1]
str.should == "fixture file contents to test read() with RSTRING_PTR"
end
it "terminates the string with at least (encoding min length) \\0 bytes" do
@s.RSTRING_PTR_null_terminate("abc", 1).should == "\x00"
@s.RSTRING_PTR_null_terminate("abc".encode("UTF-16BE"), 2).should == "\x00\x00"
@s.RSTRING_PTR_null_terminate("abc".encode("UTF-32BE"), 4).should == "\x00\x00\x00\x00"
end
end
describe "RSTRING_LEN" do

View file

@ -15,8 +15,9 @@ describe "C-API Util function" do
end
it "assigns the required arguments scanned" do
@o.rb_scan_args([1, 2], "2", 2, @acc).should == 2
ScratchPad.recorded.should == [1, 2]
obj = Object.new
@o.rb_scan_args([obj, 2], "2", 2, @acc).should == 2
ScratchPad.recorded.should == [obj, 2]
end
it "raises an ArgumentError if there are insufficient arguments" do

View file

@ -5,16 +5,17 @@ require 'rubygems/command_manager'
describe "CVE-2019-8325 is resisted by" do
describe "sanitising error message components" do
silent_ui = Module.new do
attr_accessor :ui
def self.extended(obj)
obj.ui = Gem::SilentUI.new
end
before :each do
@ui = Gem::SilentUI.new
end
after :each do
@ui.close
end
it "for the 'while executing' message" do
manager = Gem::CommandManager.new
manager.extend(silent_ui)
manager.ui = @ui
def manager.process_args(args, build_args)
raise StandardError, "\e]2;nyan\a"
end
@ -34,7 +35,7 @@ describe "CVE-2019-8325 is resisted by" do
it "for the 'loading command' message" do
manager = Gem::CommandManager.new
manager.extend(silent_ui)
manager.ui = @ui
def manager.require(x)
raise 'foo'
end

View file

@ -1,7 +1,12 @@
describe :sizedqueue_new, shared: true do
it "raises a TypeError when the given argument is not Numeric" do
-> { @object.call("foo") }.should raise_error(TypeError)
it "raises a TypeError when the given argument doesn't respond to #to_int" do
-> { @object.call("12") }.should raise_error(TypeError)
-> { @object.call(Object.new) }.should raise_error(TypeError)
@object.call(12.9).max.should == 12
object = Object.new
object.define_singleton_method(:to_int) { 42 }
@object.call(object).max.should == 42
end
it "raises an argument error when no argument is given" do