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
IncludeSpecsTop
IncludesMath
InvalidTostrTest
JSON
KSAutoloadA
KSAutoloadB
@ -177,6 +176,7 @@ StringRefinement
StringScanner
StringSubclass
StructClasses
Syck
Syslog
TCPServer
TCPSocket
@ -205,7 +205,6 @@ UserObject
UserPreviouslyDefinedWithInitializedIvar
UserRegexp
UserString
ValidTostrTest
Vector
WEBrick
WIN32OLE

View file

@ -96,3 +96,7 @@ Lint/UnreachableCode:
Lint/UriRegexp:
Exclude:
- '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
matrix:
include:
- rvm: 2.5.3
- rvm: 2.5.5
env: MSPEC_OPTS="-R2 -ff"
- rvm: 2.3.8
- rvm: 2.4.5
env: CHECK_LEAKS=true
- rvm: 2.5.3
- rvm: 2.5.5
env: CHECK_LEAKS=true
- rvm: 2.6.1
- rvm: 2.6.2
env: CHECK_LEAKS=true
- env: RUBOCOP=true
rvm: 2.4.5

View file

@ -1,23 +1,6 @@
require_relative '../spec_helper'
require_relative 'shared/change_directory'
describe 'The -C command line option' do
before :all do
@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
describe "The -C command line option" do
it_behaves_like :command_line_change_directory, "-C"
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")
ENV["RUBYLIB"] = @pre + dir
paths = ruby_exe("puts $LOAD_PATH").lines.map(&:chomp)
paths.shift if paths.first.end_with?('/gem-rehash')
if PlatformGuard.implementation? :ruby
# 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.

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
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
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"
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"
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"
end
@ -95,6 +95,201 @@ describe "Float#to_s" do
it "outputs the minimal, unique form to represent the value" do
0.56.to_s.should == "0.56"
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
with_feature :encoding do

View file

@ -1,4 +1,6 @@
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
all_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"]
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
h = { a: 1, b: 2, c: 3, d: 5 }
keys = []

View file

@ -77,6 +77,13 @@ describe "IO#read_nonblock" do
buffer.should == "1"
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
lambda { IOSpecs.closed_io.read_nonblock(5) }.should raise_error(IOError)
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)
end
it "returns an Integer" do
sleep(0.001).should be_kind_of(Integer)
end
it "accepts a Float" do
sleep(0.1).should be_close(0, 2)
sleep(0.001).should >= 0
end
it "accepts a Fixnum" do
sleep(0).should be_close(0, 2)
sleep(0).should >= 0
end
it "accepts a Rational" do
sleep(Rational(1, 9)).should be_close(0, 2)
sleep(Rational(1, 999)).should >= 0
end
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.method(:writer=).parameters.should == [[:req]]
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

View file

@ -90,4 +90,15 @@ describe "Method#to_proc" do
array.each(&obj)
ScratchPad.recorded.should == [[1, 2]]
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

View file

