1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65388 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
eregon 2018-10-27 10:48:40 +00:00
parent ecc707e233
commit 3e6337b88b
69 changed files with 742 additions and 141 deletions

View file

@ -6,15 +6,15 @@ script:
- ../mspec/bin/mspec $MSPEC_OPTS - ../mspec/bin/mspec $MSPEC_OPTS
matrix: matrix:
include: include:
- rvm: 2.5.1 - rvm: 2.5.3
env: MSPEC_OPTS="-R2 -ff" env: MSPEC_OPTS="-R2 -ff"
- rvm: 2.3.7 - rvm: 2.3.8
- rvm: 2.4.4 - rvm: 2.4.5
- rvm: 2.5.1 - rvm: 2.5.3
env: CHECK_LEAKS=true env: CHECK_LEAKS=true
- rvm: ruby-head - rvm: ruby-head
- env: RUBOCOP=true - env: RUBOCOP=true
rvm: 2.4.4 rvm: 2.4.5
script: script:
- gem install rubocop -v 0.54.0 - gem install rubocop -v 0.54.0
- rubocop - rubocop

View file

@ -6,14 +6,14 @@ describe "Array#eql?" do
it_behaves_like :array_eql, :eql? it_behaves_like :array_eql, :eql?
it "returns false if any corresponding elements are not #eql?" do it "returns false if any corresponding elements are not #eql?" do
[1, 2, 3, 4].send(@method, [1, 2, 3, 4.0]).should be_false [1, 2, 3, 4].should_not eql([1, 2, 3, 4.0])
end end
it "returns false if other is not a kind of Array" do it "returns false if other is not a kind of Array" do
obj = mock("array eql?") obj = mock("array eql?")
obj.should_not_receive(:to_ary) obj.should_not_receive(:to_ary)
obj.should_not_receive(@method) obj.should_not_receive(:eql?)
[1, 2, 3].send(@method, obj).should be_false [1, 2, 3].should_not eql(obj)
end end
end end

View file

@ -2,9 +2,10 @@ class Object
# This helper is defined here rather than in MSpec because # This helper is defined here rather than in MSpec because
# it is only used in #pack specs. # it is only used in #pack specs.
def pack_format(count=nil, repeat=nil) def pack_format(count=nil, repeat=nil)
format = "#{instance_variable_get(:@method)}#{count}" format = instance_variable_get(:@method)
format += count.to_s unless format == 'P' || format == 'p'
format *= repeat if repeat format *= repeat if repeat
format format.dup # because it may then become tainted
end end
end end

View file

@ -3,12 +3,14 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require_relative 'shared/basic' require_relative 'shared/basic'
require_relative 'shared/string' require_relative 'shared/string'
require_relative 'shared/taint'
describe "Array#pack with format 'A'" do describe "Array#pack with format 'A'" do
it_behaves_like :array_pack_basic, 'A' it_behaves_like :array_pack_basic, 'A'
it_behaves_like :array_pack_basic_non_float, 'A' it_behaves_like :array_pack_basic_non_float, 'A'
it_behaves_like :array_pack_no_platform, 'A' it_behaves_like :array_pack_no_platform, 'A'
it_behaves_like :array_pack_string, 'A' it_behaves_like :array_pack_string, 'A'
it_behaves_like :array_pack_taint, 'A'
it "adds all the bytes to the output when passed the '*' modifier" do it "adds all the bytes to the output when passed the '*' modifier" do
["abc"].pack("A*").should == "abc" ["abc"].pack("A*").should == "abc"
@ -36,6 +38,7 @@ describe "Array#pack with format 'a'" do
it_behaves_like :array_pack_basic_non_float, 'a' it_behaves_like :array_pack_basic_non_float, 'a'
it_behaves_like :array_pack_no_platform, 'a' it_behaves_like :array_pack_no_platform, 'a'
it_behaves_like :array_pack_string, 'a' it_behaves_like :array_pack_string, 'a'
it_behaves_like :array_pack_taint, 'a'
it "adds all the bytes to the output when passed the '*' modifier" do it "adds all the bytes to the output when passed the '*' modifier" do
["abc"].pack("a*").should == "abc" ["abc"].pack("a*").should == "abc"

View file

@ -3,12 +3,14 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require_relative 'shared/basic' require_relative 'shared/basic'
require_relative 'shared/encodings' require_relative 'shared/encodings'
require_relative 'shared/taint'
describe "Array#pack with format 'B'" do describe "Array#pack with format 'B'" do
it_behaves_like :array_pack_basic, 'B' it_behaves_like :array_pack_basic, 'B'
it_behaves_like :array_pack_basic_non_float, 'B' it_behaves_like :array_pack_basic_non_float, 'B'
it_behaves_like :array_pack_arguments, 'B' it_behaves_like :array_pack_arguments, 'B'
it_behaves_like :array_pack_hex, 'B' it_behaves_like :array_pack_hex, 'B'
it_behaves_like :array_pack_taint, 'B'
it "calls #to_str to convert an Object to a String" do it "calls #to_str to convert an Object to a String" do
obj = mock("pack H string") obj = mock("pack H string")
@ -59,6 +61,7 @@ describe "Array#pack with format 'b'" do
it_behaves_like :array_pack_basic_non_float, 'b' it_behaves_like :array_pack_basic_non_float, 'b'
it_behaves_like :array_pack_arguments, 'b' it_behaves_like :array_pack_arguments, 'b'
it_behaves_like :array_pack_hex, 'b' it_behaves_like :array_pack_hex, 'b'
it_behaves_like :array_pack_taint, 'b'
it "calls #to_str to convert an Object to a String" do it "calls #to_str to convert an Object to a String" do
obj = mock("pack H string") obj = mock("pack H string")

View file

@ -3,12 +3,14 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require_relative 'shared/basic' require_relative 'shared/basic'
require_relative 'shared/encodings' require_relative 'shared/encodings'
require_relative 'shared/taint'
describe "Array#pack with format 'H'" do describe "Array#pack with format 'H'" do
it_behaves_like :array_pack_basic, 'H' it_behaves_like :array_pack_basic, 'H'
it_behaves_like :array_pack_basic_non_float, 'H' it_behaves_like :array_pack_basic_non_float, 'H'
it_behaves_like :array_pack_arguments, 'H' it_behaves_like :array_pack_arguments, 'H'
it_behaves_like :array_pack_hex, 'H' it_behaves_like :array_pack_hex, 'H'
it_behaves_like :array_pack_taint, 'H'
it "calls #to_str to convert an Object to a String" do it "calls #to_str to convert an Object to a String" do
obj = mock("pack H string") obj = mock("pack H string")
@ -105,6 +107,7 @@ describe "Array#pack with format 'h'" do
it_behaves_like :array_pack_basic_non_float, 'h' it_behaves_like :array_pack_basic_non_float, 'h'
it_behaves_like :array_pack_arguments, 'h' it_behaves_like :array_pack_arguments, 'h'
it_behaves_like :array_pack_hex, 'h' it_behaves_like :array_pack_hex, 'h'
it_behaves_like :array_pack_taint, 'h'
it "calls #to_str to convert an Object to a String" do it "calls #to_str to convert an Object to a String" do
obj = mock("pack H string") obj = mock("pack H string")

View file

@ -2,11 +2,13 @@
require_relative '../../../spec_helper' require_relative '../../../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require_relative 'shared/basic' require_relative 'shared/basic'
require_relative 'shared/taint'
describe "Array#pack with format 'M'" do describe "Array#pack with format 'M'" do
it_behaves_like :array_pack_basic, 'M' it_behaves_like :array_pack_basic, 'M'
it_behaves_like :array_pack_basic_non_float, 'M' it_behaves_like :array_pack_basic_non_float, 'M'
it_behaves_like :array_pack_arguments, 'M' it_behaves_like :array_pack_arguments, 'M'
it_behaves_like :array_pack_taint, 'M'
it "encodes an empty string as an empty string" do it "encodes an empty string as an empty string" do
[""].pack("M").should == "" [""].pack("M").should == ""
@ -192,6 +194,7 @@ describe "Array#pack with format 'm'" do
it_behaves_like :array_pack_basic, 'm' it_behaves_like :array_pack_basic, 'm'
it_behaves_like :array_pack_basic_non_float, 'm' it_behaves_like :array_pack_basic_non_float, 'm'
it_behaves_like :array_pack_arguments, 'm' it_behaves_like :array_pack_arguments, 'm'
it_behaves_like :array_pack_taint, 'm'
it "encodes an empty string as an empty string" do it "encodes an empty string as an empty string" do
[""].pack("m").should == "" [""].pack("m").should == ""

View file

