1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67361 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
eregon 2019-03-28 14:22:29 +00:00
parent 0f64776745
commit a28aa80c73
53 changed files with 932 additions and 106 deletions

View file

@ -88,7 +88,6 @@ IncludeSpecsClass
IncludeSpecsMiddle IncludeSpecsMiddle
IncludeSpecsTop IncludeSpecsTop
IncludesMath IncludesMath
InvalidTostrTest
JSON JSON
KSAutoloadA KSAutoloadA
KSAutoloadB KSAutoloadB
@ -177,6 +176,7 @@ StringRefinement
StringScanner StringScanner
StringSubclass StringSubclass
StructClasses StructClasses
Syck
Syslog Syslog
TCPServer TCPServer
TCPSocket TCPSocket
@ -205,7 +205,6 @@ UserObject
UserPreviouslyDefinedWithInitializedIvar UserPreviouslyDefinedWithInitializedIvar
UserRegexp UserRegexp
UserString UserString
ValidTostrTest
Vector Vector
WEBrick WEBrick
WIN32OLE WIN32OLE

View file

@ -96,3 +96,7 @@ Lint/UnreachableCode:
Lint/UriRegexp: Lint/UriRegexp:
Exclude: Exclude:
- 'library/uri/regexp_spec.rb' - 'library/uri/regexp_spec.rb'
Lint/Debugger:
Exclude:
- 'core/binding/fixtures/irb.rb'

View file

@ -6,14 +6,14 @@ script:
- ../mspec/bin/mspec $MSPEC_OPTS - ../mspec/bin/mspec $MSPEC_OPTS
matrix: matrix:
include: include:
- rvm: 2.5.3 - rvm: 2.5.5
env: MSPEC_OPTS="-R2 -ff" env: MSPEC_OPTS="-R2 -ff"
- rvm: 2.3.8 - rvm: 2.3.8
- rvm: 2.4.5 - rvm: 2.4.5
env: CHECK_LEAKS=true env: CHECK_LEAKS=true
- rvm: 2.5.3 - rvm: 2.5.5
env: CHECK_LEAKS=true env: CHECK_LEAKS=true
- rvm: 2.6.1 - rvm: 2.6.2
env: CHECK_LEAKS=true env: CHECK_LEAKS=true
- env: RUBOCOP=true - env: RUBOCOP=true
rvm: 2.4.5 rvm: 2.4.5

View file

@ -1,23 +1,6 @@
require_relative '../spec_helper' require_relative '../spec_helper'
require_relative 'shared/change_directory'
describe 'The -C command line option' do describe "The -C command line option" do
before :all do it_behaves_like :command_line_change_directory, "-C"
@script = fixture(__FILE__, 'dash_upper_c_script.rb')
@tempdir = File.dirname(@script)
end
it 'changes the PWD when using a file' do
output = ruby_exe(@script, options: "-C #{@tempdir}")
output.should == @tempdir
end
it 'does not need a space after -C for the argument' do
output = ruby_exe(@script, options: "-C#{@tempdir}")
output.should == @tempdir
end
it 'changes the PWD when using -e' do
output = ruby_exe(nil, options: "-C #{@tempdir} -e 'print Dir.pwd'")
output.should == @tempdir
end
end end

View file

@ -0,0 +1,6 @@
require_relative '../spec_helper'
require_relative 'shared/change_directory'
describe "The -X command line option" do
it_behaves_like :command_line_change_directory, "-X"
end

View file

@ -0,0 +1,65 @@
require_relative '../spec_helper'
describe "The --enable and --disable flags" do
it "can be used with gems" do
ruby_exe("p defined?(Gem)", options: "--enable=gems").chomp.should == "\"constant\""
ruby_exe("p defined?(Gem)", options: "--disable=gems").chomp.should == "nil"
ruby_exe("p defined?(Gem)", options: "--enable-gems").chomp.should == "\"constant\""
ruby_exe("p defined?(Gem)", options: "--disable-gems").chomp.should == "nil"
end
it "can be used with gem" do
ruby_exe("p defined?(Gem)", options: "--enable=gem").chomp.should == "\"constant\""
ruby_exe("p defined?(Gem)", options: "--disable=gem").chomp.should == "nil"
ruby_exe("p defined?(Gem)", options: "--enable-gem").chomp.should == "\"constant\""
ruby_exe("p defined?(Gem)", options: "--disable-gem").chomp.should == "nil"
end
it "can be used with did_you_mean" do
ruby_exe("p defined?(DidYouMean)", options: "--enable=did_you_mean").chomp.should == "\"constant\""
ruby_exe("p defined?(DidYouMean)", options: "--disable=did_you_mean").chomp.should == "nil"
ruby_exe("p defined?(DidYouMean)", options: "--enable-did_you_mean").chomp.should == "\"constant\""
ruby_exe("p defined?(DidYouMean)", options: "--disable-did_you_mean").chomp.should == "nil"
end
it "can be used with rubyopt" do
ruby_exe("p $VERBOSE", options: "--enable=rubyopt", env: {'RUBYOPT' => '-w'}).chomp.should == "true"
ruby_exe("p $VERBOSE", options: "--disable=rubyopt", env: {'RUBYOPT' => '-w'}).chomp.should == "false"
ruby_exe("p $VERBOSE", options: "--enable-rubyopt", env: {'RUBYOPT' => '-w'}).chomp.should == "true"
ruby_exe("p $VERBOSE", options: "--disable-rubyopt", env: {'RUBYOPT' => '-w'}).chomp.should == "false"
end
it "can be used with frozen-string-literal" do
ruby_exe("p 'foo'.frozen?", options: "--enable=frozen-string-literal").chomp.should == "true"
ruby_exe("p 'foo'.frozen?", options: "--disable=frozen-string-literal").chomp.should == "false"
ruby_exe("p 'foo'.frozen?", options: "--enable-frozen-string-literal").chomp.should == "true"
ruby_exe("p 'foo'.frozen?", options: "--disable-frozen-string-literal").chomp.should == "false"
end
ruby_version_is "2.6" do
it "can be used with jit" do
ruby_exe("p RubyVM::MJIT.enabled?", options: "--enable=jit").chomp.should == "true"
ruby_exe("p RubyVM::MJIT.enabled?", options: "--disable=jit").chomp.should == "false"
ruby_exe("p RubyVM::MJIT.enabled?", options: "--enable-jit").chomp.should == "true"
ruby_exe("p RubyVM::MJIT.enabled?", options: "--disable-jit").chomp.should == "false"
end
end
it "can be used with all" do
e = "p [defined?(Gem), defined?(DidYouMean), $VERBOSE, 'foo'.frozen?]"
env = {'RUBYOPT' => '-w'}
ruby_exe(e, options: "--enable=all", env: env).chomp.should == "[\"constant\", \"constant\", true, true]"
ruby_exe(e, options: "--enable-all", env: env).chomp.should == "[\"constant\", \"constant\", true, true]"
ruby_exe(e, options: "--disable=all", env: env).chomp.should == "[nil, nil, false, false]"
ruby_exe(e, options: "--disable-all", env: env).chomp.should == "[nil, nil, false, false]"
end
it "prints a warning for unknown features" do
ruby_exe("p 14", options: "--enable=ruby-spec-feature-does-not-exist 2>&1").chomp.should include('warning: unknown argument for --enable')
ruby_exe("p 14", options: "--disable=ruby-spec-feature-does-not-exist 2>&1").chomp.should include('warning: unknown argument for --disable')
ruby_exe("p 14", options: "--enable-ruby-spec-feature-does-not-exist 2>&1").chomp.should include('warning: unknown argument for --enable')
ruby_exe("p 14", options: "--disable-ruby-spec-feature-does-not-exist 2>&1").chomp.should include('warning: unknown argument for --disable')
end
end

View file

@ -30,6 +30,7 @@ describe "The RUBYLIB environment variable" do
dir = tmp("rubylib/incl_front") dir = tmp("rubylib/incl_front")
ENV["RUBYLIB"] = @pre + dir ENV["RUBYLIB"] = @pre + dir
paths = ruby_exe("puts $LOAD_PATH").lines.map(&:chomp) paths = ruby_exe("puts $LOAD_PATH").lines.map(&:chomp)
paths.shift if paths.first.end_with?('/gem-rehash')
if PlatformGuard.implementation? :ruby if PlatformGuard.implementation? :ruby
# In a MRI checkout, $PWD and some extra -I entries end up as # In a MRI checkout, $PWD and some extra -I entries end up as
# the first entries in $LOAD_PATH. So just assert that it's not last. # the first entries in $LOAD_PATH. So just assert that it's not last.

View file

@ -0,0 +1,21 @@
describe :command_line_change_directory, shared: true do
before :all do
@script = fixture(__FILE__, 'change_directory_script.rb')
@tempdir = File.dirname(@script)
end
it 'changes the PWD when using a file' do
output = ruby_exe(@script, options: "#{@method} #{@tempdir}")
output.should == @tempdir
end
it 'does not need a space after -C for the argument' do
output = ruby_exe(@script, options: "#{@method}#{@tempdir}")
output.should == @tempdir
end
it 'changes the PWD when using -e' do
output = ruby_exe(nil, options: "#{@method} #{@tempdir} -e 'print Dir.pwd'")
output.should == @tempdir
end
end

View file

@ -0,0 +1,3 @@
a = 10
binding.irb

View file

