diff --git a/spec/ruby/appveyor.yml b/spec/ruby/appveyor.yml index 8ee5abd8b4..88dd753070 100644 --- a/spec/ruby/appveyor.yml +++ b/spec/ruby/appveyor.yml @@ -3,16 +3,20 @@ version: "{build}" clone_depth: 5 init: # To avoid duplicated executables in PATH, see https://github.com/ruby/spec/pull/468 - - set PATH=C:\ruby%RUBY_VERSION%\bin;C:\Program Files\7-Zip;C:\Program Files\AppVeyor\BuildAgent;C:\Program Files\Git\cmd;C:\Windows\system32;C:\Program Files;C:\Windows + - set PATH=C:\Ruby%ruby_version%\bin;C:\Program Files\7-Zip;C:\Program Files\AppVeyor\BuildAgent;C:\Program Files\Git\cmd;C:\Windows\system32;C:\Program Files;C:\Windows # Loads trunk build and updates MSYS2 / MinGW to most recent gcc compiler - - if %ruby_version%==_trunk ( - appveyor DownloadFile https://ci.appveyor.com/api/projects/MSP-Greg/ruby-loco/artifacts/ruby_trunk.7z -FileName C:\ruby_trunk.7z & - 7z x C:\ruby_trunk.7z -oC:\ruby_trunk & C:\ruby_trunk\trunk_msys2.cmd) + - ps: | + if ($env:ruby_version -eq '_trunk') { + $trunk_uri = 'https://ci.appveyor.com/api/projects/MSP-Greg/ruby-loco/artifacts/ruby_trunk.7z' + (New-Object Net.WebClient).DownloadFile($trunk_uri, 'C:\ruby_trunk.7z') + 7z.exe x C:\ruby_trunk.7z -oC:\Ruby_trunk + } + environment: matrix: - - RUBY_VERSION: 23-x64 - - RUBY_VERSION: 24-x64 - - RUBY_VERSION: _trunk # So the folder name is ruby_trunk + - ruby_version: 24-x64 + - ruby_version: 25-x64 + - ruby_version: _trunk # So the folder name is ruby_trunk install: - git clone https://github.com/ruby/mspec.git ../mspec build: off diff --git a/spec/ruby/core/enumerable/all_spec.rb b/spec/ruby/core/enumerable/all_spec.rb index 1c96cdea17..b0edb14532 100644 --- a/spec/ruby/core/enumerable/all_spec.rb +++ b/spec/ruby/core/enumerable/all_spec.rb @@ -2,12 +2,11 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Enumerable#all?" do - before :each do @enum = EnumerableSpecs::Numerous.new @empty = EnumerableSpecs::Empty.new() - @enum1 = [0, 1, 2, -1] - @enum2 = [nil, false, true] + @enum1 = EnumerableSpecs::Numerous.new(0, 1, 2, -1) + @enum2 = EnumerableSpecs::Numerous.new(nil, false, true) end it "always returns true on empty enumeration" do @@ -21,6 +20,21 @@ describe "Enumerable#all?" do {}.all? { nil }.should == true end + it "raises an ArgumentError when more than 1 argument is provided" do + lambda { @enum.all?(1, 2, 3) }.should raise_error(ArgumentError) + lambda { [].all?(1, 2, 3) }.should raise_error(ArgumentError) + lambda { {}.all?(1, 2, 3) }.should raise_error(ArgumentError) + end + + ruby_version_is ""..."2.5" do + it "raises an ArgumentError when any arguments provided" do + lambda { @enum.all?(Proc.new {}) }.should raise_error(ArgumentError) + lambda { @enum.all?(nil) }.should raise_error(ArgumentError) + lambda { @empty.all?(1) }.should raise_error(ArgumentError) + lambda { @enum1.all?(1) {} }.should raise_error(ArgumentError) + end + end + it "does not hide exceptions out of #each" do lambda { EnumerableSpecs::ThrowingEach.new.all? @@ -58,16 +72,6 @@ describe "Enumerable#all?" do multi = EnumerableSpecs::YieldsMultiWithFalse.new multi.all?.should be_true end - - ruby_version_is "2.5" do - describe "given a pattern argument" do - # This spec should be replaced by more extensive ones - it "returns true iff all match that pattern" do - @enum.all?(Integer).should == true - @enum2.all?(NilClass).should == false - end - end - end end describe "with block" do @@ -117,14 +121,79 @@ describe "Enumerable#all?" do it "gathers initial args as elements when each yields multiple" do multi = EnumerableSpecs::YieldsMulti.new - multi.all? {|e| !(Array === e) }.should be_true + yielded = [] + multi.all? { |e| yielded << e }.should == true + yielded.should == [1, 3, 6] end it "yields multiple arguments when each yields multiple" do multi = EnumerableSpecs::YieldsMulti.new yielded = [] - multi.all? {|e, i| yielded << [e, i] } - yielded.should == [[1, 2], [3, 4], [6, 7]] + multi.all? { |*args| yielded << args }.should == true + yielded.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]] + end + end + + ruby_version_is "2.5" do + describe 'when given a pattern argument' do + it "calls `===` on the pattern the return value " do + pattern = EnumerableSpecs::Pattern.new { |x| x >= 0 } + @enum1.all?(pattern).should == false + pattern.yielded.should == [[0], [1], [2], [-1]] + end + + it "ignores block" do + @enum2.all?(NilClass) { raise }.should == false + [1, 2, nil].all?(NilClass) { raise }.should == false + {a: 1}.all?(Array) { raise }.should == true + end + + it "always returns true on empty enumeration" do + @empty.all?(Integer).should == true + [].all?(Integer).should == true + {}.all?(NilClass).should == true + end + + it "does not hide exceptions out of #each" do + lambda { + EnumerableSpecs::ThrowingEach.new.all?(Integer) + }.should raise_error(RuntimeError) + end + + it "returns true if the pattern never returns false or nil" do + pattern = EnumerableSpecs::Pattern.new { |x| 42 } + @enum.all?(pattern).should == true + + [1, 42, 3].all?(pattern).should == true + + pattern = EnumerableSpecs::Pattern.new { |x| Array === x } + {a: 1, b: 2}.all?(pattern).should == true + end + + it "returns false if the pattern ever returns false or nil" do + pattern = EnumerableSpecs::Pattern.new { |x| x >= 0 } + @enum1.all?(pattern).should == false + pattern.yielded.should == [[0], [1], [2], [-1]] + + [1, 2, 3, -1].all?(pattern).should == false + + pattern = EnumerableSpecs::Pattern.new { |x| x[1] >= 0 } + {a: 1, b: -1}.all?(pattern).should == false + end + + it "does not hide exceptions out of pattern#===" do + pattern = EnumerableSpecs::Pattern.new { raise "from pattern" } + lambda { + @enum.all?(pattern) + }.should raise_error(RuntimeError) + end + + it "calls the pattern with gathered array when yielded with multiple arguments" do + multi = EnumerableSpecs::YieldsMulti.new + pattern = EnumerableSpecs::Pattern.new { true } + multi.all?(pattern).should == true + pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]] + end end end end diff --git a/spec/ruby/core/enumerable/any_spec.rb b/spec/ruby/core/enumerable/any_spec.rb index cd25f1440c..a4e98df736 100644 --- a/spec/ruby/core/enumerable/any_spec.rb +++ b/spec/ruby/core/enumerable/any_spec.rb @@ -4,9 +4,9 @@ require_relative 'fixtures/classes' describe "Enumerable#any?" do before :each do @enum = EnumerableSpecs::Numerous.new - @empty = EnumerableSpecs::Empty.new() - @enum1 = [0, 1, 2, -1] - @enum2 = [nil, false, true] + @empty = EnumerableSpecs::Empty.new + @enum1 = EnumerableSpecs::Numerous.new(0, 1, 2, -1) + @enum2 = EnumerableSpecs::Numerous.new(nil, false, true) end it "always returns false on empty enumeration" do @@ -86,7 +86,7 @@ describe "Enumerable#any?" do @enum2.any? { |i| i == nil }.should == true end - it "any? should return false if the block never returns other than false or nil" do + it "returns false if the block never returns other than false or nil" do @enum.any? { false }.should == false @enum.any? { nil }.should == false @@ -134,32 +134,21 @@ describe "Enumerable#any?" do it "gathers initial args as elements when each yields multiple" do multi = EnumerableSpecs::YieldsMulti.new - multi.any? {|e| e == 1 }.should be_true + yielded = [] + multi.any? { |e| yielded << e; false }.should == false + yielded.should == [1, 3, 6] end it "yields multiple arguments when each yields multiple" do multi = EnumerableSpecs::YieldsMulti.new yielded = [] - multi.any? {|e, i| yielded << [e, i] } - yielded.should == [[1, 2]] + multi.any? { |*args| yielded << args; false }.should == false + yielded.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]] end - end ruby_version_is "2.5" do describe 'when given a pattern argument' do - class EnumerableSpecs::Pattern - attr_reader :yielded - def initialize(&block) - @block = block - @yielded = [] - end - def ===(*args) - @yielded << args - @block.call(*args) - end - end - it "calls `===` on the pattern the return value " do pattern = EnumerableSpecs::Pattern.new { |x| x == 2 } @enum1.any?(pattern).should == true @@ -195,7 +184,7 @@ describe "Enumerable#any?" do {a: 1, b: 2}.any?(pattern).should == true end - it "any? should return false if the block never returns other than false or nil" do + it "returns false if the block never returns other than false or nil" do pattern = EnumerableSpecs::Pattern.new { |x| nil } @enum1.any?(pattern).should == false pattern.yielded.should == [[0], [1], [2], [-1]] @@ -204,7 +193,7 @@ describe "Enumerable#any?" do {a: 1}.any?(pattern).should == false end - it "does not hide exceptions out of the block" do + it "does not hide exceptions out of pattern#===" do pattern = EnumerableSpecs::Pattern.new { raise "from pattern" } lambda { @enum.any?(pattern) @@ -212,13 +201,10 @@ describe "Enumerable#any?" do end it "calls the pattern with gathered array when yielded with multiple arguments" do + multi = EnumerableSpecs::YieldsMulti.new pattern = EnumerableSpecs::Pattern.new { false } - EnumerableSpecs::YieldsMixed2.new.any?(pattern).should == false - pattern.yielded.should == EnumerableSpecs::YieldsMixed2.gathered_yields.map { |x| [x] } - - pattern = EnumerableSpecs::Pattern.new { false } - {a: 1, b: 2}.any?(pattern).should == false - pattern.yielded.should == [[[:a, 1]], [[:b, 2]]] + multi.any?(pattern).should == false + pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]] end end end diff --git a/spec/ruby/core/enumerable/fixtures/classes.rb b/spec/ruby/core/enumerable/fixtures/classes.rb index 26a8aff8e2..e50bf34779 100644 --- a/spec/ruby/core/enumerable/fixtures/classes.rb +++ b/spec/ruby/core/enumerable/fixtures/classes.rb @@ -328,4 +328,18 @@ module EnumerableSpecs EnumerableMapping.new(self, block) end end + + class Pattern + attr_reader :yielded + + def initialize(&block) + @block = block + @yielded = [] + end + + def ===(*args) + @yielded << args + @block.call(*args) + end + end end # EnumerableSpecs utility classes diff --git a/spec/ruby/core/enumerable/none_spec.rb b/spec/ruby/core/enumerable/none_spec.rb index 4425875f4b..04fb64e089 100644 --- a/spec/ruby/core/enumerable/none_spec.rb +++ b/spec/ruby/core/enumerable/none_spec.rb @@ -2,67 +2,164 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Enumerable#none?" do - it "returns true if none of the elements in self are true" do - e = EnumerableSpecs::Numerous.new(false, nil, false) - e.none?.should be_true + before :each do + @empty = EnumerableSpecs::Empty.new + @enum = EnumerableSpecs::Numerous.new + @enum1 = EnumerableSpecs::Numerous.new(0, 1, 2, -1) + @enum2 = EnumerableSpecs::Numerous.new(nil, false, true) end - it "returns false if at least one of the elements in self are true" do - e = EnumerableSpecs::Numerous.new(false, nil, true, false) - e.none?.should be_false + it "always returns true on empty enumeration" do + @empty.none?.should == true + @empty.none? { true }.should == true end - 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.none?.should be_false + it "raises an ArgumentError when more than 1 argument is provided" do + lambda { @enum.none?(1, 2, 3) }.should raise_error(ArgumentError) + lambda { [].none?(1, 2, 3) }.should raise_error(ArgumentError) + lambda { {}.none?(1, 2, 3) }.should raise_error(ArgumentError) + end + + ruby_version_is ""..."2.5" do + it "raises an ArgumentError when any arguments provided" do + lambda { @enum.none?(Proc.new {}) }.should raise_error(ArgumentError) + lambda { @enum.none?(nil) }.should raise_error(ArgumentError) + lambda { @empty.none?(1) }.should raise_error(ArgumentError) + lambda { @enum.none?(1) {} }.should raise_error(ArgumentError) + end + end + + it "does not hide exceptions out of #each" do + lambda { + EnumerableSpecs::ThrowingEach.new.none? + }.should raise_error(RuntimeError) + + lambda { + EnumerableSpecs::ThrowingEach.new.none? { false } + }.should raise_error(RuntimeError) + end + + describe "with no block" do + it "returns true if none of the elements in self are true" do + e = EnumerableSpecs::Numerous.new(false, nil, false) + e.none?.should be_true + end + + it "returns false if at least one of the elements in self are true" do + e = EnumerableSpecs::Numerous.new(false, nil, true, false) + e.none?.should be_false + end + + 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.none?.should be_false + end + end + + describe "with a block" do + before :each do + @e = EnumerableSpecs::Numerous.new(1,1,2,3,4) + end + + it "passes each element to the block in turn until it returns true" do + acc = [] + @e.none? {|e| acc << e; false } + acc.should == [1,1,2,3,4] + end + + it "stops passing elements to the block when it returns true" do + acc = [] + @e.none? {|e| acc << e; e == 3 ? true : false } + acc.should == [1,1,2,3] + end + + it "returns true if the block never returns true" do + @e.none? {|e| false }.should be_true + end + + it "returns false if the block ever returns true" do + @e.none? {|e| e == 3 ? true : false }.should be_false + end + + it "does not hide exceptions out of the block" do + lambda { + @enum.none? { raise "from block" } + }.should raise_error(RuntimeError) + end + + it "gathers initial args as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + yielded = [] + multi.none? { |e| yielded << e; false } + yielded.should == [1, 3, 6] + end + + it "yields multiple arguments when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + yielded = [] + multi.none? { |*args| yielded << args; false } + yielded.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]] + end end ruby_version_is "2.5" do - describe "given a pattern argument" do - # This spec should be replaced by more extensive ones - it "returns true iff none match that pattern" do - EnumerableSpecs::Numerous.new.none?(Float).should == true - [nil, false, true].none?(NilClass).should == false + describe 'when given a pattern argument' do + it "calls `===` on the pattern the return value " do + pattern = EnumerableSpecs::Pattern.new { |x| x == 3 } + @enum1.none?(pattern).should == true + pattern.yielded.should == [[0], [1], [2], [-1]] + end + + it "ignores block" do + @enum2.none?(Integer) { raise }.should == true + [1, 2, nil].none?(TrueClass) { raise }.should == true + {a: 1}.none?(Hash) { raise }.should == true + end + + it "always returns true on empty enumeration" do + @empty.none?(Integer).should == true + [].none?(Integer).should == true + {}.none?(NilClass).should == true + end + + it "does not hide exceptions out of #each" do + lambda { + EnumerableSpecs::ThrowingEach.new.none?(Integer) + }.should raise_error(RuntimeError) + end + + it "returns true if the pattern never returns a truthy value" do + @enum2.none?(Integer).should == true + pattern = EnumerableSpecs::Pattern.new { |x| nil } + @enum.none?(pattern).should == true + + [1, 42, 3].none?(pattern).should == true + {a: 1, b: 2}.none?(pattern).should == true + end + + it "returns false if the pattern ever returns other than false or nil" do + pattern = EnumerableSpecs::Pattern.new { |x| x < 0 } + @enum1.none?(pattern).should == false + pattern.yielded.should == [[0], [1], [2], [-1]] + + [1, 2, 3, -1].none?(pattern).should == false + {a: 1}.none?(Array).should == false + end + + it "does not hide exceptions out of pattern#===" do + pattern = EnumerableSpecs::Pattern.new { raise "from pattern" } + lambda { + @enum.none?(pattern) + }.should raise_error(RuntimeError) + end + + it "calls the pattern with gathered array when yielded with multiple arguments" do + multi = EnumerableSpecs::YieldsMulti.new + pattern = EnumerableSpecs::Pattern.new { false } + multi.none?(pattern).should == true + pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]] end end end end - -describe "Enumerable#none? with a block" do - before :each do - @e = EnumerableSpecs::Numerous.new(1,1,2,3,4) - end - - it "passes each element to the block in turn until it returns true" do - acc = [] - @e.none? {|e| acc << e; false } - acc.should == [1,1,2,3,4] - end - - it "stops passing elements to the block when it returns true" do - acc = [] - @e.none? {|e| acc << e; e == 3 ? true : false } - acc.should == [1,1,2,3] - end - - it "returns true if the block never returns true" do - @e.none? {|e| false }.should be_true - end - - it "returns false if the block ever returns true" do - @e.none? {|e| e == 3 ? true : false }.should be_false - end - - it "gathers initial args as elements when each yields multiple" do - multi = EnumerableSpecs::YieldsMulti.new - multi.none? {|e| e == [1, 2] }.should be_true - end - - it "yields multiple arguments when each yields multiple" do - multi = EnumerableSpecs::YieldsMulti.new - yielded = [] - multi.none? {|e, i| yielded << [e, i] } - yielded.should == [[1, 2]] - end -end diff --git a/spec/ruby/core/enumerable/one_spec.rb b/spec/ruby/core/enumerable/one_spec.rb index facaad7670..67653749dd 100644 --- a/spec/ruby/core/enumerable/one_spec.rb +++ b/spec/ruby/core/enumerable/one_spec.rb @@ -2,44 +2,44 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Enumerable#one?" do - describe "when passed a block" do - it "returns true if block returns true once" do - [:a, :b, :c].one? { |s| s == :a }.should be_true - end + before :each do + @empty = EnumerableSpecs::Empty.new + @enum = EnumerableSpecs::Numerous.new + @enum1 = EnumerableSpecs::Numerous.new(0, 1, 2, -1) + @enum2 = EnumerableSpecs::Numerous.new(nil, false, true) + end - it "returns false if the block returns true more than once" do - [:a, :b, :c].one? { |s| s == :a || s == :b }.should be_false - end + it "always returns false on empty enumeration" do + @empty.one?.should == false + @empty.one? { true }.should == false + end - it "returns false if the block only returns false" do - [:a, :b, :c].one? { |s| s == :d }.should be_false - end + it "raises an ArgumentError when more than 1 argument is provided" do + lambda { @enum.one?(1, 2, 3) }.should raise_error(ArgumentError) + lambda { [].one?(1, 2, 3) }.should raise_error(ArgumentError) + lambda { {}.one?(1, 2, 3) }.should raise_error(ArgumentError) + end - 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.one? {|e| e == 1 }.should be_true - end - - it "yields multiple arguments when each yields multiple" do - multi = EnumerableSpecs::YieldsMulti.new - yielded = [] - multi.one? {|e, i| yielded << [e, i] } - yielded.should == [[1, 2], [3, 4]] - end - - ruby_version_is "2.5" do - describe "given a pattern argument" do - # This spec should be replaced by more extensive ones - it "returns true iff none match that pattern" do - EnumerableSpecs::Numerous.new.one?(Integer).should == false - [nil, false, true].one?(NilClass).should == true - end - end + ruby_version_is ""..."2.5" do + it "raises an ArgumentError when any arguments provided" do + lambda { @enum.one?(Proc.new {}) }.should raise_error(ArgumentError) + lambda { @enum.one?(nil) }.should raise_error(ArgumentError) + lambda { @empty.one?(1) }.should raise_error(ArgumentError) + lambda { @enum.one?(1) {} }.should raise_error(ArgumentError) end end - describe "when not passed a block" do + it "does not hide exceptions out of #each" do + lambda { + EnumerableSpecs::ThrowingEach.new.one? + }.should raise_error(RuntimeError) + + lambda { + EnumerableSpecs::ThrowingEach.new.one? { false } + }.should raise_error(RuntimeError) + end + + describe "with no block" do it "returns true if only one element evaluates to true" do [false, nil, true].one?.should be_true end @@ -57,4 +57,111 @@ describe "Enumerable#one?" do multi.one?.should be_false end end + + describe "with a block" do + it "returns true if block returns true once" do + [:a, :b, :c].one? { |s| s == :a }.should be_true + end + + it "returns false if the block returns true more than once" do + [:a, :b, :c].one? { |s| s == :a || s == :b }.should be_false + end + + it "returns false if the block only returns false" do + [:a, :b, :c].one? { |s| s == :d }.should be_false + end + + it "does not hide exceptions out of the block" do + lambda { + @enum.one? { raise "from block" } + }.should raise_error(RuntimeError) + end + + 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 + yielded = [] + multi.one? { |e| yielded << e; false }.should == false + yielded.should == [1, 3, 6] + end + + it "yields multiple arguments when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + yielded = [] + multi.one? { |*args| yielded << args; false }.should == false + yielded.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]] + end + end + + + ruby_version_is "2.5" do + describe 'when given a pattern argument' do + it "calls `===` on the pattern the return value " do + pattern = EnumerableSpecs::Pattern.new { |x| x == 1 } + @enum1.one?(pattern).should == true + pattern.yielded.should == [[0], [1], [2], [-1]] + end + + it "ignores block" do + @enum2.one?(NilClass) { raise }.should == true + [1, 2, nil].one?(NilClass) { raise }.should == true + {a: 1}.one?(Array) { raise }.should == true + end + + it "always returns false on empty enumeration" do + @empty.one?(Integer).should == false + [].one?(Integer).should == false + {}.one?(NilClass).should == false + end + + it "does not hide exceptions out of #each" do + lambda { + EnumerableSpecs::ThrowingEach.new.one?(Integer) + }.should raise_error(RuntimeError) + end + + it "returns true if the pattern returns a truthy value only once" do + @enum2.one?(NilClass).should == true + pattern = EnumerableSpecs::Pattern.new { |x| x == 2 } + @enum1.one?(pattern).should == true + + [1, 2, 42, 3].one?(pattern).should == true + + pattern = EnumerableSpecs::Pattern.new { |x| x == [:b, 2] } + {a: 1, b: 2}.one?(pattern).should == true + end + + it "returns false if the pattern returns a truthy value more than once" do + pattern = EnumerableSpecs::Pattern.new { |x| !x } + @enum2.one?(pattern).should == false + pattern.yielded.should == [[nil], [false]] + + [1, 2, 3].one?(Integer).should == false + {a: 1, b: 2}.one?(Array).should == false + end + + it "returns false if the pattern never returns a truthy value" do + pattern = EnumerableSpecs::Pattern.new { |x| nil } + @enum1.one?(pattern).should == false + pattern.yielded.should == [[0], [1], [2], [-1]] + + [1, 2, 3].one?(pattern).should == false + {a: 1}.one?(pattern).should == false + end + + it "does not hide exceptions out of pattern#===" do + pattern = EnumerableSpecs::Pattern.new { raise "from pattern" } + lambda { + @enum.one?(pattern) + }.should raise_error(RuntimeError) + end + + it "calls the pattern with gathered array when yielded with multiple arguments" do + multi = EnumerableSpecs::YieldsMulti.new + pattern = EnumerableSpecs::Pattern.new { false } + multi.one?(pattern).should == false + pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]] + end + end + end end diff --git a/spec/ruby/core/kernel/autoload_spec.rb b/spec/ruby/core/kernel/autoload_spec.rb index 038dfd1db1..c2573ffac6 100644 --- a/spec/ruby/core/kernel/autoload_spec.rb +++ b/spec/ruby/core/kernel/autoload_spec.rb @@ -60,6 +60,25 @@ describe "Kernel#autoload" do ruby_exe(fixture(__FILE__, "autoload_frozen.rb")).should == "#{frozen_error_class} - nil" end end + + describe "when called from included module's method" do + before :all do + @path = fixture(__FILE__, "autoload_from_included_module.rb") + KernelSpecs::AutoloadMethodIncluder.new.setup_autoload(@path) + end + + it "setups the autoload on the included module" do + KernelSpecs::AutoloadMethod.autoload?(:AutoloadFromIncludedModule).should == @path + end + + it "the autoload is reacheable from the class too" do + KernelSpecs::AutoloadMethodIncluder.autoload?(:AutoloadFromIncludedModule).should == @path + end + + it "the autoload relative to the included module works" do + KernelSpecs::AutoloadMethod::AutoloadFromIncludedModule.loaded.should == :autoload_from_included_module + end + end end describe "Kernel#autoload?" do @@ -107,6 +126,25 @@ describe "Kernel.autoload" do p.should_receive(:to_path).and_return @non_existent Kernel.autoload :KSAutoloadAA, p end + + describe "when called from included module's method" do + before :all do + @path = fixture(__FILE__, "autoload_from_included_module2.rb") + KernelSpecs::AutoloadMethodIncluder2.new.setup_autoload(@path) + end + + it "setups the autoload on the included module" do + KernelSpecs::AutoloadMethod2.autoload?(:AutoloadFromIncludedModule2).should == @path + end + + it "the autoload is reacheable from the class too" do + KernelSpecs::AutoloadMethodIncluder2.autoload?(:AutoloadFromIncludedModule2).should == @path + end + + it "the autoload relative to the included module works" do + KernelSpecs::AutoloadMethod2::AutoloadFromIncludedModule2.loaded.should == :autoload_from_included_module2 + end + end end describe "Kernel.autoload?" do diff --git a/spec/ruby/core/kernel/fixtures/autoload_from_included_module.rb b/spec/ruby/core/kernel/fixtures/autoload_from_included_module.rb new file mode 100644 index 0000000000..f5bedc6992 --- /dev/null +++ b/spec/ruby/core/kernel/fixtures/autoload_from_included_module.rb @@ -0,0 +1,9 @@ +module KernelSpecs + module AutoloadMethod + module AutoloadFromIncludedModule + def self.loaded + :autoload_from_included_module + end + end + end +end diff --git a/spec/ruby/core/kernel/fixtures/autoload_from_included_module2.rb b/spec/ruby/core/kernel/fixtures/autoload_from_included_module2.rb new file mode 100644 index 0000000000..f4f1cfbf7c --- /dev/null +++ b/spec/ruby/core/kernel/fixtures/autoload_from_included_module2.rb @@ -0,0 +1,9 @@ +module KernelSpecs + module AutoloadMethod2 + module AutoloadFromIncludedModule2 + def self.loaded + :autoload_from_included_module2 + end + end + end +end diff --git a/spec/ruby/core/kernel/fixtures/classes.rb b/spec/ruby/core/kernel/fixtures/classes.rb index afa2bec12f..cc475ed758 100644 --- a/spec/ruby/core/kernel/fixtures/classes.rb +++ b/spec/ruby/core/kernel/fixtures/classes.rb @@ -378,6 +378,49 @@ module KernelSpecs [3, 4] end end + + module AutoloadMethod + def setup_autoload(file) + autoload :AutoloadFromIncludedModule, file + end + end + + class AutoloadMethodIncluder + include AutoloadMethod + end + + module AutoloadMethod2 + def setup_autoload(file) + Kernel.autoload :AutoloadFromIncludedModule2, file + end + end + + class AutoloadMethodIncluder2 + include AutoloadMethod2 + end + + class WarnInNestedCall + def f4(s = "", n) + f3(s, n) + end + + def f3(s, n) + f2(s, n) + end + + def f2(s, n) + f1(s, n) + end + + def f1(s, n) + warn(s, uplevel: n) + end + + def warn_call_lineno; method(:f1).source_location[1] + 1; end + def f1_call_lineno; method(:f2).source_location[1] + 1; end + def f2_call_lineno; method(:f3).source_location[1] + 1; end + def f3_call_lineno; method(:f4).source_location[1] + 1; end + end end class EvalSpecs diff --git a/spec/ruby/core/kernel/shared/then.rb b/spec/ruby/core/kernel/shared/then.rb new file mode 100644 index 0000000000..b52075371f --- /dev/null +++ b/spec/ruby/core/kernel/shared/then.rb @@ -0,0 +1,20 @@ +describe :kernel_then, shared: true do + it "yields self" do + object = Object.new + object.send(@method) { |o| o.should equal object } + end + + it "returns the block return value" do + object = Object.new + object.send(@method) { 42 }.should equal 42 + end + + it "returns a sized Enumerator when no block given" do + object = Object.new + enum = object.send(@method) + enum.should be_an_instance_of Enumerator + enum.size.should equal 1 + enum.peek.should equal object + enum.first.should equal object + end +end diff --git a/spec/ruby/core/kernel/then_spec.rb b/spec/ruby/core/kernel/then_spec.rb new file mode 100644 index 0000000000..fa896b52b1 --- /dev/null +++ b/spec/ruby/core/kernel/then_spec.rb @@ -0,0 +1,8 @@ +require_relative '../../spec_helper' +require_relative 'shared/then' + +ruby_version_is "2.6" do + describe "Kernel#then" do + it_behaves_like :kernel_then, :then + end +end diff --git a/spec/ruby/core/kernel/warn_spec.rb b/spec/ruby/core/kernel/warn_spec.rb index f1dcdf5949..7a0c431ff0 100644 --- a/spec/ruby/core/kernel/warn_spec.rb +++ b/spec/ruby/core/kernel/warn_spec.rb @@ -76,4 +76,60 @@ describe "Kernel#warn" do warn("") }.should output(nil, /\n/) end + + ruby_version_is "2.5" do + describe ":uplevel keyword argument" do + before :each do + $VERBOSE = true + end + + it "prepends a message with specified line from the backtrace" do + w = KernelSpecs::WarnInNestedCall.new + + -> { w.f4("foo", 0) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.warn_call_lineno}: warning: foo|) + -> { w.f4("foo", 1) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f1_call_lineno}: warning: foo|) + -> { w.f4("foo", 2) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f2_call_lineno}: warning: foo|) + -> { w.f4("foo", 3) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.f3_call_lineno}: warning: foo|) + end + + ruby_bug "#14846", "2.5"..."2.6" do + it "does not prepend caller information if line number is too big" do + w = KernelSpecs::WarnInNestedCall.new + -> { w.f4("foo", 100) }.should output(nil, "warning: foo\n") + end + end + + it "prepends even if a message is empty or nil" do + w = KernelSpecs::WarnInNestedCall.new + + -> { w.f4("", 0) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.warn_call_lineno}: warning: \n$|) + -> { w.f4(nil, 0) }.should output(nil, %r|core/kernel/fixtures/classes.rb:#{w.warn_call_lineno}: warning: \n$|) + end + + it "converts value to Integer" do + w = KernelSpecs::WarnInNestedCall.new + + -> { w.f4(0.1) }.should output(nil, %r|classes.rb:#{w.warn_call_lineno}:|) + -> { w.f4(Rational(1, 2)) }.should output(nil, %r|classes.rb:#{w.warn_call_lineno}:|) + end + + it "raises ArgumentError if passed negative value" do + -> { warn "", uplevel: -2 }.should raise_error(ArgumentError) + -> { warn "", uplevel: -100 }.should raise_error(ArgumentError) + end + + ruby_bug "#14846", "2.5"..."2.6" do + it "raises ArgumentError if passed -1" do + -> { warn "", uplevel: -1 }.should raise_error(ArgumentError) + end + end + + it "raises TypeError if passed not Integer" do + -> { warn "", uplevel: "" }.should raise_error(TypeError) + -> { warn "", uplevel: [] }.should raise_error(TypeError) + -> { warn "", uplevel: {} }.should raise_error(TypeError) + -> { warn "", uplevel: Object.new }.should raise_error(TypeError) + end + end + end end diff --git a/spec/ruby/core/kernel/yield_self_spec.rb b/spec/ruby/core/kernel/yield_self_spec.rb index 0bcf0660c2..affedae144 100644 --- a/spec/ruby/core/kernel/yield_self_spec.rb +++ b/spec/ruby/core/kernel/yield_self_spec.rb @@ -1,29 +1,8 @@ require_relative '../../spec_helper' +require_relative 'shared/then' ruby_version_is "2.5" do describe "Kernel#yield_self" do - it "yields self" do - object = Object.new - object.yield_self { |o| o.should equal object } - end - - it "returns the block return value" do - object = Object.new - object.yield_self { 42 }.should equal 42 - end - - it "returns a sized Enumerator when no block given" do - object = Object.new - enum = object.yield_self - enum.should be_an_instance_of Enumerator - enum.size.should equal 1 - enum.peek.should equal object - enum.first.should equal object - end - - it "has an alias `then`" do - object = Object.new - object.then { 42 }.should equal 42 - end + it_behaves_like :kernel_then, :yield_self end end diff --git a/spec/ruby/core/string/dump_spec.rb b/spec/ruby/core/string/dump_spec.rb index cfe7bea6f0..e67367b5b0 100644 --- a/spec/ruby/core/string/dump_spec.rb +++ b/spec/ruby/core/string/dump_spec.rb @@ -13,10 +13,18 @@ describe "String#dump" do "foo\n".untrust.dump.untrusted?.should == true end + it "does not take into account if a string is frozen" do + "foo".freeze.dump.frozen?.should == false + end + it "returns a subclass instance" do StringSpecs::MyString.new.dump.should be_an_instance_of(StringSpecs::MyString) end + it "wraps string with \"" do + "foo".dump.should == '"foo"' + end + it "returns a string with special characters replaced with \\ notation" do [ ["\a", '"\\a"'], ["\b", '"\\b"'], @@ -35,10 +43,11 @@ describe "String#dump" do ].should be_computed_by(:dump) end - it "returns a string with \\# when # is followed by $, @, {" do - [ ["\#$", '"\\#$"'], - ["\#@", '"\\#@"'], - ["\#{", '"\\#{"'] + it "returns a string with \\# when # is followed by $, @, @@, {" do + [ ["\#$PATH", '"\\#$PATH"'], + ["\#@a", '"\\#@a"'], + ["\#@@a", '"\\#@@a"'], + ["\#{a}", '"\\#{a}"'] ].should be_computed_by(:dump) end @@ -381,7 +390,7 @@ describe "String#dump" do end ruby_version_is '2.4' do - it "returns a string with multi-byte UTF-8 characters replaced by \\u{} notation with lower-case hex digits" do + it "returns a string with multi-byte UTF-8 characters replaced by \\u{} notation with upper-case hex digits" do [ [0200.chr('utf-8'), '"\u0080"'], [0201.chr('utf-8'), '"\u0081"'], [0202.chr('utf-8'), '"\u0082"'], @@ -421,4 +430,10 @@ describe "String#dump" do "\u{876}".encode('utf-16be').dump.end_with?(".force_encoding(\"UTF-16BE\")").should be_true "\u{876}".encode('utf-16le').dump.end_with?(".force_encoding(\"UTF-16LE\")").should be_true end + + it "keeps origin encoding" do + "foo".encode("ISO-8859-1").dump.encoding.should == Encoding::ISO_8859_1 + "foo".encode('windows-1251').dump.encoding.should == Encoding::Windows_1251 + 1.chr.dump.encoding.should == Encoding::US_ASCII + end end diff --git a/spec/ruby/core/string/uminus_spec.rb b/spec/ruby/core/string/uminus_spec.rb index f5f77f0d2e..fd9e8c1d52 100644 --- a/spec/ruby/core/string/uminus_spec.rb +++ b/spec/ruby/core/string/uminus_spec.rb @@ -5,7 +5,7 @@ describe 'String#-@' do input = 'foo'.freeze output = -input - output.equal?(input).should == true + output.should equal(input) output.frozen?.should == true end @@ -14,6 +14,7 @@ describe 'String#-@' do output = -input output.frozen?.should == true + output.should_not equal(input) output.should == 'foo' end @@ -30,11 +31,25 @@ describe 'String#-@' do (-"unfrozen string").should equal(-"unfrozen string") (-"unfrozen string").should_not equal(-"another unfrozen string") end + end + ruby_version_is "2.5"..."2.6" do + it "does not deduplicate already frozen strings" do + dynamic = %w(this string is frozen).join(' ').freeze + + dynamic.should_not equal("this string is frozen".freeze) + + (-dynamic).should_not equal("this string is frozen".freeze) + (-dynamic).should_not equal(-"this string is frozen".freeze) + end + end + + ruby_version_is "2.6" do it "deduplicates frozen strings" do dynamic = %w(this string is frozen).join(' ').freeze dynamic.should_not equal("this string is frozen".freeze) + (-dynamic).should equal("this string is frozen".freeze) (-dynamic).should equal(-"this string is frozen".freeze) end diff --git a/spec/ruby/core/string/undump_spec.rb b/spec/ruby/core/string/undump_spec.rb new file mode 100644 index 0000000000..ec13308c16 --- /dev/null +++ b/spec/ruby/core/string/undump_spec.rb @@ -0,0 +1,451 @@ +# encoding: utf-8 +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is '2.5' do + describe "String#undump" do + it "taints the result if self is tainted" do + '"foo"'.taint.undump.tainted?.should == true + end + + it "untrusts the result if self is untrusted" do + '"foo"'.untrust.undump.untrusted?.should == true + end + + it "does not take into account if a string is frozen" do + '"foo"'.freeze.undump.frozen?.should == false + end + + it "always returns String instance" do + StringSpecs::MyString.new('"foo"').undump.should be_an_instance_of(String) + end + + it "strips outer \"" do + '"foo"'.undump.should == 'foo' + end + + it "returns a string with special characters in \\ notation replaced with the characters" do + [ ['"\\a"', "\a"], + ['"\\b"', "\b"], + ['"\\t"', "\t"], + ['"\\n"', "\n"], + ['"\\v"', "\v"], + ['"\\f"', "\f"], + ['"\\r"', "\r"], + ['"\\e"', "\e"] + ].should be_computed_by(:undump) + end + + it "returns a string with unescaped sequencies \" and \\" do + [ ['"\\""' , "\""], + ['"\\\\"', "\\"] + ].should be_computed_by(:undump) + end + + it "returns a string with unescaped sequences \\# when # is followed by $, @, {" do + [ ['"\\#$PATH"', "\#$PATH"], + ['"\\#@a"', "\#@a"], + ['"\\#@@a"', "\#@@a"], + ['"\\#{a}"', "\#{a}"] + ].should be_computed_by(:undump) + end + + it "returns a string with # not escaped when followed by any other character" do + [ ['"#"', '#'], + ['"#1"', '#1'] + ].should be_computed_by(:undump) + end + + it "returns a string with printable non-alphanumeric characters" do + [ ['" "', ' '], + ['"!"', '!'], + ['"$"', '$'], + ['"%"', '%'], + ['"&"', '&'], + ['"\'"', '\''], + ['"("', '('], + ['")"', ')'], + ['"*"', '*'], + ['"+"', '+'], + ['","', ','], + ['"-"', '-'], + ['"."', '.'], + ['"/"', '/'], + ['":"', ':'], + ['";"', ';'], + ['"<"', '<'], + ['"="', '='], + ['">"', '>'], + ['"?"', '?'], + ['"@"', '@'], + ['"["', '['], + ['"]"', ']'], + ['"^"', '^'], + ['"_"', '_'], + ['"`"', '`'], + ['"{"', '{'], + ['"|"', '|'], + ['"}"', '}'], + ['"~"', '~'] + ].should be_computed_by(:undump) + end + + it "returns a string with numeric characters unescaped" do + [ ['"0"', "0"], + ['"1"', "1"], + ['"2"', "2"], + ['"3"', "3"], + ['"4"', "4"], + ['"5"', "5"], + ['"6"', "6"], + ['"7"', "7"], + ['"8"', "8"], + ['"9"', "9"], + ].should be_computed_by(:undump) + end + + it "returns a string with upper-case alpha characters unescaped" do + [ ['"A"', 'A'], + ['"B"', 'B'], + ['"C"', 'C'], + ['"D"', 'D'], + ['"E"', 'E'], + ['"F"', 'F'], + ['"G"', 'G'], + ['"H"', 'H'], + ['"I"', 'I'], + ['"J"', 'J'], + ['"K"', 'K'], + ['"L"', 'L'], + ['"M"', 'M'], + ['"N"', 'N'], + ['"O"', 'O'], + ['"P"', 'P'], + ['"Q"', 'Q'], + ['"R"', 'R'], + ['"S"', 'S'], + ['"T"', 'T'], + ['"U"', 'U'], + ['"V"', 'V'], + ['"W"', 'W'], + ['"X"', 'X'], + ['"Y"', 'Y'], + ['"Z"', 'Z'] + ].should be_computed_by(:undump) + end + + it "returns a string with lower-case alpha characters unescaped" do + [ ['"a"', 'a'], + ['"b"', 'b'], + ['"c"', 'c'], + ['"d"', 'd'], + ['"e"', 'e'], + ['"f"', 'f'], + ['"g"', 'g'], + ['"h"', 'h'], + ['"i"', 'i'], + ['"j"', 'j'], + ['"k"', 'k'], + ['"l"', 'l'], + ['"m"', 'm'], + ['"n"', 'n'], + ['"o"', 'o'], + ['"p"', 'p'], + ['"q"', 'q'], + ['"r"', 'r'], + ['"s"', 's'], + ['"t"', 't'], + ['"u"', 'u'], + ['"v"', 'v'], + ['"w"', 'w'], + ['"x"', 'x'], + ['"y"', 'y'], + ['"z"', 'z'] + ].should be_computed_by(:undump) + end + + it "returns a string with \\x notation replaced with non-printing ASCII character" do + [ ['"\\x00"', 0000.chr.force_encoding('utf-8')], + ['"\\x01"', 0001.chr.force_encoding('utf-8')], + ['"\\x02"', 0002.chr.force_encoding('utf-8')], + ['"\\x03"', 0003.chr.force_encoding('utf-8')], + ['"\\x04"', 0004.chr.force_encoding('utf-8')], + ['"\\x05"', 0005.chr.force_encoding('utf-8')], + ['"\\x06"', 0006.chr.force_encoding('utf-8')], + ['"\\x0E"', 0016.chr.force_encoding('utf-8')], + ['"\\x0F"', 0017.chr.force_encoding('utf-8')], + ['"\\x10"', 0020.chr.force_encoding('utf-8')], + ['"\\x11"', 0021.chr.force_encoding('utf-8')], + ['"\\x12"', 0022.chr.force_encoding('utf-8')], + ['"\\x13"', 0023.chr.force_encoding('utf-8')], + ['"\\x14"', 0024.chr.force_encoding('utf-8')], + ['"\\x15"', 0025.chr.force_encoding('utf-8')], + ['"\\x16"', 0026.chr.force_encoding('utf-8')], + ['"\\x17"', 0027.chr.force_encoding('utf-8')], + ['"\\x18"', 0030.chr.force_encoding('utf-8')], + ['"\\x19"', 0031.chr.force_encoding('utf-8')], + ['"\\x1A"', 0032.chr.force_encoding('utf-8')], + ['"\\x1C"', 0034.chr.force_encoding('utf-8')], + ['"\\x1D"', 0035.chr.force_encoding('utf-8')], + ['"\\x1E"', 0036.chr.force_encoding('utf-8')], + ['"\\x1F"', 0037.chr.force_encoding('utf-8')], + ['"\\x7F"', 0177.chr.force_encoding('utf-8')], + ['"\\x80"', 0200.chr.force_encoding('utf-8')], + ['"\\x81"', 0201.chr.force_encoding('utf-8')], + ['"\\x82"', 0202.chr.force_encoding('utf-8')], + ['"\\x83"', 0203.chr.force_encoding('utf-8')], + ['"\\x84"', 0204.chr.force_encoding('utf-8')], + ['"\\x85"', 0205.chr.force_encoding('utf-8')], + ['"\\x86"', 0206.chr.force_encoding('utf-8')], + ['"\\x87"', 0207.chr.force_encoding('utf-8')], + ['"\\x88"', 0210.chr.force_encoding('utf-8')], + ['"\\x89"', 0211.chr.force_encoding('utf-8')], + ['"\\x8A"', 0212.chr.force_encoding('utf-8')], + ['"\\x8B"', 0213.chr.force_encoding('utf-8')], + ['"\\x8C"', 0214.chr.force_encoding('utf-8')], + ['"\\x8D"', 0215.chr.force_encoding('utf-8')], + ['"\\x8E"', 0216.chr.force_encoding('utf-8')], + ['"\\x8F"', 0217.chr.force_encoding('utf-8')], + ['"\\x90"', 0220.chr.force_encoding('utf-8')], + ['"\\x91"', 0221.chr.force_encoding('utf-8')], + ['"\\x92"', 0222.chr.force_encoding('utf-8')], + ['"\\x93"', 0223.chr.force_encoding('utf-8')], + ['"\\x94"', 0224.chr.force_encoding('utf-8')], + ['"\\x95"', 0225.chr.force_encoding('utf-8')], + ['"\\x96"', 0226.chr.force_encoding('utf-8')], + ['"\\x97"', 0227.chr.force_encoding('utf-8')], + ['"\\x98"', 0230.chr.force_encoding('utf-8')], + ['"\\x99"', 0231.chr.force_encoding('utf-8')], + ['"\\x9A"', 0232.chr.force_encoding('utf-8')], + ['"\\x9B"', 0233.chr.force_encoding('utf-8')], + ['"\\x9C"', 0234.chr.force_encoding('utf-8')], + ['"\\x9D"', 0235.chr.force_encoding('utf-8')], + ['"\\x9E"', 0236.chr.force_encoding('utf-8')], + ['"\\x9F"', 0237.chr.force_encoding('utf-8')], + ['"\\xA0"', 0240.chr.force_encoding('utf-8')], + ['"\\xA1"', 0241.chr.force_encoding('utf-8')], + ['"\\xA2"', 0242.chr.force_encoding('utf-8')], + ['"\\xA3"', 0243.chr.force_encoding('utf-8')], + ['"\\xA4"', 0244.chr.force_encoding('utf-8')], + ['"\\xA5"', 0245.chr.force_encoding('utf-8')], + ['"\\xA6"', 0246.chr.force_encoding('utf-8')], + ['"\\xA7"', 0247.chr.force_encoding('utf-8')], + ['"\\xA8"', 0250.chr.force_encoding('utf-8')], + ['"\\xA9"', 0251.chr.force_encoding('utf-8')], + ['"\\xAA"', 0252.chr.force_encoding('utf-8')], + ['"\\xAB"', 0253.chr.force_encoding('utf-8')], + ['"\\xAC"', 0254.chr.force_encoding('utf-8')], + ['"\\xAD"', 0255.chr.force_encoding('utf-8')], + ['"\\xAE"', 0256.chr.force_encoding('utf-8')], + ['"\\xAF"', 0257.chr.force_encoding('utf-8')], + ['"\\xB0"', 0260.chr.force_encoding('utf-8')], + ['"\\xB1"', 0261.chr.force_encoding('utf-8')], + ['"\\xB2"', 0262.chr.force_encoding('utf-8')], + ['"\\xB3"', 0263.chr.force_encoding('utf-8')], + ['"\\xB4"', 0264.chr.force_encoding('utf-8')], + ['"\\xB5"', 0265.chr.force_encoding('utf-8')], + ['"\\xB6"', 0266.chr.force_encoding('utf-8')], + ['"\\xB7"', 0267.chr.force_encoding('utf-8')], + ['"\\xB8"', 0270.chr.force_encoding('utf-8')], + ['"\\xB9"', 0271.chr.force_encoding('utf-8')], + ['"\\xBA"', 0272.chr.force_encoding('utf-8')], + ['"\\xBB"', 0273.chr.force_encoding('utf-8')], + ['"\\xBC"', 0274.chr.force_encoding('utf-8')], + ['"\\xBD"', 0275.chr.force_encoding('utf-8')], + ['"\\xBE"', 0276.chr.force_encoding('utf-8')], + ['"\\xBF"', 0277.chr.force_encoding('utf-8')], + ['"\\xC0"', 0300.chr.force_encoding('utf-8')], + ['"\\xC1"', 0301.chr.force_encoding('utf-8')], + ['"\\xC2"', 0302.chr.force_encoding('utf-8')], + ['"\\xC3"', 0303.chr.force_encoding('utf-8')], + ['"\\xC4"', 0304.chr.force_encoding('utf-8')], + ['"\\xC5"', 0305.chr.force_encoding('utf-8')], + ['"\\xC6"', 0306.chr.force_encoding('utf-8')], + ['"\\xC7"', 0307.chr.force_encoding('utf-8')], + ['"\\xC8"', 0310.chr.force_encoding('utf-8')], + ['"\\xC9"', 0311.chr.force_encoding('utf-8')], + ['"\\xCA"', 0312.chr.force_encoding('utf-8')], + ['"\\xCB"', 0313.chr.force_encoding('utf-8')], + ['"\\xCC"', 0314.chr.force_encoding('utf-8')], + ['"\\xCD"', 0315.chr.force_encoding('utf-8')], + ['"\\xCE"', 0316.chr.force_encoding('utf-8')], + ['"\\xCF"', 0317.chr.force_encoding('utf-8')], + ['"\\xD0"', 0320.chr.force_encoding('utf-8')], + ['"\\xD1"', 0321.chr.force_encoding('utf-8')], + ['"\\xD2"', 0322.chr.force_encoding('utf-8')], + ['"\\xD3"', 0323.chr.force_encoding('utf-8')], + ['"\\xD4"', 0324.chr.force_encoding('utf-8')], + ['"\\xD5"', 0325.chr.force_encoding('utf-8')], + ['"\\xD6"', 0326.chr.force_encoding('utf-8')], + ['"\\xD7"', 0327.chr.force_encoding('utf-8')], + ['"\\xD8"', 0330.chr.force_encoding('utf-8')], + ['"\\xD9"', 0331.chr.force_encoding('utf-8')], + ['"\\xDA"', 0332.chr.force_encoding('utf-8')], + ['"\\xDB"', 0333.chr.force_encoding('utf-8')], + ['"\\xDC"', 0334.chr.force_encoding('utf-8')], + ['"\\xDD"', 0335.chr.force_encoding('utf-8')], + ['"\\xDE"', 0336.chr.force_encoding('utf-8')], + ['"\\xDF"', 0337.chr.force_encoding('utf-8')], + ['"\\xE0"', 0340.chr.force_encoding('utf-8')], + ['"\\xE1"', 0341.chr.force_encoding('utf-8')], + ['"\\xE2"', 0342.chr.force_encoding('utf-8')], + ['"\\xE3"', 0343.chr.force_encoding('utf-8')], + ['"\\xE4"', 0344.chr.force_encoding('utf-8')], + ['"\\xE5"', 0345.chr.force_encoding('utf-8')], + ['"\\xE6"', 0346.chr.force_encoding('utf-8')], + ['"\\xE7"', 0347.chr.force_encoding('utf-8')], + ['"\\xE8"', 0350.chr.force_encoding('utf-8')], + ['"\\xE9"', 0351.chr.force_encoding('utf-8')], + ['"\\xEA"', 0352.chr.force_encoding('utf-8')], + ['"\\xEB"', 0353.chr.force_encoding('utf-8')], + ['"\\xEC"', 0354.chr.force_encoding('utf-8')], + ['"\\xED"', 0355.chr.force_encoding('utf-8')], + ['"\\xEE"', 0356.chr.force_encoding('utf-8')], + ['"\\xEF"', 0357.chr.force_encoding('utf-8')], + ['"\\xF0"', 0360.chr.force_encoding('utf-8')], + ['"\\xF1"', 0361.chr.force_encoding('utf-8')], + ['"\\xF2"', 0362.chr.force_encoding('utf-8')], + ['"\\xF3"', 0363.chr.force_encoding('utf-8')], + ['"\\xF4"', 0364.chr.force_encoding('utf-8')], + ['"\\xF5"', 0365.chr.force_encoding('utf-8')], + ['"\\xF6"', 0366.chr.force_encoding('utf-8')], + ['"\\xF7"', 0367.chr.force_encoding('utf-8')], + ['"\\xF8"', 0370.chr.force_encoding('utf-8')], + ['"\\xF9"', 0371.chr.force_encoding('utf-8')], + ['"\\xFA"', 0372.chr.force_encoding('utf-8')], + ['"\\xFB"', 0373.chr.force_encoding('utf-8')], + ['"\\xFC"', 0374.chr.force_encoding('utf-8')], + ['"\\xFD"', 0375.chr.force_encoding('utf-8')], + ['"\\xFE"', 0376.chr.force_encoding('utf-8')], + ['"\\xFF"', 0377.chr.force_encoding('utf-8')] + ].should be_computed_by(:undump) + end + + it "returns a string with \\u{} notation replaced with multi-byte UTF-8 characters" do + [ ['"\u{80}"', 0200.chr('utf-8')], + ['"\u{81}"', 0201.chr('utf-8')], + ['"\u{82}"', 0202.chr('utf-8')], + ['"\u{83}"', 0203.chr('utf-8')], + ['"\u{84}"', 0204.chr('utf-8')], + ['"\u{86}"', 0206.chr('utf-8')], + ['"\u{87}"', 0207.chr('utf-8')], + ['"\u{88}"', 0210.chr('utf-8')], + ['"\u{89}"', 0211.chr('utf-8')], + ['"\u{8a}"', 0212.chr('utf-8')], + ['"\u{8b}"', 0213.chr('utf-8')], + ['"\u{8c}"', 0214.chr('utf-8')], + ['"\u{8d}"', 0215.chr('utf-8')], + ['"\u{8e}"', 0216.chr('utf-8')], + ['"\u{8f}"', 0217.chr('utf-8')], + ['"\u{90}"', 0220.chr('utf-8')], + ['"\u{91}"', 0221.chr('utf-8')], + ['"\u{92}"', 0222.chr('utf-8')], + ['"\u{93}"', 0223.chr('utf-8')], + ['"\u{94}"', 0224.chr('utf-8')], + ['"\u{95}"', 0225.chr('utf-8')], + ['"\u{96}"', 0226.chr('utf-8')], + ['"\u{97}"', 0227.chr('utf-8')], + ['"\u{98}"', 0230.chr('utf-8')], + ['"\u{99}"', 0231.chr('utf-8')], + ['"\u{9a}"', 0232.chr('utf-8')], + ['"\u{9b}"', 0233.chr('utf-8')], + ['"\u{9c}"', 0234.chr('utf-8')], + ['"\u{9d}"', 0235.chr('utf-8')], + ['"\u{9e}"', 0236.chr('utf-8')], + ['"\u{9f}"', 0237.chr('utf-8')], + ].should be_computed_by(:undump) + end + + it "returns a string with \\uXXXX notation replaced with multi-byte UTF-8 characters" do + [ ['"\u0080"', 0200.chr('utf-8')], + ['"\u0081"', 0201.chr('utf-8')], + ['"\u0082"', 0202.chr('utf-8')], + ['"\u0083"', 0203.chr('utf-8')], + ['"\u0084"', 0204.chr('utf-8')], + ['"\u0086"', 0206.chr('utf-8')], + ['"\u0087"', 0207.chr('utf-8')], + ['"\u0088"', 0210.chr('utf-8')], + ['"\u0089"', 0211.chr('utf-8')], + ['"\u008a"', 0212.chr('utf-8')], + ['"\u008b"', 0213.chr('utf-8')], + ['"\u008c"', 0214.chr('utf-8')], + ['"\u008d"', 0215.chr('utf-8')], + ['"\u008e"', 0216.chr('utf-8')], + ['"\u008f"', 0217.chr('utf-8')], + ['"\u0090"', 0220.chr('utf-8')], + ['"\u0091"', 0221.chr('utf-8')], + ['"\u0092"', 0222.chr('utf-8')], + ['"\u0093"', 0223.chr('utf-8')], + ['"\u0094"', 0224.chr('utf-8')], + ['"\u0095"', 0225.chr('utf-8')], + ['"\u0096"', 0226.chr('utf-8')], + ['"\u0097"', 0227.chr('utf-8')], + ['"\u0098"', 0230.chr('utf-8')], + ['"\u0099"', 0231.chr('utf-8')], + ['"\u009a"', 0232.chr('utf-8')], + ['"\u009b"', 0233.chr('utf-8')], + ['"\u009c"', 0234.chr('utf-8')], + ['"\u009d"', 0235.chr('utf-8')], + ['"\u009e"', 0236.chr('utf-8')], + ['"\u009f"', 0237.chr('utf-8')], + ].should be_computed_by(:undump) + end + + it "undumps correctly string produced from non ASCII-compatible one" do + s = "\u{876}".encode('utf-16be') + s.dump.undump.should == s + + '"\\bv".force_encoding("UTF-16BE")'.undump.should == "\u0876".encode('utf-16be') + end + + it "keeps origin encoding" do + '"foo"'.encode("ISO-8859-1").undump.encoding.should == Encoding::ISO_8859_1 + '"foo"'.encode('windows-1251').undump.encoding.should == Encoding::Windows_1251 + end + + describe "Limitations" do + it "cannot undump non ASCII-compatible string" do + -> { '"foo"'.encode('utf-16le').undump }.should raise_error(Encoding::CompatibilityError) + end + end + + describe "invalid dump" do + it "raises RuntimeError exception if wrapping \" are missing" do + -> { 'foo'.undump }.should raise_error(RuntimeError, /invalid dumped string/) + -> { '"foo'.undump }.should raise_error(RuntimeError, /unterminated dumped string/) + -> { 'foo"'.undump }.should raise_error(RuntimeError, /invalid dumped string/) + -> { "'foo'".undump }.should raise_error(RuntimeError, /invalid dumped string/) + end + + it "raises RuntimeError if there is incorrect \\x sequence" do + -> { '"\x"'.undump }.should raise_error(RuntimeError, /invalid hex escape/) + -> { '"\\x3y"'.undump }.should raise_error(RuntimeError, /invalid hex escape/) + end + + it "raises RuntimeError in there is incorrect \\u sequence" do + -> { '"\\u"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/) + -> { '"\\u{"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/) + -> { '"\\u{3042"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/) + -> { '"\\u"'.undump }.should raise_error(RuntimeError, /invalid Unicode escape/) + end + + it "raises RuntimeError if there is malformed dump of non ASCII-compatible string" do + -> { '"".force_encoding("ASCII-8BIT"'.undump }.should raise_error(RuntimeError, /invalid dumped string/) + -> { '"".force_encoding("Unknown")'.undump }.should raise_error(RuntimeError, /dumped string has unknown encoding name/) + -> { '"".force_encoding()'.undump }.should raise_error(RuntimeError, /invalid dumped string/) + end + + it "raises RuntimeError if string contains \0 character" do + -> { "\"foo\0\"".undump }.should raise_error(RuntimeError, /string contains null byte/) + end + + it "raises RuntimeError if string contains non ASCII character" do + -> { "\"\u3042\"".undump }.should raise_error(RuntimeError, /non-ASCII character detected/) + end + + it "raises RuntimeError if there are some excessive \"" do + -> { '" "" "'.undump }.should raise_error(RuntimeError, /invalid dumped string/) + end + end + end +end diff --git a/spec/ruby/core/thread/backtrace/location/base_label_spec.rb b/spec/ruby/core/thread/backtrace/location/base_label_spec.rb index d7302c26be..139a68e2c8 100644 --- a/spec/ruby/core/thread/backtrace/location/base_label_spec.rb +++ b/spec/ruby/core/thread/backtrace/location/base_label_spec.rb @@ -9,4 +9,14 @@ describe 'Thread::Backtrace::Location#base_label' do it 'returns the base label of the call frame' do @frame.base_label.should == '' end + + describe 'when call frame is inside a block' do + before :each do + @frame = ThreadBacktraceLocationSpecs.block_location[0] + end + + it 'returns the name of the method that contains the block' do + @frame.base_label.should == 'block_location' + end + end end diff --git a/spec/ruby/core/tracepoint/parameters_spec.rb b/spec/ruby/core/tracepoint/parameters_spec.rb index 4728b0a448..550b9572c0 100644 --- a/spec/ruby/core/tracepoint/parameters_spec.rb +++ b/spec/ruby/core/tracepoint/parameters_spec.rb @@ -1,21 +1,23 @@ require_relative '../../spec_helper' -describe 'TracePoint#parameters' do - it 'returns the parameters of block' do - f = proc {|x, y, z| } - parameters = nil - TracePoint.new(:b_call) {|tp| parameters = tp.parameters }.enable do - f.call - parameters.should == [[:opt, :x], [:opt, :y], [:opt, :z]] +ruby_version_is "2.6" do + describe 'TracePoint#parameters' do + it 'returns the parameters of block' do + f = proc {|x, y, z| } + parameters = nil + TracePoint.new(:b_call) {|tp| parameters = tp.parameters }.enable do + f.call + parameters.should == [[:opt, :x], [:opt, :y], [:opt, :z]] + end end - end - it 'returns the parameters of lambda block' do - f = lambda {|x, y, z| } - parameters = nil - TracePoint.new(:b_call) {|tp| parameters = tp.parameters }.enable do - f.call(1, 2, 3) - parameters.should == [[:req, :x], [:req, :y], [:req, :z]] + it 'returns the parameters of lambda block' do + f = lambda {|x, y, z| } + parameters = nil + TracePoint.new(:b_call) {|tp| parameters = tp.parameters }.enable do + f.call(1, 2, 3) + parameters.should == [[:req, :x], [:req, :y], [:req, :z]] + end end end end diff --git a/spec/ruby/language/super_spec.rb b/spec/ruby/language/super_spec.rb index a86fb1df33..c6071f21f0 100644 --- a/spec/ruby/language/super_spec.rb +++ b/spec/ruby/language/super_spec.rb @@ -196,13 +196,9 @@ describe "The super keyword" do Super::ZSuperWithRestReassigned::B.new.a("bar").should == ["foo"] end - # Don't run this spec on Appveyor because it uses old Ruby versions - # The specs ends with segfault on old versions so let's just disable it - platform_is_not :windows do - # https://bugs.ruby-lang.org/issues/14279 - it "wraps into array and passes along reassigned rest args with non-array scalar value" do - Super::ZSuperWithRestReassignedWithScalar::B.new.a("bar").should == ["foo"] - end + # https://bugs.ruby-lang.org/issues/14279 + it "wraps into array and passes along reassigned rest args with non-array scalar value" do + Super::ZSuperWithRestReassignedWithScalar::B.new.a("bar").should == ["foo"] end it "invokes methods from a chain of anonymous modules" do diff --git a/spec/ruby/security/cve_2011_4815_spec.rb b/spec/ruby/security/cve_2011_4815_spec.rb index 44543e6206..02ef10d562 100644 --- a/spec/ruby/security/cve_2011_4815_spec.rb +++ b/spec/ruby/security/cve_2011_4815_spec.rb @@ -22,15 +22,12 @@ describe "Float#hash" do it_behaves_like :resists_cve_2011_4815, '3.14' end -# https://bugs.ruby-lang.org/issues/14420 -guard_not -> { platform_is :windows and PlatformGuard.implementation?(:ruby) } do - describe "Rational#hash" do - it_behaves_like :resists_cve_2011_4815, 'Rational(1, 2)' - end +describe "Rational#hash" do + it_behaves_like :resists_cve_2011_4815, 'Rational(1, 2)' +end - describe "Complex#hash" do - it_behaves_like :resists_cve_2011_4815, 'Complex(1, 2)' - end +describe "Complex#hash" do + it_behaves_like :resists_cve_2011_4815, 'Complex(1, 2)' end describe "String#hash" do diff --git a/spec/ruby/security/cve_2017_17742_spec.rb b/spec/ruby/security/cve_2017_17742_spec.rb index f1205412c6..72776cb497 100644 --- a/spec/ruby/security/cve_2017_17742_spec.rb +++ b/spec/ruby/security/cve_2017_17742_spec.rb @@ -4,37 +4,31 @@ require "webrick" require "stringio" require "net/http" -guard -> { - ruby_version_is "2.3.7"..."2.4" or - ruby_version_is "2.4.4"..."2.5" or - ruby_version_is "2.5.1" -} do - describe "WEBrick" do - describe "resists CVE-2017-17742" do - it "for a response splitting headers" do - config = WEBrick::Config::HTTP - res = WEBrick::HTTPResponse.new config - res['X-header'] = "malicious\r\nCookie: hack" - io = StringIO.new - res.send_response io - io.rewind - res = Net::HTTPResponse.read_new(Net::BufferedIO.new(io)) - res.code.should == '500' - io.string.should_not =~ /hack/ - end +describe "WEBrick" do + describe "resists CVE-2017-17742" do + it "for a response splitting headers" do + config = WEBrick::Config::HTTP + res = WEBrick::HTTPResponse.new config + res['X-header'] = "malicious\r\nCookie: hack" + io = StringIO.new + res.send_response io + io.rewind + res = Net::HTTPResponse.read_new(Net::BufferedIO.new(io)) + res.code.should == '500' + io.string.should_not =~ /hack/ + end - it "for a response splitting cookie headers" do - user_input = "malicious\r\nCookie: hack" - config = WEBrick::Config::HTTP - res = WEBrick::HTTPResponse.new config - res.cookies << WEBrick::Cookie.new('author', user_input) - io = StringIO.new - res.send_response io - io.rewind - res = Net::HTTPResponse.read_new(Net::BufferedIO.new(io)) - res.code.should == '500' - io.string.should_not =~ /hack/ - end + it "for a response splitting cookie headers" do + user_input = "malicious\r\nCookie: hack" + config = WEBrick::Config::HTTP + res = WEBrick::HTTPResponse.new config + res.cookies << WEBrick::Cookie.new('author', user_input) + io = StringIO.new + res.send_response io + io.rewind + res = Net::HTTPResponse.read_new(Net::BufferedIO.new(io)) + res.code.should == '500' + io.string.should_not =~ /hack/ end end end diff --git a/spec/ruby/security/cve_2018_6914_spec.rb b/spec/ruby/security/cve_2018_6914_spec.rb index 657341e474..1837ca0cef 100644 --- a/spec/ruby/security/cve_2018_6914_spec.rb +++ b/spec/ruby/security/cve_2018_6914_spec.rb @@ -2,58 +2,52 @@ require_relative '../spec_helper' require 'tempfile' -guard -> { - ruby_version_is "2.3.7"..."2.4" or - ruby_version_is "2.4.4"..."2.5" or - ruby_version_is "2.5.1" -} do - describe "CVE-2018-6914 is resisted by" do - before :all do - @traversal_path = Array.new(Dir.pwd.split('/').count, '..').join('/') + Dir.pwd + '/' - @traversal_path.delete!(':') if /mswin|mingw/ =~ RUBY_PLATFORM - end +describe "CVE-2018-6914 is resisted by" do + before :all do + @traversal_path = Array.new(Dir.pwd.split('/').count, '..').join('/') + Dir.pwd + '/' + @traversal_path.delete!(':') if /mswin|mingw/ =~ RUBY_PLATFORM + end - it "Tempfile.open by deleting separators" do - begin - expect = Dir.glob(@traversal_path + '*').count - t = Tempfile.open([@traversal_path, 'foo']) - actual = Dir.glob(@traversal_path + '*').count - actual.should == expect - ensure - t.close! - end - end - - it "Tempfile.new by deleting separators" do - begin - expect = Dir.glob(@traversal_path + '*').count - t = Tempfile.new(@traversal_path + 'foo') - actual = Dir.glob(@traversal_path + '*').count - actual.should == expect - ensure - t.close! - end - end - - it "Tempfile.create by deleting separators" do + it "Tempfile.open by deleting separators" do + begin expect = Dir.glob(@traversal_path + '*').count - Tempfile.create(@traversal_path + 'foo') - actual = Dir.glob(@traversal_path + '*').count - actual.should == expect - end - - it "Dir.mktmpdir by deleting separators" do - expect = Dir.glob(@traversal_path + '*').count - Dir.mktmpdir(@traversal_path + 'foo') - actual = Dir.glob(@traversal_path + '*').count - actual.should == expect - end - - it "Dir.mktmpdir with an array by deleting separators" do - expect = Dir.glob(@traversal_path + '*').count - Dir.mktmpdir([@traversal_path, 'foo']) + t = Tempfile.open([@traversal_path, 'foo']) actual = Dir.glob(@traversal_path + '*').count actual.should == expect + ensure + t.close! end end + + it "Tempfile.new by deleting separators" do + begin + expect = Dir.glob(@traversal_path + '*').count + t = Tempfile.new(@traversal_path + 'foo') + actual = Dir.glob(@traversal_path + '*').count + actual.should == expect + ensure + t.close! + end + end + + it "Tempfile.create by deleting separators" do + expect = Dir.glob(@traversal_path + '*').count + Tempfile.create(@traversal_path + 'foo') + actual = Dir.glob(@traversal_path + '*').count + actual.should == expect + end + + it "Dir.mktmpdir by deleting separators" do + expect = Dir.glob(@traversal_path + '*').count + Dir.mktmpdir(@traversal_path + 'foo') + actual = Dir.glob(@traversal_path + '*').count + actual.should == expect + end + + it "Dir.mktmpdir with an array by deleting separators" do + expect = Dir.glob(@traversal_path + '*').count + Dir.mktmpdir([@traversal_path, 'foo']) + actual = Dir.glob(@traversal_path + '*').count + actual.should == expect + end end diff --git a/spec/ruby/security/cve_2018_8780_spec.rb b/spec/ruby/security/cve_2018_8780_spec.rb index 44be29bf22..febb1de51d 100644 --- a/spec/ruby/security/cve_2018_8780_spec.rb +++ b/spec/ruby/security/cve_2018_8780_spec.rb @@ -1,53 +1,47 @@ require_relative '../spec_helper' -guard -> { - ruby_version_is "2.3.7"..."2.4" or - ruby_version_is "2.4.4"..."2.5" or - ruby_version_is "2.5.1" -} do - describe "CVE-2018-8780 is resisted by" do - before :all do - @root = File.realpath(tmp("")) - end +describe "CVE-2018-8780 is resisted by" do + before :all do + @root = File.realpath(tmp("")) + end - it "Dir.glob by raising an exception when there is a NUL byte" do + it "Dir.glob by raising an exception when there is a NUL byte" do + lambda { + Dir.glob([[@root, File.join(@root, "*")].join("\0")]) + }.should raise_error(ArgumentError, /(path name|string) contains null byte/) + end + + it "Dir.entries by raising an exception when there is a NUL byte" do + lambda { + Dir.entries(@root+"\0") + }.should raise_error(ArgumentError, /(path name|string) contains null byte/) + end + + it "Dir.foreach by raising an exception when there is a NUL byte" do + lambda { + Dir.foreach(@root+"\0").to_a + }.should raise_error(ArgumentError, /(path name|string) contains null byte/) + end + + ruby_version_is "2.4" do + it "Dir.empty? by raising an exception when there is a NUL byte" do lambda { - Dir.glob([[@root, File.join(@root, "*")].join("\0")]) + Dir.empty?(@root+"\0") + }.should raise_error(ArgumentError, /(path name|string) contains null byte/) + end + end + + ruby_version_is "2.5" do + it "Dir.children by raising an exception when there is a NUL byte" do + lambda { + Dir.children(@root+"\0") }.should raise_error(ArgumentError, /(path name|string) contains null byte/) end - it "Dir.entries by raising an exception when there is a NUL byte" do + it "Dir.each_child by raising an exception when there is a NUL byte" do lambda { - Dir.entries(@root+"\0") + Dir.each_child(@root+"\0").to_a }.should raise_error(ArgumentError, /(path name|string) contains null byte/) end - - it "Dir.foreach by raising an exception when there is a NUL byte" do - lambda { - Dir.foreach(@root+"\0").to_a - }.should raise_error(ArgumentError, /(path name|string) contains null byte/) - end - - ruby_version_is "2.5" do - it "Dir.children by raising an exception when there is a NUL byte" do - lambda { - Dir.children(@root+"\0") - }.should raise_error(ArgumentError, /(path name|string) contains null byte/) - end - - it "Dir.each_child by raising an exception when there is a NUL byte" do - lambda { - Dir.each_child(@root+"\0").to_a - }.should raise_error(ArgumentError, /(path name|string) contains null byte/) - end - end - - ruby_version_is "2.4" do - it "Dir.empty? by raising an exception when there is a NUL byte" do - lambda { - Dir.empty?(@root+"\0") - }.should raise_error(ArgumentError, /(path name|string) contains null byte/) - end - end end end