@ -16,17 +16,28 @@ end
describe "Module#autoload" do
before :all do
@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
before :each do
@loaded_features = $".dup
@frozen_module = Module.new.freeze
ScratchPad.clear
@remove = []
end
after :each do
$".replace @loaded_features
@remove.each { |const|
ModuleSpecs::Autoload.send :remove_const, const
}
end
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)
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
ModuleSpecs::Autoload.should_not have_constant(:X)
ModuleSpecs::Autoload.autoload :X, fixture(__FILE__, "autoload_x.rb")
@remove << :X
ModuleSpecs::Autoload::X.should == :x
ModuleSpecs::Autoload.send(:remove_const, :X)
end
it "loads the registered constant into a dynamically created class" do
cls = Class.new { autoload :C, fixture(__FILE__, "autoload_c.rb") }
ModuleSpecs::Autoload::DynClass = cls
@remove << :DynClass
ScratchPad.recorded.should be_nil
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
mod = Module.new { autoload :D, fixture(__FILE__, "autoload_d.rb") }
ModuleSpecs::Autoload::DynModule = mod
@remove << :DynModule
ScratchPad.recorded.should be_nil
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
ModuleSpecs::Autoload.autoload :I, fixture(__FILE__, "autoload_i.rb")
@remove << :I
ModuleSpecs::Autoload.const_set :I, 3
ModuleSpecs::Autoload::I.should == 3
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
filename = fixture(__FILE__, "autoload_k.rb")
ModuleSpecs::Autoload.autoload :KHash, filename
@remove << :KHash
require filename
ScratchPad.recorded.should == :loaded
@ -135,8 +162,8 @@ describe "Module#autoload" do
ScratchPad.clear
ModuleSpecs::Autoload.autoload :S, filename
@remove << :S
ModuleSpecs::Autoload.autoload?(:S).should be_nil
ModuleSpecs::Autoload.send(:remove_const, :S)
end
it "retains the autoload even if the request to require fails" do
@ -182,11 +209,10 @@ describe "Module#autoload" do
module ModuleSpecs::Autoload
autoload :GoodParent, fixture(__FILE__, "autoload_nested.rb")
end
@remove << :GoodParent
defined?(ModuleSpecs::Autoload::GoodParent::Nested).should == 'constant'
ScratchPad.recorded.should == :loaded
ModuleSpecs::Autoload.send(:remove_const, :GoodParent)
end
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
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
module ModuleSpecs::Autoload
autoload :RequiredDirectly, fixture(__FILE__, "autoload_required_directly.rb")
end
@remove << :RequiredDirectly
@path = fixture(__FILE__, "autoload_required_directly.rb")
@check = -> {
[
@ -214,10 +241,6 @@ describe "Module#autoload" do
ScratchPad.record @check
end
after :each do
ModuleSpecs::Autoload.send(:remove_const, :RequiredDirectly)
end
it "with a full path" do
@check.call.should == ["constant", @path]
require @path
@ -242,7 +265,7 @@ describe "Module#autoload" do
nested_require = -> {
result = nil
ScratchPad.record -> {
result = [@check.call, Thread.new { @check.call }.value]
result = @check.call
}
require nested
result
@ -251,24 +274,41 @@ describe "Module#autoload" do
@check.call.should == ["constant", @path]
require @path
cur, other = ScratchPad.recorded
cur.should == [nil, nil]
other.should == [nil, nil]
ScratchPad.recorded.should == [nil, nil]
@check.call.should == ["constant", nil]
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
before :each do
@path = fixture(__FILE__, "autoload_during_autoload.rb")
ModuleSpecs::Autoload.autoload :DuringAutoload, @path
@remove << :DuringAutoload
raise unless ModuleSpecs::Autoload.autoload?(:DuringAutoload) == @path
end
after :each do
ModuleSpecs::Autoload.send(:remove_const, :DuringAutoload)
end
def check_before_during_thread_after(&check)
before = check.call
to_autoload_thread, from_autoload_thread = Queue.new, Queue.new
@ -419,6 +459,7 @@ describe "Module#autoload" do
X = get_value
end
end
@remove << :U
ModuleSpecs::Autoload::U::V::X.should == :autoload_uvx
end
@ -474,6 +515,7 @@ describe "Module#autoload" do
end
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
ScratchPad.record -> {
DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
@ -494,6 +536,7 @@ describe "Module#autoload" do
end
it "in the included modules" do
@remove << :DefinedInIncludedModule
module ModuleSpecs::Autoload
ScratchPad.record -> {
module DefinedInIncludedModule
@ -507,6 +550,7 @@ describe "Module#autoload" do
end
it "in the included modules of the superclass" do
@remove << :DefinedInSuperclassIncludedModule
module ModuleSpecs::Autoload
class LookupAfterAutoloadSuper
end
@ -528,6 +572,7 @@ describe "Module#autoload" do
end
it "in the prepended modules" do
@remove << :DefinedInPrependedModule
module ModuleSpecs::Autoload
ScratchPad.record -> {
module DefinedInPrependedModule
@ -567,10 +612,10 @@ describe "Module#autoload" do
end
end
end
@remove << :W
ModuleSpecs::Autoload::W::Y.should be_kind_of(Class)
ScratchPad.recorded.should == :loaded
ModuleSpecs::Autoload::W.send(:remove_const, :Y)
end
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
require fixture(__FILE__, "autoload_s.rb")
@remove << :S
filename = fixture(__FILE__, "autoload_t.rb")
mod1 = Module.new { autoload :T, filename }
lambda {
@ -651,8 +697,9 @@ describe "Module#autoload" do
describe "on a frozen module" 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.should_not have_constant(:Foo)
frozen_module = Module.new.freeze
lambda { frozen_module.autoload :Foo, @non_existent }.should raise_error(frozen_error_class)
frozen_module.should_not have_constant(:Foo)
end
end
@ -675,6 +722,7 @@ describe "Module#autoload" do
describe "(concurrently)" do
it "blocks a second thread while a first is doing the autoload" do
ModuleSpecs::Autoload.autoload :Concur, fixture(__FILE__, "autoload_concur.rb")
@remove << :Concur
start = false
@ -717,8 +765,6 @@ describe "Module#autoload" do
t2_val.should == t1_val
t2_exc.should be_nil
ModuleSpecs::Autoload.send(:remove_const, :Concur)
end
# 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)
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
before :each do
@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
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

View file

@ -489,4 +489,12 @@ describe "String#inspect" do
].should be_computed_by(:inspect)
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

View file

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

View file

@ -2,21 +2,23 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "2.6" do
describe "#eval_script" do
ScratchPad.record []
describe "TracePoint#eval_script" do
it "is the evald source code" do
ScratchPad.record []
script = <<-CODE
def foo
p :hello
script = <<-CODE
def foo
p :hello
end
CODE
TracePoint.new(:script_compiled) do |e|
ScratchPad << e.eval_script
end.enable do
eval script
end
CODE
TracePoint.new(:script_compiled) do |e|
ScratchPad << e.eval_script
end.enable do
eval script
ScratchPad.recorded.should == [script]
end
ScratchPad.recorded.should == [script]
end
end

View file

@ -2,22 +2,24 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
ruby_version_is "2.6" do
describe "#instruction_sequence" do
ScratchPad.record []
describe "TracePoint#instruction_sequence" do
it "is an instruction sequence" do
ScratchPad.record []
script = <<-CODE
def foo
p :hello
script = <<-CODE
def foo
p :hello
end
CODE
TracePoint.new(:script_compiled) do |e|
ScratchPad << e.instruction_sequence
end.enable do
eval script
end
CODE
TracePoint.new(:script_compiled) do |e|
ScratchPad << e.instruction_sequence
end.enable do
eval script
ScratchPad.recorded.size.should == 1
ScratchPad.recorded[0].class.should == RubyVM::InstructionSequence
end
ScratchPad.recorded.size.should == 1
ScratchPad.recorded[0].class.should == RubyVM::InstructionSequence
end
end

View file

@ -244,3 +244,15 @@ describe "The alias keyword" do
}
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 'fixtures/for_scope'
# for name[, name]... in expr [do]
# body
@ -130,6 +131,11 @@ describe "The for expression" do
a.should == 123
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
for i in 1..3; end.should == (1..3)
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(*[]).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)
end

View file

@ -73,6 +73,14 @@ describe "BigDecimal#add" do
# BigDecimal("0.88").add(0.0, 1).should == BigDecimal("0.9")
# 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
BigDecimalSpecs.with_limit(1) do
BigDecimal('0.888').add(@zero, 3).should == BigDecimal('0.888')

View file

@ -42,6 +42,14 @@ describe "BigDecimal#div" do
}
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
lambda { @one.div(@nan) }.should raise_error(FloatDomainError)
lambda { @nan.div(@one) }.should raise_error(FloatDomainError)

View file

@ -9,7 +9,8 @@ end
describe "BigDecimal#mult" do
before :each do
@one = BigDecimal "1"
@e3_minus = BigDecimal "3E-20001"
@e3_minus = BigDecimal("3E-20001")
@e3_plus = BigDecimal("3E20001")
@e = BigDecimal "1.00000000000000000000123456789"
@tolerance = @e.sub @one, 1000
@tolerance2 = BigDecimal "30001E-20005"
@ -21,4 +22,11 @@ describe "BigDecimal#mult" do
@e3_minus.mult(@one, 1).should be_close(0, @tolerance2)
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

View file

@ -23,4 +23,12 @@ describe "BigDecimal#*" do
(@e3_minus * @e3_minus).should == BigDecimal("9E-40002")
(@e * @one).should == @e
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

View file

@ -5,7 +5,8 @@ describe "BigDecimal#remainder" do
before :each do
@zero = BigDecimal("0")
@one = BigDecimal("0")
@one = BigDecimal("1")
@three = BigDecimal("3")
@mixed = BigDecimal("1.23456789")
@pos_int = BigDecimal("2E5555")
@neg_int = BigDecimal("-2E5555")
@ -71,9 +72,16 @@ describe "BigDecimal#remainder" do
end
it "coerces arguments to BigDecimal if possible" do
@one.remainder(2).should == @one
@three.remainder(2).should == @one
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
lambda {

View file

@ -70,6 +70,15 @@ describe :bigdecimal_modulo, shared: true do
res.kind_of?(BigDecimal).should == true
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
@nan.send(@method, @nan).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')
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
@zero.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")
@frac_1 = BigDecimal("1E-99999")
@frac_2 = BigDecimal("0.9E-99999")
@frac_3 = BigDecimal("12345E10")
@frac_4 = BigDecimal("98765E10")
end
it "returns a - b with given precision" do
@ -32,6 +34,14 @@ describe "BigDecimal#sub" do
@frac_1.sub(@frac_1, 1000000).should == @zero
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
@one.sub(@nan, 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
# 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
rubylibdir = RbConfig::CONFIG['rubylibdir']
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));
}
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, ...) {
va_list varargs;
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_sprintf1", string_spec_rb_sprintf1, 2);
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_str_equal", string_spec_rb_str_equal, 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) {
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 = {

View file

@ -244,6 +244,10 @@ describe "C-API Kernel function" do
@s.rb_yield_splat([1, 2]) { |x, y| x + y }.should == 3
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
lambda { @s.rb_yield_splat([1, 2]) }.should raise_error(LocalJumpError)
end

View file

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

View file

@ -4,6 +4,30 @@ require_relative '../../shared/string/times'
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
it "returns a new string object calling strlen on the passed C string" do
# Hardcoded to pass const char * = "hello\0invisible"
@ -20,18 +44,6 @@ describe "C-API String function" do
@s = CApiStringSpecs.new
end
class ValidTostrTest
def to_str
"ruby"
end
end
class InvalidTostrTest
def to_str
[]
end
end
[Encoding::BINARY, Encoding::UTF_8].each do |enc|
describe "rb_str_set_len on a #{enc.name} String" do
before :each do
@ -438,12 +450,12 @@ describe "C-API String function" do
describe "rb_str_to_str" 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(ValidTostrTest.new).should == "ruby"
@s.rb_str_to_str(CApiStringSpecs::ValidTostrTest.new).should == "ruby"
end
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(InvalidTostrTest.new) }.should raise_error(TypeError)
lambda { @s.rb_str_to_str(CApiStringSpecs::InvalidTostrTest.new) }.should raise_error(TypeError)
end
end
@ -875,6 +887,26 @@ describe "C-API String function" do
s = "Awesome %s is here with %s"
@s.rb_sprintf2(s, "string", "content").should == "Awesome string is here with content"
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
describe "rb_vsprintf" do
@ -890,11 +922,11 @@ describe "C-API String function" do
end
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
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
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 'objspace'
load_extension("typed_data")
@ -7,6 +8,14 @@ describe "CApiAllocTypedSpecs (a class with an alloc func defined)" do
@s = CApiAllocTypedSpecs.new
@s.typed_wrapped_data.should == 42 # not defined in initialize
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
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)
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
@o.rb_scan_args([1, 2], "11", 2, @acc).should == 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
method(@method).arity.should < 0
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