This commit is contained in:
Benoit Daloze 2021-06-02 14:34:07 +02:00
parent a4fbc7e288
commit 22e2a6a999
66 changed files with 943 additions and 167 deletions

View File

@ -30,7 +30,7 @@ ruby/spec is known to be tested in these implementations for every commit:
* [Opal](https://github.com/opal/opal/tree/master/spec) * [Opal](https://github.com/opal/opal/tree/master/spec)
ruby/spec describes the behavior of Ruby 2.5 and more recent Ruby versions. ruby/spec describes the behavior of Ruby 2.5 and more recent Ruby versions.
More precisely, every latest stable MRI release should [pass](https://travis-ci.org/ruby/spec) all specs of ruby/spec (2.5.x, 2.6.x, 2.7.x, etc), and those are tested in TravisCI. More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (2.5.x, 2.6.x, 2.7.x, etc), and those are tested in CI.
### Synchronization with Ruby Implementations ### Synchronization with Ruby Implementations

View File

@ -25,6 +25,12 @@ describe "The --encoding command line option" do
end end
it "does not accept a third encoding" do it "does not accept a third encoding" do
ruby_exe(@test_string, options: "--disable-gems --encoding big5:#{@enc2}:utf-32le", args: "2>&1").should =~ /extra argument for --encoding: utf-32le/ options = {
options: "--disable-gems --encoding big5:#{@enc2}:utf-32le",
args: "2>&1",
exit_status: 1
}
ruby_exe(@test_string, options).should =~ /extra argument for --encoding: utf-32le/
end end
end end

View File

@ -13,7 +13,7 @@ describe "The -r command line option" do
end end
it "requires the file before parsing the main script" do it "requires the file before parsing the main script" do
out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), options: "-r #{@test_file}", args: "2>&1") out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), options: "-r #{@test_file}", args: "2>&1", exit_status: 1)
$?.should_not.success? $?.should_not.success?
out.should include("REQUIRED") out.should include("REQUIRED")
out.should include("syntax error") out.should include("syntax error")

View File

@ -31,6 +31,7 @@ describe "ruby -E" do
it "raises a RuntimeError if used with -U" do it "raises a RuntimeError if used with -U" do
ruby_exe("p 1", ruby_exe("p 1",
options: '-Eascii:ascii -U', options: '-Eascii:ascii -U',
args: '2>&1').should =~ /RuntimeError/ args: '2>&1',
exit_status: 1).should =~ /RuntimeError/
end end
end end

View File

@ -21,7 +21,7 @@ describe 'The -S command line option' do
end end
it "runs launcher found in PATH and sets the exit status to 1 if it fails" do it "runs launcher found in PATH and sets the exit status to 1 if it fails" do
result = ruby_exe(nil, options: '-S dash_s_fail', env: { 'PATH' => @path }, args: '2>&1') result = ruby_exe(nil, options: '-S dash_s_fail', env: { 'PATH' => @path }, args: '2>&1', exit_status: 1)
result.should =~ /\bdie\b/ result.should =~ /\bdie\b/
$?.exitstatus.should == 1 $?.exitstatus.should == 1
end end

View File

@ -32,12 +32,14 @@ describe "ruby -U" do
it "raises a RuntimeError if used with -Eext:int" do it "raises a RuntimeError if used with -Eext:int" do
ruby_exe("p 1", ruby_exe("p 1",
options: '-U -Eascii:ascii', options: '-U -Eascii:ascii',
args: '2>&1').should =~ /RuntimeError/ args: '2>&1',
exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError if used with -E:int" do it "raises a RuntimeError if used with -E:int" do
ruby_exe("p 1", ruby_exe("p 1",
options: '-U -E:ascii', options: '-U -E:ascii',
args: '2>&1').should =~ /RuntimeError/ args: '2>&1',
exit_status: 1).should =~ /RuntimeError/
end end
end end

View File

@ -9,7 +9,7 @@ describe "The -x command line option" do
it "fails when /\#!.*ruby.*/-ish line in target file is not found" do it "fails when /\#!.*ruby.*/-ish line in target file is not found" do
bad_embedded_ruby = fixture __FILE__, "bin/bad_embedded_ruby.txt" bad_embedded_ruby = fixture __FILE__, "bin/bad_embedded_ruby.txt"
result = ruby_exe(bad_embedded_ruby, options: '-x', args: '2>&1') result = ruby_exe(bad_embedded_ruby, options: '-x', args: '2>&1', exit_status: 1)
result.should include "no Ruby script found in input" result.should include "no Ruby script found in input"
end end

View File

@ -2,10 +2,10 @@ require_relative '../spec_helper'
describe "The error message caused by an exception" do describe "The error message caused by an exception" do
it "is not printed to stdout" do it "is not printed to stdout" do
out = ruby_exe("this_does_not_exist", args: "2> #{File::NULL}") out = ruby_exe("this_does_not_exist", args: "2> #{File::NULL}", exit_status: 1)
out.chomp.should.empty? out.chomp.should.empty?
out = ruby_exe("end #syntax error", args: "2> #{File::NULL}") out = ruby_exe("end #syntax error", args: "2> #{File::NULL}", exit_status: 1)
out.chomp.should.empty? out.chomp.should.empty?
end end
end end

View File

@ -87,101 +87,101 @@ describe "Processing RUBYOPT" do
it "raises a RuntimeError for '-a'" do it "raises a RuntimeError for '-a'" do
ENV["RUBYOPT"] = '-a' ENV["RUBYOPT"] = '-a'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-p'" do it "raises a RuntimeError for '-p'" do
ENV["RUBYOPT"] = '-p' ENV["RUBYOPT"] = '-p'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-n'" do it "raises a RuntimeError for '-n'" do
ENV["RUBYOPT"] = '-n' ENV["RUBYOPT"] = '-n'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-y'" do it "raises a RuntimeError for '-y'" do
ENV["RUBYOPT"] = '-y' ENV["RUBYOPT"] = '-y'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-c'" do it "raises a RuntimeError for '-c'" do
ENV["RUBYOPT"] = '-c' ENV["RUBYOPT"] = '-c'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-s'" do it "raises a RuntimeError for '-s'" do
ENV["RUBYOPT"] = '-s' ENV["RUBYOPT"] = '-s'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-h'" do it "raises a RuntimeError for '-h'" do
ENV["RUBYOPT"] = '-h' ENV["RUBYOPT"] = '-h'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '--help'" do it "raises a RuntimeError for '--help'" do
ENV["RUBYOPT"] = '--help' ENV["RUBYOPT"] = '--help'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-l'" do it "raises a RuntimeError for '-l'" do
ENV["RUBYOPT"] = '-l' ENV["RUBYOPT"] = '-l'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-S'" do it "raises a RuntimeError for '-S'" do
ENV["RUBYOPT"] = '-S irb' ENV["RUBYOPT"] = '-S irb'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-e'" do it "raises a RuntimeError for '-e'" do
ENV["RUBYOPT"] = '-e0' ENV["RUBYOPT"] = '-e0'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-i'" do it "raises a RuntimeError for '-i'" do
ENV["RUBYOPT"] = '-i.bak' ENV["RUBYOPT"] = '-i.bak'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-x'" do it "raises a RuntimeError for '-x'" do
ENV["RUBYOPT"] = '-x' ENV["RUBYOPT"] = '-x'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-C'" do it "raises a RuntimeError for '-C'" do
ENV["RUBYOPT"] = '-C' ENV["RUBYOPT"] = '-C'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-X'" do it "raises a RuntimeError for '-X'" do
ENV["RUBYOPT"] = '-X.' ENV["RUBYOPT"] = '-X.'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-F'" do it "raises a RuntimeError for '-F'" do
ENV["RUBYOPT"] = '-F' ENV["RUBYOPT"] = '-F'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '-0'" do it "raises a RuntimeError for '-0'" do
ENV["RUBYOPT"] = '-0' ENV["RUBYOPT"] = '-0'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '--copyright'" do it "raises a RuntimeError for '--copyright'" do
ENV["RUBYOPT"] = '--copyright' ENV["RUBYOPT"] = '--copyright'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '--version'" do it "raises a RuntimeError for '--version'" do
ENV["RUBYOPT"] = '--version' ENV["RUBYOPT"] = '--version'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
it "raises a RuntimeError for '--yydebug'" do it "raises a RuntimeError for '--yydebug'" do
ENV["RUBYOPT"] = '--yydebug' ENV["RUBYOPT"] = '--yydebug'
ruby_exe("", args: '2>&1').should =~ /RuntimeError/ ruby_exe("", args: '2>&1', exit_status: 1).should =~ /RuntimeError/
end end
end end

View File

@ -2,12 +2,12 @@ require_relative '../spec_helper'
describe "The interpreter" do describe "The interpreter" do
it "prints an error when given a file with invalid syntax" do it "prints an error when given a file with invalid syntax" do
out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), args: "2>&1") out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), args: "2>&1", exit_status: 1)
out.should include "syntax error" out.should include "syntax error"
end end
it "prints an error when given code via -e with invalid syntax" do it "prints an error when given code via -e with invalid syntax" do
out = ruby_exe(nil, args: "-e 'a{' 2>&1") out = ruby_exe(nil, args: "-e 'a{' 2>&1", exit_status: 1)
out.should include "syntax error" out.should include "syntax error"
end end
end end