@ -1,11 +1,58 @@
require_relative '../../../spec_helper' require_relative '../../../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require_relative 'shared/basic' require_relative 'shared/basic'
require_relative 'shared/taint'
describe "Array#pack with format 'P'" do describe "Array#pack with format 'P'" do
it_behaves_like :array_pack_basic_non_float, 'P' it_behaves_like :array_pack_basic_non_float, 'P'
it_behaves_like :array_pack_taint, 'P'
it "produces as many bytes as there are in a pointer" do
["hello"].pack("P").size.should == [0].pack("J").size
end
it "round-trips a string through pack and unpack" do
["hello"].pack("P").unpack("P5").should == ["hello"]
end
it "taints the input string" do
input_string = "hello"
[input_string].pack("P")
input_string.tainted?.should be_true
end
it "does not taint the output string in normal cases" do
["hello"].pack("P").tainted?.should be_false
end
it "with nil gives a null pointer" do
[nil].pack("P").unpack("J").should == [0]
end
end end
describe "Array#pack with format 'p'" do describe "Array#pack with format 'p'" do
it_behaves_like :array_pack_basic_non_float, 'p' it_behaves_like :array_pack_basic_non_float, 'p'
it_behaves_like :array_pack_taint, 'p'
it "produces as many bytes as there are in a pointer" do
["hello"].pack("p").size.should == [0].pack("J").size
end
it "round-trips a string through pack and unpack" do
["hello"].pack("p").unpack("p").should == ["hello"]
end
it "taints the input string" do
input_string = "hello"
[input_string].pack("p")
input_string.tainted?.should be_true
end
it "does not taint the output string in normal cases" do
["hello"].pack("p").tainted?.should be_false
end
it "with nil gives a null pointer" do
[nil].pack("p").unpack("J").should == [0]
end
end end

View file

