summaryrefslogtreecommitdiff
path: root/spec/ruby
diff options
context:
space:
mode:
authorBenoit Daloze <eregontp@gmail.com>2022-08-29 15:36:29 +0200
committerBenoit Daloze <eregontp@gmail.com>2022-08-29 15:36:29 +0200
commit4ee1a687768338a1928014fc6042c320a1a1af3e (patch)
tree37c1717dcd7a2a757e343a41b827fd096397fbca /spec/ruby
parenta319d3cfdc1afef8497321fee7f690052b16739c (diff)
Update to ruby/spec@d01709f
Diffstat (limited to 'spec/ruby')
-rw-r--r--spec/ruby/CONTRIBUTING.md5
-rw-r--r--spec/ruby/README.md5
-rw-r--r--spec/ruby/core/dir/fixtures/common.rb1
-rw-r--r--spec/ruby/core/dir/glob_spec.rb2
-rw-r--r--spec/ruby/core/dir/shared/glob.rb5
-rw-r--r--spec/ruby/core/io/fixtures/classes.rb12
-rw-r--r--spec/ruby/core/io/pipe_spec.rb11
-rw-r--r--spec/ruby/core/kernel/shared/sprintf.rb65
-rw-r--r--spec/ruby/core/kernel/shared/sprintf_encoding.rb33
-rw-r--r--spec/ruby/core/regexp/compile_spec.rb4
-rw-r--r--spec/ruby/core/regexp/new_spec.rb14
-rw-r--r--spec/ruby/core/regexp/shared/new.rb36
-rw-r--r--spec/ruby/core/time/shared/local.rb6
-rw-r--r--spec/ruby/language/block_spec.rb74
-rw-r--r--spec/ruby/language/keyword_arguments_spec.rb18
-rw-r--r--spec/ruby/language/method_spec.rb7
-rw-r--r--spec/ruby/language/proc_spec.rb7
-rw-r--r--spec/ruby/library/bigdecimal/to_r_spec.rb12
-rw-r--r--spec/ruby/library/stringio/open_spec.rb12
-rw-r--r--spec/ruby/library/stringio/printf_spec.rb27
-rw-r--r--spec/ruby/library/stringio/read_nonblock_spec.rb11
-rw-r--r--spec/ruby/library/stringio/write_nonblock_spec.rb6
-rw-r--r--spec/ruby/library/zlib/deflate/deflate_spec.rb5
-rw-r--r--spec/ruby/library/zlib/inflate/inflate_spec.rb7
-rw-r--r--spec/ruby/optional/capi/encoding_spec.rb42
-rw-r--r--spec/ruby/optional/capi/ext/encoding_spec.c9
-rw-r--r--spec/ruby/optional/capi/ext/string_spec.c7
-rw-r--r--spec/ruby/optional/capi/ext/util_spec.c21
-rw-r--r--spec/ruby/optional/capi/string_spec.rb32
-rw-r--r--spec/ruby/optional/capi/util_spec.rb5
-rw-r--r--spec/ruby/security/cve_2019_8325_spec.rb15
-rw-r--r--spec/ruby/shared/sizedqueue/new.rb9
32 files changed, 473 insertions, 52 deletions
diff --git a/spec/ruby/CONTRIBUTING.md b/spec/ruby/CONTRIBUTING.md
index 20258e5c36..adfc2fb0ca 100644
--- a/spec/ruby/CONTRIBUTING.md
+++ b/spec/ruby/CONTRIBUTING.md
@@ -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
diff --git a/spec/ruby/README.md b/spec/ruby/README.md
index 55b248a6c3..24b4719fdd 100644
--- a/spec/ruby/README.md
+++ b/spec/ruby/README.md
@@ -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
diff --git a/spec/ruby/core/dir/fixtures/common.rb b/spec/ruby/core/dir/fixtures/common.rb
index a8d6e69c44..087f46b331 100644
--- a/spec/ruby/core/dir/fixtures/common.rb
+++ b/spec/ruby/core/dir/fixtures/common.rb
@@ -82,6 +82,7 @@ module DirSpecs
special/test{1}/file[1]
special/{}/special
+ special/test\ +()[]{}/hello_world.erb
]
platform_is_not :windows do
diff --git a/spec/ruby/core/dir/glob_spec.rb b/spec/ruby/core/dir/glob_spec.rb
index 43dac73eee..06b52b90fb 100644
--- a/spec/ruby/core/dir/glob_spec.rb
+++ b/spec/ruby/core/dir/glob_spec.rb
@@ -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/
diff --git a/spec/ruby/core/dir/shared/glob.rb b/spec/ruby/core/dir/shared/glob.rb
index 60d4a8c97a..33b2828c27 100644
--- a/spec/ruby/core/dir/shared/glob.rb
+++ b/spec/ruby/core/dir/shared/glob.rb
@@ -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/
diff --git a/spec/ruby/core/io/fixtures/classes.rb b/spec/ruby/core/io/fixtures/classes.rb
index 067ab59d93..204a2a101b 100644
--- a/spec/ruby/core/io/fixtures/classes.rb
+++ b/spec/ruby/core/io/fixtures/classes.rb
@@ -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
diff --git a/spec/ruby/core/io/pipe_spec.rb b/spec/ruby/core/io/pipe_spec.rb
index 2f2cf06f4d..aee0d9003f 100644
--- a/spec/ruby/core/io/pipe_spec.rb
+++ b/spec/ruby/core/io/pipe_spec.rb
@@ -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
diff --git a/spec/ruby/core/kernel/shared/sprintf.rb b/spec/ruby/core/kernel/shared/sprintf.rb
index 59f5ab0036..2db50bd686 100644
--- a/spec/ruby/core/kernel/shared/sprintf.rb
+++ b/spec/ruby/core/kernel/shared/sprintf.rb
@@ -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
diff --git a/spec/ruby/core/kernel/shared/sprintf_encoding.rb b/spec/ruby/core/kernel/shared/sprintf_encoding.rb
index 5ca66b9083..9cedb8b662 100644
--- a/spec/ruby/core/kernel/shared/sprintf_encoding.rb
+++ b/spec/ruby/core/kernel/shared/sprintf_encoding.rb
@@ -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
diff --git a/spec/ruby/core/regexp/compile_spec.rb b/spec/ruby/core/regexp/compile_spec.rb
index 329cb4f753..c41399cfbb 100644
--- a/spec/ruby/core/regexp/compile_spec.rb
+++ b/spec/ruby/core/regexp/compile_spec.rb
@@ -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
diff --git a/spec/ruby/core/regexp/new_spec.rb b/spec/ruby/core/regexp/new_spec.rb
index ce662b7a4f..65f612df55 100644
--- a/spec/ruby/core/regexp/new_spec.rb
+++ b/spec/ruby/core/regexp/new_spec.rb
@@ -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
diff --git a/spec/ruby/core/regexp/shared/new.rb b/spec/ruby/core/regexp/shared/new.rb
index a6d9c48112..10c2d3d390 100644
--- a/spec/ruby/core/regexp/shared/new.rb
+++ b/spec/ruby/core/regexp/shared/new.rb
@@ -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)
diff --git a/spec/ruby/core/time/shared/local.rb b/spec/ruby/core/time/shared/local.rb
index 997b7186f1..2dba23dbd7 100644
--- a/spec/ruby/core/time/shared/local.rb
+++ b/spec/ruby/core/time/shared/local.rb
@@ -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
diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb
index 42652152a1..d918c12beb 100644
--- a/spec/ruby/language/block_spec.rb
+++ b/spec/ruby/language/block_spec.rb
@@ -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
diff --git a/spec/ruby/language/keyword_arguments_spec.rb b/spec/ruby/language/keyword_arguments_spec.rb
index 0c72f59d38..8771c5806c 100644
--- a/spec/ruby/language/keyword_arguments_spec.rb
+++ b/spec/ruby/language/keyword_arguments_spec.rb
@@ -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
diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb
index d464e79403..acca074974 100644
--- a/spec/ruby/language/method_spec.rb
+++ b/spec/ruby/language/method_spec.rb
@@ -572,6 +572,13 @@ describe "A method" do
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
diff --git a/spec/ruby/language/proc_spec.rb b/spec/ruby/language/proc_spec.rb
index 8360967ec8..f8a29962b0 100644
--- a/spec/ruby/language/proc_spec.rb
+++ b/spec/ruby/language/proc_spec.rb
@@ -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
diff --git a/spec/ruby/library/bigdecimal/to_r_spec.rb b/spec/ruby/library/bigdecimal/to_r_spec.rb
index 91d2b33993..c350beff08 100644
--- a/spec/ruby/library/bigdecimal/to_r_spec.rb
+++ b/spec/ruby/library/bigdecimal/to_r_spec.rb
@@ -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
diff --git a/spec/ruby/library/stringio/open_spec.rb b/spec/ruby/library/stringio/open_spec.rb
index acab6e9056..3068e19435 100644
--- a/spec/ruby/library/stringio/open_spec.rb
+++ b/spec/ruby/library/stringio/open_spec.rb
@@ -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
diff --git a/spec/ruby/library/stringio/printf_spec.rb b/spec/ruby/library/stringio/printf_spec.rb
index 9dd1a3b410..f3f669a185 100644
--- a/spec/ruby/library/stringio/printf_spec.rb
+++ b/spec/ruby/library/stringio/printf_spec.rb
@@ -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")
diff --git a/spec/ruby/library/stringio/read_nonblock_spec.rb b/spec/ruby/library/stringio/read_nonblock_spec.rb
index 2a8f926bd0..d4ec56d9aa 100644
--- a/spec/ruby/library/stringio/read_nonblock_spec.rb
+++ b/spec/ruby/library/stringio/read_nonblock_spec.rb
@@ -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
diff --git a/spec/ruby/library/stringio/write_nonblock_spec.rb b/spec/ruby/library/stringio/write_nonblock_spec.rb
index 4f4c5039fe..a457b97667 100644
--- a/spec/ruby/library/stringio/write_nonblock_spec.rb
+++ b/spec/ruby/library/stringio/write_nonblock_spec.rb
@@ -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
diff --git a/spec/ruby/library/zlib/deflate/deflate_spec.rb b/spec/ruby/library/zlib/deflate/deflate_spec.rb
index 828880f8d8..50a563ef6f 100644
--- a/spec/ruby/library/zlib/deflate/deflate_spec.rb
+++ b/spec/ruby/library/zlib/deflate/deflate_spec.rb
@@ -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
diff --git a/spec/ruby/library/zlib/inflate/inflate_spec.rb b/spec/ruby/library/zlib/inflate/inflate_spec.rb
index cc33bd4c32..79b72bf91c 100644
--- a/spec/ruby/library/zlib/inflate/inflate_spec.rb
+++ b/spec/ruby/library/zlib/inflate/inflate_spec.rb
@@ -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
diff --git a/spec/ruby/optional/capi/encoding_spec.rb b/spec/ruby/optional/capi/encoding_spec.rb
index ae557b03d7..aa632b963b 100644
--- a/spec/ruby/optional/capi/encoding_spec.rb
+++ b/spec/ruby/optional/capi/encoding_spec.rb
@@ -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"
diff --git a/spec/ruby/optional/capi/ext/encoding_spec.c b/spec/ruby/optional/capi/ext/encoding_spec.c
index c49f6cde7e..865fc484be 100644
--- a/spec/ruby/optional/capi/ext/encoding_spec.c
+++ b/spec/ruby/optional/capi/ext/encoding_spec.c
@@ -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);
diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c
index b9a4a55853..9cbb50484d 100644
--- a/spec/ruby/optional/capi/ext/string_spec.c
+++ b/spec/ruby/optional/capi/ext/string_spec.c
@@ -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);
diff --git a/spec/ruby/optional/capi/ext/util_spec.c b/spec/ruby/optional/capi/ext/util_spec.c
index a7269353c2..95ba71ea9d 100644
--- a/spec/ruby/optional/capi/ext/util_spec.c
+++ b/spec/ruby/optional/capi/ext/util_spec.c
@@ -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;
-
- failed = rb_intern("failed");
- a1 = a2 = a3 = a4 = a5 = a6 = failed;
-
- for(i = 0; i < argc; i++) {
- args[i] = rb_ary_entry(argv, i);
- }
+ int result, argc;
+ VALUE a1, a2, a3, a4, a5, a6;
+
+ 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);
+ } */
+
+ a1 = a2 = a3 = a4 = a5 = a6 = INT2FIX(-1);
#ifdef RB_SCAN_ARGS_KEYWORDS
if (*RSTRING_PTR(fmt) == 'k') {
diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb
index 7ad4d10ee4..0558fc9f7d 100644
--- a/spec/ruby/optional/capi/string_spec.rb
+++ b/spec/ruby/optional/capi/string_spec.rb
@@ -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
diff --git a/spec/ruby/optional/capi/util_spec.rb b/spec/ruby/optional/capi/util_spec.rb
index 64b0894087..38f6f47b1a 100644
--- a/spec/ruby/optional/capi/util_spec.rb
+++ b/spec/ruby/optional/capi/util_spec.rb
@@ -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
diff --git a/spec/ruby/security/cve_2019_8325_spec.rb b/spec/ruby/security/cve_2019_8325_spec.rb
index 7c5e216568..bbddb3a6ce 100644
--- a/spec/ruby/security/cve_2019_8325_spec.rb
+++ b/spec/ruby/security/cve_2019_8325_spec.rb
@@ -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
diff --git a/spec/ruby/shared/sizedqueue/new.rb b/spec/ruby/shared/sizedqueue/new.rb
index 713785fb50..2573194efb 100644
--- a/spec/ruby/shared/sizedqueue/new.rb
+++ b/spec/ruby/shared/sizedqueue/new.rb
@@ -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