View File

@ -36,6 +36,7 @@ describe "Array#[]=" do
a[3, 2] = ['a', 'b', 'c', 'd'] a[3, 2] = ['a', 'b', 'c', 'd']
a.should == [2, 2, 3, "a", "b", "c", "d", 6] a.should == [2, 2, 3, "a", "b", "c", "d", 6]
end end
it "replaces the section defined by [start,length] with the given values" do it "replaces the section defined by [start,length] with the given values" do
a = [1, 2, 3, 4, 5, 6] a = [1, 2, 3, 4, 5, 6]
a[3, 2] = 'a', 'b', 'c', 'd' a[3, 2] = 'a', 'b', 'c', 'd'
@ -169,6 +170,7 @@ describe "Array#[]=" do
ary[1...1] = [] ary[1...1] = []
ary.should == [1, 2, 3] ary.should == [1, 2, 3]
end end
it "does nothing if the section defined by range has negative width and the rhs is an empty array" do it "does nothing if the section defined by range has negative width and the rhs is an empty array" do
ary = [1, 2, 3, 4, 5] ary = [1, 2, 3, 4, 5]
ary[1...0] = [] ary[1...0] = []
@ -284,6 +286,12 @@ describe "Array#[]= with [index, count]" do
(a[2, 3] = [4, 5]).should == [4, 5] (a[2, 3] = [4, 5]).should == [4, 5]
end end
it "accepts a frozen String literal as RHS" do
a = ['a', 'b', 'c']
a[0, 2] = 'd'.freeze
a.should == ['d', 'c']
end
it "just sets the section defined by [start,length] to nil even if the rhs is nil" do it "just sets the section defined by [start,length] to nil even if the rhs is nil" do
a = ['a', 'b', 'c', 'd', 'e'] a = ['a', 'b', 'c', 'd', 'e']
a[1, 3] = nil a[1, 3] = nil

View File

@ -15,6 +15,8 @@ describe "Encoding#replicate" do
name = @prefix + '-ASCII' name = @prefix + '-ASCII'
e = Encoding::ASCII.replicate(name) e = Encoding::ASCII.replicate(name)
e.name.should == name e.name.should == name
Encoding.find(name).should == e
"a".force_encoding(e).valid_encoding?.should be_true "a".force_encoding(e).valid_encoding?.should be_true
"\x80".force_encoding(e).valid_encoding?.should be_false "\x80".force_encoding(e).valid_encoding?.should be_false
end end
@ -23,6 +25,8 @@ describe "Encoding#replicate" do
name = @prefix + 'UTF-8' name = @prefix + 'UTF-8'
e = Encoding::UTF_8.replicate(name) e = Encoding::UTF_8.replicate(name)
e.name.should == name e.name.should == name
Encoding.find(name).should == e
"a".force_encoding(e).valid_encoding?.should be_true "a".force_encoding(e).valid_encoding?.should be_true
"\u3042".force_encoding(e).valid_encoding?.should be_true "\u3042".force_encoding(e).valid_encoding?.should be_true
"\x80".force_encoding(e).valid_encoding?.should be_false "\x80".force_encoding(e).valid_encoding?.should be_false
@ -32,6 +36,8 @@ describe "Encoding#replicate" do
name = @prefix + 'UTF-16-BE' name = @prefix + 'UTF-16-BE'
e = Encoding::UTF_16BE.replicate(name) e = Encoding::UTF_16BE.replicate(name)
e.name.should == name e.name.should == name
Encoding.find(name).should == e
"a".force_encoding(e).valid_encoding?.should be_false "a".force_encoding(e).valid_encoding?.should be_false
"\x30\x42".force_encoding(e).valid_encoding?.should be_true "\x30\x42".force_encoding(e).valid_encoding?.should be_true
"\x80".force_encoding(e).valid_encoding?.should be_false "\x80".force_encoding(e).valid_encoding?.should be_false
@ -40,7 +46,22 @@ describe "Encoding#replicate" do
it "returns a replica of ISO-2022-JP" do it "returns a replica of ISO-2022-JP" do
name = @prefix + 'ISO-2022-JP' name = @prefix + 'ISO-2022-JP'
e = Encoding::ISO_2022_JP.replicate(name) e = Encoding::ISO_2022_JP.replicate(name)
Encoding.find(name).should == e
e.name.should == name e.name.should == name
e.dummy?.should be_true e.dummy?.should be_true
end end
# NOTE: it's unclear of the value of this (for the complexity cost of it),
# but it is the current CRuby behavior.
it "can be associated with a String" do
name = @prefix + '-US-ASCII'
e = Encoding::US_ASCII.replicate(name)
e.name.should == name
Encoding.find(name).should == e
s = "abc".force_encoding(e)
s.encoding.should == e
s.encoding.name.should == name
end
end end

View File

@ -0,0 +1,16 @@
# -*- encoding: us-ascii -*-
require_relative '../../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "2.7" do
describe "Enumerator::Lazy#filter_map" do
it "maps only truthy results" do
(1..Float::INFINITY).lazy.filter_map { |i| i if i.odd? }.first(4).should == [1, 3, 5, 7]
end
it "does not map false results" do
(1..Float::INFINITY).lazy.filter_map { |i| i.odd? ? i : false }.first(4).should == [1, 3, 5, 7]
end
end
end

View File

@ -95,7 +95,7 @@ describe "SignalException" do
platform_is_not :windows do platform_is_not :windows do
it "runs after at_exit" do it "runs after at_exit" do
output = ruby_exe(<<-RUBY) output = ruby_exe(<<-RUBY, exit_status: nil)
at_exit do at_exit do
puts "hello" puts "hello"
$stdout.flush $stdout.flush
@ -109,7 +109,7 @@ describe "SignalException" do
end end
it "cannot be trapped with Signal.trap" do it "cannot be trapped with Signal.trap" do
ruby_exe(<<-RUBY) ruby_exe(<<-RUBY, exit_status: nil)
Signal.trap("PROF") {} Signal.trap("PROF") {}
raise(SignalException, "PROF") raise(SignalException, "PROF")
RUBY RUBY
@ -118,7 +118,7 @@ describe "SignalException" do
end end
it "self-signals for USR1" do it "self-signals for USR1" do
ruby_exe("raise(SignalException, 'USR1')") ruby_exe("raise(SignalException, 'USR1')", exit_status: nil)
$?.termsig.should == Signal.list.fetch('USR1') $?.termsig.should == Signal.list.fetch('USR1')
end end
end end

View File

@ -3,14 +3,14 @@ require_relative '../../spec_helper'
describe "SystemExit" do describe "SystemExit" do
it "sets the exit status and exits silently when raised" do it "sets the exit status and exits silently when raised" do
code = 'raise SystemExit.new(7)' code = 'raise SystemExit.new(7)'
result = ruby_exe(code, args: "2>&1") result = ruby_exe(code, args: "2>&1", exit_status: 7)
result.should == "" result.should == ""
$?.exitstatus.should == 7 $?.exitstatus.should == 7
end end
it "sets the exit status and exits silently when raised when subclassed" do it "sets the exit status and exits silently when raised when subclassed" do
code = 'class CustomExit < SystemExit; end; raise CustomExit.new(8)' code = 'class CustomExit < SystemExit; end; raise CustomExit.new(8)'
result = ruby_exe(code, args: "2>&1") result = ruby_exe(code, args: "2>&1", exit_status: 8)
result.should == "" result.should == ""
$?.exitstatus.should == 8 $?.exitstatus.should == 8
end end

View File

@ -2,7 +2,7 @@ require_relative '../../spec_helper'
describe "An Exception reaching the top level" do describe "An Exception reaching the top level" do
it "is printed on STDERR" do it "is printed on STDERR" do
ruby_exe('raise "foo"', args: "2>&1").should.include?("in `<main>': foo (RuntimeError)") ruby_exe('raise "foo"', args: "2>&1", exit_status: 1).should.include?("in `<main>': foo (RuntimeError)")
end end
ruby_version_is "2.6" do ruby_version_is "2.6" do
@ -20,7 +20,7 @@ describe "An Exception reaching the top level" do
raise_wrapped raise_wrapped
end end
RUBY RUBY
lines = ruby_exe(code, args: "2>&1").lines lines = ruby_exe(code, args: "2>&1", exit_status: 1).lines
lines.reject! { |l| l.include?('rescue in') } lines.reject! { |l| l.include?('rescue in') }
lines.map! { |l| l.chomp[/:(in.+)/, 1] } lines.map! { |l| l.chomp[/:(in.+)/, 1] }
lines.should == ["in `raise_wrapped': wrapped (RuntimeError)", lines.should == ["in `raise_wrapped': wrapped (RuntimeError)",
@ -38,7 +38,7 @@ describe "An Exception reaching the top level" do
"/dir/bar.rb:20:in `caller'", "/dir/bar.rb:20:in `caller'",
] ]
RUBY RUBY
ruby_exe(code, args: "2>&1").should == <<-EOS ruby_exe(code, args: "2>&1", exit_status: 1).should == <<-EOS
/dir/foo.rb:10:in `raising': foo (RuntimeError) /dir/foo.rb:10:in `raising': foo (RuntimeError)
\tfrom /dir/bar.rb:20:in `caller' \tfrom /dir/bar.rb:20:in `caller'
EOS EOS