@ -36,38 +36,6 @@ describe :array_pack_string, shared: true do
lambda { [obj].pack(pack_format) }.should raise_error(TypeError) lambda { [obj].pack(pack_format) }.should raise_error(TypeError)
end end
it "returns a tainted string when a pack argument is tainted" do
["abcd".taint, 0x20].pack(pack_format("3C")).tainted?.should be_true
end
it "does not return a tainted string when the array is tainted" do
["abcd", 0x20].taint.pack(pack_format("3C")).tainted?.should be_false
end
it "returns a tainted string when the format is tainted" do
["abcd", 0x20].pack(pack_format("3C").taint).tainted?.should be_true
end
it "returns a tainted string when an empty format is tainted" do
["abcd", 0x20].pack("".taint).tainted?.should be_true
end
it "returns a untrusted string when the format is untrusted" do
["abcd", 0x20].pack(pack_format("3C").untrust).untrusted?.should be_true
end
it "returns a untrusted string when the empty format is untrusted" do
["abcd", 0x20].pack("".untrust).untrusted?.should be_true
end
it "returns a untrusted string when a pack argument is untrusted" do
["abcd".untrust, 0x20].pack(pack_format("3C")).untrusted?.should be_true
end
it "returns a trusted string when the array is untrusted" do
["abcd", 0x20].untrust.pack(pack_format("3C")).untrusted?.should be_false
end
it "returns a string in encoding of common to the concatenated results" do it "returns a string in encoding of common to the concatenated results" do
f = pack_format("*") f = pack_format("*")
[ [["\u{3042 3044 3046 3048}", 0x2000B].pack(f+"U"), Encoding::ASCII_8BIT], [ [["\u{3042 3044 3046 3048}", 0x2000B].pack(f+"U"), Encoding::ASCII_8BIT],

View file

@ -0,0 +1,33 @@
describe :array_pack_taint, shared: true do
it "returns a tainted string when a pack argument is tainted" do
["abcd".taint, 0x20].pack(pack_format("3C")).tainted?.should be_true
end
it "does not return a tainted string when the array is tainted" do
["abcd", 0x20].taint.pack(pack_format("3C")).tainted?.should be_false
end
it "returns a tainted string when the format is tainted" do
["abcd", 0x20].pack(pack_format("3C").taint).tainted?.should be_true
end
it "returns a tainted string when an empty format is tainted" do
["abcd", 0x20].pack("".taint).tainted?.should be_true
end
it "returns a untrusted string when the format is untrusted" do
["abcd", 0x20].pack(pack_format("3C").untrust).untrusted?.should be_true
end
it "returns a untrusted string when the empty format is untrusted" do
["abcd", 0x20].pack("".untrust).untrusted?.should be_true
end
it "returns a untrusted string when a pack argument is untrusted" do
["abcd".untrust, 0x20].pack(pack_format("3C")).untrusted?.should be_true
end
it "returns a trusted string when the array is untrusted" do
["abcd", 0x20].untrust.pack(pack_format("3C")).untrusted?.should be_false
end
end

View file

@ -3,6 +3,7 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require_relative 'shared/basic' require_relative 'shared/basic'
require_relative 'shared/unicode' require_relative 'shared/unicode'
require_relative 'shared/taint'
describe "Array#pack with format 'U'" do describe "Array#pack with format 'U'" do
it_behaves_like :array_pack_basic, 'U' it_behaves_like :array_pack_basic, 'U'
@ -15,6 +16,7 @@ describe "Array#pack with format 'u'" do
it_behaves_like :array_pack_basic, 'u' it_behaves_like :array_pack_basic, 'u'
it_behaves_like :array_pack_basic_non_float, 'u' it_behaves_like :array_pack_basic_non_float, 'u'
it_behaves_like :array_pack_arguments, 'u' it_behaves_like :array_pack_arguments, 'u'
it_behaves_like :array_pack_taint, 'u'
it "encodes an empty string as an empty string" do it "encodes an empty string as an empty string" do
[""].pack("u").should == "" [""].pack("u").should == ""

View file

@ -3,12 +3,14 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require_relative 'shared/basic' require_relative 'shared/basic'
require_relative 'shared/string' require_relative 'shared/string'
require_relative 'shared/taint'
describe "Array#pack with format 'Z'" do describe "Array#pack with format 'Z'" do
it_behaves_like :array_pack_basic, 'Z' it_behaves_like :array_pack_basic, 'Z'
it_behaves_like :array_pack_basic_non_float, 'Z' it_behaves_like :array_pack_basic_non_float, 'Z'
it_behaves_like :array_pack_no_platform, 'Z' it_behaves_like :array_pack_no_platform, 'Z'
it_behaves_like :array_pack_string, 'Z' it_behaves_like :array_pack_string, 'Z'
it_behaves_like :array_pack_taint, 'Z'
it "adds all the bytes and appends a NULL byte when passed the '*' modifier" do it "adds all the bytes and appends a NULL byte when passed the '*' modifier" do
["abc"].pack("Z*").should == "abc\x00" ["abc"].pack("Z*").should == "abc\x00"

View file

@ -68,7 +68,6 @@ describe "Enumerable#all?" do
end end
it "gathers whole arrays as elements when each yields multiple" do it "gathers whole arrays as elements when each yields multiple" do
# This spec doesn't spec what it says it does
multi = EnumerableSpecs::YieldsMultiWithFalse.new multi = EnumerableSpecs::YieldsMultiWithFalse.new
multi.all?.should be_true multi.all?.should be_true
end end

View file

@ -51,7 +51,6 @@ describe "Enumerable#none?" do
end end
it "gathers whole arrays as elements when each yields multiple" do it "gathers whole arrays as elements when each yields multiple" do
# This spec doesn't spec what it says it does
multi = EnumerableSpecs::YieldsMultiWithFalse.new multi = EnumerableSpecs::YieldsMultiWithFalse.new
multi.none?.should be_false multi.none?.should be_false
end end

View file

@ -78,7 +78,6 @@ describe "Enumerable#one?" do
end end
it "gathers initial args as elements when each yields multiple" do it "gathers initial args as elements when each yields multiple" do
# This spec doesn't spec what it says it does
multi = EnumerableSpecs::YieldsMulti.new multi = EnumerableSpecs::YieldsMulti.new
yielded = [] yielded = []
multi.one? { |e| yielded << e; false }.should == false multi.one? { |e| yielded << e; false }.should == false

View file

@ -6,10 +6,11 @@ ruby_version_is "2.5" do
@hash = { a: 1, b: 2, c: 3 } @hash = { a: 1, b: 2, c: 3 }
end end
it "returns new hash" do it "returns a new empty hash without arguments" do
ret = @hash.slice ret = @hash.slice
ret.should_not equal(@hash) ret.should_not equal(@hash)
ret.should be_an_instance_of(Hash) ret.should be_an_instance_of(Hash)
ret.should == {}
end end
it "returns the requested subset" do it "returns the requested subset" do
@ -27,10 +28,28 @@ ruby_version_is "2.5" do
it "returns a Hash instance, even on subclasses" do it "returns a Hash instance, even on subclasses" do
klass = Class.new(Hash) klass = Class.new(Hash)
h = klass.new h = klass.new
h[:bar] = 12
h[:foo] = 42 h[:foo] = 42
r = h.slice(:foo) r = h.slice(:foo)
r.should == {foo: 42} r.should == {foo: 42}
r.class.should == Hash r.class.should == Hash
end end
it "uses the regular Hash#[] method, even on subclasses that override it" do
ScratchPad.record []
klass = Class.new(Hash) do
def [](value)
ScratchPad << :used_subclassed_operator
super
end
end
h = klass.new
h[:bar] = 12
h[:foo] = 42
h.slice(:foo)
ScratchPad.recorded.should == []
end
end end
end end

View file

@ -0,0 +1,52 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
ruby_version_is "2.5" do
platform_is_not :windows do
describe "IO#pread" do
before :each do
@fname = tmp("io_pread.txt")
@contents = "1234567890"
touch(@fname) { |f| f.write @contents }
@file = File.open(@fname, "r+")
end
after :each do
@file.close
rm_r @fname
end
it "accepts a length, and an offset" do
@file.pread(4, 0).should == "1234"
@file.pread(3, 4).should == "567"
end
it "accepts a length, an offset, and an output buffer" do
buffer = "foo"
@file.pread(3, 4, buffer)
buffer.should == "567"
end
it "does not advance the file pointer" do
@file.pread(4, 0).should == "1234"
@file.read.should == "1234567890"
end
it "raises EOFError if end-of-file is reached" do
lambda { @file.pread(1, 10) }.should raise_error(EOFError)
end
it "raises IOError when file is not open in read mode" do
File.open(@fname, "w") do |file|
lambda { file.pread(1, 1) }.should raise_error(IOError)
end
end
it "raises IOError when file is closed" do
file = File.open(@fname, "r+")
file.close
lambda { file.pread(1, 1) }.should raise_error(IOError)
end
end
end
end

View file

@ -0,0 +1,45 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
ruby_version_is "2.5" do
platform_is_not :windows do
describe "IO#pwrite" do
before :each do
@fname = tmp("io_pwrite.txt")
@file = File.open(@fname, "w+")
end
after :each do
@file.close
rm_r @fname
end
it "returns the number of bytes written" do
@file.pwrite("foo", 0).should == 3
end
it "accepts a string and an offset" do
@file.pwrite("foo", 2)
@file.pread(3, 2).should == "foo"
end
it "does not advance the pointer in the file" do
@file.pwrite("bar", 3)
@file.write("foo")
@file.pread(6, 0).should == "foobar"
end
it "raises IOError when file is not open in write mode" do
File.open(@fname, "r") do |file|
lambda { file.pwrite("foo", 1) }.should raise_error(IOError)
end
end
it "raises IOError when file is closed" do
file = File.open(@fname, "w+")
file.close
lambda { file.pwrite("foo", 1) }.should raise_error(IOError)
end
end
end
end

View file

@ -127,6 +127,17 @@ end
describe "IO#write" do describe "IO#write" do
it_behaves_like :io_write, :write it_behaves_like :io_write, :write
ruby_version_is "2.5" do
it "accepts multiple arguments" do
IO.pipe do |r, w|
w.write("foo", "bar")
w.close
r.read.should == "foobar"
end
end
end
end end
platform_is :windows do platform_is :windows do

View file

@ -126,8 +126,8 @@ describe "Kernel.Complex()" do
describe "when passed a non-Numeric second argument" do describe "when passed a non-Numeric second argument" do
it "raises TypeError" do it "raises TypeError" do
lambda { Complex.send(@method, :sym, :sym) }.should raise_error(TypeError) lambda { Complex(:sym, :sym) }.should raise_error(TypeError)
lambda { Complex.send(@method, 0, :sym) }.should raise_error(TypeError) lambda { Complex(0, :sym) }.should raise_error(TypeError)
end end
end end

View file

@ -68,6 +68,7 @@ module KernelSpecs
module SomeOtherModule; end module SomeOtherModule; end
module AncestorModule; end module AncestorModule; end
module MyModule; end module MyModule; end
module MyPrependedModule; end
module MyExtensionModule; end module MyExtensionModule; end
class AncestorClass < String class AncestorClass < String
@ -80,6 +81,8 @@ module KernelSpecs
class KindaClass < AncestorClass class KindaClass < AncestorClass
include MyModule include MyModule
prepend MyPrependedModule
def initialize def initialize
self.extend MyExtensionModule self.extend MyExtensionModule
end end

View file

@ -31,7 +31,11 @@ describe :kernel_kind_of, shared: true do
@o.send(@method, KernelSpecs::MyExtensionModule).should == true @o.send(@method, KernelSpecs::MyExtensionModule).should == true
end end
it "returns false if given a Module not included in object's class nor ancestors" do it "returns true if given a Module that object has been prepended with" do
@o.send(@method, KernelSpecs::MyPrependedModule).should == true
end
it "returns false if given a Module not included nor prepended in object's class nor ancestors" do
@o.send(@method, KernelSpecs::SomeOtherModule).should == false @o.send(@method, KernelSpecs::SomeOtherModule).should == false
end end
@ -41,4 +45,11 @@ describe :kernel_kind_of, shared: true do
lambda { @o.send(@method, :KindaClass) }.should raise_error(TypeError) lambda { @o.send(@method, :KindaClass) }.should raise_error(TypeError)
lambda { @o.send(@method, Object.new) }.should raise_error(TypeError) lambda { @o.send(@method, Object.new) }.should raise_error(TypeError)
end end
it "does not take into account `class` method overriding" do
def @o.class; Integer; end
@o.send(@method, Integer).should == false
@o.send(@method, KernelSpecs::KindaClass).should == true
end
end end

View file

@ -1,6 +1,8 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'shared/call' require_relative 'shared/call'
require_relative 'shared/call_arguments' require_relative 'shared/call_arguments'
require_relative 'fixtures/proc_aref'
require_relative 'fixtures/proc_aref_frozen'
describe "Proc#[]" do describe "Proc#[]" do
it_behaves_like :proc_call, :[] it_behaves_like :proc_call, :[]
@ -14,3 +16,14 @@ end
describe "Proc#call on a Proc created with Kernel#lambda or Kernel#proc" do describe "Proc#call on a Proc created with Kernel#lambda or Kernel#proc" do
it_behaves_like :proc_call_on_proc_or_lambda, :call it_behaves_like :proc_call_on_proc_or_lambda, :call
end end
ruby_bug "#15118", ""..."2.6" do
describe "Proc#[] with frozen_string_literals" do
it "doesn't duplicate frozen strings" do
ProcArefSpecs.aref.frozen?.should be_false
ProcArefSpecs.aref_freeze.frozen?.should be_true
ProcArefFrozenSpecs.aref.frozen?.should be_true
ProcArefFrozenSpecs.aref_freeze.frozen?.should be_true
end
end
end

View file

@ -0,0 +1,9 @@
module ProcArefSpecs
def self.aref
proc {|a| a }["sometext"]
end
def self.aref_freeze
proc {|a| a }["sometext".freeze]
end
end

View file

@ -0,0 +1,10 @@
# frozen_string_literal: true
module ProcArefFrozenSpecs
def self.aref
proc {|a| a }["sometext"]
end
def self.aref_freeze
proc {|a| a }["sometext".freeze]
end
end

View file

@ -3,18 +3,30 @@ describe :proc_to_s, shared: true do
it "returns a description optionally including file and line number" do it "returns a description optionally including file and line number" do
Proc.new { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)(@([^ ]*)\/to_s\.rb:4)?>$/ Proc.new { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)(@([^ ]*)\/to_s\.rb:4)?>$/
end end
it "has an ASCII-8BIT encoding" do
Proc.new { "hello" }.send(@method).encoding.should == Encoding::ASCII_8BIT
end
end end
describe "for a proc created with lambda" do describe "for a proc created with lambda" do
it "returns a description including '(lambda)' and optionally including file and line number" do it "returns a description including '(lambda)' and optionally including file and line number" do
lambda { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)(@([^ ]*)\/to_s\.rb:10)? \(lambda\)>$/ lambda { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)(@([^ ]*)\/to_s\.rb:10)? \(lambda\)>$/
end end
it "has an ASCII-8BIT encoding" do
lambda { "hello" }.send(@method).encoding.should == Encoding::ASCII_8BIT
end
end end
describe "for a proc created with proc" do describe "for a proc created with proc" do
it "returns a description optionally including file and line number" do it "returns a description optionally including file and line number" do
proc { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)(@([^ ]*)\/to_s\.rb:16)?>$/ proc { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)(@([^ ]*)\/to_s\.rb:16)?>$/
end end
it "has an ASCII-8BIT encoding" do
proc { "hello" }.send(@method).encoding.should == Encoding::ASCII_8BIT
end
end end
describe "for a proc created with UnboundMethod#to_proc" do describe "for a proc created with UnboundMethod#to_proc" do
@ -23,5 +35,11 @@ describe :proc_to_s, shared: true do
method("hello").to_proc.send(@method).should =~ /^#<Proc:([^ ]*?)(@([^ ]*)\/to_s\.rb:22)? \(lambda\)>$/ method("hello").to_proc.send(@method).should =~ /^#<Proc:([^ ]*?)(@([^ ]*)\/to_s\.rb:22)? \(lambda\)>$/
end end
it "has an ASCII-8BIT encoding" do
def hello; end
method("hello").to_proc.send(@method).encoding.should == Encoding::ASCII_8BIT
end
end end
end end

View file

@ -1,18 +1,9 @@
# -*- encoding: binary -*- # -*- encoding: binary -*-
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'shared/bytes'
describe "Random#bytes" do describe "Random#bytes" do
it "returns a String" do it_behaves_like :random_bytes, :bytes, Random.new
Random.new.bytes(1).should be_an_instance_of(String)
end
it "returns a String of the length given as argument" do
Random.new.bytes(15).length.should == 15
end
it "returns an ASCII-8BIT String" do
Random.new.bytes(15).encoding.should == Encoding::ASCII_8BIT
end
it "returns the same output for a given seed" do it "returns the same output for a given seed" do
Random.new(33).bytes(2).should == Random.new(33).bytes(2) Random.new(33).bytes(2).should == Random.new(33).bytes(2)
@ -32,8 +23,10 @@ describe "Random#bytes" do
rnd.bytes(1000) # skip some rnd.bytes(1000) # skip some
rnd.bytes(2).should == "\x17\x12" rnd.bytes(2).should == "\x17\x12"
end end
end
it "returns a random binary String" do ruby_version_is "2.6" do
Random.new.bytes(12).should_not == Random.new.bytes(12) describe "Random.bytes" do
it_behaves_like :random_bytes, :bytes, Random
end end
end end

View file

@ -0,0 +1,17 @@
describe :random_bytes, shared: true do
it "returns a String" do
@object.bytes(1).should be_an_instance_of(String)
end
it "returns a String of the length given as argument" do
@object.bytes(15).length.should == 15
end
it "returns an ASCII-8BIT String" do
@object.bytes(15).encoding.should == Encoding::ASCII_8BIT
end
it "returns a random binary String" do
@object.bytes(12).should_not == @object.bytes(12)
end
end

View file

@ -5,6 +5,6 @@ describe "Range#eql?" do
it_behaves_like :range_eql, :eql? it_behaves_like :range_eql, :eql?
it "returns false if the endpoints are not eql?" do it "returns false if the endpoints are not eql?" do
(0..1).send(@method, 0..1.0).should == false (0..1).should_not eql(0..1.0)
end end
end end

View file

@ -5,6 +5,6 @@ describe "Range#==" do
it_behaves_like :range_eql, :== it_behaves_like :range_eql, :==
it "returns true if the endpoints are ==" do it "returns true if the endpoints are ==" do
(0..1).send(@method, 0..1.0).should == true (0..1).should == (0..1.0)
end end
end end

View file

@ -5,7 +5,6 @@ describe "String#chars" do
it_behaves_like :string_chars, :chars it_behaves_like :string_chars, :chars
it "returns an array when no block given" do it "returns an array when no block given" do
ary = "hello".send(@method) "hello".chars.should == ['h', 'e', 'l', 'l', 'o']
ary.should == ['h', 'e', 'l', 'l', 'o']
end end
end end

View file

@ -8,13 +8,13 @@ with_feature :encoding do
it_behaves_like :string_codepoints, :codepoints it_behaves_like :string_codepoints, :codepoints
it "returns an Array when no block is given" do it "returns an Array when no block is given" do
"abc".send(@method).should == [?a.ord, ?b.ord, ?c.ord] "abc".codepoints.should == [?a.ord, ?b.ord, ?c.ord]
end end
it "raises an ArgumentError when no block is given if self has an invalid encoding" do it "raises an ArgumentError when no block is given if self has an invalid encoding" do
s = "\xDF".force_encoding(Encoding::UTF_8) s = "\xDF".force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false s.valid_encoding?.should be_false
lambda {s.send(@method)}.should raise_error(ArgumentError) lambda { s.codepoints }.should raise_error(ArgumentError)
end end
end end
end end

View file

@ -0,0 +1,11 @@
require_relative 'shared/chars'
require_relative 'shared/grapheme_clusters'
require_relative 'shared/each_char_without_block'
ruby_version_is "2.5" do
describe "String#each_grapheme_cluster" do
it_behaves_like :string_chars, :each_grapheme_cluster
it_behaves_like :string_grapheme_clusters, :each_grapheme_cluster
it_behaves_like :string_each_char_without_block, :each_grapheme_cluster
end
end

View file

@ -4,7 +4,7 @@ class Object
def unpack_format(count=nil, repeat=nil) def unpack_format(count=nil, repeat=nil)
format = "#{instance_variable_get(:@method)}#{count}" format = "#{instance_variable_get(:@method)}#{count}"
format *= repeat if repeat format *= repeat if repeat
format format.dup # because it may then become tainted
end end
end end

View file

@ -0,0 +1,15 @@
require_relative 'shared/chars'
require_relative 'shared/grapheme_clusters'
ruby_version_is "2.5" do
describe "String#grapheme_clusters" do
it_behaves_like :string_chars, :grapheme_clusters
it_behaves_like :string_grapheme_clusters, :grapheme_clusters
it "returns an array when no block given" do
string = "ab\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}\u{1F43E}"
string.grapheme_clusters.should == ['a', 'b', "\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}", "\u{1F43E}"]
end
end
end

View file

@ -7,7 +7,7 @@ describe "String#lines" do
it_behaves_like :string_each_line, :lines it_behaves_like :string_each_line, :lines
it "returns an array when no block given" do it "returns an array when no block given" do
ary = "hello world".send(@method, ' ') ary = "hello world".lines(' ')
ary.should == ["hello ", "world"] ary.should == ["hello ", "world"]
end end

View file

@ -19,6 +19,23 @@ describe "String#%" do
("%d%% %s" % [10, "of chickens!"]).should == "10% of chickens!" ("%d%% %s" % [10, "of chickens!"]).should == "10% of chickens!"
end end
describe "output's encoding" do
it "is the same as the format string if passed value is encoding-compatible" do
[Encoding::ASCII_8BIT, Encoding::US_ASCII, Encoding::UTF_8, Encoding::SHIFT_JIS].each do |encoding|
("hello %s!".encode(encoding) % "world").encoding.should == encoding
end
end
it "negotiates a compatible encoding if necessary" do
("hello %s" % 195.chr).encoding.should == Encoding::ASCII_8BIT
("hello %s".encode("shift_jis") % "wörld").encoding.should == Encoding::UTF_8
end
it "raises if a compatible encoding can't be found" do
lambda { "hello %s".encode("utf-8") % "world".encode("UTF-16LE") }.should raise_error(Encoding::CompatibilityError)
end
end
ruby_version_is ""..."2.5" do ruby_version_is ""..."2.5" do
it "formats single % character at the end as literal %" do it "formats single % character at the end as literal %" do
("%" % []).should == "%" ("%" % []).should == "%"

View file

@ -0,0 +1,16 @@
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
describe :string_grapheme_clusters, shared: true do
it "passes each grapheme cluster in self to the given block" do
a = []
# test string: abc[rainbow flag emoji][paw prints]
"ab\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}\u{1F43E}".send(@method) { |c| a << c }
a.should == ['a', 'b', "\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}", "\u{1F43E}"]
end
it "returns self" do
s = StringSpecs::MyString.new "ab\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}\u{1F43E}"
s.send(@method) {}.should equal(s)
end
end

View file

@ -75,9 +75,9 @@ describe "String#slice! with index" do
with_feature :encoding do with_feature :encoding do
it "returns the character given by the character index" do it "returns the character given by the character index" do
"hellö there".send(@method, 1).should == "e" "hellö there".slice!(1).should == "e"
"hellö there".send(@method, 4).should == "ö" "hellö there".slice!(4).should == "ö"
"hellö there".send(@method, 6).should == "t" "hellö there".slice!(6).should == "t"
end end
end end
@ -151,15 +151,15 @@ describe "String#slice! with index, length" do
with_feature :encoding do with_feature :encoding do
it "returns the substring given by the character offsets" do it "returns the substring given by the character offsets" do
"hellö there".send(@method, 1,0).should == "" "hellö there".slice!(1,0).should == ""
"hellö there".send(@method, 1,3).should == "ell" "hellö there".slice!(1,3).should == "ell"
"hellö there".send(@method, 1,6).should == "ellö t" "hellö there".slice!(1,6).should == "ellö t"
"hellö there".send(@method, 1,9).should == "ellö ther" "hellö there".slice!(1,9).should == "ellö ther"
end end
it "treats invalid bytes as single bytes" do it "treats invalid bytes as single bytes" do
xE6xCB = [0xE6,0xCB].pack('CC').force_encoding('utf-8') xE6xCB = [0xE6,0xCB].pack('CC').force_encoding('utf-8')
"a#{xE6xCB}b".send(@method, 1, 2).should == xE6xCB "a#{xE6xCB}b".slice!(1, 2).should == xE6xCB
end end
end end
end end
@ -239,13 +239,13 @@ describe "String#slice! Range" do
with_feature :encoding do with_feature :encoding do
it "returns the substring given by the character offsets of the range" do it "returns the substring given by the character offsets of the range" do
"hellö there".send(@method, 1..1).should == "e" "hellö there".slice!(1..1).should == "e"
"hellö there".send(@method, 1..3).should == "ell" "hellö there".slice!(1..3).should == "ell"
"hellö there".send(@method, 1...3).should == "el" "hellö there".slice!(1...3).should == "el"
"hellö there".send(@method, -4..-2).should == "her" "hellö there".slice!(-4..-2).should == "her"
"hellö there".send(@method, -4...-2).should == "he" "hellö there".slice!(-4...-2).should == "he"
"hellö there".send(@method, 5..-1).should == " there" "hellö there".slice!(5..-1).should == " there"
"hellö there".send(@method, 5...-1).should == " ther" "hellö there".slice!(5...-1).should == " ther"
end end
end end
@ -307,8 +307,8 @@ describe "String#slice! with Regexp" do
with_feature :encoding do with_feature :encoding do
it "returns the matching portion of self with a multi byte character" do it "returns the matching portion of self with a multi byte character" do
"hëllo there".send(@method, /[ë](.)\1/).should == "ëll" "hëllo there".slice!(/[ë](.)\1/).should == "ëll"
"".send(@method, //).should == "" "".slice!(//).should == ""
end end
end end
@ -391,13 +391,13 @@ describe "String#slice! with Regexp, index" do
with_feature :encoding do with_feature :encoding do
it "returns the encoding aware capture for the given index" do it "returns the encoding aware capture for the given index" do
"hår".send(@method, /(.)(.)(.)/, 0).should == "hår" "hår".slice!(/(.)(.)(.)/, 0).should == "hår"
"hår".send(@method, /(.)(.)(.)/, 1).should == "h" "hår".slice!(/(.)(.)(.)/, 1).should == "h"
"hår".send(@method, /(.)(.)(.)/, 2).should == "å" "hår".slice!(/(.)(.)(.)/, 2).should == "å"
"hår".send(@method, /(.)(.)(.)/, 3).should == "r" "hår".slice!(/(.)(.)(.)/, 3).should == "r"
"hår".send(@method, /(.)(.)(.)/, -1).should == "r" "hår".slice!(/(.)(.)(.)/, -1).should == "r"
"hår".send(@method, /(.)(.)(.)/, -2).should == "å" "hår".slice!(/(.)(.)(.)/, -2).should == "å"
"hår".send(@method, /(.)(.)(.)/, -3).should == "h" "hår".slice!(/(.)(.)(.)/, -3).should == "h"
end end
end end

View file

@ -402,4 +402,14 @@ describe "String#split with Regexp" do
broken_str.force_encoding('utf-8') broken_str.force_encoding('utf-8')
lambda{ broken_str.split(/\r\n|\r|\n/) }.should raise_error(ArgumentError) lambda{ broken_str.split(/\r\n|\r|\n/) }.should raise_error(ArgumentError)
end end
ruby_version_is "2.6" do
it "yields each split substrings if a block is given" do
a = []
returned_object = "chunky bacon".split(" ") { |str| a << str.capitalize }
returned_object.should == "chunky bacon"
a.should == ["Chunky", "Bacon"]
end
end
end end

View file

@ -3,12 +3,14 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require_relative 'shared/basic' require_relative 'shared/basic'
require_relative 'shared/string' require_relative 'shared/string'
require_relative 'shared/taint'
describe "String#unpack with format 'A'" do describe "String#unpack with format 'A'" do
it_behaves_like :string_unpack_basic, 'A' it_behaves_like :string_unpack_basic, 'A'
it_behaves_like :string_unpack_no_platform, 'A' it_behaves_like :string_unpack_no_platform, 'A'
it_behaves_like :string_unpack_string, 'A' it_behaves_like :string_unpack_string, 'A'
it_behaves_like :string_unpack_Aa, 'A' it_behaves_like :string_unpack_Aa, 'A'
it_behaves_like :string_unpack_taint, 'A'
it "removes trailing space and NULL bytes from the decoded string" do it "removes trailing space and NULL bytes from the decoded string" do
[ ["a\x00 b \x00", ["a\x00 b", ""]], [ ["a\x00 b \x00", ["a\x00 b", ""]],
@ -40,6 +42,7 @@ describe "String#unpack with format 'a'" do
it_behaves_like :string_unpack_no_platform, 'a' it_behaves_like :string_unpack_no_platform, 'a'
it_behaves_like :string_unpack_string, 'a' it_behaves_like :string_unpack_string, 'a'
it_behaves_like :string_unpack_Aa, 'a' it_behaves_like :string_unpack_Aa, 'a'
it_behaves_like :string_unpack_taint, 'a'
it "does not remove trailing whitespace or NULL bytes from the decoded string" do it "does not remove trailing whitespace or NULL bytes from the decoded string" do
[ ["a\x00 b \x00", ["a\x00 b \x00"]], [ ["a\x00 b \x00", ["a\x00 b \x00"]],

View file

@ -2,10 +2,12 @@
require_relative '../../../spec_helper' require_relative '../../../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require_relative 'shared/basic' require_relative 'shared/basic'
require_relative 'shared/taint'
describe "String#unpack with format 'B'" do describe "String#unpack with format 'B'" do
it_behaves_like :string_unpack_basic, 'B' it_behaves_like :string_unpack_basic, 'B'
it_behaves_like :string_unpack_no_platform, 'B' it_behaves_like :string_unpack_no_platform, 'B'
it_behaves_like :string_unpack_taint, 'B'
it "decodes one bit from each byte for each format character starting with the most significant bit" do it "decodes one bit from each byte for each format character starting with the most significant bit" do
[ ["\x00", "B", ["0"]], [ ["\x00", "B", ["0"]],
@ -96,6 +98,7 @@ end
describe "String#unpack with format 'b'" do describe "String#unpack with format 'b'" do
it_behaves_like :string_unpack_basic, 'b' it_behaves_like :string_unpack_basic, 'b'
it_behaves_like :string_unpack_no_platform, 'b' it_behaves_like :string_unpack_no_platform, 'b'
it_behaves_like :string_unpack_taint, 'b'
it "decodes one bit from each byte for each format character starting with the least significant bit" do it "decodes one bit from each byte for each format character starting with the least significant bit" do
[ ["\x00", "b", ["0"]], [ ["\x00", "b", ["0"]],

View file

@ -2,10 +2,12 @@
require_relative '../../../spec_helper' require_relative '../../../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require_relative 'shared/basic' require_relative 'shared/basic'
require_relative 'shared/taint'
describe "String#unpack with format 'H'" do describe "String#unpack with format 'H'" do
it_behaves_like :string_unpack_basic, 'H' it_behaves_like :string_unpack_basic, 'H'
it_behaves_like :string_unpack_no_platform, 'H' it_behaves_like :string_unpack_no_platform, 'H'
it_behaves_like :string_unpack_taint, 'H'
it "decodes one nibble from each byte for each format character starting with the most significant bit" do it "decodes one nibble from each byte for each format character starting with the most significant bit" do
[ ["\x8f", "H", ["8"]], [ ["\x8f", "H", ["8"]],
@ -66,6 +68,7 @@ end
describe "String#unpack with format 'h'" do describe "String#unpack with format 'h'" do
it_behaves_like :string_unpack_basic, 'h' it_behaves_like :string_unpack_basic, 'h'
it_behaves_like :string_unpack_no_platform, 'h' it_behaves_like :string_unpack_no_platform, 'h'
it_behaves_like :string_unpack_taint, 'h'
it "decodes one nibble from each byte for each format character starting with the least significant bit" do it "decodes one nibble from each byte for each format character starting with the least significant bit" do
[ ["\x8f", "h", ["f"]], [ ["\x8f", "h", ["f"]],

View file

@ -2,10 +2,12 @@
require_relative '../../../spec_helper' require_relative '../../../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require_relative 'shared/basic' require_relative 'shared/basic'
require_relative 'shared/taint'
describe "String#unpack with format 'M'" do describe "String#unpack with format 'M'" do
it_behaves_like :string_unpack_basic, 'M' it_behaves_like :string_unpack_basic, 'M'
it_behaves_like :string_unpack_no_platform, 'M' it_behaves_like :string_unpack_no_platform, 'M'
it_behaves_like :string_unpack_taint, 'M'
it "decodes an empty string" do it "decodes an empty string" do
"".unpack("M").should == [""] "".unpack("M").should == [""]
@ -100,6 +102,7 @@ end
describe "String#unpack with format 'm'" do describe "String#unpack with format 'm'" do
it_behaves_like :string_unpack_basic, 'm' it_behaves_like :string_unpack_basic, 'm'
it_behaves_like :string_unpack_no_platform, 'm' it_behaves_like :string_unpack_no_platform, 'm'
it_behaves_like :string_unpack_taint, 'm'
it "decodes an empty string" do it "decodes an empty string" do
"".unpack("m").should == [""] "".unpack("m").should == [""]

View file

@ -1,21 +1,52 @@
require_relative '../../../spec_helper' require_relative '../../../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require_relative 'shared/basic' require_relative 'shared/basic'
require_relative 'shared/taint'
describe "String#unpack with format 'P'" do describe "String#unpack with format 'P'" do
it_behaves_like :string_unpack_basic, 'P' it_behaves_like :string_unpack_basic, 'P'
it_behaves_like :string_unpack_taint, 'P'
it "returns a random object after consuming a size-of a machine word bytes" do it "round-trips a string through pack and unpack" do
str = "\0" * 1.size ["hello"].pack("P").unpack("P5").should == ["hello"]
str.unpack("P").should be_kind_of(Object) end
it "cannot unpack a string except from the same object that created it, or a duplicate of it" do
packed = ["hello"].pack("P")
packed.unpack("P5").should == ["hello"]
packed.dup.unpack("P5").should == ["hello"]
lambda { packed.to_sym.to_s.unpack("P5") }.should raise_error(ArgumentError, /no associated pointer/)
end
it "taints the unpacked string" do
["hello"].pack("P").unpack("P5").first.tainted?.should be_true
end
it "reads as many characters as specified" do
["hello"].pack("P").unpack("P1").should == ["h"]
end
it "reads only as far as a NUL character" do
["hello"].pack("P").unpack("P10").should == ["hello"]
end end
end end
describe "String#unpack with format 'p'" do describe "String#unpack with format 'p'" do
it_behaves_like :string_unpack_basic, 'p' it_behaves_like :string_unpack_basic, 'p'
it_behaves_like :string_unpack_taint, 'p'
it "returns a random object after consuming a size-of a machine word bytes" do it "round-trips a string through pack and unpack" do
str = "\0" * 1.size ["hello"].pack("p").unpack("p").should == ["hello"]
str.unpack("p").should be_kind_of(Object) end
it "cannot unpack a string except from the same object that created it, or a duplicate of it" do
packed = ["hello"].pack("p")
packed.unpack("p").should == ["hello"]
packed.dup.unpack("p").should == ["hello"]
lambda { packed.to_sym.to_s.unpack("p") }.should raise_error(ArgumentError, /no associated pointer/)
end
it "taints the unpacked string" do
["hello"].pack("p").unpack("p").first.tainted?.should be_true
end end
end end

View file

@ -0,0 +1,81 @@
describe :string_unpack_taint, shared: true do
it "does not taint returned arrays if given an untainted format string" do
"".unpack(unpack_format(2)).tainted?.should be_false
end
it "does not taint returned arrays if given a tainted format string" do
format_string = unpack_format(2).dup
format_string.taint
"".unpack(format_string).tainted?.should be_false
end
it "does not taint returned strings if given an untainted format string" do
"".unpack(unpack_format(2)).any?(&:tainted?).should be_false
end
it "does not taint returned strings if given a tainted format string" do
format_string = unpack_format(2).dup
format_string.taint
"".unpack(format_string).any?(&:tainted?).should be_false
end
it "does not taint returned arrays if given an untainted packed string" do
"".unpack(unpack_format(2)).tainted?.should be_false
end
it "does not taint returned arrays if given a tainted packed string" do
packed_string = ""
packed_string.taint
packed_string.unpack(unpack_format(2)).tainted?.should be_false
end
it "does not taint returned strings if given an untainted packed string" do
"".unpack(unpack_format(2)).any?(&:tainted?).should be_false
end
it "taints returned strings if given a tainted packed string" do
packed_string = ""
packed_string.taint
packed_string.unpack(unpack_format(2)).all?(&:tainted?).should be_true
end
it "does not untrust returned arrays if given an untrusted format string" do
"".unpack(unpack_format(2)).untrusted?.should be_false
end
it "does not untrust returned arrays if given a untrusted format string" do
format_string = unpack_format(2).dup
format_string.untrust
"".unpack(format_string).untrusted?.should be_false
end
it "does not untrust returned strings if given an untainted format string" do
"".unpack(unpack_format(2)).any?(&:untrusted?).should be_false
end
it "does not untrust returned strings if given a untrusted format string" do
format_string = unpack_format(2).dup
format_string.untrust
"".unpack(format_string).any?(&:untrusted?).should be_false
end
it "does not untrust returned arrays if given an trusted packed string" do
"".unpack(unpack_format(2)).untrusted?.should be_false
end
it "does not untrust returned arrays if given a untrusted packed string" do
packed_string = ""
packed_string.untrust
packed_string.unpack(unpack_format(2)).untrusted?.should be_false
end
it "does not untrust returned strings if given an trusted packed string" do
"".unpack(unpack_format(2)).any?(&:untrusted?).should be_false
end
it "untrusts returned strings if given a untrusted packed string" do
packed_string = ""
packed_string.untrust
packed_string.unpack(unpack_format(2)).all?(&:untrusted?).should be_true
end
end

View file

@ -3,11 +3,13 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require_relative 'shared/basic' require_relative 'shared/basic'
require_relative 'shared/unicode' require_relative 'shared/unicode'
require_relative 'shared/taint'
describe "String#unpack with format 'U'" do describe "String#unpack with format 'U'" do
it_behaves_like :string_unpack_basic, 'U' it_behaves_like :string_unpack_basic, 'U'
it_behaves_like :string_unpack_no_platform, 'U' it_behaves_like :string_unpack_no_platform, 'U'
it_behaves_like :string_unpack_unicode, 'U' it_behaves_like :string_unpack_unicode, 'U'
it_behaves_like :string_unpack_taint, 'U'
it "raises ArgumentError on a malformed byte sequence" do it "raises ArgumentError on a malformed byte sequence" do
lambda { "\xE3".unpack('U') }.should raise_error(ArgumentError) lambda { "\xE3".unpack('U') }.should raise_error(ArgumentError)
@ -21,6 +23,7 @@ end
describe "String#unpack with format 'u'" do describe "String#unpack with format 'u'" do
it_behaves_like :string_unpack_basic, 'u' it_behaves_like :string_unpack_basic, 'u'
it_behaves_like :string_unpack_no_platform, 'u' it_behaves_like :string_unpack_no_platform, 'u'
it_behaves_like :string_unpack_taint, 'u'
it "decodes an empty string as an empty string" do it "decodes an empty string as an empty string" do
"".unpack("u").should == [""] "".unpack("u").should == [""]

View file

@ -3,11 +3,13 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require_relative 'shared/basic' require_relative 'shared/basic'
require_relative 'shared/string' require_relative 'shared/string'
require_relative 'shared/taint'
describe "String#unpack with format 'Z'" do describe "String#unpack with format 'Z'" do
it_behaves_like :string_unpack_basic, 'Z' it_behaves_like :string_unpack_basic, 'Z'
it_behaves_like :string_unpack_no_platform, 'Z' it_behaves_like :string_unpack_no_platform, 'Z'
it_behaves_like :string_unpack_string, 'Z' it_behaves_like :string_unpack_string, 'Z'
it_behaves_like :string_unpack_taint, 'Z'
it "stops decoding at NULL bytes when passed the '*' modifier" do it "stops decoding at NULL bytes when passed the '*' modifier" do
"a\x00\x00 b \x00c".unpack('Z*Z*Z*Z*').should == ["a", "", " b ", "c"] "a\x00\x00 b \x00c".unpack('Z*Z*Z*Z*').should == ["a", "", " b ", "c"]

View file

@ -8,6 +8,6 @@ describe "Struct#eql?" do
it "returns false if any corresponding elements are not #eql?" do it "returns false if any corresponding elements are not #eql?" do
car = StructClasses::Car.new("Honda", "Accord", 1998) car = StructClasses::Car.new("Honda", "Accord", 1998)
similar_car = StructClasses::Car.new("Honda", "Accord", 1998.0) similar_car = StructClasses::Car.new("Honda", "Accord", 1998.0)
car.send(@method, similar_car).should be_false car.should_not eql(similar_car)
end end
end end

View file

@ -56,7 +56,7 @@ describe 'Thread::Backtrace::Location#path' do
end end
context 'when the script is outside of the working directory' do context 'when the script is outside of the working directory' do
before do before :each do
@parent_dir = tmp('path_outside_pwd') @parent_dir = tmp('path_outside_pwd')
@sub_dir = File.join(@parent_dir, 'sub') @sub_dir = File.join(@parent_dir, 'sub')
@script = File.join(@parent_dir, 'main.rb') @script = File.join(@parent_dir, 'main.rb')
@ -67,9 +67,7 @@ describe 'Thread::Backtrace::Location#path' do
cp(source, @script) cp(source, @script)
end end
after do after :each do
rm_r(@script)
rm_r(@sub_dir)
rm_r(@parent_dir) rm_r(@parent_dir)
end end

View file

@ -49,6 +49,14 @@ describe "Time.new with a utc_offset argument" do
Time.new(2000, 1, 1, 0, 0, 0, "-04:10").utc_offset.should == -15000 Time.new(2000, 1, 1, 0, 0, 0, "-04:10").utc_offset.should == -15000
end end
it "returns a Time with a UTC offset specified as +HH:MM:SS" do
Time.new(2000, 1, 1, 0, 0, 0, "+05:30:37").utc_offset.should == 19837
end
it "returns a Time with a UTC offset specified as -HH:MM" do
Time.new(2000, 1, 1, 0, 0, 0, "-04:10:43").utc_offset.should == -15043
end
describe "with an argument that responds to #to_str" do describe "with an argument that responds to #to_str" do
it "coerces using #to_str" do it "coerces using #to_str" do
o = mock('string') o = mock('string')
@ -96,6 +104,14 @@ describe "Time.new with a utc_offset argument" do
Time.new(2000, 1, 1, 0, 0, 0, 86400 - 1).utc_offset.should == (86400 - 1) Time.new(2000, 1, 1, 0, 0, 0, 86400 - 1).utc_offset.should == (86400 - 1)
lambda { Time.new(2000, 1, 1, 0, 0, 0, 86400) }.should raise_error(ArgumentError) lambda { Time.new(2000, 1, 1, 0, 0, 0, 86400) }.should raise_error(ArgumentError)
end end
it "raises ArgumentError if the seconds argument is negative" do
lambda { Time.new(2000, 1, 1, 0, 0, -1) }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the utc_offset argument is greater than or equal to 10e9" do
lambda { Time.new(2000, 1, 1, 0, 0, 0, 1000000000) }.should raise_error(ArgumentError)
end
end end
ruby_version_is "2.6" do ruby_version_is "2.6" do

View file

@ -46,4 +46,8 @@ describe "Regexps with back-references" do
it "resets nested \<n> backreference before match of outer subexpression" do it "resets nested \<n> backreference before match of outer subexpression" do
/(a\1?){2}/.match("aaaa").to_a.should == ["aa", "a"] /(a\1?){2}/.match("aaaa").to_a.should == ["aa", "a"]
end end
it "can match an optional quote, followed by content, followed by a matching quote, as the whole string" do
/^("|)(.*)\1$/.match('x').to_a.should == ["x", "", "x"]
end
end end

View file

@ -167,4 +167,31 @@ describe "Literal Regexps" do
pattern.to_s.should == ref pattern.to_s.should == ref
end end
end end
ruby_version_is '2.4' do
it "support handling unicode 9.0 characters with POSIX bracket expressions" do
char_lowercase = "\u{104D8}" # OSAGE SMALL LETTER A
/[[:lower:]]/.match(char_lowercase).to_s.should == char_lowercase
char_uppercase = "\u{104B0}" # OSAGE CAPITAL LETTER A
/[[:upper:]]/.match(char_uppercase).to_s.should == char_uppercase
end
end
ruby_version_is ""..."2.4" do
it "does not support handling unicode 9.0 characters with POSIX bracket expressions" do
char_lowercase = "\u{104D8}" # OSAGE SMALL LETTER A
/[[:lower:]]/.match(char_lowercase).should == nil
char_uppercase = "\u{104B0}" # OSAGE CAPITAL LETTER A
/[[:upper:]]/.match(char_lowercase).should == nil
end
it "supports handling unicode 8.0 characters with POSIX bracket expressions" do
char_lowercase = "\u{A7B5}" # LATIN SMALL LETTER BETA
/[[:lower:]]/.match(char_lowercase).to_s.should == char_lowercase
char_uppercase = "\u{A7B4}" # LATIN CAPITAL LETTER BETA
/[[:upper:]]/.match(char_uppercase).to_s.should == char_uppercase
end
end
end end

View file

@ -38,9 +38,9 @@ describe "BigDecimal#mod_part_of_divmod" do
it "raises ZeroDivisionError if other is zero" do it "raises ZeroDivisionError if other is zero" do
bd5667 = BigDecimal("5667.19") bd5667 = BigDecimal("5667.19")
lambda { bd5667.send(@method, 0) }.should raise_error(ZeroDivisionError) lambda { bd5667.mod_part_of_divmod(0) }.should raise_error(ZeroDivisionError)
lambda { bd5667.send(@method, BigDecimal("0")) }.should raise_error(ZeroDivisionError) lambda { bd5667.mod_part_of_divmod(BigDecimal("0")) }.should raise_error(ZeroDivisionError)
lambda { @zero.send(@method, @zero) }.should raise_error(ZeroDivisionError) lambda { @zero.mod_part_of_divmod(@zero) }.should raise_error(ZeroDivisionError)
end end
end end

View file

@ -15,8 +15,16 @@ describe "BigDecimal#to_s" do
@bigneg.to_s.kind_of?(String).should == true @bigneg.to_s.kind_of?(String).should == true
end end
it "the default format looks like 0.xxxxEnn" do ruby_version_is ''...'2.4' do
@bigdec.to_s.should =~ /^0\.[0-9]*E[0-9]*$/i it "the default format looks like 0.xxxxEnn" do
@bigdec.to_s.should =~ /^0\.[0-9]*E[0-9]*$/
end
end
ruby_version_is '2.4' do
it "the default format looks like 0.xxxxenn" do
@bigdec.to_s.should =~ /^0\.[0-9]*e[0-9]*$/
end
end end
it "takes an optional argument" do it "takes an optional argument" do
@ -63,10 +71,12 @@ describe "BigDecimal#to_s" do
end end
it "can use conventional floating point notation" do it "can use conventional floating point notation" do
@bigdec.to_s("F").should == @bigdec_str %w[f F].each do |format_char|
@bigneg.to_s("F").should == @bigneg_str @bigdec.to_s(format_char).should == @bigdec_str
str2 = "+123.45678901 23456789" @bigneg.to_s(format_char).should == @bigneg_str
BigDecimal('123.45678901234567890').to_s('+8F').should == str2 str2 = "+123.45678901 23456789"
BigDecimal('123.45678901234567890').to_s("+8#{format_char}").should == str2
end
end end
end end

View file

@ -0,0 +1,9 @@
require_relative '../../spec_helper'
require 'date'
describe "DateTime#+" do
it "is able to add sub-millisecond precision values" do
datetime = DateTime.new(2017)
(datetime + 0.00001).to_time.usec.should == 864000
end
end

View file

@ -0,0 +1,9 @@
require_relative '../../spec_helper'
require 'date'
describe "DateTime#-" do
it "is able to subtract sub-millisecond precision values" do
date = DateTime.new(2017)
((date + 0.00001) - date).should == Rational(1, 100000)
end
end

View file

@ -19,7 +19,7 @@ describe "UNIXSocket.open" do
end end
it "opens a unix socket on the specified file and yields it to the block" do it "opens a unix socket on the specified file and yields it to the block" do
UNIXSocket.send(@method, @path) do |client| UNIXSocket.open(@path) do |client|
client.addr[0].should == "AF_UNIX" client.addr[0].should == "AF_UNIX"
client.closed?.should == false client.closed?.should == false
end end

View file

@ -8,9 +8,9 @@ describe "StringIO#getbyte" do
it "returns the 8-bit byte at the current position" do it "returns the 8-bit byte at the current position" do
io = StringIO.new("example") io = StringIO.new("example")
io.send(@method).should == 101 io.getbyte.should == 101
io.send(@method).should == 120 io.getbyte.should == 120
io.send(@method).should == 97 io.getbyte.should == 97
end end
end end

View file

@ -8,9 +8,9 @@ describe "StringIO#getc" do
it "returns the character at the current position" do it "returns the character at the current position" do
io = StringIO.new("example") io = StringIO.new("example")
io.send(@method).should == ?e io.getc.should == ?e
io.send(@method).should == ?x io.getc.should == ?x
io.send(@method).should == ?a io.getc.should == ?a
end end
end end

View file

@ -12,32 +12,32 @@ describe "StringIO#getch" do
it "returns the character at the current position" do it "returns the character at the current position" do
io = StringIO.new("example") io = StringIO.new("example")
io.send(@method).should == ?e io.getch.should == ?e
io.send(@method).should == ?x io.getch.should == ?x
io.send(@method).should == ?a io.getch.should == ?a
end end
with_feature :encoding do with_feature :encoding do
it "increments #pos by the byte size of the character in multibyte strings" do it "increments #pos by the byte size of the character in multibyte strings" do
io = StringIO.new("föóbar") io = StringIO.new("föóbar")
io.send(@method); io.pos.should == 1 # "f" has byte size 1 io.getch; io.pos.should == 1 # "f" has byte size 1
io.send(@method); io.pos.should == 3 # "ö" has byte size 2 io.getch; io.pos.should == 3 # "ö" has byte size 2
io.send(@method); io.pos.should == 5 # "ó" has byte size 2 io.getch; io.pos.should == 5 # "ó" has byte size 2
io.send(@method); io.pos.should == 6 # "b" has byte size 1 io.getch; io.pos.should == 6 # "b" has byte size 1
end end
end end
it "returns nil at the end of the string" do it "returns nil at the end of the string" do
# empty string case # empty string case
io = StringIO.new("") io = StringIO.new("")
io.send(@method).should == nil io.getch.should == nil
io.send(@method).should == nil io.getch.should == nil
# non-empty string case # non-empty string case
io = StringIO.new("a") io = StringIO.new("a")
io.send(@method) # skip one io.getch # skip one
io.send(@method).should == nil io.getch.should == nil
end end
describe "StringIO#getch when self is not readable" do describe "StringIO#getch when self is not readable" do

View file

@ -8,10 +8,10 @@ describe "StringIO#readbyte" do
it "reads the next 8-bit byte from self's current position" do it "reads the next 8-bit byte from self's current position" do
io = StringIO.new("example") io = StringIO.new("example")
io.send(@method).should == 101 io.readbyte.should == 101
io.pos = 4 io.pos = 4
io.send(@method).should == 112 io.readbyte.should == 112
end end
end end

View file

@ -8,10 +8,10 @@ describe "StringIO#readchar" do
it "reads the next 8-bit byte from self's current position" do it "reads the next 8-bit byte from self's current position" do
io = StringIO.new("example") io = StringIO.new("example")
io.send(@method).should == ?e io.readchar.should == ?e
io.pos = 4 io.pos = 4
io.send(@method).should == ?p io.readchar.should == ?p
end end
end end

View file

@ -24,6 +24,8 @@ describe "Zlib.crc32" do
Zlib.crc32(test_string, 1).should == 1809313411 Zlib.crc32(test_string, 1).should == 1809313411
Zlib.crc32(test_string, 2**8).should == 1722745982 Zlib.crc32(test_string, 2**8).should == 1722745982
Zlib.crc32(test_string, 2**16).should == 1932511220 Zlib.crc32(test_string, 2**16).should == 1932511220
Zlib.crc32("p", ~305419896).should == 4046865307
Zlib.crc32("p", -305419897).should == 4046865307
lambda { Zlib.crc32(test_string, 2**128) }.should raise_error(RangeError) lambda { Zlib.crc32(test_string, 2**128) }.should raise_error(RangeError)
end end

View file

@ -139,21 +139,21 @@ describe "C-API Encoding function" do
it_behaves_like :rb_enc_get_index, :rb_enc_get_index it_behaves_like :rb_enc_get_index, :rb_enc_get_index
it "returns the index of the encoding of a Symbol" do it "returns the index of the encoding of a Symbol" do
@s.send(@method, :symbol).should >= 0 @s.rb_enc_get_index(:symbol).should >= 0
end end
it "returns -1 as the index of nil" do it "returns -1 as the index of nil" do
@s.send(@method, nil).should == -1 @s.rb_enc_get_index(nil).should == -1
end end
it "returns -1 as the index for immediates" do it "returns -1 as the index for immediates" do
@s.send(@method, 1).should == -1 @s.rb_enc_get_index(1).should == -1
end end
ruby_version_is "2.6" do ruby_version_is "2.6" do
it "returns -1 for an object without an encoding" do it "returns -1 for an object without an encoding" do
obj = Object.new obj = Object.new
@s.send(@method, obj).should == -1 @s.rb_enc_get_index(obj).should == -1
end end
end end
end end

View file

@ -813,6 +813,15 @@ describe "CApiObject" do
it "returns nil if the instance variable has not been initialized" do it "returns nil if the instance variable has not been initialized" do
@o.rb_ivar_get(@test, :@bar).should == nil @o.rb_ivar_get(@test, :@bar).should == nil
end end
it "returns nil if the instance variable has not been initialized and is not a valid Ruby name" do
@o.rb_ivar_get(@test, :bar).should == nil
end
it 'returns the instance variable when it is not a valid Ruby name' do
@o.rb_ivar_set(@test, :foo, 27)
@o.rb_ivar_get(@test, :foo).should == 27
end
end end
describe "rb_ivar_set" do describe "rb_ivar_set" do
@ -820,6 +829,15 @@ describe "CApiObject" do
@o.rb_ivar_set(@test, :@foo, 42).should == 42 @o.rb_ivar_set(@test, :@foo, 42).should == 42
@test.instance_eval { @foo }.should == 42 @test.instance_eval { @foo }.should == 42
end end
it "sets and returns the instance variable on an object" do
@o.rb_ivar_set(@test, :@foo, 42).should == 42
@test.instance_eval { @foo }.should == 42
end
it 'sets and returns the instance variable when it is not a valid Ruby name' do
@o.rb_ivar_set(@test, :foo, 27).should == 27
end
end end
describe "rb_ivar_defined" do describe "rb_ivar_defined" do
@ -830,6 +848,10 @@ describe "CApiObject" do
it "returns false if the instance variable is not defined" do it "returns false if the instance variable is not defined" do
@o.rb_ivar_defined(@test, :@bar).should == false @o.rb_ivar_defined(@test, :@bar).should == false
end end
it "does not throw an error if the instance variable is not a valid Ruby name" do
@o.rb_ivar_defined(@test, :bar).should == false
end
end end
end end
end end

View file

@ -0,0 +1,21 @@
require_relative '../spec_helper'
describe "Array#pack" do
it "resists CVE-2018-16396 by tainting output based on input" do
"aAZBbHhuMmPp".each_char do |f|
["123456".taint].pack(f).tainted?.should be_true
end
end
end
describe "String#unpack" do
it "resists CVE-2018-16396 by tainting output based on input" do
"aAZBbHhuMm".each_char do |f|
"123456".taint.unpack(f).first.tainted?.should be_true
end
end
end

View file

@ -29,6 +29,13 @@ describe :basicobject_send, shared: true do
SendSpecs::Foo.send(@method, :bar).should == 'done' SendSpecs::Foo.send(@method, :bar).should == 'done'
end end
it "raises a TypeError if the method name is not a string or symbol" do
-> { SendSpecs.send(@method, nil) }.should raise_error(TypeError, /not a symbol nor a string/)
-> { SendSpecs.send(@method, 42) }.should raise_error(TypeError, /not a symbol nor a string/)
-> { SendSpecs.send(@method, 3.14) }.should raise_error(TypeError, /not a symbol nor a string/)
-> { SendSpecs.send(@method, true) }.should raise_error(TypeError, /not a symbol nor a string/)
end
it "raises a NameError if the corresponding method can't be found" do it "raises a NameError if the corresponding method can't be found" do
class SendSpecs::Foo class SendSpecs::Foo
def bar def bar

View file

@ -41,7 +41,7 @@ describe :kernel_raise, shared: true do
lambda { @object.raise(nil) }.should raise_error(TypeError) lambda { @object.raise(nil) }.should raise_error(TypeError)
end end
it "re-raises the rescued exception" do it "re-raises the previously rescued exception if no exception is specified" do
lambda do lambda do
begin begin
raise Exception, "outer" raise Exception, "outer"
@ -60,6 +60,22 @@ describe :kernel_raise, shared: true do
ScratchPad.recorded.should be_nil ScratchPad.recorded.should be_nil
end end
it "re-raises a previously rescued exception without overwriting the backtrace" do
begin
raise 'raised'
rescue => raised
begin
raise_again_line = __LINE__; raise raised
rescue => raised_again
# This spec is written using #backtrace and matching the line number
# from the string, as backtrace_locations is a more advanced
# method that is not always supported by implementations.
raised_again.backtrace.first.should_not include(":#{raise_again_line}:")
end
end
end
it "allows Exception, message, and backtrace parameters" do it "allows Exception, message, and backtrace parameters" do
lambda do lambda do
@object.raise(ArgumentError, "message", caller) @object.raise(ArgumentError, "message", caller)