@ -0,0 +1,17 @@
require_relative '../../spec_helper'
ruby_version_is "2.5" do
describe "Binding#irb" do
it "creates an IRB session with the binding in scope" do
irb_fixture = fixture __FILE__, "irb.rb"
out = IO.popen([*ruby_exe, irb_fixture], "r+") do |pipe|
pipe.puts "a ** 2"
pipe.puts "exit"
pipe.readlines.map(&:chomp)
end
out[-3..-1].should == ["a ** 2", "100", "exit"]
end
end
end

View file

@ -12,7 +12,7 @@ describe "File.mtime" do
it "returns the modification Time of the file" do it "returns the modification Time of the file" do
File.mtime(@filename).should be_kind_of(Time) File.mtime(@filename).should be_kind_of(Time)
File.mtime(@filename).should be_close(@mtime, 2.0) File.mtime(@filename).should be_close(@mtime, 60.0)
end end
guard -> { platform_is :linux or (platform_is :windows and ruby_version_is '2.5') } do guard -> { platform_is :linux or (platform_is :windows and ruby_version_is '2.5') } do

View file

@ -75,11 +75,11 @@ describe "Float#to_s" do
-10000000000000000.0.to_s.should == "-1.0e+16" -10000000000000000.0.to_s.should == "-1.0e+16"
end end
it "uses non-e format for a positive value with whole part having 17 significant figures" do it "uses e format for a positive value with whole part having 17 significant figures" do
1000000000000000.0.to_s.should == "1.0e+15" 1000000000000000.0.to_s.should == "1.0e+15"
end end
it "uses non-e format for a negative value with whole part having 17 significant figures" do it "uses e format for a negative value with whole part having 17 significant figures" do
-1000000000000000.0.to_s.should == "-1.0e+15" -1000000000000000.0.to_s.should == "-1.0e+15"
end end
@ -95,6 +95,201 @@ describe "Float#to_s" do
it "outputs the minimal, unique form to represent the value" do it "outputs the minimal, unique form to represent the value" do
0.56.to_s.should == "0.56" 0.56.to_s.should == "0.56"
end end
describe "matches" do
ruby_version_is "2.4" do # For unpack1
it "random examples in all ranges" do
# 50.times do
# bytes = (0...8).map { rand(256) }
# string = bytes.pack('C8')
# float = string.unpack('D').first
# puts " #{bytes.pack('C8').inspect}.unpack1('D').to_s.should == #{float.to_s.inspect}"
# end
"\x97\x15\xC1| \xF5\x19\xAD".unpack1('D').to_s.should == "-1.9910613439044092e-91"
"\xBF\xF0\x14\xAD\xDF\x17q\xD1".unpack1('D').to_s.should == "-2.075408637901046e+84"
"\xDF\xBD\xC0\x89\xDA\x1F&$".unpack1('D').to_s.should == "1.5219626883645564e-134"
"|0<?a\xFB\xBFG".unpack1('D').to_s.should == "4.251130678455814e+37"
"U\xEE*\xB7\xF1\xB8\xE7\x18".unpack1('D').to_s.should == "1.0648588700899858e-188"
"\x15Y\xD1J\x80/7\xD0".unpack1('D').to_s.should == "-2.6847034291392176e+78"
"\x1D\x1E\xD2\x9A3)\xF5q".unpack1('D').to_s.should == "8.818842365424256e+240"
"M\xD0C\xA3\x19-\xE3\xE5".unpack1('D').to_s.should == "-6.365746090981858e+182"
"\xAFf\xFE\xF0$\x85\x01L".unpack1('D').to_s.should == "1.374692728674642e+58"
"'N\xB7\x12\xE0\xC8t\t".unpack1('D').to_s.should == "4.1254080603298014e-263"
"\xAFn\xF2x\x85\xB5\x15j".unpack1('D').to_s.should == "1.0635019031720867e+203"
"nQ\x95\xFA\xD9\xE3\xC5)".unpack1('D').to_s.should == "1.8641386367625094e-107"
"\xC2\x9A\xB1|/\xCAJM".unpack1('D').to_s.should == "2.204135837758401e+64"
"q n\xD8\x86\xF2\xA8D".unpack1('D').to_s.should == "5.890531214599543e+22"
"dmR\xC6\xB3\xF3\x95G".unpack1('D').to_s.should == "7.294790578028111e+36"
"6I\x0E)?E\xB5\xE1".unpack1('D').to_s.should == "-4.7847061687992665e+162"
"\xCD\xE0\xBBy\x9F\xD8\xE89".unpack1('D').to_s.should == "9.800091365433584e-30"
"\xB8\x98TN\x98\xEE\xC1\xF9".unpack1('D').to_s.should == "-3.178740061599073e+278"
"\x8F_\xFF\x15\x1F2\x17B".unpack1('D').to_s.should == "24906286463.84332"
"\x94\x18V\xC5&\xE6\xEAi".unpack1('D').to_s.should == "1.6471900588998988e+202"
"\xECq\xB1\x01\ai\xBD,".unpack1('D').to_s.should == "3.5248469410018065e-93"
"\x9C\xC6\x13pG\xDAx\x9A".unpack1('D').to_s.should == "-3.743306318201459e-181"
"\xEA7,gJ\xEE\x8E*".unpack1('D').to_s.should == "1.0789044330549825e-103"
"1\xD3\xF5K\x8D\xEF\xA7\r".unpack1('D').to_s.should == "7.011009309284311e-243"
"o\xB3\x02\xAF\x9D\xFC\r\xF6".unpack1('D').to_s.should == "-4.610585875652112e+260"
"&:x\x15\xFC3P\x01".unpack1('D').to_s.should == "2.362770515774595e-302"
"\xE6<C\xB8\x90\xF2\xCF\x90".unpack1('D').to_s.should == "-1.0535871178808475e-227"
"\x9Al\aB6's}".unpack1('D').to_s.should == "1.957205609213647e+296"
"+\v\x16\xFD\x19\x0E\x9B\x06".unpack1('D').to_s.should == "7.631200870990123e-277"
"\xEC\xF8~\xDA\xE7Tf\x92".unpack1('D').to_s.should == "-4.942358450191624e-220"
"\xE0\xA0\xC9\x906\xBDcI".unpack1('D').to_s.should == "3.521575588133954e+45"
"\xBD\xFD\xC9\xFD\rp\x02\x0F".unpack1('D').to_s.should == "2.2651682962118346e-236"
"\xE9\xA8\xAD\xC4\xF6u\xF7\x19".unpack1('D').to_s.should == "1.3803378872547194e-183"
"\"f\xED9\x17\xF0\xF1!".unpack1('D').to_s.should == "3.591307506787987e-145"
"\xE6\xF2\xB6\x9CFl\xB3O".unpack1('D').to_s.should == "8.785250953340842e+75"
"g\xFD\xEA\r~x\xBA\x9D".unpack1('D').to_s.should == "-1.7955908504285607e-165"
"\xE2\x84J\xC7\x00\n/\x06".unpack1('D').to_s.should == "6.839790344291208e-279"
"s\xFB\xA58x\xF1\xA9\xD9".unpack1('D').to_s.should == "-8.574967051032431e+123"
"\xE2\x9D\xBE\xE2\x10k{\xFC".unpack1('D').to_s.should == "-4.2751876153404507e+291"
"!z \xB4i4\x8C5".unpack1('D').to_s.should == "9.423078517655126e-51"
"!_\xEAp- 7R".unpack1('D').to_s.should == "1.1500944673871687e+88"
"\x03\xAD=\\\xCB >\xBB".unpack1('D').to_s.should == "-2.4921382721208654e-23"
"\x94\x01\xB1\x87\x10\x9B#\x88".unpack1('D').to_s.should == "-1.8555672851958583e-269"
"\x90H\xFF\\S\x01)\x89".unpack1('D').to_s.should == "-1.5509713490195968e-264"
"HW@\x13\x85&=)".unpack1('D').to_s.should == "4.848496966571536e-110"
"\x14\xDB\\\x10\x93\x9C\xD66".unpack1('D').to_s.should == "1.5842813502410472e-44"
"\x9D8p>\xFF\x9B[\xF3".unpack1('D').to_s.should == "-4.826061446912647e+247"
"c\x9D}\t]\xF9pg".unpack1('D').to_s.should == "1.8907034486212682e+190"
"\xA51\xC9WJ\xB5a^".unpack1('D').to_s.should == "4.422435231445608e+146"
"\x8BL\x90\xCB\xEARf\f".unpack1('D').to_s.should == "6.235963569982745e-249"
end
it "random examples in human ranges" do
# 50.times do
# formatted = ''
# rand(1..3).times do
# formatted << rand(10).to_s
# end
# formatted << '.'
# rand(1..9).times do
# formatted << rand(10).to_s
# end
# float = formatted.to_f
# string = [float].pack('D')
# puts " #{string.inspect}.unpack1('D').to_s.should == #{float.to_s.inspect}"
# end
";\x01M\x84\r\xF7M@".unpack1('D').to_s.should == "59.9301"
"\xAE\xD3HKe|\x8A@".unpack1('D').to_s.should == "847.54946"
"/\xDD$\x06\x81u8@".unpack1('D').to_s.should == "24.459"
"E\xD8\xF0\xF4JY\xF0?".unpack1('D').to_s.should == "1.0218"
"[\brP\xC2\xCC\x05@".unpack1('D').to_s.should == "2.72498"
"\xE6w\x9A\xCCx\xF6T@".unpack1('D').to_s.should == "83.851123"
"\xB4\xD4&\xC0C\xFD.@".unpack1('D').to_s.should == "15.494657521"
"\xCD\xCC\xCC\xCC\xCCLM@".unpack1('D').to_s.should == "58.6"
"\xA1\x84\x99\xB6\x7F\xE5\x13@".unpack1('D').to_s.should == "4.97412"
"\xD7\xA3p=\n\x9C\x80@".unpack1('D').to_s.should == "531.505"
"S\x96!\x8E\xF5\x0E\x8F@".unpack1('D').to_s.should == "993.8699"
"\xF1F\xE6\x91?\x18\xD7?".unpack1('D').to_s.should == "0.360855"
"=\n\xD7\xA3p=\x15@".unpack1('D').to_s.should == "5.31"
"\x90Ci\x147\xC74@".unpack1('D').to_s.should == "20.7781842"
"A\ft\xED\v\xE8\xB9?".unpack1('D').to_s.should == "0.101197"
"\x9A\x99\x99\x99\x999T@".unpack1('D').to_s.should == "80.9"
"\x00\x00\x00\x00\x00\x00\x1A@".unpack1('D').to_s.should == "6.5"
"\xD3J\xC6\xD6\x98\x8Es@".unpack1('D').to_s.should == "312.9123142"
"SQ\xE5I\fQ\x1E@".unpack1('D').to_s.should == "7.57914844"
"k]Q\xE7\xDDb\x1E@".unpack1('D').to_s.should == "7.59654962"
"\x1F\x85\xEBQ\xB8\xEAz@".unpack1('D').to_s.should == "430.67"
"\x00\x00\x00\x00\x00\x00\x14@".unpack1('D').to_s.should == "5.0"
"{\x14\xAEG\xE1\n}@".unpack1('D').to_s.should == "464.68"
"\x12\x83\xC0\xCA\xA1=V@".unpack1('D').to_s.should == "88.963"
"\x9Aw\x9C\xA2#y\e@".unpack1('D').to_s.should == "6.8683"
"(\x0F\v\xB5\xA6y\xFB?".unpack1('D').to_s.should == "1.7172"
"\xD5x\xE9&1H!@".unpack1('D').to_s.should == "8.641"
"w'Deh\x1Ab@".unpack1('D').to_s.should == "144.8252436"
":X\xFF\xE70_\x04@".unpack1('D').to_s.should == "2.54648"
"E4\xB2\x12\x90\xCA\x1E@".unpack1('D').to_s.should == "7.69781522"
"fffff\xAA\x80@".unpack1('D').to_s.should == "533.3"
"\xCD\x92\x005\xB5p:@".unpack1('D').to_s.should == "26.440265"
"\xBE\x1D<nS\x7F\x19@".unpack1('D').to_s.should == "6.3743417"
"R\xB8\x1E\x85\xEBYb@".unpack1('D').to_s.should == "146.81"
"\x02\x87\xAB^\xD9\xC0\xF4?".unpack1('D').to_s.should == "1.2970823"
"\x00\x00\x00\x00\x00\x00\"@".unpack1('D').to_s.should == "9.0"
"Zd;\xDFO3\x84@".unpack1('D').to_s.should == "646.414"
"\x9A\x99\x99\x99\x99\x99\t@".unpack1('D').to_s.should == "3.2"
"\xCD#\x7F0\xF0\xE5i@".unpack1('D').to_s.should == "207.18557"
"\xBE\x9F\x1A/\xDD$\xF2?".unpack1('D').to_s.should == "1.134"
"\xEE|?5^\xBA\xF3?".unpack1('D').to_s.should == "1.233"
"\xB4\xB7\xFE\xD7\x05\x03i@".unpack1('D').to_s.should == "200.094463346"
"N\x95\xD6|\xE8HG@".unpack1('D').to_s.should == "46.56959496"
"Y\x868\xD6\xC5-!@".unpack1('D').to_s.should == "8.5894"
"myE\xED\a;\x12@".unpack1('D').to_s.should == "4.557647426"
"\xA7s\xEAo\xAE\x96B@".unpack1('D').to_s.should == "37.1771984"
"\x14\x7Fo.\x99\x11|@".unpack1('D').to_s.should == "449.0998978"
"\xB2\x9EZ}u\x89;@".unpack1('D').to_s.should == "27.536949"
"\xD7\xA3p=\nwY@".unpack1('D').to_s.should == "101.86"
"\xF3\xE6p\xAD\xF6\xC3x@".unpack1('D').to_s.should == "396.247724"
end
end
it "random values from divisions" do
(1.0 / 7).to_s.should == "0.14285714285714285"
# 50.times do
# a = rand(10)
# b = rand(10)
# c = rand(10)
# d = rand(10)
# expression = "#{a}.#{b} / #{c}.#{d}"
# puts " (#{expression}).to_s.should == #{eval(expression).to_s.inspect}"
# end
(1.1 / 7.1).to_s.should == "0.15492957746478875"
(6.5 / 8.8).to_s.should == "0.7386363636363635"
(4.8 / 4.3).to_s.should == "1.1162790697674418"
(4.0 / 1.9).to_s.should == "2.1052631578947367"
(9.1 / 0.8).to_s.should == "11.374999999999998"
(5.3 / 7.5).to_s.should == "0.7066666666666667"
(2.8 / 1.8).to_s.should == "1.5555555555555554"
(2.1 / 2.5).to_s.should == "0.8400000000000001"
(3.5 / 6.0).to_s.should == "0.5833333333333334"
(4.6 / 0.3).to_s.should == "15.333333333333332"
(0.6 / 2.4).to_s.should == "0.25"
(1.3 / 9.1).to_s.should == "0.14285714285714288"
(0.3 / 5.0).to_s.should == "0.06"
(5.0 / 4.2).to_s.should == "1.1904761904761905"
(3.0 / 2.0).to_s.should == "1.5"
(6.3 / 2.0).to_s.should == "3.15"
(5.4 / 6.0).to_s.should == "0.9"
(9.6 / 8.1).to_s.should == "1.1851851851851851"
(8.7 / 1.6).to_s.should == "5.437499999999999"
(1.9 / 7.8).to_s.should == "0.24358974358974358"
(0.5 / 2.1).to_s.should == "0.23809523809523808"
(9.3 / 5.8).to_s.should == "1.6034482758620692"
(2.7 / 8.0).to_s.should == "0.3375"
(9.7 / 7.8).to_s.should == "1.2435897435897436"
(8.1 / 2.4).to_s.should == "3.375"
(7.7 / 2.7).to_s.should == "2.8518518518518516"
(7.9 / 1.7).to_s.should == "4.647058823529412"
(6.5 / 8.2).to_s.should == "0.7926829268292683"
(7.8 / 9.6).to_s.should == "0.8125"
(2.2 / 4.6).to_s.should == "0.47826086956521746"
(0.0 / 1.0).to_s.should == "0.0"
(8.3 / 2.9).to_s.should == "2.8620689655172415"
(3.1 / 6.1).to_s.should == "0.5081967213114754"
(2.8 / 7.8).to_s.should == "0.358974358974359"
(8.0 / 0.1).to_s.should == "80.0"
(1.7 / 6.4).to_s.should == "0.265625"
(1.8 / 5.4).to_s.should == "0.3333333333333333"
(8.0 / 5.8).to_s.should == "1.3793103448275863"
(5.2 / 4.1).to_s.should == "1.2682926829268295"
(9.8 / 5.8).to_s.should == "1.6896551724137934"
(5.4 / 9.5).to_s.should == "0.5684210526315789"
(8.4 / 4.9).to_s.should == "1.7142857142857142"
(1.7 / 3.5).to_s.should == "0.4857142857142857"
(1.2 / 5.1).to_s.should == "0.23529411764705882"
(1.4 / 2.0).to_s.should == "0.7"
(4.8 / 8.0).to_s.should == "0.6"
(9.0 / 2.5).to_s.should == "3.6"
(0.2 / 0.6).to_s.should == "0.33333333333333337"
(7.8 / 5.2).to_s.should == "1.5"
(9.5 / 5.5).to_s.should == "1.7272727272727273"
end
end
end end
with_feature :encoding do with_feature :encoding do