View File

@ -72,6 +72,26 @@ ruby_version_is "2.7" do
-> { fiber.raise }.should raise_error -> { fiber.raise }.should raise_error
-> { fiber.resume }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/) -> { fiber.resume }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
end end
it "returns to calling fiber after raise" do
fiber_one = Fiber.new do
Fiber.yield :yield_one
:unreachable
end
fiber_two = Fiber.new do
results = []
results << fiber_one.resume
begin
fiber_one.raise
rescue
results << :rescued
end
results
end
fiber_two.resume.should == [:yield_one, :rescued]
end
end end
end end

View File

@ -16,20 +16,17 @@ describe "File.atime" do
end end
platform_is :linux, :windows do platform_is :linux, :windows do
## NOTE also that some Linux systems disable atime (e.g. via mount params) for better filesystem speed. platform_is_not :"powerpc64le-linux" do # https://bugs.ruby-lang.org/issues/17926
it "returns the last access time for the named file with microseconds" do ## NOTE also that some Linux systems disable atime (e.g. via mount params) for better filesystem speed.
supports_subseconds = Integer(`stat -c%x '#{__FILE__}'`[/\.(\d+)/, 1], 10) it "returns the last access time for the named file with microseconds" do
if supports_subseconds != 0 supports_subseconds = Integer(`stat -c%x '#{__FILE__}'`[/\.(\d+)/, 1], 10)
expected_time = Time.at(Time.now.to_i + 0.123456) if supports_subseconds != 0
File.utime expected_time, 0, @file expected_time = Time.at(Time.now.to_i + 0.123456)
# FIXME: A random failing test on Travis ppc64le. File.utime expected_time, 0, @file
# https://bugs.ruby-lang.org/issues/17926 File.atime(@file).usec.should == expected_time.usec
if ENV.key?('TRAVIS') && ENV['TRAVIS_CPU_ARCH'] == 'ppc64le' else
skip '[ruby-core:17926] A random failure on Travis ppc64le' File.atime(__FILE__).usec.should == 0
end end
File.atime(@file).usec.should == expected_time.usec
else
File.atime(__FILE__).usec.should == 0
end end
end end
end end

View File

@ -164,5 +164,20 @@ describe "File.basename" do
basename.encoding.should == Encoding::Windows_1250 basename.encoding.should == Encoding::Windows_1250
end end
it "returns a new unfrozen String" do
exts = [nil, '.rb', '.*', '.txt']
['foo.rb','//', '/test/', 'test'].each do |example|
exts.each do |ext|
original = example.freeze
result = if ext
File.basename(original, ext)
else
File.basename(original)
end
result.should_not equal(original)
result.frozen?.should == false
end
end
end
end end

View File

@ -59,6 +59,24 @@ describe "Hash#rehash" do
h.keys.should == [a] h.keys.should == [a]
end end
it "removes duplicate keys for large hashes" do
a = [1,2]
b = [1]
h = {}
h[a] = true
h[b] = true
100.times { |n| h[n] = true }
b << 2
h.size.should == 102
h.keys.should.include? a
h.keys.should.include? b
h.rehash
h.size.should == 101
h.keys.should.include? a
h.keys.should_not.include? [1]
end
it "raises a FrozenError if called on a frozen instance" do it "raises a FrozenError if called on a frozen instance" do
-> { HashSpecs.frozen_hash.rehash }.should raise_error(FrozenError) -> { HashSpecs.frozen_hash.rehash }.should raise_error(FrozenError)
-> { HashSpecs.empty_frozen_hash.rehash }.should raise_error(FrozenError) -> { HashSpecs.empty_frozen_hash.rehash }.should raise_error(FrozenError)

View File

@ -57,4 +57,8 @@ describe "IO#binmode?" do
@duped = @file.dup @duped = @file.dup
@duped.binmode?.should == @file.binmode? @duped.binmode?.should == @file.binmode?
end end
it "raises an IOError on closed stream" do
-> { IOSpecs.closed_io.binmode? }.should raise_error(IOError)
end
end end

View File

@ -84,4 +84,23 @@ end
dup.close dup.close
end end
end end
it "always sets the autoclose flag for the new IO object" do
@f.autoclose = true
dup = @f.dup
begin
dup.should.autoclose?
ensure
dup.close
end
@f.autoclose = false
dup = @f.dup
begin
dup.should.autoclose?
ensure
dup.close
@f.autoclose = true
end
end
end end

View File

@ -1,4 +1,5 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe :io_external_encoding_write, shared: true do describe :io_external_encoding_write, shared: true do
describe "when Encoding.default_internal is nil" do describe "when Encoding.default_internal is nil" do
@ -93,6 +94,10 @@ describe "IO#external_encoding" do
rm_r @name rm_r @name
end end
it "raises an IOError on closed stream" do
-> { IOSpecs.closed_io.external_encoding }.should raise_error(IOError)
end
describe "with 'r' mode" do describe "with 'r' mode" do
describe "when Encoding.default_internal is nil" do describe "when Encoding.default_internal is nil" do
before :each do before :each do

View File

@ -1,4 +1,5 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe :io_internal_encoding, shared: true do describe :io_internal_encoding, shared: true do
describe "when Encoding.default_internal is not set" do describe "when Encoding.default_internal is not set" do
@ -112,6 +113,10 @@ describe "IO#internal_encoding" do
Encoding.default_internal = @internal Encoding.default_internal = @internal
end end
it "raises an IOError on closed stream" do
-> { IOSpecs.closed_io.internal_encoding }.should raise_error(IOError)
end
describe "with 'r' mode" do describe "with 'r' mode" do
it_behaves_like :io_internal_encoding, nil, "r" it_behaves_like :io_internal_encoding, nil, "r"
end end

View File

@ -14,6 +14,24 @@ describe "IO#lineno" do
-> { IOSpecs.closed_io.lineno }.should raise_error(IOError) -> { IOSpecs.closed_io.lineno }.should raise_error(IOError)
end end
it "raises an IOError on a write-only stream" do
name = tmp("io_lineno.txt")
begin
File.open(name, 'w') do |f|
-> { f.lineno }.should raise_error(IOError)
end
ensure
rm_r name
end
end
it "raises an IOError on a duplexed stream with the read side closed" do
IO.popen('cat', 'r+') do |p|
p.close_read
-> { p.lineno }.should raise_error(IOError)
end
end
it "returns the current line number" do it "returns the current line number" do
@io.lineno.should == 0 @io.lineno.should == 0
@ -40,6 +58,24 @@ describe "IO#lineno=" do
-> { IOSpecs.closed_io.lineno = 5 }.should raise_error(IOError) -> { IOSpecs.closed_io.lineno = 5 }.should raise_error(IOError)
end end
it "raises an IOError on a write-only stream" do
name = tmp("io_lineno.txt")
begin
File.open(name, 'w') do |f|
-> { f.lineno = 0 }.should raise_error(IOError)
end
ensure
rm_r name
end
end
it "raises an IOError on a duplexed stream with the read side closed" do
IO.popen('cat', 'r+') do |p|
p.close_read
-> { p.lineno = 0 }.should raise_error(IOError)
end
end
it "calls #to_int on a non-numeric argument" do it "calls #to_int on a non-numeric argument" do
obj = mock('123') obj = mock('123')
obj.should_receive(:to_int).and_return(123) obj.should_receive(:to_int).and_return(123)

View File

@ -34,6 +34,20 @@ describe "IO#set_encoding_by_bom" do
@io.external_encoding.should == Encoding::UTF_16BE @io.external_encoding.should == Encoding::UTF_16BE
end end
it "returns the result encoding if found BOM UTF_32LE sequence" do
File.binwrite(@name, "\xFF\xFE\x00\x00abc")
@io.set_encoding_by_bom.should == Encoding::UTF_32LE
@io.external_encoding.should == Encoding::UTF_32LE
end
it "returns the result encoding if found BOM UTF_32BE sequence" do
File.binwrite(@name, "\x00\x00\xFE\xFFabc")
@io.set_encoding_by_bom.should == Encoding::UTF_32BE
@io.external_encoding.should == Encoding::UTF_32BE
end
it "returns nil if found BOM sequence not provided" do it "returns nil if found BOM sequence not provided" do
File.write(@name, "abc") File.write(@name, "abc")

View File

@ -50,6 +50,11 @@ describe "IO#sysread on a file" do
@file.sysread(5).should == "56789" @file.sysread(5).should == "56789"
end end
it "raises an error when called after buffered reads" do
@file.readline
-> { @file.sysread(5) }.should raise_error(IOError)
end
it "reads normally even when called immediately after a buffered IO#read" do it "reads normally even when called immediately after a buffered IO#read" do
@file.read(15) @file.read(15)
@file.sysread(5).should == "56789" @file.sysread(5).should == "56789"

View File

