diff options
author | eregon <eregon@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2019-03-28 14:22:29 +0000 |
---|---|---|
committer | eregon <eregon@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2019-03-28 14:22:29 +0000 |
commit | a28aa80c739a1d169649a4da833ef48cfb3465b3 (patch) | |
tree | c2f6bb79c268bd60116b54319ea96f01bb7dda79 | |
parent | 0f64776745ef31e626dec0d42b7fb2a5988397ec (diff) |
Update to ruby/spec@e81b3cd
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@67361 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
53 files changed, 932 insertions, 106 deletions
diff --git a/spec/ruby/.mspec.constants b/spec/ruby/.mspec.constants index 6347a0c701..44f0011df9 100644 --- a/spec/ruby/.mspec.constants +++ b/spec/ruby/.mspec.constants @@ -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 diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml index 58529f15b2..5de7154442 100644 --- a/spec/ruby/.rubocop.yml +++ b/spec/ruby/.rubocop.yml @@ -96,3 +96,7 @@ Lint/UnreachableCode: Lint/UriRegexp: Exclude: - 'library/uri/regexp_spec.rb' + +Lint/Debugger: + Exclude: + - 'core/binding/fixtures/irb.rb' diff --git a/spec/ruby/.travis.yml b/spec/ruby/.travis.yml index 779fe5ba2a..11bd7a55fd 100644 --- a/spec/ruby/.travis.yml +++ b/spec/ruby/.travis.yml @@ -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 diff --git a/spec/ruby/command_line/dash_upper_c_spec.rb b/spec/ruby/command_line/dash_upper_c_spec.rb index 761beaadab..ece1b32105 100644 --- a/spec/ruby/command_line/dash_upper_c_spec.rb +++ b/spec/ruby/command_line/dash_upper_c_spec.rb @@ -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 diff --git a/spec/ruby/command_line/dash_upper_x_spec.rb b/spec/ruby/command_line/dash_upper_x_spec.rb new file mode 100644 index 0000000000..8ef9aae4b1 --- /dev/null +++ b/spec/ruby/command_line/dash_upper_x_spec.rb @@ -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 diff --git a/spec/ruby/command_line/feature_spec.rb b/spec/ruby/command_line/feature_spec.rb new file mode 100644 index 0000000000..fa2a82cb4b --- /dev/null +++ b/spec/ruby/command_line/feature_spec.rb @@ -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 diff --git a/spec/ruby/command_line/fixtures/dash_upper_c_script.rb b/spec/ruby/command_line/fixtures/change_directory_script.rb index abe244705f..abe244705f 100644 --- a/spec/ruby/command_line/fixtures/dash_upper_c_script.rb +++ b/spec/ruby/command_line/fixtures/change_directory_script.rb diff --git a/spec/ruby/command_line/rubylib_spec.rb b/spec/ruby/command_line/rubylib_spec.rb index 20e9c2cf95..b45919b997 100644 --- a/spec/ruby/command_line/rubylib_spec.rb +++ b/spec/ruby/command_line/rubylib_spec.rb @@ -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. diff --git a/spec/ruby/command_line/shared/change_directory.rb b/spec/ruby/command_line/shared/change_directory.rb new file mode 100644 index 0000000000..9cb6e90ac6 --- /dev/null +++ b/spec/ruby/command_line/shared/change_directory.rb @@ -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 diff --git a/spec/ruby/core/binding/fixtures/irb.rb b/spec/ruby/core/binding/fixtures/irb.rb new file mode 100644 index 0000000000..5f305f2d5d --- /dev/null +++ b/spec/ruby/core/binding/fixtures/irb.rb @@ -0,0 +1,3 @@ +a = 10 + +binding.irb diff --git a/spec/ruby/core/binding/irb_spec.rb b/spec/ruby/core/binding/irb_spec.rb new file mode 100644 index 0000000000..dd3df0b28a --- /dev/null +++ b/spec/ruby/core/binding/irb_spec.rb @@ -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 diff --git a/spec/ruby/core/file/mtime_spec.rb b/spec/ruby/core/file/mtime_spec.rb index d5769c0584..c5d854bb08 100644 --- a/spec/ruby/core/file/mtime_spec.rb +++ b/spec/ruby/core/file/mtime_spec.rb @@ -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 diff --git a/spec/ruby/core/float/to_s_spec.rb b/spec/ruby/core/float/to_s_spec.rb index 58a58549ed..127132b567 100644 --- a/spec/ruby/core/float/to_s_spec.rb +++ b/spec/ruby/core/float/to_s_spec.rb @@ -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 diff --git a/spec/ruby/core/hash/shared/each.rb b/spec/ruby/core/hash/shared/each.rb index bf4c569cfc..1d89cfdd39 100644 --- a/spec/ruby/core/hash/shared/each.rb +++ b/spec/ruby/core/hash/shared/each.rb @@ -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 = [] diff --git a/spec/ruby/core/io/read_nonblock_spec.rb b/spec/ruby/core/io/read_nonblock_spec.rb index 3c02f662f6..59f5064922 100644 --- a/spec/ruby/core/io/read_nonblock_spec.rb +++ b/spec/ruby/core/io/read_nonblock_spec.rb @@ -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 diff --git a/spec/ruby/core/kernel/pp_spec.rb b/spec/ruby/core/kernel/pp_spec.rb new file mode 100644 index 0000000000..e19dc64caf --- /dev/null +++ b/spec/ruby/core/kernel/pp_spec.rb @@ -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 diff --git a/spec/ruby/core/kernel/sleep_spec.rb b/spec/ruby/core/kernel/sleep_spec.rb index 489f4f8410..a510ae3dc1 100644 --- a/spec/ruby/core/kernel/sleep_spec.rb +++ b/spec/ruby/core/kernel/sleep_spec.rb @@ -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 diff --git a/spec/ruby/core/method/parameters_spec.rb b/spec/ruby/core/method/parameters_spec.rb index d750f4c221..750abe13d0 100644 --- a/spec/ruby/core/method/parameters_spec.rb +++ b/spec/ruby/core/method/parameters_spec.rb @@ -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 diff --git a/spec/ruby/core/method/to_proc_spec.rb b/spec/ruby/core/method/to_proc_spec.rb index 92bd64aaf1..29b7bec2b3 100644 --- a/spec/ruby/core/method/to_proc_spec.rb +++ b/spec/ruby/core/method/to_proc_spec.rb @@ -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 diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb index 224d5fd57b..918eb61764 100644 --- a/spec/ruby/core/module/autoload_spec.rb +++ b/spec/ruby/core/module/autoload_spec.rb @@ -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 diff --git a/spec/ruby/core/module/const_set_spec.rb b/spec/ruby/core/module/const_set_spec.rb index f3c69cd3e0..25d22ffaba 100644 --- a/spec/ruby/core/module/const_set_spec.rb +++ b/spec/ruby/core/module/const_set_spec.rb @@ -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 diff --git a/spec/ruby/core/module/fixtures/autoload_overridden.rb b/spec/ruby/core/module/fixtures/autoload_overridden.rb new file mode 100644 index 0000000000..7062bcfabc --- /dev/null +++ b/spec/ruby/core/module/fixtures/autoload_overridden.rb @@ -0,0 +1,3 @@ +module ModuleSpecs::Autoload + Overridden = :overridden +end diff --git a/spec/ruby/core/string/end_with_spec.rb b/spec/ruby/core/string/end_with_spec.rb index 7268378a38..429888803c 100644 --- a/spec/ruby/core/string/end_with_spec.rb +++ b/spec/ruby/core/string/end_with_spec.rb @@ -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 diff --git a/spec/ruby/core/string/inspect_spec.rb b/spec/ruby/core/string/inspect_spec.rb index 2cfcfe0e76..c1674c73c8 100644 --- a/spec/ruby/core/string/inspect_spec.rb +++ b/spec/ruby/core/string/inspect_spec.rb @@ -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 diff --git a/spec/ruby/core/thread/list_spec.rb b/spec/ruby/core/thread/list_spec.rb index bd56cb4c52..80dd15c6ca 100644 --- a/spec/ruby/core/thread/list_spec.rb +++ b/spec/ruby/core/thread/list_spec.rb @@ -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 diff --git a/spec/ruby/core/tracepoint/eval_script_spec.rb b/spec/ruby/core/tracepoint/eval_script_spec.rb index 8a153156d1..1d8e425a9a 100644 --- a/spec/ruby/core/tracepoint/eval_script_spec.rb +++ b/spec/ruby/core/tracepoint/eval_script_spec.rb @@ -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 diff --git a/spec/ruby/core/tracepoint/instruction_sequence_spec.rb b/spec/ruby/core/tracepoint/instruction_sequence_spec.rb index 50a9cd5722..3e3b73cccc 100644 --- a/spec/ruby/core/tracepoint/instruction_sequence_spec.rb +++ b/spec/ruby/core/tracepoint/instruction_sequence_spec.rb @@ -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 diff --git a/spec/ruby/language/alias_spec.rb b/spec/ruby/language/alias_spec.rb index 306c2776b4..a7f34146d1 100644 --- a/spec/ruby/language/alias_spec.rb +++ b/spec/ruby/language/alias_spec.rb @@ -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 diff --git a/spec/ruby/language/fixtures/for_scope.rb b/spec/ruby/language/fixtures/for_scope.rb new file mode 100644 index 0000000000..9c44a23a2c --- /dev/null +++ b/spec/ruby/language/fixtures/for_scope.rb @@ -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 diff --git a/spec/ruby/language/for_spec.rb b/spec/ruby/language/for_spec.rb index 7d725430c6..0ad5ea88af 100644 --- a/spec/ruby/language/for_spec.rb +++ b/spec/ruby/language/for_spec.rb @@ -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 } diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb index 49837fa638..b0fc521d69 100644 --- a/spec/ruby/language/method_spec.rb +++ b/spec/ruby/language/method_spec.rb @@ -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 diff --git a/spec/ruby/library/bigdecimal/add_spec.rb b/spec/ruby/library/bigdecimal/add_spec.rb index 024dd576cc..1ae5b7f428 100644 --- a/spec/ruby/library/bigdecimal/add_spec.rb +++ b/spec/ruby/library/bigdecimal/add_spec.rb @@ -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') diff --git a/spec/ruby/library/bigdecimal/div_spec.rb b/spec/ruby/library/bigdecimal/div_spec.rb index a774376f55..23d1ae1efd 100644 --- a/spec/ruby/library/bigdecimal/div_spec.rb +++ b/spec/ruby/library/bigdecimal/div_spec.rb @@ -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) diff --git a/spec/ruby/library/bigdecimal/mult_spec.rb b/spec/ruby/library/bigdecimal/mult_spec.rb index a4c1602182..b7f8044b0b 100644 --- a/spec/ruby/library/bigdecimal/mult_spec.rb +++ b/spec/ruby/library/bigdecimal/mult_spec.rb @@ -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 diff --git a/spec/ruby/library/bigdecimal/multiply_spec.rb b/spec/ruby/library/bigdecimal/multiply_spec.rb index 2741d3623e..4e5a8d6681 100644 --- a/spec/ruby/library/bigdecimal/multiply_spec.rb +++ b/spec/ruby/library/bigdecimal/multiply_spec.rb @@ -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 diff --git a/spec/ruby/library/bigdecimal/remainder_spec.rb b/spec/ruby/library/bigdecimal/remainder_spec.rb index 28b25f8566..8626064a2f 100644 --- a/spec/ruby/library/bigdecimal/remainder_spec.rb +++ b/spec/ruby/library/bigdecimal/remainder_spec.rb @@ -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 { diff --git a/spec/ruby/library/bigdecimal/shared/modulo.rb b/spec/ruby/library/bigdecimal/shared/modulo.rb index c9691cbf37..d570b86d7a 100644 --- a/spec/ruby/library/bigdecimal/shared/modulo.rb +++ b/spec/ruby/library/bigdecimal/shared/modulo.rb @@ -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 diff --git a/spec/ruby/library/bigdecimal/shared/quo.rb b/spec/ruby/library/bigdecimal/shared/quo.rb index cb51c10d71..4d6d64b787 100644 --- a/spec/ruby/library/bigdecimal/shared/quo.rb +++ b/spec/ruby/library/bigdecimal/shared/quo.rb @@ -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 diff --git a/spec/ruby/library/bigdecimal/sub_spec.rb b/spec/ruby/library/bigdecimal/sub_spec.rb index 7f0305a1c6..f0068b12a9 100644 --- a/spec/ruby/library/bigdecimal/sub_spec.rb +++ b/spec/ruby/library/bigdecimal/sub_spec.rb @@ -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 diff --git a/spec/ruby/library/bigdecimal/util_spec.rb b/spec/ruby/library/bigdecimal/util_spec.rb new file mode 100644 index 0000000000..f41e131144 --- /dev/null +++ b/spec/ruby/library/bigdecimal/util_spec.rb @@ -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 diff --git a/spec/ruby/library/rbconfig/rbconfig_spec.rb b/spec/ruby/library/rbconfig/rbconfig_spec.rb index 8fa63b6e27..71e3d376d1 100644 --- a/spec/ruby/library/rbconfig/rbconfig_spec.rb +++ b/spec/ruby/library/rbconfig/rbconfig_spec.rb @@ -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 diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c index 3eeceae743..3255c4450d 100644 --- a/spec/ruby/optional/capi/ext/string_spec.c +++ b/spec/ruby/optional/capi/ext/string_spec.c @@ -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); diff --git a/spec/ruby/optional/capi/ext/typed_data_spec.c b/spec/ruby/optional/capi/ext/typed_data_spec.c index 60408a5750..a2cc53f54d 100644 --- a/spec/ruby/optional/capi/ext/typed_data_spec.c +++ b/spec/ruby/optional/capi/ext/typed_data_spec.c @@ -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 = { diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb index 627442104f..f68a46ed50 100644 --- a/spec/ruby/optional/capi/kernel_spec.rb +++ b/spec/ruby/optional/capi/kernel_spec.rb @@ -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 diff --git a/spec/ruby/optional/capi/mutex_spec.rb b/spec/ruby/optional/capi/mutex_spec.rb index 8844d311f2..1b76c5c250 100644 --- a/spec/ruby/optional/capi/mutex_spec.rb +++ b/spec/ruby/optional/capi/mutex_spec.rb @@ -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 diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb index 5ad8169e8e..ac23198662 100644 --- a/spec/ruby/optional/capi/string_spec.rb +++ b/spec/ruby/optional/capi/string_spec.rb @@ -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 diff --git a/spec/ruby/optional/capi/typed_data_spec.rb b/spec/ruby/optional/capi/typed_data_spec.rb index b0c0cd48ed..8d2910457c 100644 --- a/spec/ruby/optional/capi/typed_data_spec.rb +++ b/spec/ruby/optional/capi/typed_data_spec.rb @@ -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 diff --git a/spec/ruby/optional/capi/util_spec.rb b/spec/ruby/optional/capi/util_spec.rb index da2f758bec..b3e43d29ce 100644 --- a/spec/ruby/optional/capi/util_spec.rb +++ b/spec/ruby/optional/capi/util_spec.rb @@ -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] diff --git a/spec/ruby/security/cve_2019_8321_spec.rb b/spec/ruby/security/cve_2019_8321_spec.rb new file mode 100644 index 0000000000..affcd00e02 --- /dev/null +++ b/spec/ruby/security/cve_2019_8321_spec.rb @@ -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 diff --git a/spec/ruby/security/cve_2019_8322_spec.rb b/spec/ruby/security/cve_2019_8322_spec.rb new file mode 100644 index 0000000000..04fb1a7a26 --- /dev/null +++ b/spec/ruby/security/cve_2019_8322_spec.rb @@ -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 diff --git a/spec/ruby/security/cve_2019_8323_spec.rb b/spec/ruby/security/cve_2019_8323_spec.rb new file mode 100644 index 0000000000..af0b270880 --- /dev/null +++ b/spec/ruby/security/cve_2019_8323_spec.rb @@ -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 diff --git a/spec/ruby/security/cve_2019_8325_spec.rb b/spec/ruby/security/cve_2019_8325_spec.rb new file mode 100644 index 0000000000..dcdbe34210 --- /dev/null +++ b/spec/ruby/security/cve_2019_8325_spec.rb @@ -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 diff --git a/spec/ruby/shared/basicobject/send.rb b/spec/ruby/shared/basicobject/send.rb index 2b79ab4c2c..f96a3593bd 100644 --- a/spec/ruby/shared/basicobject/send.rb +++ b/spec/ruby/shared/basicobject/send.rb @@ -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 |