View file

@ -1,4 +1,6 @@
describe :hash_each, shared: true do describe :hash_each, shared: true do
# This is inconsistent with below, MRI checks the block arity in rb_hash_each_pair()
it "yields a [[key, value]] Array for each pair to a block expecting |*args|" do it "yields a [[key, value]] Array for each pair to a block expecting |*args|" do
all_args = [] all_args = []
{ 1 => 2, 3 => 4 }.send(@method) { |*args| all_args << args } { 1 => 2, 3 => 4 }.send(@method) { |*args| all_args << args }
@ -19,6 +21,21 @@ describe :hash_each, shared: true do
ary.sort.should == ["a", "b", "c"] ary.sort.should == ["a", "b", "c"]
end end
it "yields 2 values and not an Array of 2 elements" do
obj = Object.new
def obj.foo(key, value)
ScratchPad << key << value
end
ScratchPad.record([])
{ "a" => 1 }.send(@method, &obj.method(:foo))
ScratchPad.recorded.should == ["a", 1]
ScratchPad.record([])
{ "a" => 1 }.send(@method, &-> key, value { ScratchPad << key << value })
ScratchPad.recorded.should == ["a", 1]
end
it "uses the same order as keys() and values()" do it "uses the same order as keys() and values()" do
h = { a: 1, b: 2, c: 3, d: 5 } h = { a: 1, b: 2, c: 3, d: 5 }
keys = [] keys = []