@ -26,6 +26,11 @@ describe "IO#sysseek" do
-> { @io.sysseek(-5, IO::SEEK_CUR) }.should raise_error(IOError) -> { @io.sysseek(-5, IO::SEEK_CUR) }.should raise_error(IOError)
end end
it "seeks normally even when called immediately after a buffered IO#read" do
@io.read(15)
@io.sysseek(-5, IO::SEEK_CUR).should == 10
end
it "moves the read position relative to the start with SEEK_SET" do it "moves the read position relative to the start with SEEK_SET" do
@io.sysseek(43, IO::SEEK_SET) @io.sysseek(43, IO::SEEK_SET)
@io.readline.should == "Aquí está la línea tres.\n" @io.readline.should == "Aquí está la línea tres.\n"

View File

@ -33,31 +33,32 @@ describe "Kernel.at_exit" do
end end
EOC EOC
result = ruby_exe(code, args: "2>&1") result = ruby_exe(code, args: "2>&1", exit_status: 1)
result.lines.should.include?("The exception matches: true (message=foo)\n") result.lines.should.include?("The exception matches: true (message=foo)\n")
end end
it "both exceptions in at_exit and in the main script are printed" do it "both exceptions in at_exit and in the main script are printed" do
result = ruby_exe('at_exit { raise "at_exit_error" }; raise "main_script_error"', args: "2>&1") code = 'at_exit { raise "at_exit_error" }; raise "main_script_error"'
result = ruby_exe(code, args: "2>&1", exit_status: 1)
result.should.include?('at_exit_error (RuntimeError)') result.should.include?('at_exit_error (RuntimeError)')
result.should.include?('main_script_error (RuntimeError)') result.should.include?('main_script_error (RuntimeError)')
end end
it "decides the exit status if both at_exit and the main script raise SystemExit" do it "decides the exit status if both at_exit and the main script raise SystemExit" do
ruby_exe('at_exit { exit 43 }; exit 42', args: "2>&1") ruby_exe('at_exit { exit 43 }; exit 42', args: "2>&1", exit_status: 43)
$?.exitstatus.should == 43 $?.exitstatus.should == 43
end end
it "runs all at_exit even if some raise exceptions" do it "runs all at_exit even if some raise exceptions" do
code = 'at_exit { STDERR.puts "last" }; at_exit { exit 43 }; at_exit { STDERR.puts "first" }; exit 42' code = 'at_exit { STDERR.puts "last" }; at_exit { exit 43 }; at_exit { STDERR.puts "first" }; exit 42'
result = ruby_exe(code, args: "2>&1") result = ruby_exe(code, args: "2>&1", exit_status: 43)
result.should == "first\nlast\n" result.should == "first\nlast\n"
$?.exitstatus.should == 43 $?.exitstatus.should == 43
end end
it "runs at_exit handlers even if the main script fails to parse" do it "runs at_exit handlers even if the main script fails to parse" do
script = fixture(__FILE__, "at_exit.rb") script = fixture(__FILE__, "at_exit.rb")
result = ruby_exe('{', options: "-r#{script}", args: "2>&1") result = ruby_exe('{', options: "-r#{script}", args: "2>&1", exit_status: 1)
$?.should_not.success? $?.should_not.success?
result.should.include?("at_exit ran\n") result.should.include?("at_exit ran\n")
result.should.include?("syntax error") result.should.include?("syntax error")

View File

@ -228,6 +228,17 @@ describe "Kernel#eval" do
ruby_exe(code).chomp.should == "a,b,c,e,LocalJumpError,f" ruby_exe(code).chomp.should == "a,b,c,e,LocalJumpError,f"
end end
it "can be called with Method#call" do
method(:eval).call("2 * 3").should == 6
end
it "has the correct default definee when called through Method#call" do
class EvalSpecs
method(:eval).call("def eval_spec_method_call; end")
EvalSpecs.should have_instance_method(:eval_spec_method_call)
end
end
# See language/magic_comment_spec.rb for more magic comments specs # See language/magic_comment_spec.rb for more magic comments specs
describe "with a magic encoding comment" do describe "with a magic encoding comment" do
it "uses the magic comment encoding for the encoding of literal strings" do it "uses the magic comment encoding for the encoding of literal strings" do
@ -374,43 +385,45 @@ CODE
end end
end end
it "activates refinements from the eval scope" do describe 'with refinements' do
refinery = Module.new do it "activates refinements from the eval scope" do
refine EvalSpecs::A do refinery = Module.new do
def foo refine EvalSpecs::A do
"bar" def foo
"bar"
end
end end
end end
result = nil
Module.new do
using refinery
result = eval "EvalSpecs::A.new.foo"
end
result.should == "bar"
end end
result = nil it "activates refinements from the binding" do
refinery = Module.new do
Module.new do refine EvalSpecs::A do
using refinery def foo
"bar"
result = eval "EvalSpecs::A.new.foo" end
end
result.should == "bar"
end
it "activates refinements from the binding" do
refinery = Module.new do
refine EvalSpecs::A do
def foo
"bar"
end end
end end
b = nil
m = Module.new do
using refinery
b = binding
end
result = eval "EvalSpecs::A.new.foo", b
result.should == "bar"
end end
b = nil
m = Module.new do
using refinery
b = binding
end
result = eval "EvalSpecs::A.new.foo", b
result.should == "bar"
end end
end end

View File

@ -1,6 +1,7 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative 'fixtures/classes' require_relative 'fixtures/classes'
# NOTE: most specs are in sprintf_spec.rb, this is just an alias
describe "Kernel#format" do describe "Kernel#format" do
it "is a private method" do it "is a private method" do
Kernel.should have_private_instance_method(:format) Kernel.should have_private_instance_method(:format)

View File

@ -30,4 +30,12 @@ describe "Kernel#inspect" do
obj = Object.new obj = Object.new
obj.inspect.should =~ /^#<Object:0x[0-9a-f]+>$/ obj.inspect.should =~ /^#<Object:0x[0-9a-f]+>$/
end end
it "returns a String for an object without #class method" do
obj = Object.new
class << obj
undef_method :class
end
obj.inspect.should be_kind_of(String)
end
end end

View File

@ -342,6 +342,23 @@ describe :kernel_sprintf, shared: true do
sub_string = long_string[8, 5] sub_string = long_string[8, 5]
sprintf("%.#{1 * 3}s", sub_string).should == "hel" sprintf("%.#{1 * 3}s", sub_string).should == "hel"
end end
it "formats string with precision" do
Kernel.format("%.3s", "hello").should == "hel"
Kernel.format("%-3.3s", "hello").should == "hel"
end
it "formats multibyte string with precision" do
Kernel.format("%.2s", "été").should == "ét"
end
it "preserves encoding of the format string" do
str = format('%s'.encode(Encoding::UTF_8), 'foobar')
str.encoding.should == Encoding::UTF_8
str = format('%s'.encode(Encoding::US_ASCII), 'foobar')
str.encoding.should == Encoding::US_ASCII
end
end end
describe "%" do describe "%" do

View File

@ -88,6 +88,23 @@ describe "Module#define_method when given an UnboundMethod" do
end end
end end
describe "Module#define_method" do
describe "when the default definee is not the same as the module" do
it "sets the visibility of the method to public" do
klass = Class.new
class << klass
private
define_method(:meta) do
define_method(:foo) { :foo }
end
end
klass.send :meta
klass.new.foo.should == :foo
end
end
end
describe "Module#define_method when name is not a special private name" do describe "Module#define_method when name is not a special private name" do
describe "given an UnboundMethod" do describe "given an UnboundMethod" do
describe "and called from the target module" do describe "and called from the target module" do
@ -491,7 +508,36 @@ describe "Module#define_method" do
it "receives the value passed as the argument when passed one argument" do it "receives the value passed as the argument when passed one argument" do
@klass.new.m(1).should == 1 @klass.new.m(1).should == 1
end end
end
describe "passed { |a,| } creates a method that" do
before :each do
@klass = Class.new do
define_method(:m) { |a,| a }
end
end
it "raises an ArgumentError when passed zero arguments" do
-> { @klass.new.m }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when passed zero arguments and a block" do
-> { @klass.new.m { :computed } }.should raise_error(ArgumentError)
end
it "raises an ArgumentError when passed two arguments" do
-> { @klass.new.m 1, 2 }.should raise_error(ArgumentError)
end
it "receives the value passed as the argument when passed one argument" do
@klass.new.m(1).should == 1
end
it "does not destructure the passed argument" do
@klass.new.m([1, 2]).should == [1, 2]
# for comparison:
proc { |a,| a }.call([1, 2]).should == 1
end
end end
describe "passed { |*a| } creates a method that" do describe "passed { |*a| } creates a method that" do

View File

@ -234,6 +234,148 @@ describe "Module#include" do
remove_const :C remove_const :C
end end
end end
it "updates the method when an included module is updated" do
a_class = Class.new do
def foo
'a'
end
end
m_module = Module.new
b_class = Class.new(a_class) do
include m_module
end
b = b_class.new
foo = -> { b.foo }
foo.call.should == 'a'
m_module.module_eval do
def foo
'm'
end
end
foo.call.should == 'm'
end
it "updates the method when a module included after a call is later updated" do
m_module = Module.new
a_class = Class.new do
def foo
'a'
end
end
b_class = Class.new(a_class)
b = b_class.new
foo = -> { b.foo }
foo.call.should == 'a'
b_class.include m_module
foo.call.should == 'a'
m_module.module_eval do
def foo
"m"
end
end
foo.call.should == 'm'
end
it "updates the method when a nested included module is updated" do
a_class = Class.new do
def foo
'a'
end
end
n_module = Module.new
m_module = Module.new do
include n_module
end
b_class = Class.new(a_class) do
include m_module
end
b = b_class.new
foo = -> { b.foo }
foo.call.should == 'a'
n_module.module_eval do
def foo
'n'
end
end
foo.call.should == 'n'
end
it "updates the method when a new module is included" do
a_class = Class.new do
def foo
'a'
end
end
m_module = Module.new do
def foo
'm'
end
end
b_class = Class.new(a_class)
b = b_class.new
foo = -> { b.foo }
foo.call.should == 'a'
b_class.class_eval do
include m_module
end
foo.call.should == 'm'
end
it "updates the method when a new module with nested module is included" do
a_class = Class.new do
def foo
'a'
end
end
n_module = Module.new do
def foo
'n'
end
end
m_module = Module.new do
include n_module
end
b_class = Class.new(a_class)
b = b_class.new
foo = -> { b.foo }
foo.call.should == 'a'
b_class.class_eval do
include m_module
end
foo.call.should == 'n'
end
end end
describe "Module#include?" do describe "Module#include?" do

View File

@ -36,6 +36,192 @@ describe "Module#prepend" do
ScratchPad.recorded.should == [ [ m3, c], [ m2, c ], [ m, c ] ] ScratchPad.recorded.should == [ [ m3, c], [ m2, c ], [ m, c ] ]
end end
it "updates the method when a module is prepended" do
m_module = Module.new do
def foo
"m"
end
end
a_class = Class.new do
def foo
'a'
end
end
a = a_class.new
foo = -> { a.foo }
foo.call.should == 'a'
a_class.class_eval do
prepend m_module
end
foo.call.should == 'm'
end
it "updates the method when a prepended module is updated" do
m_module = Module.new
a_class = Class.new do
prepend m_module
def foo
'a'
end
end
a = a_class.new
foo = -> { a.foo }
foo.call.should == 'a'
m_module.module_eval do
def foo
"m"
end
end
foo.call.should == 'm'
end
it "updates the method when there is a base included method and the prepended module overrides it" do
base_module = Module.new do
def foo
'a'
end
end
a_class = Class.new do
include base_module
end
a = a_class.new
foo = -> { a.foo }
foo.call.should == 'a'
m_module = Module.new do
def foo
"m"
end
end
a_class.prepend m_module
foo.call.should == 'm'
end
it "updates the method when there is a base included method and the prepended module is later updated" do
base_module = Module.new do
def foo
'a'
end
end
a_class = Class.new do
include base_module
end
a = a_class.new
foo = -> { a.foo }
foo.call.should == 'a'
m_module = Module.new
a_class.prepend m_module
foo.call.should == 'a'
m_module.module_eval do
def foo
"m"
end
end
foo.call.should == 'm'
end
it "updates the method when a module prepended after a call is later updated" do
m_module = Module.new
a_class = Class.new do
def foo
'a'
end
end
a = a_class.new
foo = -> { a.foo }
foo.call.should == 'a'
a_class.prepend m_module
foo.call.should == 'a'
m_module.module_eval do
def foo
"m"
end
end
foo.call.should == 'm'
end
it "updates the method when a module is prepended after another and the method is defined later on that module" do
m_module = Module.new do
def foo
'a'
end
end
a_class = Class.new
a_class.prepend m_module
a = a_class.new
foo = -> { a.foo }
foo.call.should == 'a'
n_module = Module.new
a_class.prepend n_module
foo.call.should == 'a'
n_module.module_eval do
def foo
"n"
end
end
foo.call.should == 'n'
end
it "updates the method when a module is included in a prepended module and the method is defined later" do
a_class = Class.new
base_module = Module.new do
def foo
'a'
end
end
a_class.prepend base_module
a = a_class.new
foo = -> { a.foo }
foo.call.should == 'a'
m_module = Module.new
n_module = Module.new
m_module.include n_module
a_class.prepend m_module
n_module.module_eval do
def foo
"n"
end
end
foo.call.should == 'n'
end
it "updates the method when a new module with an included module is prepended" do
a_class = Class.new do
def foo
'a'
end
end
n_module = Module.new do
def foo
'n'
end
end
m_module = Module.new do
include n_module
end
a = a_class.new
foo = -> { a.foo }
foo.call.should == 'a'
a_class.class_eval do
prepend m_module
end
foo.call.should == 'n'
end
it "raises a TypeError when the argument is not a Module" do it "raises a TypeError when the argument is not a Module" do
-> { ModuleSpecs::Basic.prepend(Class.new) }.should raise_error(TypeError) -> { ModuleSpecs::Basic.prepend(Class.new) }.should raise_error(TypeError)
end end

View File

@ -43,6 +43,28 @@ describe "Module#remove_method" do
x.method_to_remove.should == 1 x.method_to_remove.should == 1
end end
it "updates the method implementation" do
m_module = Module.new do
def foo
'm'
end
end
a_class = Class.new do
include m_module
def foo
'a'
end
end
a = a_class.new
foo = -> { a.foo }
foo.call.should == 'a'
a_class.remove_method(:foo)
foo.call.should == 'm'
end
it "removes multiple methods with 1 call" do it "removes multiple methods with 1 call" do
klass = Class.new do klass = Class.new do
def method_to_remove_1; 1; end def method_to_remove_1; 1; end

View File

@ -7,16 +7,43 @@ describe "ObjectSpace._id2ref" do
r.should == s r.should == s
end end
it "retrieves an Integer by object_id" do it "retrieves true by object_id" do
f = 1 ObjectSpace._id2ref(true.object_id).should == true
r = ObjectSpace._id2ref(f.object_id) end
r.should == f
it "retrieves false by object_id" do
ObjectSpace._id2ref(false.object_id).should == false
end
it "retrieves nil by object_id" do
ObjectSpace._id2ref(nil.object_id).should == nil
end
it "retrieves a small Integer by object_id" do
ObjectSpace._id2ref(1.object_id).should == 1
ObjectSpace._id2ref((-42).object_id).should == -42
end
it "retrieves a large Integer by object_id" do
obj = 1 << 88
ObjectSpace._id2ref(obj.object_id).should.equal?(obj)
end end
it "retrieves a Symbol by object_id" do it "retrieves a Symbol by object_id" do
s = :sym ObjectSpace._id2ref(:sym.object_id).should.equal?(:sym)
r = ObjectSpace._id2ref(s.object_id) end
r.should == s
it "retrieves a String by object_id" do
obj = "str"
ObjectSpace._id2ref(obj.object_id).should.equal?(obj)
end
it "retrieves a frozen literal String by object_id" do
ObjectSpace._id2ref("frozen string literal _id2ref".freeze.object_id).should.equal?("frozen string literal _id2ref".freeze)
end
it "retrieves an Encoding by object_id" do
ObjectSpace._id2ref(Encoding::UTF_8.object_id).should.equal?(Encoding::UTF_8)
end end
it 'raises RangeError when an object could not be found' do it 'raises RangeError when an object could not be found' do

View File

@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
# Why do we not test that finalizers are run by the GC? The documentation # Why do we not test that finalizers are run by the GC? The documentation
# says that finalizers are never guaranteed to be run, so we can't # says that finalizers are never guaranteed to be run, so we can't
# spec that they are. On some implementations of Ruby the finalizers may # spec that they are. On some implementations of Ruby the finalizers may
# run asyncronously, meaning that we can't predict when they'll run, # run asynchronously, meaning that we can't predict when they'll run,
# even if they were guaranteed to do so. Even on MRI finalizers can be # even if they were guaranteed to do so. Even on MRI finalizers can be
# very unpredictable, due to conservative stack scanning and references # very unpredictable, due to conservative stack scanning and references
# left in unused memory. # left in unused memory.

View File

@ -2,13 +2,13 @@ require_relative '../../../spec_helper'
describe "Process::Status#==" do describe "Process::Status#==" do
it "returns true when compared to the integer status of an exited child" do it "returns true when compared to the integer status of an exited child" do
ruby_exe("exit(29)") ruby_exe("exit(29)", exit_status: 29)
$?.to_i.should == $? $?.to_i.should == $?
$?.should == $?.to_i $?.should == $?.to_i
end end
it "returns true when compared to the integer status of a terminated child" do it "returns true when compared to the integer status of a terminated child" do
ruby_exe("Process.kill(:KILL, $$); exit(29)") ruby_exe("Process.kill(:KILL, $$); exit(29)", exit_status: platform_is(:windows) ? 0 : nil)
$?.to_i.should == $? $?.to_i.should == $?
$?.should == $?.to_i $?.should == $?.to_i
end end

View File

@ -1,9 +1,7 @@
require_relative '../../../spec_helper' require_relative '../../../spec_helper'
describe "Process::Status#exited?" do describe "Process::Status#exited?" do
describe "for a child that exited normally" do describe "for a child that exited normally" do
before :each do before :each do
ruby_exe("exit(0)") ruby_exe("exit(0)")
end end
@ -15,9 +13,8 @@ describe "Process::Status#exited?" do
describe "for a terminated child" do describe "for a terminated child" do
before :each do before :each do
ruby_exe("Process.kill(:KILL, $$); exit(42)") ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
end end
platform_is_not :windows do platform_is_not :windows do
@ -31,7 +28,5 @@ describe "Process::Status#exited?" do
$?.exited?.should be_true $?.exited?.should be_true
end end
end end
end end
end end