View file

@ -77,6 +77,13 @@ describe "IO#read_nonblock" do
buffer.should == "1" buffer.should == "1"
end end
it "returns the passed buffer" do
buffer = ""
@write.write("1")
output = @read.read_nonblock(1, buffer)
output.should equal(buffer)
end
it "raises IOError on closed stream" do it "raises IOError on closed stream" do
lambda { IOSpecs.closed_io.read_nonblock(5) }.should raise_error(IOError) lambda { IOSpecs.closed_io.read_nonblock(5) }.should raise_error(IOError)
end end

View file

@ -0,0 +1,11 @@
require_relative '../../spec_helper'
ruby_version_is "2.5" do
describe "Kernel#pp" do
it "lazily loads the 'pp' library and delegates the call to that library" do
# Run in child process to ensure 'pp' hasn't been loaded yet.
output = ruby_exe("pp [1, 2, 3]")
output.should == "[1, 2, 3]\n"
end
end
end

View file

@ -6,16 +6,20 @@ describe "Kernel#sleep" do
Kernel.should have_private_instance_method(:sleep) Kernel.should have_private_instance_method(:sleep)
end end
it "returns an Integer" do
sleep(0.001).should be_kind_of(Integer)
end
it "accepts a Float" do it "accepts a Float" do
sleep(0.1).should be_close(0, 2) sleep(0.001).should >= 0
end end
it "accepts a Fixnum" do it "accepts a Fixnum" do
sleep(0).should be_close(0, 2) sleep(0).should >= 0
end end
it "accepts a Rational" do it "accepts a Rational" do
sleep(Rational(1, 9)).should be_close(0, 2) sleep(Rational(1, 999)).should >= 0
end end
it "raises an ArgumentError when passed a negative duration" do it "raises an ArgumentError when passed a negative duration" do

View file

@ -241,4 +241,19 @@ describe "Method#parameters" do
m = MethodSpecs::Methods.new m = MethodSpecs::Methods.new
m.method(:writer=).parameters.should == [[:req]] m.method(:writer=).parameters.should == [[:req]]
end end
it "returns [[:rest]] for core methods with variable-length argument lists" do
m = "foo"
# match takes rest args
m.method(:match).parameters.should == [[:rest]]
# [] takes 1 to 3 args
m.method(:[]).parameters.should == [[:rest]]
end
it "returns [[:req]] for each parameter for core methods with fixed-length argument lists" do
m = "foo"
m.method(:+).parameters.should == [[:req]]
end
end end

View file

@ -90,4 +90,15 @@ describe "Method#to_proc" do
array.each(&obj) array.each(&obj)
ScratchPad.recorded.should == [[1, 2]] ScratchPad.recorded.should == [[1, 2]]
end end
it "returns a proc that properly invokes module methods with super" do
m1 = Module.new { def foo(ary); ary << :m1; end; }
m2 = Module.new { def foo(ary = []); super(ary); ary << :m2; end; }
c2 = Class.new do
include m1
include m2
end
c2.new.method(:foo).to_proc.call.should == %i[m1 m2]
end
end end

View file

@ -16,17 +16,28 @@ end
describe "Module#autoload" do describe "Module#autoload" do
before :all do before :all do
@non_existent = fixture __FILE__, "no_autoload.rb" @non_existent = fixture __FILE__, "no_autoload.rb"
# Require RubyGems eagerly, to ensure #require is already the RubyGems
# version, before starting #autoload specs which snapshot #require, and
# could end up redefining #require as the original core Kernel#require.
begin
require "rubygems"
rescue LoadError
end
end end
before :each do before :each do
@loaded_features = $".dup @loaded_features = $".dup
@frozen_module = Module.new.freeze
ScratchPad.clear ScratchPad.clear
@remove = []
end end
after :each do after :each do
$".replace @loaded_features $".replace @loaded_features
@remove.each { |const|
ModuleSpecs::Autoload.send :remove_const, const
}
end end
it "registers a file to load the first time the named constant is accessed" do it "registers a file to load the first time the named constant is accessed" do
@ -39,16 +50,29 @@ describe "Module#autoload" do
ModuleSpecs::Autoload.should have_constant(:B) ModuleSpecs::Autoload.should have_constant(:B)
end end
it "can be overridden with a second autoload on the same constant" do
ModuleSpecs::Autoload.autoload :Overridden, @non_existent
@remove << :Overridden
ModuleSpecs::Autoload.autoload?(:Overridden).should == @non_existent
path = fixture(__FILE__, "autoload_overridden.rb")
ModuleSpecs::Autoload.autoload :Overridden, path
ModuleSpecs::Autoload.autoload?(:Overridden).should == path
ModuleSpecs::Autoload::Overridden.should == :overridden
end
it "loads the registered constant when it is accessed" do it "loads the registered constant when it is accessed" do
ModuleSpecs::Autoload.should_not have_constant(:X) ModuleSpecs::Autoload.should_not have_constant(:X)
ModuleSpecs::Autoload.autoload :X, fixture(__FILE__, "autoload_x.rb") ModuleSpecs::Autoload.autoload :X, fixture(__FILE__, "autoload_x.rb")
@remove << :X
ModuleSpecs::Autoload::X.should == :x ModuleSpecs::Autoload::X.should == :x
ModuleSpecs::Autoload.send(:remove_const, :X)
end end
it "loads the registered constant into a dynamically created class" do it "loads the registered constant into a dynamically created class" do
cls = Class.new { autoload :C, fixture(__FILE__, "autoload_c.rb") } cls = Class.new { autoload :C, fixture(__FILE__, "autoload_c.rb") }
ModuleSpecs::Autoload::DynClass = cls ModuleSpecs::Autoload::DynClass = cls
@remove << :DynClass
ScratchPad.recorded.should be_nil ScratchPad.recorded.should be_nil
ModuleSpecs::Autoload::DynClass::C.new.loaded.should == :dynclass_c ModuleSpecs::Autoload::DynClass::C.new.loaded.should == :dynclass_c
@ -58,6 +82,7 @@ describe "Module#autoload" do
it "loads the registered constant into a dynamically created module" do it "loads the registered constant into a dynamically created module" do
mod = Module.new { autoload :D, fixture(__FILE__, "autoload_d.rb") } mod = Module.new { autoload :D, fixture(__FILE__, "autoload_d.rb") }
ModuleSpecs::Autoload::DynModule = mod ModuleSpecs::Autoload::DynModule = mod
@remove << :DynModule
ScratchPad.recorded.should be_nil ScratchPad.recorded.should be_nil
ModuleSpecs::Autoload::DynModule::D.new.loaded.should == :dynmodule_d ModuleSpecs::Autoload::DynModule::D.new.loaded.should == :dynmodule_d
@ -95,6 +120,7 @@ describe "Module#autoload" do
it "does not load the file when the constant is already set" do it "does not load the file when the constant is already set" do
ModuleSpecs::Autoload.autoload :I, fixture(__FILE__, "autoload_i.rb") ModuleSpecs::Autoload.autoload :I, fixture(__FILE__, "autoload_i.rb")
@remove << :I
ModuleSpecs::Autoload.const_set :I, 3 ModuleSpecs::Autoload.const_set :I, 3
ModuleSpecs::Autoload::I.should == 3 ModuleSpecs::Autoload::I.should == 3
ScratchPad.recorded.should be_nil ScratchPad.recorded.should be_nil
@ -116,6 +142,7 @@ describe "Module#autoload" do
it "does not load the file if the file is manually required" do it "does not load the file if the file is manually required" do
filename = fixture(__FILE__, "autoload_k.rb") filename = fixture(__FILE__, "autoload_k.rb")
ModuleSpecs::Autoload.autoload :KHash, filename ModuleSpecs::Autoload.autoload :KHash, filename
@remove << :KHash
require filename require filename
ScratchPad.recorded.should == :loaded ScratchPad.recorded.should == :loaded
@ -135,8 +162,8 @@ describe "Module#autoload" do
ScratchPad.clear ScratchPad.clear
ModuleSpecs::Autoload.autoload :S, filename ModuleSpecs::Autoload.autoload :S, filename
@remove << :S
ModuleSpecs::Autoload.autoload?(:S).should be_nil ModuleSpecs::Autoload.autoload?(:S).should be_nil
ModuleSpecs::Autoload.send(:remove_const, :S)
end end
it "retains the autoload even if the request to require fails" do it "retains the autoload even if the request to require fails" do
@ -182,11 +209,10 @@ describe "Module#autoload" do
module ModuleSpecs::Autoload module ModuleSpecs::Autoload
autoload :GoodParent, fixture(__FILE__, "autoload_nested.rb") autoload :GoodParent, fixture(__FILE__, "autoload_nested.rb")
end end
@remove << :GoodParent
defined?(ModuleSpecs::Autoload::GoodParent::Nested).should == 'constant' defined?(ModuleSpecs::Autoload::GoodParent::Nested).should == 'constant'
ScratchPad.recorded.should == :loaded ScratchPad.recorded.should == :loaded
ModuleSpecs::Autoload.send(:remove_const, :GoodParent)
end end
it "returns nil when it fails to load an autoloaded parent when referencing a nested constant" do it "returns nil when it fails to load an autoloaded parent when referencing a nested constant" do
@ -199,11 +225,12 @@ describe "Module#autoload" do
end end
end end
describe "the autoload is removed when the same file is required directly without autoload" do describe "the autoload is triggered when the same file is required directly" do
before :each do before :each do
module ModuleSpecs::Autoload module ModuleSpecs::Autoload
autoload :RequiredDirectly, fixture(__FILE__, "autoload_required_directly.rb") autoload :RequiredDirectly, fixture(__FILE__, "autoload_required_directly.rb")
end end
@remove << :RequiredDirectly
@path = fixture(__FILE__, "autoload_required_directly.rb") @path = fixture(__FILE__, "autoload_required_directly.rb")
@check = -> { @check = -> {
[ [
@ -214,10 +241,6 @@ describe "Module#autoload" do
ScratchPad.record @check ScratchPad.record @check
end end
after :each do
ModuleSpecs::Autoload.send(:remove_const, :RequiredDirectly)
end
it "with a full path" do it "with a full path" do
@check.call.should == ["constant", @path] @check.call.should == ["constant", @path]
require @path require @path
@ -242,7 +265,7 @@ describe "Module#autoload" do
nested_require = -> { nested_require = -> {
result = nil result = nil
ScratchPad.record -> { ScratchPad.record -> {
result = [@check.call, Thread.new { @check.call }.value] result = @check.call
} }
require nested require nested
result result
@ -251,24 +274,41 @@ describe "Module#autoload" do
@check.call.should == ["constant", @path] @check.call.should == ["constant", @path]
require @path require @path
cur, other = ScratchPad.recorded ScratchPad.recorded.should == [nil, nil]
cur.should == [nil, nil]
other.should == [nil, nil]
@check.call.should == ["constant", nil] @check.call.should == ["constant", nil]
end end
end end
describe "after the autoload is triggered by require" do
before :each do
@path = tmp("autoload.rb")
end
after :each do
rm_r @path
end
it "the mapping feature to autoload is removed, and a new autoload with the same path is considered" do
ModuleSpecs::Autoload.autoload :RequireMapping1, @path
touch(@path) { |f| f.puts "ModuleSpecs::Autoload::RequireMapping1 = 1" }
ModuleSpecs::Autoload::RequireMapping1.should == 1
$LOADED_FEATURES.delete(@path)
ModuleSpecs::Autoload.autoload :RequireMapping2, @path[0...-3]
@remove << :RequireMapping2
touch(@path) { |f| f.puts "ModuleSpecs::Autoload::RequireMapping2 = 2" }
ModuleSpecs::Autoload::RequireMapping2.should == 2
end
end
describe "during the autoload before the constant is assigned" do describe "during the autoload before the constant is assigned" do
before :each do before :each do
@path = fixture(__FILE__, "autoload_during_autoload.rb") @path = fixture(__FILE__, "autoload_during_autoload.rb")
ModuleSpecs::Autoload.autoload :DuringAutoload, @path ModuleSpecs::Autoload.autoload :DuringAutoload, @path
@remove << :DuringAutoload
raise unless ModuleSpecs::Autoload.autoload?(:DuringAutoload) == @path raise unless ModuleSpecs::Autoload.autoload?(:DuringAutoload) == @path
end end
after :each do
ModuleSpecs::Autoload.send(:remove_const, :DuringAutoload)
end
def check_before_during_thread_after(&check) def check_before_during_thread_after(&check)
before = check.call before = check.call
to_autoload_thread, from_autoload_thread = Queue.new, Queue.new to_autoload_thread, from_autoload_thread = Queue.new, Queue.new
@ -419,6 +459,7 @@ describe "Module#autoload" do
X = get_value X = get_value
end end
end end
@remove << :U
ModuleSpecs::Autoload::U::V::X.should == :autoload_uvx ModuleSpecs::Autoload::U::V::X.should == :autoload_uvx
end end
@ -474,6 +515,7 @@ describe "Module#autoload" do
end end
it "and fails when finding the undefined autoload constant in the the current scope when declared in current and defined in parent" do it "and fails when finding the undefined autoload constant in the the current scope when declared in current and defined in parent" do
@remove << :DeclaredInCurrentDefinedInParent
module ModuleSpecs::Autoload module ModuleSpecs::Autoload
ScratchPad.record -> { ScratchPad.record -> {
DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
@ -494,6 +536,7 @@ describe "Module#autoload" do
end end
it "in the included modules" do it "in the included modules" do
@remove << :DefinedInIncludedModule
module ModuleSpecs::Autoload module ModuleSpecs::Autoload
ScratchPad.record -> { ScratchPad.record -> {
module DefinedInIncludedModule module DefinedInIncludedModule
@ -507,6 +550,7 @@ describe "Module#autoload" do
end end
it "in the included modules of the superclass" do it "in the included modules of the superclass" do
@remove << :DefinedInSuperclassIncludedModule
module ModuleSpecs::Autoload module ModuleSpecs::Autoload
class LookupAfterAutoloadSuper class LookupAfterAutoloadSuper
end end
@ -528,6 +572,7 @@ describe "Module#autoload" do
end end
it "in the prepended modules" do it "in the prepended modules" do
@remove << :DefinedInPrependedModule
module ModuleSpecs::Autoload module ModuleSpecs::Autoload
ScratchPad.record -> { ScratchPad.record -> {
module DefinedInPrependedModule module DefinedInPrependedModule
@ -567,10 +612,10 @@ describe "Module#autoload" do
end end
end end
end end
@remove << :W
ModuleSpecs::Autoload::W::Y.should be_kind_of(Class) ModuleSpecs::Autoload::W::Y.should be_kind_of(Class)
ScratchPad.recorded.should == :loaded ScratchPad.recorded.should == :loaded
ModuleSpecs::Autoload::W.send(:remove_const, :Y)
end end
it "does not call #require a second time and does not warn if already loading the same feature with #require" do it "does not call #require a second time and does not warn if already loading the same feature with #require" do
@ -611,6 +656,7 @@ describe "Module#autoload" do
it "shares the autoload request across dup'ed copies of modules" do it "shares the autoload request across dup'ed copies of modules" do
require fixture(__FILE__, "autoload_s.rb") require fixture(__FILE__, "autoload_s.rb")
@remove << :S
filename = fixture(__FILE__, "autoload_t.rb") filename = fixture(__FILE__, "autoload_t.rb")
mod1 = Module.new { autoload :T, filename } mod1 = Module.new { autoload :T, filename }
lambda { lambda {
@ -651,8 +697,9 @@ describe "Module#autoload" do
describe "on a frozen module" do describe "on a frozen module" do
it "raises a #{frozen_error_class} before setting the name" do it "raises a #{frozen_error_class} before setting the name" do
lambda { @frozen_module.autoload :Foo, @non_existent }.should raise_error(frozen_error_class) frozen_module = Module.new.freeze
@frozen_module.should_not have_constant(:Foo) lambda { frozen_module.autoload :Foo, @non_existent }.should raise_error(frozen_error_class)
frozen_module.should_not have_constant(:Foo)
end end
end end
@ -675,6 +722,7 @@ describe "Module#autoload" do
describe "(concurrently)" do describe "(concurrently)" do
it "blocks a second thread while a first is doing the autoload" do it "blocks a second thread while a first is doing the autoload" do
ModuleSpecs::Autoload.autoload :Concur, fixture(__FILE__, "autoload_concur.rb") ModuleSpecs::Autoload.autoload :Concur, fixture(__FILE__, "autoload_concur.rb")
@remove << :Concur
start = false start = false
@ -717,8 +765,6 @@ describe "Module#autoload" do
t2_val.should == t1_val t2_val.should == t1_val
t2_exc.should be_nil t2_exc.should be_nil
ModuleSpecs::Autoload.send(:remove_const, :Concur)
end end
# https://bugs.ruby-lang.org/issues/10892 # https://bugs.ruby-lang.org/issues/10892

View file

@ -72,6 +72,53 @@ describe "Module#const_set" do
lambda { ConstantSpecs.const_set name, 1 }.should raise_error(TypeError) lambda { ConstantSpecs.const_set name, 1 }.should raise_error(TypeError)
end end
describe "when overwriting an existing constant" do
it "warns if the previous value was a normal value" do
mod = Module.new
mod.const_set :Foo, 42
-> {
mod.const_set :Foo, 1
}.should complain(/already initialized constant/)
mod.const_get(:Foo).should == 1
end
it "does not warn if the previous value was an autoload" do
mod = Module.new
mod.autoload :Foo, "not-existing"
-> {
mod.const_set :Foo, 1
}.should_not complain
mod.const_get(:Foo).should == 1
end
it "does not warn if the previous value was undefined" do
path = fixture(__FILE__, "autoload_o.rb")
ScratchPad.record []
mod = Module.new
mod.autoload :Foo, path
-> { mod::Foo }.should raise_error(NameError)
mod.should have_constant(:Foo)
mod.const_defined?(:Foo).should == false
mod.autoload?(:Foo).should == nil
-> {
mod.const_set :Foo, 1
}.should_not complain
mod.const_get(:Foo).should == 1
end
it "does not warn if the new value is an autoload" do
mod = Module.new
mod.const_set :Foo, 42
-> {
mod.autoload :Foo, "not-existing"
}.should_not complain
mod.const_get(:Foo).should == 42
end
end
describe "on a frozen module" do describe "on a frozen module" do
before :each do before :each do
@frozen = Module.new.freeze @frozen = Module.new.freeze

View file

@ -0,0 +1,3 @@
module ModuleSpecs::Autoload
Overridden = :overridden
end

View file

@ -47,4 +47,11 @@ describe "String#end_with?" do
"céréale".end_with?("réale").should be_true "céréale".end_with?("réale").should be_true
end end
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
pat = "".encode Encoding::EUC_JP
lambda do
"あれ".end_with?(pat)
end.should raise_error(Encoding::CompatibilityError)
end
end end

View file

@ -489,4 +489,12 @@ describe "String#inspect" do
].should be_computed_by(:inspect) ].should be_computed_by(:inspect)
end end
end end
describe "when the string's encoding is different than the result's encoding" do
describe "and the string's encoding is ASCII-compatible but the characters are non-ASCII" do
it "returns a string with the non-ASCII characters replaced by \\x notation" do
"\u{3042}".encode("EUC-JP").inspect.should == '"\\x{A4A2}"'
end
end
end
end end

View file

@ -35,8 +35,21 @@ describe "Thread.list" do
t.join t.join
end end
end end
it "returns instances of Thread and not null or nil values" do
spawner = Thread.new do
Array.new(100) do
Thread.new {}
end
end end
describe "Thread.list" do while spawner.alive?
it "needs to be reviewed for spec completeness" Thread.list.each { |th|
th.should be_kind_of(Thread)
}
end
threads = spawner.value
threads.each(&:join)
end
end end

View file

@ -2,7 +2,8 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes' require_relative 'fixtures/classes'
ruby_version_is "2.6" do ruby_version_is "2.6" do
describe "#eval_script" do describe "TracePoint#eval_script" do
it "is the evald source code" do
ScratchPad.record [] ScratchPad.record []
script = <<-CODE script = <<-CODE
@ -20,3 +21,4 @@ ruby_version_is "2.6" do
ScratchPad.recorded.should == [script] ScratchPad.recorded.should == [script]
end end
end end
end

View file

@ -2,7 +2,8 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes' require_relative 'fixtures/classes'
ruby_version_is "2.6" do ruby_version_is "2.6" do
describe "#instruction_sequence" do describe "TracePoint#instruction_sequence" do
it "is an instruction sequence" do
ScratchPad.record [] ScratchPad.record []
script = <<-CODE script = <<-CODE
@ -21,3 +22,4 @@ ruby_version_is "2.6" do
ScratchPad.recorded[0].class.should == RubyVM::InstructionSequence ScratchPad.recorded[0].class.should == RubyVM::InstructionSequence
end end
end end
end

View file

@ -244,3 +244,15 @@ describe "The alias keyword" do
} }
end end
end end
describe "The alias keyword" do
it "can create a new global variable, synonym of the original" do
code = '$a = 1; alias $b $a; p [$a, $b]; $b = 2; p [$a, $b]'
ruby_exe(code).should == "[1, 1]\n[2, 2]\n"
end
it "can override an existing global variable and make them synonyms" do
code = '$a = 1; $b = 2; alias $b $a; p [$a, $b]; $b = 3; p [$a, $b]'
ruby_exe(code).should == "[1, 1]\n[3, 3]\n"
end
end

View file

@ -0,0 +1,15 @@
module ForSpecs
class ForInClassMethod
m = :same_variable_set_outside
def self.foo
all = []
for m in [:bar, :baz]
all << m
end
all
end
READER = -> { m }
end
end

View file

@ -1,4 +1,5 @@
require_relative '../spec_helper' require_relative '../spec_helper'
require_relative 'fixtures/for_scope'
# for name[, name]... in expr [do] # for name[, name]... in expr [do]
# body # body
@ -130,6 +131,11 @@ describe "The for expression" do
a.should == 123 a.should == 123
end end
it "does not try to access variables outside the method" do
ForSpecs::ForInClassMethod.foo.should == [:bar, :baz]
ForSpecs::ForInClassMethod::READER.call.should == :same_variable_set_outside
end
it "returns expr" do it "returns expr" do
for i in 1..3; end.should == (1..3) for i in 1..3; end.should == (1..3)
for i,j in { 1 => 10, 2 => 20 }; end.should == { 1 => 10, 2 => 20 } for i,j in { 1 => 10, 2 => 20 }; end.should == { 1 => 10, 2 => 20 }

View file

@ -574,6 +574,7 @@ describe "A method" do
m(a: 1, b: 2).should == { a: 1, b: 2 } m(a: 1, b: 2).should == { a: 1, b: 2 }
m(*[]).should == {} m(*[]).should == {}
m(**{}).should == {} m(**{}).should == {}
m(**{a: 1, b: 2}, **{a: 4, c: 7}).should == { a: 4, b: 2, c: 7 }
lambda { m(2) }.should raise_error(ArgumentError) lambda { m(2) }.should raise_error(ArgumentError)
end end

View file

@ -73,6 +73,14 @@ describe "BigDecimal#add" do
# BigDecimal("0.88").add(0.0, 1).should == BigDecimal("0.9") # BigDecimal("0.88").add(0.0, 1).should == BigDecimal("0.9")
# end # end
describe "with Object" do
it "tries to coerce the other operand to self" do
object = mock("Object")
object.should_receive(:coerce).with(@frac_3).and_return([@frac_3, @frac_4])
@frac_3.add(object, 1).should == BigDecimal("0.1E16")
end
end
it "favors the precision specified in the second argument over the global limit" do it "favors the precision specified in the second argument over the global limit" do
BigDecimalSpecs.with_limit(1) do BigDecimalSpecs.with_limit(1) do
BigDecimal('0.888').add(@zero, 3).should == BigDecimal('0.888') BigDecimal('0.888').add(@zero, 3).should == BigDecimal('0.888')

View file

@ -42,6 +42,14 @@ describe "BigDecimal#div" do
} }
end end
describe "with Object" do
it "tries to coerce the other operand to self" do
object = mock("Object")
object.should_receive(:coerce).with(@one).and_return([@one, @two])
@one.div(object).should == @zero
end
end
it "raises FloatDomainError if NaN is involved" do it "raises FloatDomainError if NaN is involved" do
lambda { @one.div(@nan) }.should raise_error(FloatDomainError) lambda { @one.div(@nan) }.should raise_error(FloatDomainError)
lambda { @nan.div(@one) }.should raise_error(FloatDomainError) lambda { @nan.div(@one) }.should raise_error(FloatDomainError)

View file

@ -9,7 +9,8 @@ end
describe "BigDecimal#mult" do describe "BigDecimal#mult" do
before :each do before :each do
@one = BigDecimal "1" @one = BigDecimal "1"
@e3_minus = BigDecimal "3E-20001" @e3_minus = BigDecimal("3E-20001")
@e3_plus = BigDecimal("3E20001")
@e = BigDecimal "1.00000000000000000000123456789" @e = BigDecimal "1.00000000000000000000123456789"
@tolerance = @e.sub @one, 1000 @tolerance = @e.sub @one, 1000
@tolerance2 = BigDecimal "30001E-20005" @tolerance2 = BigDecimal "30001E-20005"
@ -21,4 +22,11 @@ describe "BigDecimal#mult" do
@e3_minus.mult(@one, 1).should be_close(0, @tolerance2) @e3_minus.mult(@one, 1).should be_close(0, @tolerance2)
end end
describe "with Object" do
it "tries to coerce the other operand to self" do
object = mock("Object")
object.should_receive(:coerce).with(@e3_minus).and_return([@e3_minus, @e3_plus])
@e3_minus.mult(object, 1).should == BigDecimal("9")
end
end
end end

View file

@ -23,4 +23,12 @@ describe "BigDecimal#*" do
(@e3_minus * @e3_minus).should == BigDecimal("9E-40002") (@e3_minus * @e3_minus).should == BigDecimal("9E-40002")
(@e * @one).should == @e (@e * @one).should == @e
end end
describe "with Object" do
it "tries to coerce the other operand to self" do
object = mock("Object")
object.should_receive(:coerce).with(@e3_minus).and_return([@e3_minus, @e3_plus])
(@e3_minus * object).should == BigDecimal("9")
end
end
end end

View file

@ -5,7 +5,8 @@ describe "BigDecimal#remainder" do
before :each do before :each do
@zero = BigDecimal("0") @zero = BigDecimal("0")
@one = BigDecimal("0") @one = BigDecimal("1")
@three = BigDecimal("3")
@mixed = BigDecimal("1.23456789") @mixed = BigDecimal("1.23456789")
@pos_int = BigDecimal("2E5555") @pos_int = BigDecimal("2E5555")
@neg_int = BigDecimal("-2E5555") @neg_int = BigDecimal("-2E5555")
@ -71,9 +72,16 @@ describe "BigDecimal#remainder" do
end end
it "coerces arguments to BigDecimal if possible" do it "coerces arguments to BigDecimal if possible" do
@one.remainder(2).should == @one @three.remainder(2).should == @one
end end
describe "with Object" do
it "tries to coerce the other operand to self" do
object = mock("Object")
object.should_receive(:coerce).with(@three).and_return([@three, 2])
@three.remainder(object).should == @one
end
end
it "raises TypeError if the argument cannot be coerced to BigDecimal" do it "raises TypeError if the argument cannot be coerced to BigDecimal" do
lambda { lambda {

View file

@ -70,6 +70,15 @@ describe :bigdecimal_modulo, shared: true do
res.kind_of?(BigDecimal).should == true res.kind_of?(BigDecimal).should == true
end end
describe "with Object" do
it "tries to coerce the other operand to self" do
bd6543 = BigDecimal("6543.21")
object = mock("Object")
object.should_receive(:coerce).with(bd6543).and_return([bd6543, 137])
bd6543.send(@method, object, *@object).should == BigDecimal("104.21")
end
end
it "returns NaN if NaN is involved" do it "returns NaN if NaN is involved" do
@nan.send(@method, @nan).nan?.should == true @nan.send(@method, @nan).nan?.should == true
@nan.send(@method, @one).nan?.should == true @nan.send(@method, @one).nan?.should == true

View file

@ -29,6 +29,14 @@ describe :bigdecimal_quo, shared: true do
@one.send(@method, BigDecimal('2E-5555'), *@object).should == BigDecimal('0.5E5555') @one.send(@method, BigDecimal('2E-5555'), *@object).should == BigDecimal('0.5E5555')
end end
describe "with Object" do
it "tries to coerce the other operand to self" do
object = mock("Object")
object.should_receive(:coerce).with(@one).and_return([@one, @two])
@one.send(@method, object, *@object).should == BigDecimal("0.5")
end
end
it "returns 0 if divided by Infinity" do it "returns 0 if divided by Infinity" do
@zero.send(@method, @infinity, *@object).should == 0 @zero.send(@method, @infinity, *@object).should == 0
@frac_2.send(@method, @infinity, *@object).should == 0 @frac_2.send(@method, @infinity, *@object).should == 0

View file

@ -13,6 +13,8 @@ describe "BigDecimal#sub" do
@one_minus = BigDecimal("-1") @one_minus = BigDecimal("-1")
@frac_1 = BigDecimal("1E-99999") @frac_1 = BigDecimal("1E-99999")
@frac_2 = BigDecimal("0.9E-99999") @frac_2 = BigDecimal("0.9E-99999")
@frac_3 = BigDecimal("12345E10")
@frac_4 = BigDecimal("98765E10")
end end
it "returns a - b with given precision" do it "returns a - b with given precision" do
@ -32,6 +34,14 @@ describe "BigDecimal#sub" do
@frac_1.sub(@frac_1, 1000000).should == @zero @frac_1.sub(@frac_1, 1000000).should == @zero
end end
describe "with Object" do
it "tries to coerce the other operand to self" do
object = mock("Object")
object.should_receive(:coerce).with(@frac_3).and_return([@frac_3, @frac_4])
@frac_3.sub(object, 1).should == BigDecimal("-0.9E15")
end
end
it "returns NaN if NaN is involved" do it "returns NaN if NaN is involved" do
@one.sub(@nan, 1).nan?.should == true @one.sub(@nan, 1).nan?.should == true
@nan.sub(@one, 1).nan?.should == true @nan.sub(@one, 1).nan?.should == true

View file

@ -0,0 +1,42 @@
require_relative '../../spec_helper'
require 'bigdecimal'
require 'bigdecimal/util'
describe "BigDecimal's util method definitions" do
describe "#to_d" do
it "should define #to_d on Integer" do
42.to_d.should == BigDecimal(42)
end
it "should define #to_d on Float" do
0.5.to_d.should == BigDecimal(0.5, Float::DIG)
1.234.to_d(2).should == BigDecimal(1.234, 2)
end
it "should define #to_d on String" do
"0.5".to_d.should == BigDecimal(0.5, Float::DIG)
"45.67 degrees".to_d.should == BigDecimal(45.67, Float::DIG)
end
it "should define #to_d on BigDecimal" do
bd = BigDecimal("3.14")
bd.to_d.should equal(bd)
end
it "should define #to_d on Rational" do
Rational(22, 7).to_d(3).should == BigDecimal(3.14, 3)
end
ruby_version_is "2.6" do
it "should define #to_d on nil" do
nil.to_d.should == BigDecimal(0)
end
end
end
describe "#to_digits" do
it "should define #to_digits on BigDecimal" do
BigDecimal("3.14").to_digits.should == "3.14"
end
end
end

View file

@ -10,7 +10,7 @@ describe 'RbConfig::CONFIG' do
end end
# These directories have no meanings before the installation. # These directories have no meanings before the installation.
if RbConfig::TOPDIR guard -> { RbConfig::TOPDIR } do
it "['rubylibdir'] returns the directory containing Ruby standard libraries" do it "['rubylibdir'] returns the directory containing Ruby standard libraries" do
rubylibdir = RbConfig::CONFIG['rubylibdir'] rubylibdir = RbConfig::CONFIG['rubylibdir']
File.directory?(rubylibdir).should == true File.directory?(rubylibdir).should == true

View file

@ -358,6 +358,14 @@ static VALUE string_spec_rb_sprintf2(VALUE self, VALUE str, VALUE repl1, VALUE r
return rb_sprintf(RSTRING_PTR(str), RSTRING_PTR(repl1), RSTRING_PTR(repl2)); return rb_sprintf(RSTRING_PTR(str), RSTRING_PTR(repl1), RSTRING_PTR(repl2));
} }
static VALUE string_spec_rb_sprintf3(VALUE self, VALUE str) {
return rb_sprintf("Result: %"PRIsVALUE".", str);
}
static VALUE string_spec_rb_sprintf4(VALUE self, VALUE str) {
return rb_sprintf("Result: %+"PRIsVALUE".", str);
}
static VALUE string_spec_rb_vsprintf_worker(char* fmt, ...) { static VALUE string_spec_rb_vsprintf_worker(char* fmt, ...) {
va_list varargs; va_list varargs;
VALUE str; VALUE str;
@ -463,6 +471,8 @@ void Init_string_spec(void) {
rb_define_method(cls, "rb_str_free", string_spec_rb_str_free, 1); rb_define_method(cls, "rb_str_free", string_spec_rb_str_free, 1);
rb_define_method(cls, "rb_sprintf1", string_spec_rb_sprintf1, 2); rb_define_method(cls, "rb_sprintf1", string_spec_rb_sprintf1, 2);
rb_define_method(cls, "rb_sprintf2", string_spec_rb_sprintf2, 3); rb_define_method(cls, "rb_sprintf2", string_spec_rb_sprintf2, 3);
rb_define_method(cls, "rb_sprintf3", string_spec_rb_sprintf3, 1);
rb_define_method(cls, "rb_sprintf4", string_spec_rb_sprintf4, 1);
rb_define_method(cls, "rb_vsprintf", string_spec_rb_vsprintf, 4); rb_define_method(cls, "rb_vsprintf", string_spec_rb_vsprintf, 4);
rb_define_method(cls, "rb_str_equal", string_spec_rb_str_equal, 2); rb_define_method(cls, "rb_str_equal", string_spec_rb_str_equal, 2);
rb_define_method(cls, "rb_usascii_str_new", string_spec_rb_usascii_str_new, 2); rb_define_method(cls, "rb_usascii_str_new", string_spec_rb_usascii_str_new, 2);

View file

@ -43,7 +43,11 @@ void sample_typed_wrapped_struct_mark(void* st) {
} }
size_t sample_typed_wrapped_struct_memsize(const void* st) { size_t sample_typed_wrapped_struct_memsize(const void* st) {
return sizeof(struct sample_typed_wrapped_struct); if (st == NULL) {
return 0;
} else {
return ((struct sample_typed_wrapped_struct *)st)->foo;
}
} }
static const rb_data_type_t sample_typed_wrapped_struct_data_type = { static const rb_data_type_t sample_typed_wrapped_struct_data_type = {

View file

@ -244,6 +244,10 @@ describe "C-API Kernel function" do
@s.rb_yield_splat([1, 2]) { |x, y| x + y }.should == 3 @s.rb_yield_splat([1, 2]) { |x, y| x + y }.should == 3
end end
it "passes arguments to a block accepting splatted args" do
@s.rb_yield_splat([1, 2]) { |*v| v }.should == [1, 2]
end
it "raises LocalJumpError when no block is given" do it "raises LocalJumpError when no block is given" do
lambda { @s.rb_yield_splat([1, 2]) }.should raise_error(LocalJumpError) lambda { @s.rb_yield_splat([1, 2]) }.should raise_error(LocalJumpError)
end end

View file

@ -72,9 +72,10 @@ describe "C-API Mutex functions" do
it "sleeps when the mutex is locked" do it "sleeps when the mutex is locked" do
@m.lock @m.lock
start = Time.now t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
@s.rb_mutex_sleep(@m, 0.1) @s.rb_mutex_sleep(@m, 0.001)
(Time.now - start).should be_close(0.1, 0.2) t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
(t2 - t1).should >= 0
@m.locked?.should be_true @m.locked?.should be_true
end end
end end

View file

@ -4,6 +4,30 @@ require_relative '../../shared/string/times'
load_extension('string') load_extension('string')
class CApiStringSpecs
class ValidTostrTest
def to_str
"ruby"
end
end
class InvalidTostrTest
def to_str
[]
end
end
class ToSOrInspect
def to_s
'A string'
end
def inspect
'A different string'
end
end
end
describe :rb_str_new2, shared: true do describe :rb_str_new2, shared: true do
it "returns a new string object calling strlen on the passed C string" do it "returns a new string object calling strlen on the passed C string" do
# Hardcoded to pass const char * = "hello\0invisible" # Hardcoded to pass const char * = "hello\0invisible"
@ -20,18 +44,6 @@ describe "C-API String function" do
@s = CApiStringSpecs.new @s = CApiStringSpecs.new
end end
class ValidTostrTest
def to_str
"ruby"
end
end
class InvalidTostrTest
def to_str
[]
end
end
[Encoding::BINARY, Encoding::UTF_8].each do |enc| [Encoding::BINARY, Encoding::UTF_8].each do |enc|
describe "rb_str_set_len on a #{enc.name} String" do describe "rb_str_set_len on a #{enc.name} String" do
before :each do before :each do
@ -438,12 +450,12 @@ describe "C-API String function" do
describe "rb_str_to_str" do describe "rb_str_to_str" do
it "calls #to_str to coerce the value to a String" do it "calls #to_str to coerce the value to a String" do
@s.rb_str_to_str("foo").should == "foo" @s.rb_str_to_str("foo").should == "foo"
@s.rb_str_to_str(ValidTostrTest.new).should == "ruby" @s.rb_str_to_str(CApiStringSpecs::ValidTostrTest.new).should == "ruby"
end end
it "raises a TypeError if coercion fails" do it "raises a TypeError if coercion fails" do
lambda { @s.rb_str_to_str(0) }.should raise_error(TypeError) lambda { @s.rb_str_to_str(0) }.should raise_error(TypeError)
lambda { @s.rb_str_to_str(InvalidTostrTest.new) }.should raise_error(TypeError) lambda { @s.rb_str_to_str(CApiStringSpecs::InvalidTostrTest.new) }.should raise_error(TypeError)
end end
end end
@ -875,6 +887,26 @@ describe "C-API String function" do
s = "Awesome %s is here with %s" s = "Awesome %s is here with %s"
@s.rb_sprintf2(s, "string", "content").should == "Awesome string is here with content" @s.rb_sprintf2(s, "string", "content").should == "Awesome string is here with content"
end end
it "formats a string VALUE using to_s if sign not specified in format" do
s = 'Result: A string.'
@s.rb_sprintf3(CApiStringSpecs::ToSOrInspect.new).should == s
end
it "formats a string VALUE using inspect if sign specified in format" do
s = 'Result: A different string.'
@s.rb_sprintf4(CApiStringSpecs::ToSOrInspect.new).should == s
end
it "formats a TrueClass VALUE as `TrueClass` if sign not specified in format" do
s = 'Result: TrueClass.'
@s.rb_sprintf3(true.class).should == s
end
it "formats a TrueClass VALUE as 'true' if sign specified in format" do
s = 'Result: true.'
@s.rb_sprintf4(true.class).should == s
end
end end
describe "rb_vsprintf" do describe "rb_vsprintf" do
@ -890,11 +922,11 @@ describe "C-API String function" do
end end
it "tries to convert the passed argument to a string by calling #to_str first" do it "tries to convert the passed argument to a string by calling #to_str first" do
@s.rb_String(ValidTostrTest.new).should == "ruby" @s.rb_String(CApiStringSpecs::ValidTostrTest.new).should == "ruby"
end end
it "raises a TypeError if #to_str does not return a string" do it "raises a TypeError if #to_str does not return a string" do
lambda { @s.rb_String(InvalidTostrTest.new) }.should raise_error(TypeError) lambda { @s.rb_String(CApiStringSpecs::InvalidTostrTest.new) }.should raise_error(TypeError)
end end
it "tries to convert the passed argument to a string by calling #to_s" do it "tries to convert the passed argument to a string by calling #to_s" do

View file

@ -1,4 +1,5 @@
require_relative 'spec_helper' require_relative 'spec_helper'
require 'objspace'
load_extension("typed_data") load_extension("typed_data")
@ -7,6 +8,14 @@ describe "CApiAllocTypedSpecs (a class with an alloc func defined)" do
@s = CApiAllocTypedSpecs.new @s = CApiAllocTypedSpecs.new
@s.typed_wrapped_data.should == 42 # not defined in initialize @s.typed_wrapped_data.should == 42 # not defined in initialize
end end
it "uses the specified memsize function for ObjectSpace.memsize" do
@s = CApiAllocTypedSpecs.new
# The defined memsize function for the type should return 42 as
# the size, and this should be added to the size of the object as
# known by Ruby.
ObjectSpace.memsize_of(@s).should > 42
end
end end
describe "CApiWrappedTypedStruct" do describe "CApiWrappedTypedStruct" do

View file

@ -23,6 +23,10 @@ describe "C-API Util function" do
lambda { @o.rb_scan_args([1, 2], "3", 0, @acc) }.should raise_error(ArgumentError) lambda { @o.rb_scan_args([1, 2], "3", 0, @acc) }.should raise_error(ArgumentError)
end end
it "raises an ArgumentError if there are too many arguments" do
lambda { @o.rb_scan_args([1, 2, 3, 4], "3", 0, @acc) }.should raise_error(ArgumentError)
end
it "assigns the required and optional arguments scanned" do it "assigns the required and optional arguments scanned" do
@o.rb_scan_args([1, 2], "11", 2, @acc).should == 2 @o.rb_scan_args([1, 2], "11", 2, @acc).should == 2
ScratchPad.recorded.should == [1, 2] ScratchPad.recorded.should == [1, 2]

View file

@ -0,0 +1,22 @@
require_relative '../spec_helper'
require 'rubygems'
require 'rubygems/user_interaction'
ruby_version_is "2.5.5" do
describe "CVE-2019-8321 is resisted by" do
it "sanitising verbose messages" do
ui = Class.new {
include Gem::UserInteraction
}.new
ui.should_receive(:say).with(".]2;nyan.")
verbose_before = Gem.configuration.verbose
begin
Gem.configuration.verbose = :really_verbose
ui.verbose("\e]2;nyan\a")
ensure
Gem.configuration.verbose = verbose_before
end
end
end
end

View file

@ -0,0 +1,23 @@
require_relative '../spec_helper'
require 'yaml'
require 'rubygems'
require 'rubygems/safe_yaml'
require 'rubygems/commands/owner_command'
ruby_version_is "2.5.5" do
describe "CVE-2019-8322 is resisted by" do
it "sanitising owner names" do
command = Gem::Commands::OwnerCommand.new
def command.rubygems_api_request(*args)
Struct.new(:body).new("---\n- email: \"\e]2;nyan\a\"\n handle: handle\n id: id\n")
end
def command.with_response(response)
yield response
end
command.should_receive(:say).with("Owners for gem: name")
command.should_receive(:say).with("- .]2;nyan.")
command.show_owners "name"
end
end
end

View file

@ -0,0 +1,38 @@
require_relative '../spec_helper'
require 'optparse'
require 'rubygems'
require 'rubygems/gemcutter_utilities'
ruby_version_is "2.5.5" do
describe "CVE-2019-8323 is resisted by" do
describe "sanitising the body" do
it "for success codes" do
cutter = Class.new {
include Gem::GemcutterUtilities
}.new
response = Net::HTTPSuccess.new(nil, nil, nil)
def response.body
"\e]2;nyan\a"
end
cutter.should_receive(:say).with(".]2;nyan.")
cutter.with_response response
end
it "for error codes" do
cutter = Class.new {
include Gem::GemcutterUtilities
}.new
def cutter.terminate_interaction(n)
end
response = Net::HTTPNotFound.new(nil, nil, nil)
def response.body
"\e]2;nyan\a"
end
cutter.should_receive(:say).with(".]2;nyan.")
cutter.with_response response
end
end
end
end

View file

@ -0,0 +1,38 @@
require_relative '../spec_helper'
require 'rubygems'
require 'rubygems/command_manager'
ruby_version_is "2.5.5" do
describe "CVE-2019-8325 is resisted by" do
describe "sanitising error message components" do
it "for the 'while executing' message" do
manager = Gem::CommandManager.new
def manager.process_args(args, build_args)
raise StandardError, "\e]2;nyan\a"
end
def manager.terminate_interaction(n)
end
manager.should_receive(:alert_error).with("While executing gem ... (StandardError)\n .]2;nyan.")
manager.run nil, nil
end
it "for the 'invalid option' message" do
manager = Gem::CommandManager.new
def manager.terminate_interaction(n)
end
manager.should_receive(:alert_error).with("Invalid option: --.]2;nyan.. See 'gem --help'.")
manager.process_args ["--\e]2;nyan\a"], nil
end
it "for the 'loading command' message" do
manager = Gem::CommandManager.new
def manager.require(x)
raise 'foo'
end
manager.should_receive(:alert_error).with("Loading command: .]2;nyan. (RuntimeError)\n\tfoo")
manager.send :load_and_instantiate, "\e]2;nyan\a"
end
end
end
end

View file

@ -114,4 +114,15 @@ describe :basicobject_send, shared: true do
it "has a negative arity" do it "has a negative arity" do
method(@method).arity.should < 0 method(@method).arity.should < 0
end end
it "invokes module methods with super correctly" do
m1 = Module.new { def foo(ary); ary << :m1; end; }
m2 = Module.new { def foo(ary = []); super(ary); ary << :m2; end; }
c2 = Class.new do
include m1
include m2
end
c2.new.send(@method, :foo, *[[]]).should == %i[m1 m2]
end
end end