View File

@ -2,7 +2,7 @@ require_relative '../../../spec_helper'
describe "Process::Status#exitstatus" do describe "Process::Status#exitstatus" do
before :each do before :each do
ruby_exe("exit(42)") ruby_exe("exit(42)", exit_status: 42)
end end
it "returns the process exit code" do it "returns the process exit code" do
@ -11,7 +11,7 @@ describe "Process::Status#exitstatus" do
describe "for a child that raised SignalException" do describe "for a child that raised SignalException" do
before :each do before :each do
ruby_exe("Process.kill(:KILL, $$); exit(42)") ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
end end
platform_is_not :windows do platform_is_not :windows do

View File

@ -1,9 +1,7 @@
require_relative '../../../spec_helper' require_relative '../../../spec_helper'
describe "Process::Status#signaled?" do describe "Process::Status#signaled?" do
describe "for a cleanly exited child" do describe "for a cleanly exited child" do
before :each do before :each do
ruby_exe("exit(0)") ruby_exe("exit(0)")
end end
@ -14,9 +12,8 @@ describe "Process::Status#signaled?" do
end end
describe "for a terminated child" do describe "for a terminated child" do
before :each do before :each do
ruby_exe("Process.kill(:KILL, $$); exit(42)") ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
end end
platform_is_not :windows do platform_is_not :windows do
@ -30,6 +27,5 @@ describe "Process::Status#signaled?" do
$?.signaled?.should be_false $?.signaled?.should be_false
end end
end end
end end
end end

View File

@ -1,9 +1,7 @@
require_relative '../../../spec_helper' require_relative '../../../spec_helper'
describe "Process::Status#success?" do describe "Process::Status#success?" do
describe "for a child that exited normally" do describe "for a child that exited normally" do
before :each do before :each do
ruby_exe("exit(0)") ruby_exe("exit(0)")
end end
@ -14,9 +12,8 @@ describe "Process::Status#success?" do
end end
describe "for a child that exited with a non zero status" do describe "for a child that exited with a non zero status" do
before :each do before :each do
ruby_exe("exit(42)") ruby_exe("exit(42)", exit_status: 42)
end end
it "returns false" do it "returns false" do
@ -25,27 +22,20 @@ describe "Process::Status#success?" do
end end
describe "for a child that was terminated" do describe "for a child that was terminated" do
before :each do before :each do
ruby_exe("Process.kill(:KILL, $$); exit(42)") ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
end end
platform_is_not :windows do platform_is_not :windows do
it "returns nil" do it "returns nil" do
$?.success?.should be_nil $?.success?.should be_nil
end end
end end
platform_is :windows do platform_is :windows do
it "always returns true" do it "always returns true" do
$?.success?.should be_true $?.success?.should be_true
end end
end end
end end
end end

View File

@ -13,7 +13,7 @@ describe "Process::Status#termsig" do
describe "for a child that raised SignalException" do describe "for a child that raised SignalException" do
before :each do before :each do
ruby_exe("raise SignalException, 'SIGTERM'") ruby_exe("raise SignalException, 'SIGTERM'", exit_status: nil)
end end
platform_is_not :windows do platform_is_not :windows do
@ -25,7 +25,7 @@ describe "Process::Status#termsig" do
describe "for a child that was sent a signal" do describe "for a child that was sent a signal" do
before :each do before :each do
ruby_exe("Process.kill(:KILL, $$); exit(42)") ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
end end
platform_is_not :windows do platform_is_not :windows do

View File

@ -2,12 +2,12 @@ require_relative '../../../spec_helper'
describe "Process::Status#to_i" do describe "Process::Status#to_i" do
it "returns an integer when the child exits" do it "returns an integer when the child exits" do
ruby_exe('exit 48') ruby_exe('exit 48', exit_status: 48)
$?.to_i.should be_an_instance_of(Integer) $?.to_i.should be_an_instance_of(Integer)
end end
it "returns an integer when the child is signaled" do it "returns an integer when the child is signaled" do
ruby_exe('raise SignalException, "TERM"') ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : nil)
$?.to_i.should be_an_instance_of(Integer) $?.to_i.should be_an_instance_of(Integer)
end end
end end

View File

@ -207,11 +207,17 @@ describe "Range#step" do
ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5]) ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
end end
it "returns Float values of 'step * n + begin < end'" do
(1.0...6.4).step(1.8) { |x| ScratchPad << x }
ScratchPad.recorded.should eql([1.0, 2.8, 4.6])
end
ruby_version_is '3.1' do ruby_version_is '3.1' do
it "returns Float values of 'step * n + begin < end'" do it "correctly handles values near the upper limit" do # https://bugs.ruby-lang.org/issues/16612
(1.0...6.4).step(1.8) { |x| ScratchPad << x }
(1.0...55.6).step(18.2) { |x| ScratchPad << x } (1.0...55.6).step(18.2) { |x| ScratchPad << x }
ScratchPad.recorded.should eql([1.0, 2.8, 4.6, 1.0, 19.2, 37.4, 55.599999999999994]) ScratchPad.recorded.should eql([1.0, 19.2, 37.4, 55.599999999999994])
(1.0...55.6).step(18.2).size.should == 4
end end
end end
@ -459,21 +465,18 @@ describe "Range#step" do
(-1.0...1.0).step(0.5).size.should == 4 (-1.0...1.0).step(0.5).size.should == 4
end end
ruby_version_is '3.1' do it "returns the range size when there's no step_size" do
it "returns the range size when there's no step_size" do (-2..2).step.size.should == 5
(-2..2).step.size.should == 5 (-2.0..2.0).step.size.should == 5
(-2.0..2.0).step.size.should == 5 (-2..2.0).step.size.should == 5
(-2..2.0).step.size.should == 5 (-2.0..2).step.size.should == 5
(-2.0..2).step.size.should == 5 (1.0..6.4).step(1.8).size.should == 4
(1.0..6.4).step(1.8).size.should == 4 (1.0..12.7).step(1.3).size.should == 10
(1.0..12.7).step(1.3).size.should == 10 (-2...2).step.size.should == 4
(-2...2).step.size.should == 4 (-2.0...2.0).step.size.should == 4
(-2.0...2.0).step.size.should == 4 (-2...2.0).step.size.should == 4
(-2...2.0).step.size.should == 4 (-2.0...2).step.size.should == 4
(-2.0...2).step.size.should == 4 (1.0...6.4).step(1.8).size.should == 3
(1.0...6.4).step(1.8).size.should == 3
(1.0...55.6).step(18.2).size.should == 4
end
end end
it "returns nil with begin and end are String" do it "returns nil with begin and end are String" do

View File

@ -254,7 +254,7 @@ describe "Signal.trap" do
r.close r.close
loop { w.write("a"*1024) } loop { w.write("a"*1024) }
RUBY RUBY
out = ruby_exe(code) out = ruby_exe(code, exit_status: nil)
status = $? status = $?
out.should == "nil\n" out.should == "nil\n"
status.should.signaled? status.should.signaled?

View File

@ -502,5 +502,11 @@ describe "String#inspect" do
"\u{3042}".encode("EUC-JP").inspect.should == '"\\x{A4A2}"' "\u{3042}".encode("EUC-JP").inspect.should == '"\\x{A4A2}"'
end end
end end
describe "and the string has both ASCII-compatible and ASCII-incompatible chars" do
it "returns a string with the non-ASCII characters replaced by \\u notation" do
"hello привет".encode("utf-16le").inspect.should == '"hello \\u043F\\u0440\\u0438\\u0432\\u0435\\u0442"'
end
end
end end
end end

View File

@ -11,6 +11,19 @@ describe "String#rpartition with String" do
"hello".rpartition("hello").should == ["", "hello", ""] "hello".rpartition("hello").should == ["", "hello", ""]
end end
it "returns original string if regexp doesn't match" do
"hello".rpartition("/x/").should == ["", "", "hello"]
end
it "returns new object if doesn't match" do
str = "hello"
str.rpartition("/no_match/").last.should_not.equal?(str)
end
it "handles multibyte string correctly" do
"ユーザ@ドメイン".rpartition(/@/).should == ["ユーザ", "@", "ドメイン"]
end
it "accepts regexp" do it "accepts regexp" do
"hello!".rpartition(/l./).should == ["hel", "lo", "!"] "hello!".rpartition(/l./).should == ["hel", "lo", "!"]
end end

View File

@ -461,6 +461,16 @@ describe "String#split with Regexp" do
->{ broken_str.split(/\r\n|\r|\n/) }.should raise_error(ArgumentError) ->{ broken_str.split(/\r\n|\r|\n/) }.should raise_error(ArgumentError)
end end
# See https://bugs.ruby-lang.org/issues/12689 and https://github.com/jruby/jruby/issues/4868
it "allows concurrent Regexp calls in a shared context" do
str = 'a,b,c,d,e'
p = proc { str.split(/,/) }
results = 10.times.map { Thread.new { x = nil; 100.times { x = p.call }; x } }.map(&:value)
results.should == [%w[a b c d e]] * 10
end
ruby_version_is "2.6" do ruby_version_is "2.6" do
context "when a block is given" do context "when a block is given" do
it "yields each split substring with default pattern" do it "yields each split substring with default pattern" do

View File

@ -10,6 +10,16 @@ describe "Struct#dig" do
@instance.dig(:a, :a).should == { b: [1, 2, 3] } @instance.dig(:a, :a).should == { b: [1, 2, 3] }
end end
it "accepts String keys" do
@instance.dig('a', 'a').should == { b: [1, 2, 3] }
end
it "returns the value by the index" do
instance = Struct.new(:a, :b).new(:one, :two)
instance.dig(0).should == :one
instance.dig(1).should == :two
end
it "returns the nested value specified if the sequence includes an index" do it "returns the nested value specified if the sequence includes an index" do
@instance.dig(:a, :a, :b, 0).should == 1 @instance.dig(:a, :a, :b, 0).should == 1
end end

View File

@ -101,18 +101,14 @@ module ReturnSpecs
# return value will go into val before we run the ensure. # return value will go into val before we run the ensure.
# #
# If lamb's return keeps unwinding incorrectly, val will still # If lamb's return keeps unwinding incorrectly, val will still
# have it's old value. # have its old value.
# #
# We can therefore use val to figure out what happened. # We can therefore use val to figure out what happened.
begin begin
val = foo() val = foo()
ensure ensure
if val != :good return val
return :bad
end
end end
return val
end end
end end

View File

@ -48,6 +48,21 @@ describe "Hash literal" do
}.should complain(/key :foo is duplicated|duplicated key/) }.should complain(/key :foo is duplicated|duplicated key/)
@h.keys.size.should == 1 @h.keys.size.should == 1
@h.should == {foo: :foo} @h.should == {foo: :foo}
-> {
@h = eval "{%q{a} => :bar, %q{a} => :foo}"
}.should complain(/key "a" is duplicated|duplicated key/)
@h.keys.size.should == 1
@h.should == {%q{a} => :foo}
-> {
@h = eval "{1000 => :bar, 1000 => :foo}"
}.should complain(/key 1000 is duplicated|duplicated key/)
@h.keys.size.should == 1
@h.should == {1000 => :foo}
-> {
@h = eval "{1.0 => :bar, 1.0 => :foo}"
}.should complain(/key 1.0 is duplicated|duplicated key/)
@h.keys.size.should == 1
@h.should == {1.0 => :foo}
end end
it "accepts a hanging comma" do it "accepts a hanging comma" do

View File

@ -29,7 +29,7 @@ describe "Source files" do
touch(path, "wb") { |f| f.write source } touch(path, "wb") { |f| f.write source }
begin begin
ruby_exe(path, args: "2>&1").should =~ /invalid multibyte char/ ruby_exe(path, args: "2>&1", exit_status: 1).should =~ /invalid multibyte char/
ensure ensure
rm_r path rm_r path
end end
@ -51,7 +51,7 @@ describe "Source files" do
touch(path, "wb") { |f| f.write source } touch(path, "wb") { |f| f.write source }
begin begin
ruby_exe(path, args: "2>&1").should =~ /invalid multibyte char/ ruby_exe(path, args: "2>&1", exit_status: 1).should =~ /invalid multibyte char/
ensure ensure
rm_r path rm_r path
end end

View File

@ -1,3 +1,4 @@
require_relative '../../spec_helper'
require 'date' require 'date'
require_relative '../../shared/time/strftime_for_date' require_relative '../../shared/time/strftime_for_date'
require_relative '../../shared/time/strftime_for_time' require_relative '../../shared/time/strftime_for_time'

View File

@ -22,6 +22,12 @@ describe 'RbConfig::CONFIG' do
File.directory?(archdir).should == true File.directory?(archdir).should == true
File.should.exist?("#{archdir}/etc.#{RbConfig::CONFIG['DLEXT']}") File.should.exist?("#{archdir}/etc.#{RbConfig::CONFIG['DLEXT']}")
end end
it "['sitelibdir'] is set and is part of $LOAD_PATH" do
sitelibdir = RbConfig::CONFIG['sitelibdir']
sitelibdir.should be_kind_of String
$LOAD_PATH.should.include? sitelibdir
end
end end
it "contains no frozen strings even with --enable-frozen-string-literal" do it "contains no frozen strings even with --enable-frozen-string-literal" do
@ -36,7 +42,7 @@ describe 'RbConfig::CONFIG' do
RUBY RUBY
end end
guard -> {RbConfig::TOPDIR} do guard -> { RbConfig::TOPDIR } do
it "libdir/LIBRUBY_SO is the path to libruby and it exists if and only if ENABLE_SHARED" do it "libdir/LIBRUBY_SO is the path to libruby and it exists if and only if ENABLE_SHARED" do
libdirname = RbConfig::CONFIG['LIBPATHENV'] == 'PATH' ? 'bindir' : libdirname = RbConfig::CONFIG['LIBPATHENV'] == 'PATH' ? 'bindir' :
RbConfig::CONFIG['libdirname'] RbConfig::CONFIG['libdirname']

View File

@ -0,0 +1,10 @@
require_relative '../../../spec_helper'
require 'rubygems'
describe "Gem.load_path_insert_index" do
guard -> { RbConfig::TOPDIR } do
it "is set for an installed an installed Ruby" do
Gem.load_path_insert_index.should be_kind_of Integer
end
end
end

View File

@ -36,6 +36,13 @@ describe "CApiWrappedStruct" do
end end
end end
describe "rb_check_type" do
it "does not raise an exception when checking data objects" do
a = @s.wrap_struct(1024)
@s.rb_check_type(a, a).should == true
end
end
describe "DATA_PTR" do describe "DATA_PTR" do
it "returns the struct data" do it "returns the struct data" do
a = @s.wrap_struct(1024) a = @s.wrap_struct(1024)

View File

@ -66,6 +66,11 @@ VALUE sws_change_struct(VALUE self, VALUE obj, VALUE new_val) {
return Qnil; return Qnil;
} }
VALUE sws_rb_check_type(VALUE self, VALUE obj, VALUE other) {
rb_check_type(obj, TYPE(other));
return Qtrue;
}
void Init_data_spec(void) { void Init_data_spec(void) {
VALUE cls = rb_define_class("CApiAllocSpecs", rb_cObject); VALUE cls = rb_define_class("CApiAllocSpecs", rb_cObject);
rb_define_alloc_func(cls, sdaf_alloc_func); rb_define_alloc_func(cls, sdaf_alloc_func);
@ -76,6 +81,7 @@ void Init_data_spec(void) {
rb_define_method(cls, "get_struct_rdata", sws_get_struct_rdata, 1); rb_define_method(cls, "get_struct_rdata", sws_get_struct_rdata, 1);
rb_define_method(cls, "get_struct_data_ptr", sws_get_struct_data_ptr, 1); rb_define_method(cls, "get_struct_data_ptr", sws_get_struct_data_ptr, 1);
rb_define_method(cls, "change_struct", sws_change_struct, 2); rb_define_method(cls, "change_struct", sws_change_struct, 2);
rb_define_method(cls, "rb_check_type", sws_rb_check_type, 2);
} }
#ifdef __cplusplus #ifdef __cplusplus

View File

@ -189,6 +189,11 @@ static VALUE object_spec_RTEST(VALUE self, VALUE value) {
return RTEST(value) ? Qtrue : Qfalse; return RTEST(value) ? Qtrue : Qfalse;
} }
static VALUE so_check_type(VALUE self, VALUE obj, VALUE other) {
rb_check_type(obj, TYPE(other));
return Qtrue;
}
static VALUE so_is_type_nil(VALUE self, VALUE obj) { static VALUE so_is_type_nil(VALUE self, VALUE obj) {
if(TYPE(obj) == T_NIL) { if(TYPE(obj) == T_NIL) {
return Qtrue; return Qtrue;
@ -434,6 +439,7 @@ void Init_object_spec(void) {
rb_define_method(cls, "rb_to_id", so_to_id, 1); rb_define_method(cls, "rb_to_id", so_to_id, 1);
rb_define_method(cls, "RTEST", object_spec_RTEST, 1); rb_define_method(cls, "RTEST", object_spec_RTEST, 1);
rb_define_method(cls, "rb_check_type", so_check_type, 2);
rb_define_method(cls, "rb_is_type_nil", so_is_type_nil, 1); rb_define_method(cls, "rb_is_type_nil", so_is_type_nil, 1);
rb_define_method(cls, "rb_is_type_object", so_is_type_object, 1); rb_define_method(cls, "rb_is_type_object", so_is_type_object, 1);
rb_define_method(cls, "rb_is_type_array", so_is_type_array, 1); rb_define_method(cls, "rb_is_type_array", so_is_type_array, 1);

View File

@ -148,6 +148,11 @@ VALUE sws_typed_change_struct(VALUE self, VALUE obj, VALUE new_val) {
return Qnil; return Qnil;
} }
VALUE sws_typed_rb_check_type(VALUE self, VALUE obj, VALUE other) {
rb_check_type(obj, TYPE(other));
return Qtrue;
}
VALUE sws_typed_rb_check_typeddata_same_type(VALUE self, VALUE obj) { VALUE sws_typed_rb_check_typeddata_same_type(VALUE self, VALUE obj) {
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse; return rb_check_typeddata(obj, &sample_typed_wrapped_struct_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
} }
@ -172,6 +177,7 @@ void Init_typed_data_spec(void) {
rb_define_method(cls, "typed_get_struct_rdata", sws_typed_get_struct_rdata, 1); rb_define_method(cls, "typed_get_struct_rdata", sws_typed_get_struct_rdata, 1);
rb_define_method(cls, "typed_get_struct_data_ptr", sws_typed_get_struct_data_ptr, 1); rb_define_method(cls, "typed_get_struct_data_ptr", sws_typed_get_struct_data_ptr, 1);
rb_define_method(cls, "typed_change_struct", sws_typed_change_struct, 2); rb_define_method(cls, "typed_change_struct", sws_typed_change_struct, 2);
rb_define_method(cls, "rb_check_type", sws_typed_rb_check_type, 2);
rb_define_method(cls, "rb_check_typeddata_same_type", sws_typed_rb_check_typeddata_same_type, 1); rb_define_method(cls, "rb_check_typeddata_same_type", sws_typed_rb_check_typeddata_same_type, 1);
rb_define_method(cls, "rb_check_typeddata_same_type_parent", sws_typed_rb_check_typeddata_same_type_parent, 1); rb_define_method(cls, "rb_check_typeddata_same_type_parent", sws_typed_rb_check_typeddata_same_type_parent, 1);
rb_define_method(cls, "rb_check_typeddata_different_type", sws_typed_rb_check_typeddata_different_type, 1); rb_define_method(cls, "rb_check_typeddata_different_type", sws_typed_rb_check_typeddata_different_type, 1);

View File

@ -499,20 +499,43 @@ describe "CApiObject" do
@o.rb_is_type_array([]).should == true @o.rb_is_type_array([]).should == true
@o.rb_is_type_array(DescArray.new).should == true @o.rb_is_type_array(DescArray.new).should == true
@o.rb_is_type_module(ObjectTest).should == false @o.rb_is_type_module(ObjectTest).should == false
@o.rb_is_type_module(Module.new).should == true
@o.rb_is_type_class(ObjectTest).should == true @o.rb_is_type_class(ObjectTest).should == true
@o.rb_is_type_data(Time.now).should == true @o.rb_is_type_data(Time.now).should == true
end end
end end
describe "rb_check_type" do
it "checks if the object is of the given type" do
@o.rb_check_type(nil, nil).should == true
@o.rb_check_type(ObjectTest.new, Object.new).should == true
@o.rb_check_type([], []).should == true
@o.rb_check_type(Class.new(Array).new, []).should == true
@o.rb_check_type(ObjectTest, Object).should == true
end
it "raises an exception if the object is not of the expected type" do
-> {
@o.rb_check_type([], Object.new)
}.should raise_error(TypeError, 'wrong argument type Array (expected Object)')
-> {
@o.rb_check_type(ObjectTest, Module.new)
}.should raise_error(TypeError, 'wrong argument type Class (expected Module)')
-> {
@o.rb_check_type(nil, "string")
}.should raise_error(TypeError, 'wrong argument type nil (expected String)')
end
end
describe "rb_type_p" do describe "rb_type_p" do
it "returns whether object is of the given type" do it "returns whether object is of the given type" do
class DescArray < Array
end
@o.rb_is_rb_type_p_nil(nil).should == true @o.rb_is_rb_type_p_nil(nil).should == true
@o.rb_is_rb_type_p_object([]).should == false @o.rb_is_rb_type_p_object([]).should == false
@o.rb_is_rb_type_p_object(ObjectTest.new).should == true @o.rb_is_rb_type_p_object(ObjectTest.new).should == true
@o.rb_is_rb_type_p_array([]).should == true @o.rb_is_rb_type_p_array([]).should == true
@o.rb_is_rb_type_p_array(DescArray.new).should == true @o.rb_is_rb_type_p_array(Class.new(Array).new).should == true
@o.rb_is_rb_type_p_module(ObjectTest).should == false @o.rb_is_rb_type_p_module(ObjectTest).should == false
@o.rb_is_rb_type_p_class(ObjectTest).should == true @o.rb_is_rb_type_p_class(ObjectTest).should == true
@o.rb_is_rb_type_p_data(Time.now).should == true @o.rb_is_rb_type_p_data(Time.now).should == true
@ -521,12 +544,10 @@ describe "CApiObject" do
describe "BUILTIN_TYPE" do describe "BUILTIN_TYPE" do
it "returns the type constant for the object" do it "returns the type constant for the object" do
class DescArray < Array
end
@o.rb_is_builtin_type_object([]).should == false @o.rb_is_builtin_type_object([]).should == false
@o.rb_is_builtin_type_object(ObjectTest.new).should == true @o.rb_is_builtin_type_object(ObjectTest.new).should == true
@o.rb_is_builtin_type_array([]).should == true @o.rb_is_builtin_type_array([]).should == true
@o.rb_is_builtin_type_array(DescArray.new).should == true @o.rb_is_builtin_type_array(Class.new(Array).new).should == true
@o.rb_is_builtin_type_module(ObjectTest).should == false @o.rb_is_builtin_type_module(ObjectTest).should == false
@o.rb_is_builtin_type_class(ObjectTest).should == true @o.rb_is_builtin_type_class(ObjectTest).should == true
@o.rb_is_builtin_type_data(Time.now).should == true @o.rb_is_builtin_type_data(Time.now).should == true

View File

@ -58,6 +58,17 @@ describe "CApiWrappedTypedStruct" do
end end
end end
describe "rb_check_type" do
it "raises an exception when checking typed data objects" do
-> {
a = @s.typed_wrap_struct(1024)
@s.rb_check_type(a, a)
}.should raise_error(TypeError) { |e|
e.message.should == 'wrong argument type Object (expected Data)'
}
end
end
describe "rb_check_typeddata" do describe "rb_check_typeddata" do
it "returns data pointer when the struct has the given type" do it "returns data pointer when the struct has the given type" do
a = @s.typed_wrap_struct(1024) a = @s.typed_wrap_struct(1024)

View File

@ -75,25 +75,25 @@ end
describe :process_exit!, shared: true do describe :process_exit!, shared: true do
it "exits with the given status" do it "exits with the given status" do
out = ruby_exe("#{@object}.send(:exit!, 21)", args: '2>&1') out = ruby_exe("#{@object}.send(:exit!, 21)", args: '2>&1', exit_status: 21)
out.should == "" out.should == ""
$?.exitstatus.should == 21 $?.exitstatus.should == 21
end end
it "exits when called from a thread" do it "exits when called from a thread" do
out = ruby_exe("Thread.new { #{@object}.send(:exit!, 21) }.join; sleep", args: '2>&1') out = ruby_exe("Thread.new { #{@object}.send(:exit!, 21) }.join; sleep", args: '2>&1', exit_status: 21)
out.should == "" out.should == ""
$?.exitstatus.should == 21 $?.exitstatus.should == 21
end end
it "exits when called from a fiber" do it "exits when called from a fiber" do
out = ruby_exe("Fiber.new { #{@object}.send(:exit!, 21) }.resume", args: '2>&1') out = ruby_exe("Fiber.new { #{@object}.send(:exit!, 21) }.resume", args: '2>&1', exit_status: 21)
out.should == "" out.should == ""
$?.exitstatus.should == 21 $?.exitstatus.should == 21
end end
it "skips at_exit handlers" do it "skips at_exit handlers" do
out = ruby_exe("at_exit { STDERR.puts 'at_exit' }; #{@object}.send(:exit!, 21)", args: '2>&1') out = ruby_exe("at_exit { STDERR.puts 'at_exit' }; #{@object}.send(:exit!, 21)", args: '2>&1', exit_status: 21)
out.should == "" out.should == ""
$?.exitstatus.should == 21 $?.exitstatus.should == 21
end end
@ -107,7 +107,7 @@ describe :process_exit!, shared: true do
end end
raise 'original error' raise 'original error'
RUBY RUBY
out = ruby_exe(code, args: '2>&1') out = ruby_exe(code, args: '2>&1', exit_status: 21)
out.should == "in at_exit\n$! is RuntimeError:original error\n" out.should == "in at_exit\n$! is RuntimeError:original error\n"
$?.exitstatus.should == 21 $?.exitstatus.should == 21
end end

View File

@ -170,4 +170,12 @@ describe :strftime_time, shared: true do
time.strftime("%-k%p").should == "8AM" time.strftime("%-k%p").should == "8AM"
time.strftime("%-l%p").should == "8AM" time.strftime("%-l%p").should == "8AM"
end end
it "should be able to show default Logger format" do
default_logger_format = "%Y-%m-%dT%H:%M:%S.%6N "
@new_time[2001, 2, 3, 4, 5, 6].strftime(default_logger_format).should == "2001-02-03T04:05:06.000000 "
@new_time[2001, 12, 3, 4, 5, 6 + 1/10r].strftime(default_logger_format).should == "2001-12-03T04:05:06.100000 "
@new_time[2001, 2, 13, 4, 5, 6 + 1/100r].strftime(default_logger_format).should == "2001-02-13T04:05:06.010000 "
@new_time[2001, 2, 3, 14, 5, 6 + 1/1000r].strftime(default_logger_format).should == "2001-02-03T14:05:06.001000 "
end
end end