diff options
author | Benoit Daloze <[email protected]> | 2024-11-06 21:57:34 +0100 |
---|---|---|
committer | Benoit Daloze <[email protected]> | 2024-11-06 21:58:28 +0100 |
commit | fdc82cca83bbbfe88f90d2888e139a6dde481101 (patch) | |
tree | 99165cce6af5eaca59316c06fed33f958c85e16a | |
parent | 9bc63e7ba066b31314bbd66def4932b398eaf4c9 (diff) |
Update to ruby/spec@54c391e
95 files changed, 1945 insertions, 365 deletions
diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml index 5a902e0f01..a385b5e79c 100644 --- a/spec/ruby/.rubocop.yml +++ b/spec/ruby/.rubocop.yml @@ -5,9 +5,13 @@ AllCops: DisplayCopNames: true Exclude: - command_line/fixtures/bad_syntax.rb + - core/exception/fixtures/syntax_error.rb DisabledByDefault: true NewCops: disable +Layout/IndentationConsistency: + Enabled: true + Layout/TrailingWhitespace: Enabled: true @@ -43,9 +47,23 @@ Lint/InterpolationCheck: Lint/LiteralAsCondition: Enabled: false +# Required to support Ruby 3.0 +Lint/RedundantRequireStatement: + Exclude: + - core/fiber/**/*.rb + - library/fiber/**/*.rb + - optional/capi/fiber_spec.rb + +Lint/RedundantSafeNavigation: + Exclude: + - language/safe_navigator_spec.rb + Lint/RedundantSplatExpansion: Enabled: false +Lint/RescueException: + Enabled: false + Lint/UnifiedInteger: Enabled: false diff --git a/spec/ruby/.rubocop_todo.yml b/spec/ruby/.rubocop_todo.yml index 3ebb23a8bb..6b43db9b9a 100644 --- a/spec/ruby/.rubocop_todo.yml +++ b/spec/ruby/.rubocop_todo.yml @@ -1,6 +1,6 @@ # This configuration was generated by # `rubocop --auto-gen-config` -# on 2019-12-12 22:16:26 +0900 using RuboCop version 0.77.0. +# on 2024-10-12 16:01:45 UTC using RuboCop version 1.66.1. # The point is for the user to remove these configuration records # one by one as the offenses are removed from the code base. # Note that changes in the inspected code, or installation of new @@ -21,6 +21,7 @@ Lint/DuplicateMethods: - 'fixtures/class.rb' # Offense count: 8 +# This cop supports safe autocorrection (--autocorrect). Lint/EnsureReturn: Exclude: - 'language/fixtures/ensure.rb' @@ -39,6 +40,7 @@ Lint/FloatOutOfRange: - 'core/string/modulo_spec.rb' # Offense count: 2 +# This cop supports safe autocorrection (--autocorrect). Lint/ImplicitStringConcatenation: Exclude: - 'language/string_spec.rb' @@ -50,8 +52,8 @@ Lint/IneffectiveAccessModifier: - 'core/module/fixtures/classes.rb' - 'language/fixtures/private.rb' -# Offense count: 72 -# Cop supports --auto-correct. +# Offense count: 71 +# This cop supports safe autocorrection (--autocorrect). Lint/LiteralInInterpolation: Exclude: - 'core/module/refine_spec.rb' @@ -65,47 +67,28 @@ Lint/LiteralInInterpolation: - 'language/undef_spec.rb' # Offense count: 8 -# Cop supports --auto-correct. +# This cop supports safe autocorrection (--autocorrect). Lint/MultipleComparison: Exclude: - 'language/precedence_spec.rb' # Offense count: 9 +# This cop supports safe autocorrection (--autocorrect). Lint/ParenthesesAsGroupedExpression: Exclude: - - 'core/string/fixtures/freeze_magic_comment.rb' - 'language/block_spec.rb' - - 'language/fixtures/send.rb' - 'language/method_spec.rb' # Offense count: 2 -# Cop supports --auto-correct. +# This cop supports safe autocorrection (--autocorrect). Lint/RedundantStringCoercion: Exclude: - 'core/io/print_spec.rb' # Offense count: 1 -# Cop supports --auto-correct. -Lint/RedundantWithIndex: - Exclude: - - 'core/enumerator/with_index_spec.rb' - -# Offense count: 22 -Lint/RescueException: +Lint/SelfAssignment: Exclude: - - 'command_line/fixtures/debug_info.rb' - - 'core/dir/fileno_spec.rb' - - 'core/exception/cause_spec.rb' - - 'core/exception/no_method_error_spec.rb' - - 'core/fiber/kill_spec.rb' - - 'core/kernel/fixtures/autoload_frozen.rb' - - 'core/kernel/raise_spec.rb' - - 'core/module/autoload_spec.rb' - - 'core/mutex/sleep_spec.rb' - - 'core/thread/abort_on_exception_spec.rb' - - 'core/thread/shared/exit.rb' - - 'language/rescue_spec.rb' - - 'library/erb/filename_spec.rb' + - 'core/gc/auto_compact_spec.rb' # Offense count: 4 # Configuration parameters: IgnoreImplicitReferences. @@ -113,8 +96,8 @@ Lint/ShadowedArgument: Exclude: - 'language/fixtures/super.rb' -# Offense count: 39 -# Configuration parameters: AllowComments. +# Offense count: 45 +# Configuration parameters: AllowComments, AllowNil. Lint/SuppressedException: Enabled: false @@ -127,7 +110,8 @@ Lint/UnderscorePrefixedVariableName: - 'language/block_spec.rb' # Offense count: 7 -# Configuration parameters: ContextCreatingMethods, MethodCreatingMethods. +# This cop supports safe autocorrection (--autocorrect). +# Configuration parameters: AutoCorrect, ContextCreatingMethods, MethodCreatingMethods. Lint/UselessAccessModifier: Exclude: - 'core/module/define_method_spec.rb' diff --git a/spec/ruby/CONTRIBUTING.md b/spec/ruby/CONTRIBUTING.md index e9314208d1..5c3256948b 100644 --- a/spec/ruby/CONTRIBUTING.md +++ b/spec/ruby/CONTRIBUTING.md @@ -179,7 +179,9 @@ In case there is a bug in MRI and the fix will be backported to previous version If it is not backported or not likely, use `ruby_version_is` instead. First, file a bug at https://bugs.ruby-lang.org/. The problem is `ruby_bug` would make non-MRI implementations fail this spec while MRI itself does not pass it, so it should only be used if the bug is/will be fixed and backported. -Otherwise, non-MRI implementations would have to choose between being incompatible with the latest release of MRI to pass the spec or fail the spec, both which make no sense. +Otherwise, non-MRI implementations would have to choose between being incompatible with the latest release of MRI (which has the bug) to pass the spec, or behave the same as the latest release of MRI (which has the bug) and fail the spec, both which make no sense. + +IOW, `ruby_bug '#NN', ''...'X.Y' do` is equivalent to `guard_not { RUBY_ENGINE == "ruby" && ruby_version_is ''...'X.Y' } do`. So it skips tests on MRI on specified versions (where a bug is present) and runs tests on alternative implementations only. ```ruby ruby_bug '#13669', ''...'3.2' do diff --git a/spec/ruby/bin/rubocop b/spec/ruby/bin/rubocop new file mode 100755 index 0000000000..38254f13e4 --- /dev/null +++ b/spec/ruby/bin/rubocop @@ -0,0 +1,12 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +require 'bundler/inline' + +gemfile do + source 'https://rubygems.org' + + gem 'rubocop', '1.66.1' +end + +exec(Gem.bin_path('rubocop', 'rubocop'), *ARGV) diff --git a/spec/ruby/command_line/rubyopt_spec.rb b/spec/ruby/command_line/rubyopt_spec.rb index 18a5959b18..38e29c0d21 100644 --- a/spec/ruby/command_line/rubyopt_spec.rb +++ b/spec/ruby/command_line/rubyopt_spec.rb @@ -22,15 +22,15 @@ describe "Processing RUBYOPT" do result.should =~ /value of \$DEBUG is true/ end - guard -> { not CROSS_COMPILING } do + guard -> { RbConfig::CONFIG["CROSS_COMPILING"] != "yes" } do it "prints the version number for '-v'" do ENV["RUBYOPT"] = '-v' - ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION.sub("+PRISM ", "") + ruby_exe("").sub("+PRISM ", "")[/\A.*/].should == RUBY_DESCRIPTION.sub("+PRISM ", "") end it "ignores whitespace around the option" do ENV["RUBYOPT"] = ' -v ' - ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION.sub("+PRISM ", "") + ruby_exe("").sub("+PRISM ", "")[/\A.*/].should == RUBY_DESCRIPTION.sub("+PRISM ", "") end end diff --git a/spec/ruby/core/basicobject/instance_exec_spec.rb b/spec/ruby/core/basicobject/instance_exec_spec.rb index 289fdd889b..370f03d33c 100644 --- a/spec/ruby/core/basicobject/instance_exec_spec.rb +++ b/spec/ruby/core/basicobject/instance_exec_spec.rb @@ -84,17 +84,17 @@ describe "BasicObject#instance_exec" do end.should raise_error(TypeError) end -quarantine! do # Not clean, leaves cvars lying around to break other specs - it "scopes class var accesses in the caller when called on an Integer" do - # Integer can take instance vars - Integer.class_eval "@@__tmp_instance_exec_spec = 1" - (defined? @@__tmp_instance_exec_spec).should == nil - - @@__tmp_instance_exec_spec = 2 - 1.instance_exec { @@__tmp_instance_exec_spec }.should == 2 - Integer.__send__(:remove_class_variable, :@@__tmp_instance_exec_spec) + quarantine! do # Not clean, leaves cvars lying around to break other specs + it "scopes class var accesses in the caller when called on an Integer" do + # Integer can take instance vars + Integer.class_eval "@@__tmp_instance_exec_spec = 1" + (defined? @@__tmp_instance_exec_spec).should == nil + + @@__tmp_instance_exec_spec = 2 + 1.instance_exec { @@__tmp_instance_exec_spec }.should == 2 + Integer.__send__(:remove_class_variable, :@@__tmp_instance_exec_spec) + end end -end it "raises a TypeError when defining methods on numerics" do -> do diff --git a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb index 1960f5721f..eaf311783a 100644 --- a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb +++ b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb @@ -4,6 +4,10 @@ describe "RUBY_VERSION" do it "is a String" do RUBY_VERSION.should be_kind_of(String) end + + it "is frozen" do + RUBY_VERSION.should.frozen? + end end describe "RUBY_PATCHLEVEL" do @@ -16,34 +20,58 @@ describe "RUBY_COPYRIGHT" do it "is a String" do RUBY_COPYRIGHT.should be_kind_of(String) end + + it "is frozen" do + RUBY_COPYRIGHT.should.frozen? + end end describe "RUBY_DESCRIPTION" do it "is a String" do RUBY_DESCRIPTION.should be_kind_of(String) end + + it "is frozen" do + RUBY_DESCRIPTION.should.frozen? + end end describe "RUBY_ENGINE" do it "is a String" do RUBY_ENGINE.should be_kind_of(String) end + + it "is frozen" do + RUBY_ENGINE.should.frozen? + end end describe "RUBY_PLATFORM" do it "is a String" do RUBY_PLATFORM.should be_kind_of(String) end + + it "is frozen" do + RUBY_PLATFORM.should.frozen? + end end describe "RUBY_RELEASE_DATE" do it "is a String" do RUBY_RELEASE_DATE.should be_kind_of(String) end + + it "is frozen" do + RUBY_RELEASE_DATE.should.frozen? + end end describe "RUBY_REVISION" do it "is a String" do RUBY_REVISION.should be_kind_of(String) end + + it "is frozen" do + RUBY_REVISION.should.frozen? + end end diff --git a/spec/ruby/core/complex/equal_value_spec.rb b/spec/ruby/core/complex/equal_value_spec.rb index ad7236b1bd..97c486d820 100644 --- a/spec/ruby/core/complex/equal_value_spec.rb +++ b/spec/ruby/core/complex/equal_value_spec.rb @@ -76,7 +76,7 @@ describe "Complex#==" do (Complex(real, 0) == @other).should be_true end - it "returns false when when the imaginary part is not zero" do + it "returns false when the imaginary part is not zero" do (Complex(3, 1) == @other).should be_false end end diff --git a/spec/ruby/core/data/to_h_spec.rb b/spec/ruby/core/data/to_h_spec.rb new file mode 100644 index 0000000000..41d6960c97 --- /dev/null +++ b/spec/ruby/core/data/to_h_spec.rb @@ -0,0 +1,65 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "3.2" do + describe "Data#to_h" do + it "transforms the data object into a hash" do + data = DataSpecs::Measure.new(amount: 42, unit: 'km') + data.to_h.should == { amount: 42, unit: 'km' } + end + + context "with block" do + it "transforms [key, value] pairs returned by the block into a hash" do + data = DataSpecs::Measure.new(amount: 42, unit: 'km') + data.to_h { |key, value| [value, key] }.should == { 42 => :amount, 'km' => :unit } + end + + it "passes to a block each pair's key and value as separate arguments" do + ScratchPad.record [] + data = DataSpecs::Measure.new(amount: 42, unit: 'km') + data.to_h { |k, v| ScratchPad << [k, v]; [k, v] } + ScratchPad.recorded.sort.should == [[:amount, 42], [:unit, 'km']] + + ScratchPad.record [] + data.to_h { |*args| ScratchPad << args; [args[0], args[1]] } + ScratchPad.recorded.sort.should == [[:amount, 42], [:unit, 'km']] + end + + it "raises ArgumentError if block returns longer or shorter array" do + data = DataSpecs::Measure.new(amount: 42, unit: 'km') + -> do + data.to_h { |k, v| [k.to_s, v*v, 1] } + end.should raise_error(ArgumentError, /element has wrong array length/) + + -> do + data.to_h { |k, v| [k] } + end.should raise_error(ArgumentError, /element has wrong array length/) + end + + it "raises TypeError if block returns something other than Array" do + data = DataSpecs::Measure.new(amount: 42, unit: 'km') + -> do + data.to_h { |k, v| "not-array" } + end.should raise_error(TypeError, /wrong element type String/) + end + + it "coerces returned pair to Array with #to_ary" do + x = mock('x') + x.stub!(:to_ary).and_return([:b, 'b']) + data = DataSpecs::Measure.new(amount: 42, unit: 'km') + + data.to_h { |k| x }.should == { :b => 'b' } + end + + it "does not coerce returned pair to Array with #to_a" do + x = mock('x') + x.stub!(:to_a).and_return([:b, 'b']) + data = DataSpecs::Measure.new(amount: 42, unit: 'km') + + -> do + data.to_h { |k| x } + end.should raise_error(TypeError, /wrong element type MockObject/) + end + end + end +end diff --git a/spec/ruby/core/encoding/compatible_spec.rb b/spec/ruby/core/encoding/compatible_spec.rb index f18d8680a9..d5b958ea0b 100644 --- a/spec/ruby/core/encoding/compatible_spec.rb +++ b/spec/ruby/core/encoding/compatible_spec.rb @@ -161,6 +161,379 @@ describe "Encoding.compatible? String, String" do Encoding.compatible?(@str, "").should == Encoding::UTF_7 end end + + # Encoding negotiation depends on whether encodings are ASCII-compatible, empty + # and contain only ASCII characters (that take 7 bits). Check US-ASCII, UTF-8 and + # BINARY encodings (as most common) as well as an ASCII-compatible, a non-ASCII-compatible and a dummy + # encodings in all possible combinations. + describe "compatibility matrix" do + +# Use the following script to regenerate the matrix: +# +# ``` +# # -*- encoding: binary -*- +# +# ENCODINGS = [ +# "US-ASCII", +# "UTF-8", +# "ASCII-8BIT", +# "ISO-8859-1", # ASCII-compatible +# "UTF-16BE", # non-ASCII-compatible +# "ISO-2022-JP" # dummy +# ] +# +# TYPES = [:empty, :"7bits", :non7bits] +# +# VALUES = { +# empty: "", +# :"7bits" => "\x01", +# non7bits: "\x81" +# } +# +# ENCODINGS.product(TYPES, ENCODINGS, TYPES).each do |encoding1, type1, encoding2, type2| +# value1 = VALUES[type1].dup.force_encoding(encoding1) +# value2 = VALUES[type2].dup.force_encoding(encoding2) +# +# result_encoding = Encoding.compatible?(value1, value2) +# +# puts "[#{encoding1.inspect}, #{value1.inspect}, #{encoding2.inspect}, #{value2.inspect}, #{result_encoding&.name.inspect}]," +# end +# ``` + + matrix = [ + ["US-ASCII", "", "US-ASCII", "", "US-ASCII"], + ["US-ASCII", "", "US-ASCII", "\x01", "US-ASCII"], + ["US-ASCII", "", "US-ASCII", "\x81", "US-ASCII"], + ["US-ASCII", "", "UTF-8", "", "US-ASCII"], + ["US-ASCII", "", "UTF-8", "\u0001", "US-ASCII"], + ["US-ASCII", "", "UTF-8", "\x81", "UTF-8"], + ["US-ASCII", "", "ASCII-8BIT", "", "US-ASCII"], + ["US-ASCII", "", "ASCII-8BIT", "\x01", "US-ASCII"], + ["US-ASCII", "", "ASCII-8BIT", "\x81", "ASCII-8BIT"], + ["US-ASCII", "", "ISO-8859-1", "", "US-ASCII"], + ["US-ASCII", "", "ISO-8859-1", "\x01", "US-ASCII"], + ["US-ASCII", "", "ISO-8859-1", "\x81", "ISO-8859-1"], + ["US-ASCII", "", "UTF-16BE", "", "US-ASCII"], + ["US-ASCII", "", "UTF-16BE", "\x01", "UTF-16BE"], + ["US-ASCII", "", "UTF-16BE", "\x81", "UTF-16BE"], + ["US-ASCII", "", "ISO-2022-JP", "", "US-ASCII"], + ["US-ASCII", "", "ISO-2022-JP", "\x01", "ISO-2022-JP"], + ["US-ASCII", "", "ISO-2022-JP", "\x81", "ISO-2022-JP"], + ["US-ASCII", "\x01", "US-ASCII", "", "US-ASCII"], + ["US-ASCII", "\x01", "US-ASCII", "\x01", "US-ASCII"], + ["US-ASCII", "\x01", "US-ASCII", "\x81", "US-ASCII"], + ["US-ASCII", "\x01", "UTF-8", "", "US-ASCII"], + ["US-ASCII", "\x01", "UTF-8", "\u0001", "US-ASCII"], + ["US-ASCII", "\x01", "UTF-8", "\x81", "UTF-8"], + ["US-ASCII", "\x01", "ASCII-8BIT", "", "US-ASCII"], + ["US-ASCII", "\x01", "ASCII-8BIT", "\x01", "US-ASCII"], + ["US-ASCII", "\x01", "ASCII-8BIT", "\x81", "ASCII-8BIT"], + ["US-ASCII", "\x01", "ISO-8859-1", "", "US-ASCII"], + ["US-ASCII", "\x01", "ISO-8859-1", "\x01", "US-ASCII"], + ["US-ASCII", "\x01", "ISO-8859-1", "\x81", "ISO-8859-1"], + ["US-ASCII", "\x01", "UTF-16BE", "", "US-ASCII"], + ["US-ASCII", "\x01", "UTF-16BE", "\x01", nil], + ["US-ASCII", "\x01", "UTF-16BE", "\x81", nil], + ["US-ASCII", "\x01", "ISO-2022-JP", "", "US-ASCII"], + ["US-ASCII", "\x01", "ISO-2022-JP", "\x01", nil], + ["US-ASCII", "\x01", "ISO-2022-JP", "\x81", nil], + ["US-ASCII", "\x81", "US-ASCII", "", "US-ASCII"], + ["US-ASCII", "\x81", "US-ASCII", "\x01", "US-ASCII"], + ["US-ASCII", "\x81", "US-ASCII", "\x81", "US-ASCII"], + ["US-ASCII", "\x81", "UTF-8", "", "US-ASCII"], + ["US-ASCII", "\x81", "UTF-8", "\u0001", "US-ASCII"], + ["US-ASCII", "\x81", "UTF-8", "\x81", nil], + ["US-ASCII", "\x81", "ASCII-8BIT", "", "US-ASCII"], + ["US-ASCII", "\x81", "ASCII-8BIT", "\x01", "US-ASCII"], + ["US-ASCII", "\x81", "ASCII-8BIT", "\x81", nil], + ["US-ASCII", "\x81", "ISO-8859-1", "", "US-ASCII"], + ["US-ASCII", "\x81", "ISO-8859-1", "\x01", "US-ASCII"], + ["US-ASCII", "\x81", "ISO-8859-1", "\x81", nil], + ["US-ASCII", "\x81", "UTF-16BE", "", "US-ASCII"], + ["US-ASCII", "\x81", "UTF-16BE", "\x01", nil], + ["US-ASCII", "\x81", "UTF-16BE", "\x81", nil], + ["US-ASCII", "\x81", "ISO-2022-JP", "", "US-ASCII"], + ["US-ASCII", "\x81", "ISO-2022-JP", "\x01", nil], + ["US-ASCII", "\x81", "ISO-2022-JP", "\x81", nil], + ["UTF-8", "", "US-ASCII", "", "UTF-8"], + ["UTF-8", "", "US-ASCII", "\x01", "UTF-8"], + ["UTF-8", "", "US-ASCII", "\x81", "US-ASCII"], + ["UTF-8", "", "UTF-8", "", "UTF-8"], + ["UTF-8", "", "UTF-8", "\u0001", "UTF-8"], + ["UTF-8", "", "UTF-8", "\x81", "UTF-8"], + ["UTF-8", "", "ASCII-8BIT", "", "UTF-8"], + ["UTF-8", "", "ASCII-8BIT", "\x01", "UTF-8"], + ["UTF-8", "", "ASCII-8BIT", "\x81", "ASCII-8BIT"], + ["UTF-8", "", "ISO-8859-1", "", "UTF-8"], + ["UTF-8", "", "ISO-8859-1", "\x01", "UTF-8"], + ["UTF-8", "", "ISO-8859-1", "\x81", "ISO-8859-1"], + ["UTF-8", "", "UTF-16BE", "", "UTF-8"], + ["UTF-8", "", "UTF-16BE", "\x01", "UTF-16BE"], + ["UTF-8", "", "UTF-16BE", "\x81", "UTF-16BE"], + ["UTF-8", "", "ISO-2022-JP", "", "UTF-8"], + ["UTF-8", "", "ISO-2022-JP", "\x01", "ISO-2022-JP"], + ["UTF-8", "", "ISO-2022-JP", "\x81", "ISO-2022-JP"], + ["UTF-8", "\u0001", "US-ASCII", "", "UTF-8"], + ["UTF-8", "\u0001", "US-ASCII", "\x01", "UTF-8"], + ["UTF-8", "\u0001", "US-ASCII", "\x81", "US-ASCII"], + ["UTF-8", "\u0001", "UTF-8", "", "UTF-8"], + ["UTF-8", "\u0001", "UTF-8", "\u0001", "UTF-8"], + ["UTF-8", "\u0001", "UTF-8", "\x81", "UTF-8"], + ["UTF-8", "\u0001", "ASCII-8BIT", "", "UTF-8"], + ["UTF-8", "\u0001", "ASCII-8BIT", "\x01", "UTF-8"], + ["UTF-8", "\u0001", "ASCII-8BIT", "\x81", "ASCII-8BIT"], + ["UTF-8", "\u0001", "ISO-8859-1", "", "UTF-8"], + ["UTF-8", "\u0001", "ISO-8859-1", "\x01", "UTF-8"], + ["UTF-8", "\u0001", "ISO-8859-1", "\x81", "ISO-8859-1"], + ["UTF-8", "\u0001", "UTF-16BE", "", "UTF-8"], + ["UTF-8", "\u0001", "UTF-16BE", "\x01", nil], + ["UTF-8", "\u0001", "UTF-16BE", "\x81", nil], + ["UTF-8", "\u0001", "ISO-2022-JP", "", "UTF-8"], + ["UTF-8", "\u0001", "ISO-2022-JP", "\x01", nil], + ["UTF-8", "\u0001", "ISO-2022-JP", "\x81", nil], + ["UTF-8", "\x81", "US-ASCII", "", "UTF-8"], + ["UTF-8", "\x81", "US-ASCII", "\x01", "UTF-8"], + ["UTF-8", "\x81", "US-ASCII", "\x81", nil], + ["UTF-8", "\x81", "UTF-8", "", "UTF-8"], + ["UTF-8", "\x81", "UTF-8", "\u0001", "UTF-8"], + ["UTF-8", "\x81", "UTF-8", "\x81", "UTF-8"], + ["UTF-8", "\x81", "ASCII-8BIT", "", "UTF-8"], + ["UTF-8", "\x81", "ASCII-8BIT", "\x01", "UTF-8"], + ["UTF-8", "\x81", "ASCII-8BIT", "\x81", nil], + ["UTF-8", "\x81", "ISO-8859-1", "", "UTF-8"], + ["UTF-8", "\x81", "ISO-8859-1", "\x01", "UTF-8"], + ["UTF-8", "\x81", "ISO-8859-1", "\x81", nil], + ["UTF-8", "\x81", "UTF-16BE", "", "UTF-8"], + ["UTF-8", "\x81", "UTF-16BE", "\x01", nil], + ["UTF-8", "\x81", "UTF-16BE", "\x81", nil], + ["UTF-8", "\x81", "ISO-2022-JP", "", "UTF-8"], + ["UTF-8", "\x81", "ISO-2022-JP", "\x01", nil], + ["UTF-8", "\x81", "ISO-2022-JP", "\x81", nil], + ["ASCII-8BIT", "", "US-ASCII", "", "ASCII-8BIT"], + ["ASCII-8BIT", "", "US-ASCII", "\x01", "ASCII-8BIT"], + ["ASCII-8BIT", "", "US-ASCII", "\x81", "US-ASCII"], + ["ASCII-8BIT", "", "UTF-8", "", "ASCII-8BIT"], + ["ASCII-8BIT", "", "UTF-8", "\u0001", "ASCII-8BIT"], + ["ASCII-8BIT", "", "UTF-8", "\x81", "UTF-8"], + ["ASCII-8BIT", "", "ASCII-8BIT", "", "ASCII-8BIT"], + ["ASCII-8BIT", "", "ASCII-8BIT", "\x01", "ASCII-8BIT"], + ["ASCII-8BIT", "", "ASCII-8BIT", "\x81", "ASCII-8BIT"], + ["ASCII-8BIT", "", "ISO-8859-1", "", "ASCII-8BIT"], + ["ASCII-8BIT", "", "ISO-8859-1", "\x01", "ASCII-8BIT"], + ["ASCII-8BIT", "", "ISO-8859-1", "\x81", "ISO-8859-1"], + ["ASCII-8BIT", "", "UTF-16BE", "", "ASCII-8BIT"], + ["ASCII-8BIT", "", "UTF-16BE", "\x01", "UTF-16BE"], + ["ASCII-8BIT", "", "UTF-16BE", "\x81", "UTF-16BE"], + ["ASCII-8BIT", "", "ISO-2022-JP", "", "ASCII-8BIT"], + ["ASCII-8BIT", "", "ISO-2022-JP", "\x01", "ISO-2022-JP"], + ["ASCII-8BIT", "", "ISO-2022-JP", "\x81", "ISO-2022-JP"], + ["ASCII-8BIT", "\x01", "US-ASCII", "", "ASCII-8BIT"], + ["ASCII-8BIT", "\x01", "US-ASCII", "\x01", "ASCII-8BIT"], + ["ASCII-8BIT", "\x01", "US-ASCII", "\x81", "US-ASCII"], + ["ASCII-8BIT", "\x01", "UTF-8", "", "ASCII-8BIT"], + ["ASCII-8BIT", "\x01", "UTF-8", "\u0001", "ASCII-8BIT"], + ["ASCII-8BIT", "\x01", "UTF-8", "\x81", "UTF-8"], + ["ASCII-8BIT", "\x01", "ASCII-8BIT", "", "ASCII-8BIT"], + ["ASCII-8BIT", "\x01", "ASCII-8BIT", "\x01", "ASCII-8BIT"], + ["ASCII-8BIT", "\x01", "ASCII-8BIT", "\x81", "ASCII-8BIT"], + ["ASCII-8BIT", "\x01", "ISO-8859-1", "", "ASCII-8BIT"], + ["ASCII-8BIT", "\x01", "ISO-8859-1", "\x01", "ASCII-8BIT"], + ["ASCII-8BIT", "\x01", "ISO-8859-1", "\x81", "ISO-8859-1"], + ["ASCII-8BIT", "\x01", "UTF-16BE", "", "ASCII-8BIT"], + ["ASCII-8BIT", "\x01", "UTF-16BE", "\x01", nil], + ["ASCII-8BIT", "\x01", "UTF-16BE", "\x81", nil], + ["ASCII-8BIT", "\x01", "ISO-2022-JP", "", "ASCII-8BIT"], + ["ASCII-8BIT", "\x01", "ISO-2022-JP", "\x01", nil], + ["ASCII-8BIT", "\x01", "ISO-2022-JP", "\x81", nil], + ["ASCII-8BIT", "\x81", "US-ASCII", "", "ASCII-8BIT"], + ["ASCII-8BIT", "\x81", "US-ASCII", "\x01", "ASCII-8BIT"], + ["ASCII-8BIT", "\x81", "US-ASCII", "\x81", nil], + ["ASCII-8BIT", "\x81", "UTF-8", "", "ASCII-8BIT"], + ["ASCII-8BIT", "\x81", "UTF-8", "\u0001", "ASCII-8BIT"], + ["ASCII-8BIT", "\x81", "UTF-8", "\x81", nil], + ["ASCII-8BIT", "\x81", "ASCII-8BIT", "", "ASCII-8BIT"], + ["ASCII-8BIT", "\x81", "ASCII-8BIT", "\x01", "ASCII-8BIT"], + ["ASCII-8BIT", "\x81", "ASCII-8BIT", "\x81", "ASCII-8BIT"], + ["ASCII-8BIT", "\x81", "ISO-8859-1", "", "ASCII-8BIT"], + ["ASCII-8BIT", "\x81", "ISO-8859-1", "\x01", "ASCII-8BIT"], + ["ASCII-8BIT", "\x81", "ISO-8859-1", "\x81", nil], + ["ASCII-8BIT", "\x81", "UTF-16BE", "", "ASCII-8BIT"], + ["ASCII-8BIT", "\x81", "UTF-16BE", "\x01", nil], + ["ASCII-8BIT", "\x81", "UTF-16BE", "\x81", nil], + ["ASCII-8BIT", "\x81", "ISO-2022-JP", "", "ASCII-8BIT"], + ["ASCII-8BIT", "\x81", "ISO-2022-JP", "\x01", nil], + ["ASCII-8BIT", "\x81", "ISO-2022-JP", "\x81", nil], + ["ISO-8859-1", "", "US-ASCII", "", "ISO-8859-1"], + ["ISO-8859-1", "", "US-ASCII", "\x01", "ISO-8859-1"], + ["ISO-8859-1", "", "US-ASCII", "\x81", "US-ASCII"], + ["ISO-8859-1", "", "UTF-8", "", "ISO-8859-1"], + ["ISO-8859-1", "", "UTF-8", "\u0001", "ISO-8859-1"], + ["ISO-8859-1", "", "UTF-8", "\x81", "UTF-8"], + ["ISO-8859-1", "", "ASCII-8BIT", "", "ISO-8859-1"], + ["ISO-8859-1", "", "ASCII-8BIT", "\x01", "ISO-8859-1"], + ["ISO-8859-1", "", "ASCII-8BIT", "\x81", "ASCII-8BIT"], + ["ISO-8859-1", "", "ISO-8859-1", "", "ISO-8859-1"], + ["ISO-8859-1", "", "ISO-8859-1", "\x01", "ISO-8859-1"], + ["ISO-8859-1", "", "ISO-8859-1", "\x81", "ISO-8859-1"], + ["ISO-8859-1", "", "UTF-16BE", "", "ISO-8859-1"], + ["ISO-8859-1", "", "UTF-16BE", "\x01", "UTF-16BE"], + ["ISO-8859-1", "", "UTF-16BE", "\x81", "UTF-16BE"], + ["ISO-8859-1", "", "ISO-2022-JP", "", "ISO-8859-1"], + ["ISO-8859-1", "", "ISO-2022-JP", "\x01", "ISO-2022-JP"], + ["ISO-8859-1", "", "ISO-2022-JP", "\x81", "ISO-2022-JP"], + ["ISO-8859-1", "\x01", "US-ASCII", "", "ISO-8859-1"], + ["ISO-8859-1", "\x01", "US-ASCII", "\x01", "ISO-8859-1"], + ["ISO-8859-1", "\x01", "US-ASCII", "\x81", "US-ASCII"], + ["ISO-8859-1", "\x01", "UTF-8", "", "ISO-8859-1"], + ["ISO-8859-1", "\x01", "UTF-8", "\u0001", "ISO-8859-1"], + ["ISO-8859-1", "\x01", "UTF-8", "\x81", "UTF-8"], + ["ISO-8859-1", "\x01", "ASCII-8BIT", "", "ISO-8859-1"], + ["ISO-8859-1", "\x01", "ASCII-8BIT", "\x01", "ISO-8859-1"], + ["ISO-8859-1", "\x01", "ASCII-8BIT", "\x81", "ASCII-8BIT"], + ["ISO-8859-1", "\x01", "ISO-8859-1", "", "ISO-8859-1"], + ["ISO-8859-1", "\x01", "ISO-8859-1", "\x01", "ISO-8859-1"], + ["ISO-8859-1", "\x01", "ISO-8859-1", "\x81", "ISO-8859-1"], + ["ISO-8859-1", "\x01", "UTF-16BE", "", "ISO-8859-1"], + ["ISO-8859-1", "\x01", "UTF-16BE", "\x01", nil], + ["ISO-8859-1", "\x01", "UTF-16BE", "\x81", nil], + ["ISO-8859-1", "\x01", "ISO-2022-JP", "", "ISO-8859-1"], + ["ISO-8859-1", "\x01", "ISO-2022-JP", "\x01", nil], + ["ISO-8859-1", "\x01", "ISO-2022-JP", "\x81", nil], + ["ISO-8859-1", "\x81", "US-ASCII", "", "ISO-8859-1"], + ["ISO-8859-1", "\x81", "US-ASCII", "\x01", "ISO-8859-1"], + ["ISO-8859-1", "\x81", "US-ASCII", "\x81", nil], + ["ISO-8859-1", "\x81", "UTF-8", "", "ISO-8859-1"], + ["ISO-8859-1", "\x81", "UTF-8", "\u0001", "ISO-8859-1"], + ["ISO-8859-1", "\x81", "UTF-8", "\x81", nil], + ["ISO-8859-1", "\x81", "ASCII-8BIT", "", "ISO-8859-1"], + ["ISO-8859-1", "\x81", "ASCII-8BIT", "\x01", "ISO-8859-1"], + ["ISO-8859-1", "\x81", "ASCII-8BIT", "\x81", nil], + ["ISO-8859-1", "\x81", "ISO-8859-1", "", "ISO-8859-1"], + ["ISO-8859-1", "\x81", "ISO-8859-1", "\x01", "ISO-8859-1"], + ["ISO-8859-1", "\x81", "ISO-8859-1", "\x81", "ISO-8859-1"], + ["ISO-8859-1", "\x81", "UTF-16BE", "", "ISO-8859-1"], + ["ISO-8859-1", "\x81", "UTF-16BE", "\x01", nil], + ["ISO-8859-1", "\x81", "UTF-16BE", "\x81", nil], + ["ISO-8859-1", "\x81", "ISO-2022-JP", "", "ISO-8859-1"], + ["ISO-8859-1", "\x81", "ISO-2022-JP", "\x01", nil], + ["ISO-8859-1", "\x81", "ISO-2022-JP", "\x81", nil], + ["UTF-16BE", "", "US-ASCII", "", "UTF-16BE"], + ["UTF-16BE", "", "US-ASCII", "\x01", "US-ASCII"], + ["UTF-16BE", "", "US-ASCII", "\x81", "US-ASCII"], + ["UTF-16BE", "", "UTF-8", "", "UTF-16BE"], + ["UTF-16BE", "", "UTF-8", "\u0001", "UTF-8"], + ["UTF-16BE", "", "UTF-8", "\x81", "UTF-8"], + ["UTF-16BE", "", "ASCII-8BIT", "", "UTF-16BE"], + ["UTF-16BE", "", "ASCII-8BIT", "\x01", "ASCII-8BIT"], + ["UTF-16BE", "", "ASCII-8BIT", "\x81", "ASCII-8BIT"], + ["UTF-16BE", "", "ISO-8859-1", "", "UTF-16BE"], + ["UTF-16BE", "", "ISO-8859-1", "\x01", "ISO-8859-1"], + ["UTF-16BE", "", "ISO-8859-1", "\x81", "ISO-8859-1"], + ["UTF-16BE", "", "UTF-16BE", "", "UTF-16BE"], + ["UTF-16BE", "", "UTF-16BE", "\x01", "UTF-16BE"], + ["UTF-16BE", "", "UTF-16BE", "\x81", "UTF-16BE"], + ["UTF-16BE", "", "ISO-2022-JP", "", "UTF-16BE"], + ["UTF-16BE", "", "ISO-2022-JP", "\x01", "ISO-2022-JP"], + ["UTF-16BE", "", "ISO-2022-JP", "\x81", "ISO-2022-JP"], + ["UTF-16BE", "\x01", "US-ASCII", "", "UTF-16BE"], + ["UTF-16BE", "\x01", "US-ASCII", "\x01", nil], + ["UTF-16BE", "\x01", "US-ASCII", "\x81", nil], + ["UTF-16BE", "\x01", "UTF-8", "", "UTF-16BE"], + ["UTF-16BE", "\x01", "UTF-8", "\u0001", nil], + ["UTF-16BE", "\x01", "UTF-8", "\x81", nil], + ["UTF-16BE", "\x01", "ASCII-8BIT", "", "UTF-16BE"], + ["UTF-16BE", "\x01", "ASCII-8BIT", "\x01", nil], + ["UTF-16BE", "\x01", "ASCII-8BIT", "\x81", nil], + ["UTF-16BE", "\x01", "ISO-8859-1", "", "UTF-16BE"], + ["UTF-16BE", "\x01", "ISO-8859-1", "\x01", nil], + ["UTF-16BE", "\x01", "ISO-8859-1", "\x81", nil], + ["UTF-16BE", "\x01", "UTF-16BE", "", "UTF-16BE"], + ["UTF-16BE", "\x01", "UTF-16BE", "\x01", "UTF-16BE"], + ["UTF-16BE", "\x01", "UTF-16BE", "\x81", "UTF-16BE"], + ["UTF-16BE", "\x01", "ISO-2022-JP", "", "UTF-16BE"], + ["UTF-16BE", "\x01", "ISO-2022-JP", "\x01", nil], + ["UTF-16BE", "\x01", "ISO-2022-JP", "\x81", nil], + ["UTF-16BE", "\x81", "US-ASCII", "", "UTF-16BE"], + ["UTF-16BE", "\x81", "US-ASCII", "\x01", nil], + ["UTF-16BE", "\x81", "US-ASCII", "\x81", nil], + ["UTF-16BE", "\x81", "UTF-8", "", "UTF-16BE"], + ["UTF-16BE", "\x81", "UTF-8", "\u0001", nil], + ["UTF-16BE", "\x81", "UTF-8", "\x81", nil], + ["UTF-16BE", "\x81", "ASCII-8BIT", "", "UTF-16BE"], + ["UTF-16BE", "\x81", "ASCII-8BIT", "\x01", nil], + ["UTF-16BE", "\x81", "ASCII-8BIT", "\x81", nil], + ["UTF-16BE", "\x81", "ISO-8859-1", "", "UTF-16BE"], + ["UTF-16BE", "\x81", "ISO-8859-1", "\x01", nil], + ["UTF-16BE", "\x81", "ISO-8859-1", "\x81", nil], + ["UTF-16BE", "\x81", "UTF-16BE", "", "UTF-16BE"], + ["UTF-16BE", "\x81", "UTF-16BE", "\x01", "UTF-16BE"], + ["UTF-16BE", "\x81", "UTF-16BE", "\x81", "UTF-16BE"], + ["UTF-16BE", "\x81", "ISO-2022-JP", "", "UTF-16BE"], + ["UTF-16BE", "\x81", "ISO-2022-JP", "\x01", nil], + ["UTF-16BE", "\x81", "ISO-2022-JP", "\x81", nil], + ["ISO-2022-JP", "", "US-ASCII", "", "ISO-2022-JP"], + ["ISO-2022-JP", "", "US-ASCII", "\x01", "US-ASCII"], + ["ISO-2022-JP", "", "US-ASCII", "\x81", "US-ASCII"], + ["ISO-2022-JP", "", "UTF-8", "", "ISO-2022-JP"], + ["ISO-2022-JP", "", "UTF-8", "\u0001", "UTF-8"], + ["ISO-2022-JP", "", "UTF-8", "\x81", "UTF-8"], + ["ISO-2022-JP", "", "ASCII-8BIT", "", "ISO-2022-JP"], + ["ISO-2022-JP", "", "ASCII-8BIT", "\x01", "ASCII-8BIT"], + ["ISO-2022-JP", "", "ASCII-8BIT", "\x81", "ASCII-8BIT"], + ["ISO-2022-JP", "", "ISO-8859-1", "", "ISO-2022-JP"], + ["ISO-2022-JP", "", "ISO-8859-1", "\x01", "ISO-8859-1"], + ["ISO-2022-JP", "", "ISO-8859-1", "\x81", "ISO-8859-1"], + ["ISO-2022-JP", "", "UTF-16BE", "", "ISO-2022-JP"], + ["ISO-2022-JP", "", "UTF-16BE", "\x01", "UTF-16BE"], + ["ISO-2022-JP", "", "UTF-16BE", "\x81", "UTF-16BE"], + ["ISO-2022-JP", "", "ISO-2022-JP", "", "ISO-2022-JP"], + ["ISO-2022-JP", "", "ISO-2022-JP", "\x01", "ISO-2022-JP"], + ["ISO-2022-JP", "", "ISO-2022-JP", "\x81", "ISO-2022-JP"], + ["ISO-2022-JP", "\x01", "US-ASCII", "", "ISO-2022-JP"], + ["ISO-2022-JP", "\x01", "US-ASCII", "\x01", nil], + ["ISO-2022-JP", "\x01", "US-ASCII", "\x81", nil], + ["ISO-2022-JP", "\x01", "UTF-8", "", "ISO-2022-JP"], + ["ISO-2022-JP", "\x01", "UTF-8", "\u0001", nil], + ["ISO-2022-JP", "\x01", "UTF-8", "\x81", nil], + ["ISO-2022-JP", "\x01", "ASCII-8BIT", "", "ISO-2022-JP"], + ["ISO-2022-JP", "\x01", "ASCII-8BIT", "\x01", nil], + ["ISO-2022-JP", "\x01", "ASCII-8BIT", "\x81", nil], + ["ISO-2022-JP", "\x01", "ISO-8859-1", "", "ISO-2022-JP"], + ["ISO-2022-JP", "\x01", "ISO-8859-1", "\x01", nil], + ["ISO-2022-JP", "\x01", "ISO-8859-1", "\x81", nil], + ["ISO-2022-JP", "\x01", "UTF-16BE", "", "ISO-2022-JP"], + ["ISO-2022-JP", "\x01", "UTF-16BE", "\x01", nil], + ["ISO-2022-JP", "\x01", "UTF-16BE", "\x81", nil], + ["ISO-2022-JP", "\x01", "ISO-2022-JP", "", "ISO-2022-JP"], + ["ISO-2022-JP", "\x01", "ISO-2022-JP", "\x01", "ISO-2022-JP"], + ["ISO-2022-JP", "\x01", "ISO-2022-JP", "\x81", "ISO-2022-JP"], + ["ISO-2022-JP", "\x81", "US-ASCII", "", "ISO-2022-JP"], + ["ISO-2022-JP", "\x81", "US-ASCII", "\x01", nil], + ["ISO-2022-JP", "\x81", "US-ASCII", "\x81", nil], + ["ISO-2022-JP", "\x81", "UTF-8", "", "ISO-2022-JP"], + ["ISO-2022-JP", "\x81", "UTF-8", "\u0001", nil], + ["ISO-2022-JP", "\x81", "UTF-8", "\x81", nil], + ["ISO-2022-JP", "\x81", "ASCII-8BIT", "", "ISO-2022-JP"], + ["ISO-2022-JP", "\x81", "ASCII-8BIT", "\x01", nil], + ["ISO-2022-JP", "\x81", "ASCII-8BIT", "\x81", nil], + ["ISO-2022-JP", "\x81", "ISO-8859-1", "", "ISO-2022-JP"], + ["ISO-2022-JP", "\x81", "ISO-8859-1", "\x01", nil], + ["ISO-2022-JP", "\x81", "ISO-8859-1", "\x81", nil], + ["ISO-2022-JP", "\x81", "UTF-16BE", "", "ISO-2022-JP"], + ["ISO-2022-JP", "\x81", "UTF-16BE", "\x01", nil], + ["ISO-2022-JP", "\x81", "UTF-16BE", "\x81", nil], + ["ISO-2022-JP", "\x81", "ISO-2022-JP", "", "ISO-2022-JP"], + ["ISO-2022-JP", "\x81", "ISO-2022-JP", "\x01", "ISO-2022-JP"], + ["ISO-2022-JP", "\x81", "ISO-2022-JP", "\x81", "ISO-2022-JP"], + ] + + matrix.each do |encoding1, value1, encoding2, value2, compatible_encoding| + it "returns #{compatible_encoding} for #{value1.inspect} in #{encoding1} and #{value2.inspect} in #{encoding2}" do + actual_encoding = Encoding.compatible?(value1.dup.force_encoding(encoding1), value2.dup.force_encoding(encoding2)) + actual_encoding&.name.should == compatible_encoding + end + end + end end describe "Encoding.compatible? String, Regexp" do @@ -377,3 +750,9 @@ describe "Encoding.compatible? Object, Object" do Encoding.compatible?(:sym, Object.new).should be_nil end end + +describe "Encoding.compatible? nil, nil" do + it "returns nil" do + Encoding.compatible?(nil, nil).should be_nil + end +end diff --git a/spec/ruby/core/enumerator/each_with_index_spec.rb b/spec/ruby/core/enumerator/each_with_index_spec.rb index 96e53a2804..271e61fec6 100644 --- a/spec/ruby/core/enumerator/each_with_index_spec.rb +++ b/spec/ruby/core/enumerator/each_with_index_spec.rb @@ -21,16 +21,16 @@ describe "Enumerator#each_with_index" do it "passes on the given block's return value" do arr = [1,2,3] - arr.delete_if.with_index { |a,b| false } + arr.delete_if.each_with_index { |a,b| false } arr.should == [1,2,3] end it "returns the iterator's return value" do - [1,2,3].select.with_index { |a,b| false }.should == [] + [1,2,3].select.each_with_index { |a,b| false }.should == [] + [1,2,3].select.each_with_index { |a,b| true }.should == [1,2,3] end it "returns the correct value if chained with itself" do [:a].each_with_index.each_with_index.to_a.should == [[[:a,0],0]] - [:a].each.with_index.with_index.to_a.should == [[[:a,0],0]] end end diff --git a/spec/ruby/core/enumerator/with_index_spec.rb b/spec/ruby/core/enumerator/with_index_spec.rb index ac37cee508..3aeb3fc869 100644 --- a/spec/ruby/core/enumerator/with_index_spec.rb +++ b/spec/ruby/core/enumerator/with_index_spec.rb @@ -69,4 +69,21 @@ describe "Enumerator#with_index" do @enum.with_index(-1) { |*x| res << x} res.should == [[1,-1], [2,0], [3,1], [4,2]] end + + it "passes on the given block's return value" do + arr = [1,2,3] + arr.delete_if.with_index { |a,b| false } + arr.should == [1,2,3] + + arr.delete_if.with_index { |a,b| true } + arr.should == [] + end + + it "returns the iterator's return value" do + @enum.select.with_index { |a,b| false }.should == [] + end + + it "returns the correct value if chained with itself" do + [:a].each.with_index.with_index.to_a.should == [[[:a,0],0]] + end end diff --git a/spec/ruby/core/exception/full_message_spec.rb b/spec/ruby/core/exception/full_message_spec.rb index 5154354555..d752083db2 100644 --- a/spec/ruby/core/exception/full_message_spec.rb +++ b/spec/ruby/core/exception/full_message_spec.rb @@ -79,6 +79,24 @@ describe "Exception#full_message" do err.full_message(highlight: true).should !~ /unhandled exception/ err.full_message(highlight: false).should !~ /unhandled exception/ end + + it "adds escape sequences to highlight some strings if the message is not specified and :highlight option is specified" do + e = RuntimeError.new("") + + full_message = e.full_message(highlight: true, order: :top).lines + full_message[0].should.end_with? "\e[1;4munhandled exception\e[m\n" + + full_message = e.full_message(highlight: true, order: :bottom).lines + full_message[0].should == "\e[1mTraceback\e[m (most recent call last):\n" + full_message[-1].should.end_with? "\e[1;4munhandled exception\e[m\n" + + full_message = e.full_message(highlight: false, order: :top).lines + full_message[0].should.end_with? "unhandled exception\n" + + full_message = e.full_message(highlight: false, order: :bottom).lines + full_message[0].should == "Traceback (most recent call last):\n" + full_message[-1].should.end_with? "unhandled exception\n" + end end describe "generic Error" do diff --git a/spec/ruby/core/fiber/raise_spec.rb b/spec/ruby/core/fiber/raise_spec.rb index b3e021e636..2f2baa4a12 100644 --- a/spec/ruby/core/fiber/raise_spec.rb +++ b/spec/ruby/core/fiber/raise_spec.rb @@ -42,7 +42,7 @@ describe "Fiber#raise" do -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error' }.should raise_error(FiberSpecs::CustomError, 'test error') end - it 'accepts error class with with error message and backtrace information' do + it 'accepts error class with error message and backtrace information' do -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error', ['foo', 'boo'] }.should raise_error(FiberSpecs::CustomError) { |e| diff --git a/spec/ruby/core/file/chown_spec.rb b/spec/ruby/core/file/chown_spec.rb index 8cc8f0d04b..4db0e3712c 100644 --- a/spec/ruby/core/file/chown_spec.rb +++ b/spec/ruby/core/file/chown_spec.rb @@ -78,15 +78,15 @@ describe "File.chown" do end describe "File#chown" do - before :each do - @fname = tmp('file_chown_test') - @file = File.open(@fname, 'w') - end + before :each do + @fname = tmp('file_chown_test') + @file = File.open(@fname, 'w') + end - after :each do - @file.close unless @file.closed? - rm_r @fname - end + after :each do + @file.close unless @file.closed? + rm_r @fname + end as_superuser do platform_is :windows do diff --git a/spec/ruby/core/float/ceil_spec.rb b/spec/ruby/core/float/ceil_spec.rb index 7fc18d304c..75f5610292 100644 --- a/spec/ruby/core/float/ceil_spec.rb +++ b/spec/ruby/core/float/ceil_spec.rb @@ -1,6 +1,11 @@ require_relative '../../spec_helper' +require_relative '../integer/shared/integer_ceil_precision' describe "Float#ceil" do + context "with precision" do + it_behaves_like :integer_ceil_precision, :Float + end + it "returns the smallest Integer greater than or equal to self" do -1.2.ceil.should eql( -1) -1.0.ceil.should eql( -1) diff --git a/spec/ruby/core/float/comparison_spec.rb b/spec/ruby/core/float/comparison_spec.rb index 1373b3a1fb..d2e47937ff 100644 --- a/spec/ruby/core/float/comparison_spec.rb +++ b/spec/ruby/core/float/comparison_spec.rb @@ -72,7 +72,7 @@ describe "Float#<=>" do (-Float::MAX.to_i*2 <=> -infinity_value).should == 1 end - it "returns 0 when self is Infinity and other other is infinite?=1" do + it "returns 0 when self is Infinity and other is infinite?=1" do obj = Object.new def obj.infinite? 1 diff --git a/spec/ruby/core/float/floor_spec.rb b/spec/ruby/core/float/floor_spec.rb index 046216d36d..8b492ef473 100644 --- a/spec/ruby/core/float/floor_spec.rb +++ b/spec/ruby/core/float/floor_spec.rb @@ -1,6 +1,11 @@ require_relative '../../spec_helper' +require_relative '../integer/shared/integer_floor_precision' describe "Float#floor" do + context "with precision" do + it_behaves_like :integer_floor_precision, :Float + end + it "returns the largest Integer less than or equal to self" do -1.2.floor.should eql( -2) -1.0.floor.should eql( -1) diff --git a/spec/ruby/core/hash/element_reference_spec.rb b/spec/ruby/core/hash/element_reference_spec.rb index 94e8237839..d5859cb342 100644 --- a/spec/ruby/core/hash/element_reference_spec.rb +++ b/spec/ruby/core/hash/element_reference_spec.rb @@ -12,7 +12,7 @@ describe "Hash#[]" do h[[]].should == "baz" end - it "returns nil as default default value" do + it "returns nil as default value" do { 0 => 0 }[5].should == nil end diff --git a/spec/ruby/core/hash/hash_spec.rb b/spec/ruby/core/hash/hash_spec.rb index 19eb806dc4..9b47d4b2bf 100644 --- a/spec/ruby/core/hash/hash_spec.rb +++ b/spec/ruby/core/hash/hash_spec.rb @@ -47,7 +47,7 @@ describe "Hash#hash" do a = 1 b = 2 - eval('{a:, b:}.should == { a: 1, b: 2 }') + eval('{a:, b:}.should == { a: 1, b: 2 }') end end end diff --git a/spec/ruby/core/integer/ceil_spec.rb b/spec/ruby/core/integer/ceil_spec.rb index 13bdaf838d..eb633fba78 100644 --- a/spec/ruby/core/integer/ceil_spec.rb +++ b/spec/ruby/core/integer/ceil_spec.rb @@ -1,11 +1,16 @@ require_relative '../../spec_helper' require_relative 'shared/to_i' require_relative 'shared/integer_rounding' +require_relative 'shared/integer_ceil_precision' describe "Integer#ceil" do it_behaves_like :integer_to_i, :ceil it_behaves_like :integer_rounding_positive_precision, :ceil + context "with precision" do + it_behaves_like :integer_ceil_precision, :Integer + end + context "precision argument specified as part of the ceil method is negative" do it "returns the smallest integer greater than self with at least precision.abs trailing zeros" do 18.ceil(-1).should eql(20) diff --git a/spec/ruby/core/integer/floor_spec.rb b/spec/ruby/core/integer/floor_spec.rb index aaa816fdc5..8fb84d58cb 100644 --- a/spec/ruby/core/integer/floor_spec.rb +++ b/spec/ruby/core/integer/floor_spec.rb @@ -1,19 +1,13 @@ require_relative '../../spec_helper' require_relative 'shared/to_i' require_relative 'shared/integer_rounding' +require_relative 'shared/integer_floor_precision' describe "Integer#floor" do it_behaves_like :integer_to_i, :floor it_behaves_like :integer_rounding_positive_precision, :floor - context "precision argument specified as part of the floor method is negative" do - it "returns the largest integer less than self with at least precision.abs trailing zeros" do - 1832.floor(-1).should eql(1830) - 1832.floor(-2).should eql(1800) - 1832.floor(-3).should eql(1000) - -1832.floor(-1).should eql(-1840) - -1832.floor(-2).should eql(-1900) - -1832.floor(-3).should eql(-2000) - end + context "with precision" do + it_behaves_like :integer_floor_precision, :Integer end end diff --git a/spec/ruby/core/integer/pow_spec.rb b/spec/ruby/core/integer/pow_spec.rb index 4712911095..ecaca01eff 100644 --- a/spec/ruby/core/integer/pow_spec.rb +++ b/spec/ruby/core/integer/pow_spec.rb @@ -19,13 +19,13 @@ describe "Integer#pow" do 2.pow(61, 5843009213693951).should eql 3697379018277258 2.pow(62, 5843009213693952).should eql 1551748822859776 2.pow(63, 5843009213693953).should eql 3103497645717974 - 2.pow(64, 5843009213693954).should eql 363986077738838 + 2.pow(64, 5843009213693954).should eql 363986077738838 end it "handles sign like #divmod does" do - 2.pow(5, 12).should == 8 - 2.pow(5, -12).should == -4 - -2.pow(5, 12).should == 4 + 2.pow(5, 12).should == 8 + 2.pow(5, -12).should == -4 + -2.pow(5, 12).should == 4 -2.pow(5, -12).should == -8 end diff --git a/spec/ruby/core/integer/remainder_spec.rb b/spec/ruby/core/integer/remainder_spec.rb index 96268b3af5..757e42fbe8 100644 --- a/spec/ruby/core/integer/remainder_spec.rb +++ b/spec/ruby/core/integer/remainder_spec.rb @@ -15,8 +15,8 @@ describe "Integer#remainder" do end it "keeps sign of self" do - 5.remainder( 3).should == 2 - 5.remainder(-3).should == 2 + 5.remainder( 3).should == 2 + 5.remainder(-3).should == 2 -5.remainder( 3).should == -2 -5.remainder(-3).should == -2 end diff --git a/spec/ruby/core/integer/shared/integer_ceil_precision.rb b/spec/ruby/core/integer/shared/integer_ceil_precision.rb new file mode 100644 index 0000000000..9f31c2cf61 --- /dev/null +++ b/spec/ruby/core/integer/shared/integer_ceil_precision.rb @@ -0,0 +1,43 @@ +describe :integer_ceil_precision, shared: true do + context "precision is zero" do + it "returns integer self" do + send(@method, 0).ceil(0).should.eql?(0) + send(@method, 123).ceil(0).should.eql?(123) + send(@method, -123).ceil(0).should.eql?(-123) + end + end + + context "precision is positive" do + it "returns self" do + send(@method, 0).ceil(1).should.eql?(send(@method, 0)) + send(@method, 0).ceil(10).should.eql?(send(@method, 0)) + + send(@method, 123).ceil(10).should.eql?(send(@method, 123)) + send(@method, -123).ceil(10).should.eql?(send(@method, -123)) + end + end + + context "precision is negative" do + it "always returns 0 when self is 0" do + send(@method, 0).ceil(-1).should.eql?(0) + send(@method, 0).ceil(-10).should.eql?(0) + end + + it "returns largest integer less than self with at least precision.abs trailing zeros" do + send(@method, 123).ceil(-1).should.eql?(130) + send(@method, 123).ceil(-2).should.eql?(200) + send(@method, 123).ceil(-3).should.eql?(1000) + + send(@method, -123).ceil(-1).should.eql?(-120) + send(@method, -123).ceil(-2).should.eql?(-100) + send(@method, -123).ceil(-3).should.eql?(0) + end + + ruby_bug "#20654", ""..."3.4" do + it "returns 10**precision.abs when precision.abs is larger than the number digits of self" do + send(@method, 123).ceil(-20).should.eql?(100000000000000000000) + send(@method, 123).ceil(-50).should.eql?(100000000000000000000000000000000000000000000000000) + end + end + end +end diff --git a/spec/ruby/core/integer/shared/integer_floor_precision.rb b/spec/ruby/core/integer/shared/integer_floor_precision.rb new file mode 100644 index 0000000000..4c5888c6c4 --- /dev/null +++ b/spec/ruby/core/integer/shared/integer_floor_precision.rb @@ -0,0 +1,43 @@ +describe :integer_floor_precision, shared: true do + context "precision is zero" do + it "returns integer self" do + send(@method, 0).floor(0).should.eql?(0) + send(@method, 123).floor(0).should.eql?(123) + send(@method, -123).floor(0).should.eql?(-123) + end + end + + context "precision is positive" do + it "returns self" do + send(@method, 0).floor(1).should.eql?(send(@method, 0)) + send(@method, 0).floor(10).should.eql?(send(@method, 0)) + + send(@method, 123).floor(10).should.eql?(send(@method, 123)) + send(@method, -123).floor(10).should.eql?(send(@method, -123)) + end + end + + context "precision is negative" do + it "always returns 0 when self is 0" do + send(@method, 0).floor(-1).should.eql?(0) + send(@method, 0).floor(-10).should.eql?(0) + end + + it "returns largest integer less than self with at least precision.abs trailing zeros" do + send(@method, 123).floor(-1).should.eql?(120) + send(@method, 123).floor(-2).should.eql?(100) + send(@method, 123).floor(-3).should.eql?(0) + + send(@method, -123).floor(-1).should.eql?(-130) + send(@method, -123).floor(-2).should.eql?(-200) + send(@method, -123).floor(-3).should.eql?(-1000) + end + + ruby_bug "#20654", ""..."3.4" do + it "returns -(10**precision.abs) when self is negative and precision.abs is larger than the number digits of self" do + send(@method, -123).floor(-20).should.eql?(-100000000000000000000) + send(@method, -123).floor(-50).should.eql?(-100000000000000000000000000000000000000000000000000) + end + end + end +end diff --git a/spec/ruby/core/io/dup_spec.rb b/spec/ruby/core/io/dup_spec.rb index 68d538377f..564e007438 100644 --- a/spec/ruby/core/io/dup_spec.rb +++ b/spec/ruby/core/io/dup_spec.rb @@ -25,27 +25,27 @@ describe "IO#dup" do @i.fileno.should_not == @f.fileno end -quarantine! do # This does not appear to be consistent across platforms - it "shares the original stream between the two IOs" do - start = @f.pos - @i.pos.should == start + quarantine! do # This does not appear to be consistent across platforms + it "shares the original stream between the two IOs" do + start = @f.pos + @i.pos.should == start - s = "Hello, wo.. wait, where am I?\n" - s2 = "<evil voice> Muhahahaa!" + s = "Hello, wo.. wait, where am I?\n" + s2 = "<evil voice> Muhahahaa!" - @f.write s - @i.pos.should == @f.pos + @f.write s + @i.pos.should == @f.pos - @i.rewind - @i.gets.should == s + @i.rewind + @i.gets.should == s - @i.rewind - @i.write s2 + @i.rewind + @i.write s2 - @f.rewind - @f.gets.should == "#{s2}\n" + @f.rewind + @f.gets.should == "#{s2}\n" + end end -end it "allows closing the new IO without affecting the original" do @i.close diff --git a/spec/ruby/core/io/puts_spec.rb b/spec/ruby/core/io/puts_spec.rb index 9ed343c94c..a186ddaa5d 100644 --- a/spec/ruby/core/io/puts_spec.rb +++ b/spec/ruby/core/io/puts_spec.rb @@ -33,7 +33,7 @@ describe "IO#puts" do ScratchPad.recorded.should == "\n" end - it "writes empty string with a newline when when given nil as multiple args" do + it "writes empty string with a newline when given nil as multiple args" do @io.puts(nil, nil).should == nil ScratchPad.recorded.should == "\n\n" end diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb index 8741d9f017..567daa55df 100644 --- a/spec/ruby/core/io/read_spec.rb +++ b/spec/ruby/core/io/read_spec.rb @@ -217,19 +217,19 @@ describe "IO.read from a pipe" do end end -quarantine! do # The process tried to write to a nonexistent pipe. - platform_is :windows do - # TODO: It should raise Errno::ESPIPE on Windows as well - # once https://bugs.ruby-lang.org/issues/12230 is fixed. - it "raises Errno::EINVAL if passed an offset" do - -> { - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - IO.read("|cmd.exe /C echo hello", 1, 1) - end - }.should raise_error(Errno::EINVAL) + quarantine! do # The process tried to write to a nonexistent pipe. + platform_is :windows do + # TODO: It should raise Errno::ESPIPE on Windows as well + # once https://bugs.ruby-lang.org/issues/12230 is fixed. + it "raises Errno::EINVAL if passed an offset" do + -> { + suppress_warning do # https://bugs.ruby-lang.org/issues/19630 + IO.read("|cmd.exe /C echo hello", 1, 1) + end + }.should raise_error(Errno::EINVAL) + end end end -end ruby_version_is "3.3" do # https://bugs.ruby-lang.org/issues/19630 diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb index 454bc4a58e..5f4cd27da0 100644 --- a/spec/ruby/core/kernel/eval_spec.rb +++ b/spec/ruby/core/kernel/eval_spec.rb @@ -274,6 +274,26 @@ describe "Kernel#eval" do eval("").should == nil end + context "with shebang" do + it "ignores shebang with ruby interpreter" do + pid = eval(<<~CODE.b) + #!/usr/bin/env ruby + Process.pid + CODE + + pid.should == Process.pid + end + + it "ignores shebang with non-ruby interpreter" do + pid = eval(<<~CODE.b) + #!/usr/bin/env puma + Process.pid + CODE + + pid.should == Process.pid + end + end + # See language/magic_comment_spec.rb for more magic comments specs describe "with a magic encoding comment" do it "uses the magic comment encoding for the encoding of literal strings" do diff --git a/spec/ruby/core/kernel/extend_spec.rb b/spec/ruby/core/kernel/extend_spec.rb index 47b22f3a18..6342d8cae1 100644 --- a/spec/ruby/core/kernel/extend_spec.rb +++ b/spec/ruby/core/kernel/extend_spec.rb @@ -76,4 +76,16 @@ describe "Kernel#extend" do -> { @frozen.extend @module }.should raise_error(FrozenError) end end + + it "updated class methods of a module when it extends self and includes another module" do + a = Module.new do + extend self + end + b = Module.new do + def foo; :foo; end + end + + a.include b + a.foo.should == :foo + end end diff --git a/spec/ruby/core/kernel/raise_spec.rb b/spec/ruby/core/kernel/raise_spec.rb index 4f190c120b..a038dcf031 100644 --- a/spec/ruby/core/kernel/raise_spec.rb +++ b/spec/ruby/core/kernel/raise_spec.rb @@ -46,6 +46,22 @@ describe "Kernel#raise" do cause = StandardError.new -> { raise(cause: cause) }.should raise_error(ArgumentError) end + + it "re-raises a rescued exception" do + -> do + begin + raise StandardError, "aaa" + rescue Exception + begin + raise ArgumentError + rescue ArgumentError + end + + # should raise StandardError "aaa" + raise + end + end.should raise_error(StandardError, "aaa") + end end describe "Kernel#raise" do diff --git a/spec/ruby/core/kernel/select_spec.rb b/spec/ruby/core/kernel/select_spec.rb index e0d82f3079..df23414b28 100644 --- a/spec/ruby/core/kernel/select_spec.rb +++ b/spec/ruby/core/kernel/select_spec.rb @@ -10,9 +10,9 @@ end describe "Kernel.select" do it 'does not block when timeout is 0' do IO.pipe do |read, write| - IO.select([read], [], [], 0).should == nil + select([read], [], [], 0).should == nil write.write 'data' - IO.select([read], [], [], 0).should == [[read], [], []] + select([read], [], [], 0).should == [[read], [], []] end end end diff --git a/spec/ruby/core/kernel/sleep_spec.rb b/spec/ruby/core/kernel/sleep_spec.rb index d35e313006..1de52a707f 100644 --- a/spec/ruby/core/kernel/sleep_spec.rb +++ b/spec/ruby/core/kernel/sleep_spec.rb @@ -51,6 +51,20 @@ describe "Kernel#sleep" do t.value.should == 5 end + platform_is_not :darwin do + it "sleeps with nanosecond precision" do + start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) + 100.times do + sleep(0.0001) + end + end_time = Process.clock_gettime(Process::CLOCK_MONOTONIC) + + actual_duration = end_time - start_time + (actual_duration > 0.01).should == true # 100 * 0.0001 => 0.01 + (actual_duration < 0.03).should == true + end + end + ruby_version_is ""..."3.3" do it "raises a TypeError when passed nil" do -> { sleep(nil) }.should raise_error(TypeError) diff --git a/spec/ruby/core/marshal/fixtures/marshal_data.rb b/spec/ruby/core/marshal/fixtures/marshal_data.rb index a508b6bea1..aae3fce0aa 100644 --- a/spec/ruby/core/marshal/fixtures/marshal_data.rb +++ b/spec/ruby/core/marshal/fixtures/marshal_data.rb @@ -1,4 +1,7 @@ # -*- encoding: binary -*- + +require_relative 'marshal_multibyte_data' + class UserDefined class Nested def ==(other) @@ -267,17 +270,6 @@ module MarshalSpec end end - module_eval(<<~ruby.dup.force_encoding(Encoding::UTF_8)) - class MultibyteぁあぃいClass - end - - module MultibyteけげこごModule - end - - class MultibyteぁあぃいTime < Time - end - ruby - class ObjectWithFreezeRaisingException < Object def freeze raise diff --git a/spec/ruby/core/marshal/fixtures/marshal_multibyte_data.rb b/spec/ruby/core/marshal/fixtures/marshal_multibyte_data.rb new file mode 100644 index 0000000000..98a0d43392 --- /dev/null +++ b/spec/ruby/core/marshal/fixtures/marshal_multibyte_data.rb @@ -0,0 +1,12 @@ +# -*- encoding: utf-8 -*- + +module MarshalSpec + class MultibyteぁあぃいClass + end + + module MultibyteけげこごModule + end + + class MultibyteぁあぃいTime < Time + end +end diff --git a/spec/ruby/core/module/ancestors_spec.rb b/spec/ruby/core/module/ancestors_spec.rb index 5e4c196206..43ebdb864f 100644 --- a/spec/ruby/core/module/ancestors_spec.rb +++ b/spec/ruby/core/module/ancestors_spec.rb @@ -21,6 +21,17 @@ describe "Module#ancestors" do ModuleSpecs::Parent.ancestors.should == ModuleSpecs::Parent.ancestors.uniq end + it "returns a module that is included later into a nested module as well" do + m1 = Module.new + m2 = Module.new + m3 = Module.new do + include m2 + end + m2.include m1 # should be after m3 includes m2 + + m3.ancestors.should == [m3, m2, m1] + end + describe "when called on a singleton class" do it "includes the singleton classes of ancestors" do parent = Class.new diff --git a/spec/ruby/core/module/const_added_spec.rb b/spec/ruby/core/module/const_added_spec.rb index f9edda3a07..4b10dd5963 100644 --- a/spec/ruby/core/module/const_added_spec.rb +++ b/spec/ruby/core/module/const_added_spec.rb @@ -1,5 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +require_relative 'fixtures/const_added' describe "Module#const_added" do ruby_version_is "3.2" do @@ -63,6 +64,27 @@ describe "Module#const_added" do ScratchPad.recorded.should == [:SubModule] end + it "is called when a new module is defined under a named module (assigned to a constant)" do + ScratchPad.record [] + + ModuleSpecs::ConstAddedSpecs::NamedModule = Module.new do + def self.const_added(name) + ScratchPad << name + end + + module self::A + def self.const_added(name) + ScratchPad << name + end + + module self::B + end + end + end + + ScratchPad.recorded.should == [:A, :B] + end + it "is called when a new class is defined under self" do ScratchPad.record [] @@ -83,6 +105,27 @@ describe "Module#const_added" do ScratchPad.recorded.should == [:SubClass] end + it "is called when a new class is defined under a named module (assigned to a constant)" do + ScratchPad.record [] + + ModuleSpecs::ConstAddedSpecs::NamedModuleB = Module.new do + def self.const_added(name) + ScratchPad << name + end + + class self::A + def self.const_added(name) + ScratchPad << name + end + + class self::B + end + end + end + + ScratchPad.recorded.should == [:A, :B] + end + it "is called when an autoload is defined" do ScratchPad.record [] diff --git a/spec/ruby/core/module/fixtures/const_added.rb b/spec/ruby/core/module/fixtures/const_added.rb new file mode 100644 index 0000000000..0f5baad65d --- /dev/null +++ b/spec/ruby/core/module/fixtures/const_added.rb @@ -0,0 +1,4 @@ +module ModuleSpecs + module ConstAddedSpecs + end +end diff --git a/spec/ruby/core/module/fixtures/name.rb b/spec/ruby/core/module/fixtures/name.rb index fb9e66c309..25c74d3944 100644 --- a/spec/ruby/core/module/fixtures/name.rb +++ b/spec/ruby/core/module/fixtures/name.rb @@ -7,4 +7,7 @@ module ModuleSpecs Cß.name end end + + module NameSpecs + end end diff --git a/spec/ruby/core/module/include_spec.rb b/spec/ruby/core/module/include_spec.rb index 78f6b41031..862c6976e1 100644 --- a/spec/ruby/core/module/include_spec.rb +++ b/spec/ruby/core/module/include_spec.rb @@ -581,6 +581,29 @@ describe "Module#include" do c2.include(m) c2.new.foo.should == [:c2, :m1] end + + it "update a module when a nested module is updated and includes a module on its own" do + m1 = Module.new + m2 = Module.new do + def m2; [:m2]; end + end + m3 = Module.new do + def m3; [:m3]; end + end + m4 = Module.new do + def m4; [:m4]; end + end + c = Class.new + + c.include(m1) + m1.include(m2) + m2.include(m3) + m3.include(m4) + + c.new.m2.should == [:m2] + c.new.m3.should == [:m3] + c.new.m4.should == [:m4] + end end describe "Module#include?" do diff --git a/spec/ruby/core/module/name_spec.rb b/spec/ruby/core/module/name_spec.rb index 0d1f4e24d5..33e8400e88 100644 --- a/spec/ruby/core/module/name_spec.rb +++ b/spec/ruby/core/module/name_spec.rb @@ -140,6 +140,47 @@ describe "Module#name" do valid_names.should include(m::N.name) # You get one of the two, but you don't know which one. end + ruby_version_is "3.2" do + it "is set in #const_added callback when a module defined in the top-level scope" do + ruby_exe(<<~RUBY, args: "2>&1").chomp.should == "TEST1\nTEST2" + class Module + def const_added(name) + puts const_get(name).name + end + end + + # module with name + module TEST1 + end + + # anonymous module + TEST2 = Module.new + RUBY + end + + it "is set in #const_added callback for a nested module when an outer module defined in the top-level scope" do + ScratchPad.record [] + + ModuleSpecs::NameSpecs::NamedModule = Module.new do + def self.const_added(name) + ScratchPad << const_get(name).name + end + + module self::A + def self.const_added(name) + ScratchPad << const_get(name).name + end + + module self::B + end + end + end + + ScratchPad.recorded.should.one?(/#<Module.+>::A$/) + ScratchPad.recorded.should.one?(/#<Module.+>::A::B$/) + end + end + it "returns a frozen String" do ModuleSpecs.name.should.frozen? end diff --git a/spec/ruby/core/module/refine_spec.rb b/spec/ruby/core/module/refine_spec.rb index 11085c325b..8b9ea5eca8 100644 --- a/spec/ruby/core/module/refine_spec.rb +++ b/spec/ruby/core/module/refine_spec.rb @@ -245,7 +245,7 @@ describe "Module#refine" do ruby_version_is ""..."3.2" do it "looks in the included modules for builtin methods" do - result = ruby_exe(<<-RUBY) + result = ruby_exe(<<-RUBY) a = Module.new do def /(other) quo(other) end end diff --git a/spec/ruby/core/objectspace/add_finalizer_spec.rb b/spec/ruby/core/objectspace/add_finalizer_spec.rb deleted file mode 100644 index 3540ac0413..0000000000 --- a/spec/ruby/core/objectspace/add_finalizer_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require_relative '../../spec_helper' - -describe "ObjectSpace.add_finalizer" do - it "needs to be reviewed for spec completeness" -end diff --git a/spec/ruby/core/objectspace/call_finalizer_spec.rb b/spec/ruby/core/objectspace/call_finalizer_spec.rb deleted file mode 100644 index 6dce92ddd6..0000000000 --- a/spec/ruby/core/objectspace/call_finalizer_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require_relative '../../spec_helper' - -describe "ObjectSpace.call_finalizer" do - it "needs to be reviewed for spec completeness" -end diff --git a/spec/ruby/core/objectspace/define_finalizer_spec.rb b/spec/ruby/core/objectspace/define_finalizer_spec.rb index effecc41d0..4d4cfa9270 100644 --- a/spec/ruby/core/objectspace/define_finalizer_spec.rb +++ b/spec/ruby/core/objectspace/define_finalizer_spec.rb @@ -168,6 +168,31 @@ describe "ObjectSpace.define_finalizer" do ruby_exe(code).lines.sort.should == ["finalized1\n", "finalized2\n"] end + it "defines same finalizer only once" do + code = <<~RUBY + obj = Object.new + p = proc { |id| print "ok" } + ObjectSpace.define_finalizer(obj, p.dup) + ObjectSpace.define_finalizer(obj, p.dup) + RUBY + + ruby_exe(code).should == "ok" + end + + it "returns the defined finalizer" do + obj = Object.new + p = proc { |id| } + p2 = p.dup + + ret = ObjectSpace.define_finalizer(obj, p) + ret.should == [0, p] + ret[1].should.equal?(p) + + ret = ObjectSpace.define_finalizer(obj, p2) + ret.should == [0, p] + ret[1].should.equal?(p) + end + ruby_version_is "3.1" do describe "when $VERBOSE is not nil" do it "warns if an exception is raised in finalizer" do diff --git a/spec/ruby/core/objectspace/finalizers_spec.rb b/spec/ruby/core/objectspace/finalizers_spec.rb deleted file mode 100644 index e7f20fc8a0..0000000000 --- a/spec/ruby/core/objectspace/finalizers_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require_relative '../../spec_helper' - -describe "ObjectSpace.finalizers" do - it "needs to be reviewed for spec completeness" -end diff --git a/spec/ruby/core/objectspace/remove_finalizer_spec.rb b/spec/ruby/core/objectspace/remove_finalizer_spec.rb deleted file mode 100644 index 0b2b8cf16b..0000000000 --- a/spec/ruby/core/objectspace/remove_finalizer_spec.rb +++ /dev/null @@ -1,5 +0,0 @@ -require_relative '../../spec_helper' - -describe "ObjectSpace.remove_finalizer" do - it "needs to be reviewed for spec completeness" -end diff --git a/spec/ruby/core/objectspace/undefine_finalizer_spec.rb b/spec/ruby/core/objectspace/undefine_finalizer_spec.rb index 11d43121f8..f57d5a7845 100644 --- a/spec/ruby/core/objectspace/undefine_finalizer_spec.rb +++ b/spec/ruby/core/objectspace/undefine_finalizer_spec.rb @@ -1,5 +1,33 @@ require_relative '../../spec_helper' describe "ObjectSpace.undefine_finalizer" do - it "needs to be reviewed for spec completeness" + it "removes finalizers for an object" do + code = <<~RUBY + obj = Object.new + ObjectSpace.define_finalizer(obj, proc { |id| puts "hello" }) + ObjectSpace.undefine_finalizer(obj) + RUBY + + ruby_exe(code).should.empty? + end + + it "should not remove finalizers for a frozen object" do + code = <<~RUBY + obj = Object.new + ObjectSpace.define_finalizer(obj, proc { |id| print "ok" }) + obj.freeze + begin + ObjectSpace.undefine_finalizer(obj) + rescue + end + RUBY + + ruby_exe(code).should == "ok" + end + + it "should raise when removing finalizers for a frozen object" do + obj = Object.new + obj.freeze + -> { ObjectSpace.undefine_finalizer(obj) }.should raise_error(FrozenError) + end end diff --git a/spec/ruby/core/proc/curry_spec.rb b/spec/ruby/core/proc/curry_spec.rb index 24df2a8a72..6daabe0ee1 100644 --- a/spec/ruby/core/proc/curry_spec.rb +++ b/spec/ruby/core/proc/curry_spec.rb @@ -159,15 +159,14 @@ describe "Proc#curry with arity argument" do end it "can be passed more than _arity_ arguments if created from a proc" do - -> { @proc_add.curry(3)[1,2,3,4].should == 6 }.should_not - raise_error(ArgumentError) - -> { @proc_add.curry(1)[1,2].curry(3)[3,4,5,6].should == 6 }.should_not - raise_error(ArgumentError) + @proc_add.curry(3)[1,2,3,4].should == 6 + + @proc_add.curry(3)[1,2].curry(3)[3,4,5,6].should == 6 end it "raises an ArgumentError if passed more than _arity_ arguments when created from a lambda" do -> { @lambda_add.curry(3)[1,2,3,4] }.should raise_error(ArgumentError) - -> { @lambda_add.curry(1)[1,2].curry(3)[3,4,5,6] }.should raise_error(ArgumentError) + -> { @lambda_add.curry(3)[1,2].curry(3)[3,4,5,6] }.should raise_error(ArgumentError) end it "returns Procs with arities of -1 regardless of the value of _arity_" do diff --git a/spec/ruby/core/process/constants_spec.rb b/spec/ruby/core/process/constants_spec.rb index 616c54b8e1..57cacadef2 100644 --- a/spec/ruby/core/process/constants_spec.rb +++ b/spec/ruby/core/process/constants_spec.rb @@ -2,69 +2,91 @@ require_relative '../../spec_helper' describe "Process::Constants" do platform_is :darwin, :netbsd, :freebsd do - it "has the correct constant values on BSD-like systems" do - Process::WNOHANG.should == 1 - Process::WUNTRACED.should == 2 - Process::PRIO_PROCESS.should == 0 - Process::PRIO_PGRP.should == 1 - Process::PRIO_USER.should == 2 - Process::RLIM_INFINITY.should == 9223372036854775807 - Process::RLIMIT_CPU.should == 0 - Process::RLIMIT_FSIZE.should == 1 - Process::RLIMIT_DATA.should == 2 - Process::RLIMIT_STACK.should == 3 - Process::RLIMIT_CORE.should == 4 - Process::RLIMIT_RSS.should == 5 - Process::RLIMIT_MEMLOCK.should == 6 - Process::RLIMIT_NPROC.should == 7 - Process::RLIMIT_NOFILE.should == 8 + it "are all present on BSD-like systems" do + %i[ + WNOHANG + WUNTRACED + PRIO_PROCESS + PRIO_PGRP + PRIO_USER + RLIM_INFINITY + RLIMIT_CPU + RLIMIT_FSIZE + RLIMIT_DATA + RLIMIT_STACK + RLIMIT_CORE + RLIMIT_RSS + RLIMIT_MEMLOCK + RLIMIT_NPROC + RLIMIT_NOFILE + ].each do |const| + Process.const_defined?(const).should be_true + Process.const_get(const).should be_an_instance_of(Integer) + end end end platform_is :darwin do - it "has the correct constant values on Darwin" do - Process::RLIM_SAVED_MAX.should == 9223372036854775807 - Process::RLIM_SAVED_CUR.should == 9223372036854775807 - Process::RLIMIT_AS.should == 5 + it "are all present on Darwin" do + %i[ + RLIM_SAVED_MAX + RLIM_SAVED_CUR + RLIMIT_AS + ].each do |const| + Process.const_defined?(const).should be_true + Process.const_get(const).should be_an_instance_of(Integer) + end end end platform_is :linux do - it "has the correct constant values on Linux" do - Process::WNOHANG.should == 1 - Process::WUNTRACED.should == 2 - Process::PRIO_PROCESS.should == 0 - Process::PRIO_PGRP.should == 1 - Process::PRIO_USER.should == 2 - Process::RLIMIT_CPU.should == 0 - Process::RLIMIT_FSIZE.should == 1 - Process::RLIMIT_DATA.should == 2 - Process::RLIMIT_STACK.should == 3 - Process::RLIMIT_CORE.should == 4 - Process::RLIMIT_RSS.should == 5 - Process::RLIMIT_NPROC.should == 6 - Process::RLIMIT_NOFILE.should == 7 - Process::RLIMIT_MEMLOCK.should == 8 - Process::RLIMIT_AS.should == 9 - - # These values appear to change according to the platform. - values = [4294967295, 9223372036854775807, 18446744073709551615] - values.include?(Process::RLIM_INFINITY).should be_true - values.include?(Process::RLIM_SAVED_MAX).should be_true - values.include?(Process::RLIM_SAVED_CUR).should be_true + it "are all present on Linux" do + %i[ + WNOHANG + WUNTRACED + PRIO_PROCESS + PRIO_PGRP + PRIO_USER + RLIMIT_CPU + RLIMIT_FSIZE + RLIMIT_DATA + RLIMIT_STACK + RLIMIT_CORE + RLIMIT_RSS + RLIMIT_NPROC + RLIMIT_NOFILE + RLIMIT_MEMLOCK + RLIMIT_AS + RLIM_INFINITY + RLIM_SAVED_MAX + RLIM_SAVED_CUR + ].each do |const| + Process.const_defined?(const).should be_true + Process.const_get(const).should be_an_instance_of(Integer) + end end end platform_is :netbsd, :freebsd do - it "has the correct constant values on NetBSD and FreeBSD" do - Process::RLIMIT_SBSIZE.should == 9 # FIXME: what's it equal? - Process::RLIMIT_AS.should == 10 + it "are all present on NetBSD and FreeBSD" do + %i[ + RLIMIT_SBSIZE + RLIMIT_AS + ].each do |const| + Process.const_defined?(const).should be_true + Process.const_get(const).should be_an_instance_of(Integer) + end end end platform_is :freebsd do - it "has the correct constant values on FreeBSD" do - Process::RLIMIT_NPTS.should == 11 + it "are all present on FreeBSD" do + %i[ + RLIMIT_NPTS + ].each do |const| + Process.const_defined?(const).should be_true + Process.const_get(const).should be_an_instance_of(Integer) + end end end diff --git a/spec/ruby/core/queue/freeze_spec.rb b/spec/ruby/core/queue/freeze_spec.rb new file mode 100644 index 0000000000..ced2cc52dd --- /dev/null +++ b/spec/ruby/core/queue/freeze_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative '../../shared/queue/freeze' + +describe "Queue#freeze" do + it_behaves_like :queue_freeze, :freeze, -> { Queue.new } +end diff --git a/spec/ruby/core/regexp/shared/new.rb b/spec/ruby/core/regexp/shared/new.rb index 7052bcab63..3ca50d5a47 100644 --- a/spec/ruby/core/regexp/shared/new.rb +++ b/spec/ruby/core/regexp/shared/new.rb @@ -460,6 +460,10 @@ describe :regexp_new_string, shared: true do -> { Regexp.send(@method, "\\" + "u{}") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid Unicode list: /\\u{}/"))) end + it "raises a RegexpError if the \\u{} escape contains non hexadecimal digits" do + -> { Regexp.send(@method, "\\" + "u{abcX}") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid Unicode list: /\\u{abcX}/"))) + end + it "raises a RegexpError if more than six hexadecimal digits are given" do -> { Regexp.send(@method, "\\" + "u{0ffffff}") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid Unicode range: /\\u{0ffffff}/"))) end diff --git a/spec/ruby/core/regexp/shared/quote.rb b/spec/ruby/core/regexp/shared/quote.rb index b5ecc35f04..48179444f0 100644 --- a/spec/ruby/core/regexp/shared/quote.rb +++ b/spec/ruby/core/regexp/shared/quote.rb @@ -2,8 +2,8 @@ describe :regexp_quote, shared: true do it "escapes any characters with special meaning in a regular expression" do - Regexp.send(@method, '\*?{}.+^[]()- ').should == '\\\\\*\?\{\}\.\+\^\[\]\(\)\-\\ ' - Regexp.send(@method, "\*?{}.+^[]()- ").should == '\\*\\?\\{\\}\\.\\+\\^\\[\\]\\(\\)\\-\\ ' + Regexp.send(@method, '\*?{}.+^$[]()- ').should == '\\\\\*\?\{\}\.\+\^\$\[\]\(\)\-\\ ' + Regexp.send(@method, "\*?{}.+^$[]()- ").should == '\\*\\?\\{\\}\\.\\+\\^\\$\\[\\]\\(\\)\\-\\ ' Regexp.send(@method, '\n\r\f\t').should == '\\\\n\\\\r\\\\f\\\\t' Regexp.send(@method, "\n\r\f\t").should == '\\n\\r\\f\\t' end diff --git a/spec/ruby/core/sizedqueue/freeze_spec.rb b/spec/ruby/core/sizedqueue/freeze_spec.rb new file mode 100644 index 0000000000..98f01cae2f --- /dev/null +++ b/spec/ruby/core/sizedqueue/freeze_spec.rb @@ -0,0 +1,6 @@ +require_relative '../../spec_helper' +require_relative '../../shared/queue/freeze' + +describe "SizedQueue#freeze" do + it_behaves_like :queue_freeze, :freeze, -> { SizedQueue.new(1) } +end diff --git a/spec/ruby/core/string/byteslice_spec.rb b/spec/ruby/core/string/byteslice_spec.rb index 5b1027f4a5..9fe504aeb1 100644 --- a/spec/ruby/core/string/byteslice_spec.rb +++ b/spec/ruby/core/string/byteslice_spec.rb @@ -17,7 +17,7 @@ describe "String#byteslice with Range" do it_behaves_like :string_slice_range, :byteslice end -describe "String#byteslice on on non ASCII strings" do +describe "String#byteslice on non ASCII strings" do it "returns byteslice of unicode strings" do "\u3042".byteslice(1).should == "\x81".dup.force_encoding("UTF-8") "\u3042".byteslice(1, 2).should == "\x81\x82".dup.force_encoding("UTF-8") diff --git a/spec/ruby/core/string/bytesplice_spec.rb b/spec/ruby/core/string/bytesplice_spec.rb index 967edcba29..5cb3b2c158 100644 --- a/spec/ruby/core/string/bytesplice_spec.rb +++ b/spec/ruby/core/string/bytesplice_spec.rb @@ -58,6 +58,79 @@ describe "String#bytesplice" do -> { s.bytesplice(2, 1, "xxx") }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"") end end + + ruby_version_is "3.3" do + it "raises IndexError when str_index is less than -bytesize" do + -> { "hello".bytesplice(2, 1, "HELLO", -6, 0) }.should raise_error(IndexError, "index -6 out of string") + end + + it "raises IndexError when str_index is greater than bytesize" do + -> { "hello".bytesplice(2, 1, "HELLO", 6, 0) }.should raise_error(IndexError, "index 6 out of string") + end + + it "raises IndexError for negative str length" do + -> { "abc".bytesplice(0, 1, "", 0, -2) }.should raise_error(IndexError, "negative length -2") + end + + it "replaces with integer str indices" do + "hello".bytesplice(1, 2, "HELLO", -5, 0).should == "hlo" + "hello".bytesplice(1, 2, "HELLO", 0, 0).should == "hlo" + "hello".bytesplice(1, 2, "HELLO", 0, 1).should == "hHlo" + "hello".bytesplice(1, 2, "HELLO", 0, 5).should == "hHELLOlo" + "hello".bytesplice(1, 2, "HELLO", 0, 6).should == "hHELLOlo" + end + + it "raises RangeError when str range left boundary is less than -bytesize" do + -> { "hello".bytesplice(0..1, "HELLO", -6...-6) }.should raise_error(RangeError, "-6...-6 out of range") + end + + it "replaces with str ranges" do + "hello".bytesplice(1..2, "HELLO", -5...-5).should == "hlo" + "hello".bytesplice(1..2, "HELLO", 0...0).should == "hlo" + "hello".bytesplice(1..2, "HELLO", 0..0).should == "hHlo" + "hello".bytesplice(1..2, "HELLO", 0...1).should == "hHlo" + "hello".bytesplice(1..2, "HELLO", 0..1).should == "hHElo" + "hello".bytesplice(1..2, "HELLO", 0..-1).should == "hHELLOlo" + "hello".bytesplice(1..2, "HELLO", 0...5).should == "hHELLOlo" + "hello".bytesplice(1..2, "HELLO", 0...6).should == "hHELLOlo" + end + + it "raises ArgumentError when integer str index is provided without str length argument" do + -> { "hello".bytesplice(0, 1, "xxx", 0) }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 2, 3, or 5)") + end + + it "replaces on an empty string with str index/length" do + "".bytesplice(0, 0, "", 0, 0).should == "" + "".bytesplice(0, 0, "xxx", 0, 1).should == "x" + end + + it "mutates self with substring and str index/length" do + s = "hello" + s.bytesplice(2, 1, "xxx", 1, 2).should.equal?(s) + s.should.eql?("hexxlo") + end + + it "raises when string is frozen and str index/length" do + s = "hello".freeze + -> { s.bytesplice(2, 1, "xxx", 0, 1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"") + end + + it "replaces on an empty string with str range" do + "".bytesplice(0..0, "", 0..0).should == "" + "".bytesplice(0..0, "xyz", 0..1).should == "xy" + end + + it "mutates self with substring and str range" do + s = "hello" + s.bytesplice(2..2, "xyz", 1..2).should.equal?(s) + s.should.eql?("heyzlo") + end + + it "raises when string is frozen and str range" do + s = "hello".freeze + -> { s.bytesplice(2..2, "yzx", 0..1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"") + end + end end describe "String#bytesplice with multibyte characters" do @@ -131,4 +204,95 @@ describe "String#bytesplice with multibyte characters" do result.encoding.should == Encoding::UTF_8 end end + + ruby_version_is "3.3" do + it "raises IndexError when str_index is out of byte size boundary" do + -> { "こんにちは".bytesplice(3, 3, "こんにちは", -16, 0) }.should raise_error(IndexError, "index -16 out of string") + end + + it "raises IndexError when str_index is not on a codepoint boundary" do + -> { "こんにちは".bytesplice(3, 3, "こんにちは", 1, 0) }.should raise_error(IndexError, "offset 1 does not land on character boundary") + end + + it "raises IndexError when str_length is not matching the codepoint boundary" do + -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 1) }.should raise_error(IndexError, "offset 1 does not land on character boundary") + -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 2) }.should raise_error(IndexError, "offset 2 does not land on character boundary") + end + + it "replaces with integer str indices" do + "こんにちは".bytesplice(3, 3, "こんにちは", -15, 0).should == "こにちは" + "こんにちは".bytesplice(3, 3, "こんにちは", 0, 0).should == "こにちは" + "こんにちは".bytesplice(3, 3, "こんにちは", 0, 3).should == "ここにちは" + "こんにちは".bytesplice(3, 3, "はは", 3, 3).should == "こはにちは" + "こんにちは".bytesplice(3, 3, "こんにちは", 15, 0).should == "こにちは" + end + + it "replaces with str range" do + "こんにちは".bytesplice(0..2, "こんにちは", -15...-16).should == "んにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 0...0).should == "んにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 3..5).should == "んんにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 3...6).should == "んんにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 3..8).should == "んにんにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 0..-1).should == "こんにちはんにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 0...15).should == "こんにちはんにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 0...18).should == "こんにちはんにちは" + end + + it "treats negative length for str range as 0" do + "こんにちは".bytesplice(0..2, "こんにちは", 0...-100).should == "んにちは" + "こんにちは".bytesplice(0..2, "こんにちは", 3...-100).should == "んにちは" + "こんにちは".bytesplice(0..2, "こんにちは", -15...-100).should == "んにちは" + end + + it "raises when ranges not match codepoint boundaries in str" do + -> { "こんにちは".bytesplice(3...3, "こ", 0..0) }.should raise_error(IndexError, "offset 1 does not land on character boundary") + -> { "こんにちは".bytesplice(3...3, "こ", 0..1) }.should raise_error(IndexError, "offset 2 does not land on character boundary") + # Begin is incorrect + -> { "こんにちは".bytesplice(3...3, "こんにちは", -4..-1) }.should raise_error(IndexError, "offset 11 does not land on character boundary") + -> { "こんにちは".bytesplice(3...3, "こんにちは", -5..-1) }.should raise_error(IndexError, "offset 10 does not land on character boundary") + # End is incorrect + -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-2) }.should raise_error(IndexError, "offset 14 does not land on character boundary") + -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-3) }.should raise_error(IndexError, "offset 13 does not land on character boundary") + end + + it "deals with a different encoded argument with str index/length" do + s = "こんにちは" + s.encoding.should == Encoding::UTF_8 + sub = "goodbye" + sub.force_encoding(Encoding::US_ASCII) + + result = s.bytesplice(3, 3, sub, 0, 3) + result.should == "こgooにちは" + result.encoding.should == Encoding::UTF_8 + + s = "hello" + s.force_encoding(Encoding::US_ASCII) + sub = "こんにちは" + sub.encoding.should == Encoding::UTF_8 + + result = s.bytesplice(1, 2, sub, 3, 3) + result.should == "hんlo" + result.encoding.should == Encoding::UTF_8 + end + + it "deals with a different encoded argument with str range" do + s = "こんにちは" + s.encoding.should == Encoding::UTF_8 + sub = "goodbye" + sub.force_encoding(Encoding::US_ASCII) + + result = s.bytesplice(3..5, sub, 0..2) + result.should == "こgooにちは" + result.encoding.should == Encoding::UTF_8 + + s = "hello" + s.force_encoding(Encoding::US_ASCII) + sub = "こんにちは" + sub.encoding.should == Encoding::UTF_8 + + result = s.bytesplice(1..2, sub, 3..5) + result.should == "hんlo" + result.encoding.should == Encoding::UTF_8 + end + end end diff --git a/spec/ruby/core/thread/element_reference_spec.rb b/spec/ruby/core/thread/element_reference_spec.rb index 85280cb287..fde9d1f440 100644 --- a/spec/ruby/core/thread/element_reference_spec.rb +++ b/spec/ruby/core/thread/element_reference_spec.rb @@ -37,6 +37,17 @@ describe "Thread#[]" do t2["value"].should == 2 end + it "converts a key that is neither String nor Symbol with #to_str" do + key = mock('value') + key.should_receive(:to_str).and_return('value') + + th = Thread.new do + Thread.current[:value] = 1 + end.join + + th[key].should == 1 + end + it "raises exceptions on the wrong type of keys" do -> { Thread.current[nil] }.should raise_error(TypeError) -> { Thread.current[5] }.should raise_error(TypeError) diff --git a/spec/ruby/core/thread/element_set_spec.rb b/spec/ruby/core/thread/element_set_spec.rb index c7498f7ac9..f205177304 100644 --- a/spec/ruby/core/thread/element_set_spec.rb +++ b/spec/ruby/core/thread/element_set_spec.rb @@ -12,10 +12,33 @@ describe "Thread#[]=" do th.freeze -> { th[:foo] = "bar" - }.should raise_error(FrozenError, /frozen/) + }.should raise_error(FrozenError, "can't modify frozen thread locals") end.join end + it "accepts Strings and Symbols" do + t1 = Thread.new do + Thread.current[:value] = 1 + end.join + t2 = Thread.new do + Thread.current["value"] = 2 + end.join + + t1[:value].should == 1 + t2[:value].should == 2 + end + + it "converts a key that is neither String nor Symbol with #to_str" do + key = mock('value') + key.should_receive(:to_str).and_return('value') + + th = Thread.new do + Thread.current[key] = 1 + end.join + + th[:value].should == 1 + end + it "raises exceptions on the wrong type of keys" do -> { Thread.current[nil] = true }.should raise_error(TypeError) -> { Thread.current[5] = true }.should raise_error(TypeError) diff --git a/spec/ruby/core/thread/group_spec.rb b/spec/ruby/core/thread/group_spec.rb index 59f5ac37c8..d0d4704b66 100644 --- a/spec/ruby/core/thread/group_spec.rb +++ b/spec/ruby/core/thread/group_spec.rb @@ -1,5 +1,16 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' + describe "Thread#group" do - it "needs to be reviewed for spec completeness" + it "returns the default thread group for the main thread" do + Thread.main.group.should == ThreadGroup::Default + end + + it "returns the thread group explicitly set for this thread" do + thread = Thread.new { nil } + thread_group = ThreadGroup.new + thread_group.add(thread) + thread.group.should == thread_group + ensure + thread.join if thread + end end diff --git a/spec/ruby/core/thread/key_spec.rb b/spec/ruby/core/thread/key_spec.rb index 6940cf5f28..339fa98f53 100644 --- a/spec/ruby/core/thread/key_spec.rb +++ b/spec/ruby/core/thread/key_spec.rb @@ -16,6 +16,13 @@ describe "Thread#key?" do @th.key?(:stanley.to_s).should == false end + it "converts a key that is neither String nor Symbol with #to_str" do + key = mock('key') + key.should_receive(:to_str).and_return('oliver') + + @th.key?(key).should == true + end + it "raises exceptions on the wrong type of keys" do -> { Thread.current.key? nil }.should raise_error(TypeError) -> { Thread.current.key? 5 }.should raise_error(TypeError) diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb index fa5b5c56d6..c310a8631e 100644 --- a/spec/ruby/core/time/new_spec.rb +++ b/spec/ruby/core/time/new_spec.rb @@ -485,6 +485,8 @@ describe "Time.new with a timezone argument" do Time.new("2020-12-25 00:56:17 +0900").should == t Time.new("2020-12-25 00:57:47 +090130").should == t Time.new("2020-12-25T00:56:17+09:00").should == t + + Time.new("2020-12-25T00:56:17.123456+09:00").should == Time.utc(2020, 12, 24, 15, 56, 17, 123456) end it "accepts precision keyword argument and truncates specified digits of sub-second part" do @@ -511,6 +513,16 @@ describe "Time.new with a timezone argument" do Time.new("2021-12-25 00:00:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 -0100" end + it "returns Time of Jan 1 for string with just year" do + Time.new("2021").should == Time.new(2021, 1, 1) + Time.new("2021").zone.should == Time.new(2021, 1, 1).zone + Time.new("2021").utc_offset.should == Time.new(2021, 1, 1).utc_offset + end + + it "returns Time of Jan 1 for string with just year in timezone specified with in keyword argument" do + Time.new("2021", in: "+17:00").to_s.should == "2021-01-01 00:00:00 +1700" + end + it "converts precision keyword argument into Integer if is not nil" do obj = Object.new def obj.to_int; 3; end @@ -539,101 +551,109 @@ describe "Time.new with a timezone argument" do it "raises ArgumentError if part of time string is missing" do -> { Time.new("2020-12-25 00:56 +09:00") - }.should raise_error(ArgumentError, "missing sec part: 00:56 ") + }.should raise_error(ArgumentError, /missing sec part: 00:56 |can't parse:/) -> { Time.new("2020-12-25 00 +09:00") - }.should raise_error(ArgumentError, "missing min part: 00 ") + }.should raise_error(ArgumentError, /missing min part: 00 |can't parse:/) + end + + ruby_version_is "3.2.3" do + it "raises ArgumentError if the time part is missing" do + -> { + Time.new("2020-12-25") + }.should raise_error(ArgumentError, /no time information|can't parse:/) + end end it "raises ArgumentError if subsecond is missing after dot" do -> { Time.new("2020-12-25 00:56:17. +0900") - }.should raise_error(ArgumentError, "subsecond expected after dot: 00:56:17. ") + }.should raise_error(ArgumentError, /subsecond expected after dot: 00:56:17. |can't parse:/) end it "raises ArgumentError if String argument is not in the supported format" do -> { Time.new("021-12-25 00:00:00.123456 +09:00") - }.should raise_error(ArgumentError, "year must be 4 or more digits: 021") + }.should raise_error(ArgumentError, /year must be 4 or more digits: 021|can't parse:/) -> { Time.new("2020-012-25 00:56:17 +0900") - }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -012-25 00:\z/) + }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -012-25 00:\z|can't parse:/) -> { Time.new("2020-2-25 00:56:17 +0900") - }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -2-25 00:56\z/) + }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -2-25 00:56\z|can't parse:/) -> { Time.new("2020-12-215 00:56:17 +0900") - }.should raise_error(ArgumentError, /\Atwo digits mday is expected after [`']-': -215 00:56:\z/) + }.should raise_error(ArgumentError, /\Atwo digits mday is expected after [`']-': -215 00:56:\z|can't parse:/) -> { Time.new("2020-12-25 000:56:17 +0900") - }.should raise_error(ArgumentError, "two digits hour is expected: 000:56:17 ") + }.should raise_error(ArgumentError, /two digits hour is expected: 000:56:17 |can't parse:/) -> { Time.new("2020-12-25 0:56:17 +0900") - }.should raise_error(ArgumentError, "two digits hour is expected: 0:56:17 +0") + }.should raise_error(ArgumentError, /two digits hour is expected: 0:56:17 \+0|can't parse:/) -> { Time.new("2020-12-25 00:516:17 +0900") - }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :516:17 \+09\z/) + }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :516:17 \+09\z|can't parse:/) -> { Time.new("2020-12-25 00:6:17 +0900") - }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :6:17 \+0900\z/) + }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :6:17 \+0900\z|can't parse:/) -> { Time.new("2020-12-25 00:56:137 +0900") - }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :137 \+0900\z/) + }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :137 \+0900\z|can't parse:/) -> { Time.new("2020-12-25 00:56:7 +0900") - }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :7 \+0900\z/) + }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :7 \+0900\z|can't parse:/) -> { Time.new("2020-12-25 00:56. +0900") - }.should raise_error(ArgumentError, "fraction min is not supported: 00:56.") + }.should raise_error(ArgumentError, /fraction min is not supported: 00:56\.|can't parse:/) -> { Time.new("2020-12-25 00. +0900") - }.should raise_error(ArgumentError, "fraction hour is not supported: 00.") + }.should raise_error(ArgumentError, /fraction hour is not supported: 00\.|can't parse:/) end it "raises ArgumentError if date/time parts values are not valid" do -> { Time.new("2020-13-25 00:56:17 +09:00") - }.should raise_error(ArgumentError, "mon out of range") + }.should raise_error(ArgumentError, /(mon|argument) out of range/) -> { Time.new("2020-12-32 00:56:17 +09:00") - }.should raise_error(ArgumentError, "mday out of range") + }.should raise_error(ArgumentError, /(mday|argument) out of range/) -> { Time.new("2020-12-25 25:56:17 +09:00") - }.should raise_error(ArgumentError, "hour out of range") + }.should raise_error(ArgumentError, /(hour|argument) out of range/) -> { Time.new("2020-12-25 00:61:17 +09:00") - }.should raise_error(ArgumentError, "min out of range") + }.should raise_error(ArgumentError, /(min|argument) out of range/) -> { Time.new("2020-12-25 00:56:61 +09:00") - }.should raise_error(ArgumentError, "sec out of range") + }.should raise_error(ArgumentError, /(sec|argument) out of range/) -> { Time.new("2020-12-25 00:56:17 +23:59:60") - }.should raise_error(ArgumentError, /utc_offset/) + }.should raise_error(ArgumentError, /utc_offset|argument out of range/) -> { Time.new("2020-12-25 00:56:17 +24:00") - }.should raise_error(ArgumentError, /utc_offset/) + }.should raise_error(ArgumentError, /(utc_offset|argument) out of range/) -> { Time.new("2020-12-25 00:56:17 +23:61") - }.should raise_error(ArgumentError, /utc_offset/) + }.should raise_error(ArgumentError, /utc_offset|can't parse:/) ruby_bug '#20797', ''...'3.4' do -> { @@ -647,6 +667,18 @@ describe "Time.new with a timezone argument" do Time.new("2021-11-31 00:00:60 +09:00".encode("utf-32le")) }.should raise_error(ArgumentError, "time string should have ASCII compatible encoding") end + + it "raises ArgumentError if string doesn't start with year" do + -> { + Time.new("a\nb") + }.should raise_error(ArgumentError, "can't parse: \"a\\nb\"") + end + + it "raises ArgumentError if string has extra characters after offset" do + -> { + Time.new("2021-11-31 00:00:59 +09:00 abc") + }.should raise_error(ArgumentError, /can't parse.+ abc/) + end end end end diff --git a/spec/ruby/core/warning/warn_spec.rb b/spec/ruby/core/warning/warn_spec.rb index 1c21fe29e0..572885c2b4 100644 --- a/spec/ruby/core/warning/warn_spec.rb +++ b/spec/ruby/core/warning/warn_spec.rb @@ -121,7 +121,7 @@ describe "Warning.warn" do end end - ruby_bug '#19530', ''...'3.4' do + ruby_bug '#20573', ''...'3.4' do it "isn't called by Kernel.warn when category is :deprecated but Warning[:deprecated] is false" do warn_deprecated = Warning[:deprecated] begin diff --git a/spec/ruby/fixtures/constants.rb b/spec/ruby/fixtures/constants.rb index ffe45fb1f6..7f0b88daab 100644 --- a/spec/ruby/fixtures/constants.rb +++ b/spec/ruby/fixtures/constants.rb @@ -10,7 +10,7 @@ # variety in class and module configurations, including hierarchy, # containment, inclusion, singletons and toplevel. # -# Constants are numbered for for uniqueness. The CS_ prefix is uniformly used +# Constants are numbered for uniqueness. The CS_ prefix is uniformly used # and is to minimize clashes with other toplevel constants (see e.g. ModuleA # which is included in Object). Constant values are symbols. A numbered suffix # is used to distinguish constants with the same name defined in different diff --git a/spec/ruby/language/fixtures/private.rb b/spec/ruby/language/fixtures/private.rb index 96f73cea3f..da3e0a97f9 100644 --- a/spec/ruby/language/fixtures/private.rb +++ b/spec/ruby/language/fixtures/private.rb @@ -43,17 +43,17 @@ module Private end end - class E - include D - end - - class G - def foo - "foo" - end - end - - class H < A - private :foo - end + class E + include D + end + + class G + def foo + "foo" + end + end + + class H < A + private :foo + end end diff --git a/spec/ruby/language/fixtures/send.rb b/spec/ruby/language/fixtures/send.rb index 918241e171..5d1d9da214 100644 --- a/spec/ruby/language/fixtures/send.rb +++ b/spec/ruby/language/fixtures/send.rb @@ -43,9 +43,9 @@ module LangSendSpecs attr_writer :foo private :foo= - def call_self_foo_equals(value) - self.foo = value - end + def call_self_foo_equals(value) + self.foo = value + end def call_self_foo_equals_masgn(value) a, self.foo = 1, value diff --git a/spec/ruby/language/precedence_spec.rb b/spec/ruby/language/precedence_spec.rb index c5adcca2c0..5e606c16d8 100644 --- a/spec/ruby/language/precedence_spec.rb +++ b/spec/ruby/language/precedence_spec.rb @@ -294,14 +294,14 @@ describe "Operators" do -> { eval("1...2...3") }.should raise_error(SyntaxError) end - it ".. ... have higher precedence than ? :" do - # Use variables to avoid warnings - from = 1 - to = 2 - # These are flip-flop, not Range instances - (from..to ? 3 : 4).should == 3 - (from...to ? 3 : 4).should == 3 - end + it ".. ... have higher precedence than ? :" do + # Use variables to avoid warnings + from = 1 + to = 2 + # These are flip-flop, not Range instances + (from..to ? 3 : 4).should == 3 + (from...to ? 3 : 4).should == 3 + end it "? : is right-associative" do (true ? 2 : 3 ? 4 : 5).should == 2 diff --git a/spec/ruby/language/predefined_spec.rb b/spec/ruby/language/predefined_spec.rb index ac28f1e8a0..cc231e341e 100644 --- a/spec/ruby/language/predefined_spec.rb +++ b/spec/ruby/language/predefined_spec.rb @@ -243,6 +243,16 @@ describe "Predefined global $stdout" do end describe "Predefined global $!" do + it "is Fiber-local" do + Fiber.new do + raise "hi" + rescue + Fiber.yield + end.resume + + $!.should == nil + end + # See http://jira.codehaus.org/browse/JRUBY-5550 it "remains nil after a failed core class \"checked\" coercion against a class that defines method_missing" do $!.should == nil diff --git a/spec/ruby/language/regexp_spec.rb b/spec/ruby/language/regexp_spec.rb index 89d0914807..dbf341b19e 100644 --- a/spec/ruby/language/regexp_spec.rb +++ b/spec/ruby/language/regexp_spec.rb @@ -62,7 +62,7 @@ describe "Literal Regexps" do end end - it "supports non-paired delimiters delimiters with %r" do + it "supports non-paired delimiters with %r" do LanguageSpecs.non_paired_delimiters.each do |c| eval("%r#{c} foo #{c}").should == / foo / end diff --git a/spec/ruby/language/super_spec.rb b/spec/ruby/language/super_spec.rb index a98b3b3091..7d9e896d8b 100644 --- a/spec/ruby/language/super_spec.rb +++ b/spec/ruby/language/super_spec.rb @@ -70,7 +70,7 @@ describe "The super keyword" do SuperSpecs::S4::B.new.foo([],"test").should == ["B#foo(a,test)", "A#foo"] end - it "raises an error error when super method does not exist" do + it "raises an error when super method does not exist" do sup = Class.new sub_normal = Class.new(sup) do def foo diff --git a/spec/ruby/library/bigdecimal/fix_spec.rb b/spec/ruby/library/bigdecimal/fix_spec.rb index 231c9a587e..2c6276899e 100644 --- a/spec/ruby/library/bigdecimal/fix_spec.rb +++ b/spec/ruby/library/bigdecimal/fix_spec.rb @@ -2,20 +2,20 @@ require_relative '../../spec_helper' require 'bigdecimal' describe "BigDecimal#fix" do - before :each do - @zero = BigDecimal("0") - @mixed = BigDecimal("1.23456789") - @pos_int = BigDecimal("2E5555") - @neg_int = BigDecimal("-2E5555") - @pos_frac = BigDecimal("2E-9999") - @neg_frac = BigDecimal("-2E-9999") - - @infinity = BigDecimal("Infinity") - @infinity_neg = BigDecimal("-Infinity") - @nan = BigDecimal("NaN") - @zero_pos = BigDecimal("+0") - @zero_neg = BigDecimal("-0") - end + before :each do + @zero = BigDecimal("0") + @mixed = BigDecimal("1.23456789") + @pos_int = BigDecimal("2E5555") + @neg_int = BigDecimal("-2E5555") + @pos_frac = BigDecimal("2E-9999") + @neg_frac = BigDecimal("-2E-9999") + + @infinity = BigDecimal("Infinity") + @infinity_neg = BigDecimal("-Infinity") + @nan = BigDecimal("NaN") + @zero_pos = BigDecimal("+0") + @zero_neg = BigDecimal("-0") + end it "returns a BigDecimal" do BigDecimal("2E100000000").fix.kind_of?(BigDecimal).should == true diff --git a/spec/ruby/library/date/mon_spec.rb b/spec/ruby/library/date/mon_spec.rb index 724e7d6564..616d72cf88 100644 --- a/spec/ruby/library/date/mon_spec.rb +++ b/spec/ruby/library/date/mon_spec.rb @@ -1,6 +1,7 @@ require_relative '../../spec_helper' +require_relative 'shared/month' require 'date' describe "Date#mon" do - it "needs to be reviewed for spec completeness" + it_behaves_like :date_month, :mon end diff --git a/spec/ruby/library/date/month_spec.rb b/spec/ruby/library/date/month_spec.rb index e040f9a94c..f493ec8119 100644 --- a/spec/ruby/library/date/month_spec.rb +++ b/spec/ruby/library/date/month_spec.rb @@ -1,9 +1,7 @@ require_relative '../../spec_helper' +require_relative 'shared/month' require 'date' describe "Date#month" do - it "returns the month" do - m = Date.new(2000, 7, 1).month - m.should == 7 - end + it_behaves_like :date_month, :month end diff --git a/spec/ruby/library/date/shared/month.rb b/spec/ruby/library/date/shared/month.rb new file mode 100644 index 0000000000..5fcb2cbeb0 --- /dev/null +++ b/spec/ruby/library/date/shared/month.rb @@ -0,0 +1,6 @@ +describe :date_month, shared: true do + it "returns the month" do + m = Date.new(2000, 7, 1).send(@method) + m.should == 7 + end +end diff --git a/spec/ruby/library/erb/new_spec.rb b/spec/ruby/library/erb/new_spec.rb index a5aeeaeed1..f721529ab0 100644 --- a/spec/ruby/library/erb/new_spec.rb +++ b/spec/ruby/library/erb/new_spec.rb @@ -130,7 +130,7 @@ END <b><%#= item %></b> <%# end %> END - ERBSpecs.new_erb(input).result.should == "\n<b></b>\n\n" + ERBSpecs.new_erb(input).result.should == "\n<b></b>\n\n" ERBSpecs.new_erb(input, trim_mode: '<>').result.should == "<b></b>\n" end diff --git a/spec/ruby/library/logger/logger/new_spec.rb b/spec/ruby/library/logger/logger/new_spec.rb index d3100ee2d1..6dcb030ae1 100644 --- a/spec/ruby/library/logger/logger/new_spec.rb +++ b/spec/ruby/library/logger/logger/new_spec.rb @@ -13,19 +13,19 @@ describe "Logger#new" do rm_r @file_path end - it "creates a new logger object" do - l = Logger.new(STDERR) - -> { l.add(Logger::WARN, "Foo") }.should output_to_fd(/Foo/, STDERR) - end - - it "receives a logging device as first argument" do - l = Logger.new(@log_file) - l.add(Logger::WARN, "Test message") - - @log_file.rewind - LoggerSpecs.strip_date(@log_file.readline).should == "WARN -- : Test message\n" - l.close - end + it "creates a new logger object" do + l = Logger.new(STDERR) + -> { l.add(Logger::WARN, "Foo") }.should output_to_fd(/Foo/, STDERR) + end + + it "receives a logging device as first argument" do + l = Logger.new(@log_file) + l.add(Logger::WARN, "Test message") + + @log_file.rewind + LoggerSpecs.strip_date(@log_file.readline).should == "WARN -- : Test message\n" + l.close + end it "receives a frequency rotation as second argument" do -> { Logger.new(@log_file, "daily") }.should_not raise_error diff --git a/spec/ruby/library/pathname/glob_spec.rb b/spec/ruby/library/pathname/glob_spec.rb index ced810fa90..de322bab47 100644 --- a/spec/ruby/library/pathname/glob_spec.rb +++ b/spec/ruby/library/pathname/glob_spec.rb @@ -21,6 +21,10 @@ describe 'Pathname.glob' do Pathname.glob(@dir + 'lib/*.js').should == [] end + it 'returns [] when the pathname does not exist' do + Pathname.glob('i_dont_exist/lib/*.js').should == [] + end + it 'returns matching file paths' do Pathname.glob(@dir + 'lib/*i*.rb').sort.should == [Pathname.new(@file_1), Pathname.new(@file_2)].sort end @@ -67,6 +71,10 @@ describe 'Pathname#glob' do Pathname.new(@dir).glob('lib/*.js').should == [] end + it 'returns [] when the pathname does not exist' do + Pathname.new('./i_dont_exist').glob('lib/*.js').should == [] + end + it 'returns matching file paths' do Pathname.new(@dir).glob('lib/*i*.rb').sort.should == [Pathname.new(@file_1), Pathname.new(@file_2)].sort end diff --git a/spec/ruby/library/rbconfig/rbconfig_spec.rb b/spec/ruby/library/rbconfig/rbconfig_spec.rb index 3e06219621..b9a4588bf0 100644 --- a/spec/ruby/library/rbconfig/rbconfig_spec.rb +++ b/spec/ruby/library/rbconfig/rbconfig_spec.rb @@ -9,6 +9,13 @@ describe 'RbConfig::CONFIG' do end end + it 'has MAJOR, MINOR, TEENY, and PATCHLEVEL matching RUBY_VERSION and RUBY_PATCHLEVEL' do + major, minor, teeny = RUBY_VERSION.split('.') + RbConfig::CONFIG.values_at("MAJOR", "MINOR", "TEENY", "PATCHLEVEL").should == [ + major, minor, teeny, RUBY_PATCHLEVEL.to_s + ] + end + # These directories have no meanings before the installation. guard -> { RbConfig::TOPDIR } do it "['rubylibdir'] returns the directory containing Ruby standard libraries" do diff --git a/spec/ruby/library/set/hash_spec.rb b/spec/ruby/library/set/hash_spec.rb index 47c43c05f1..c5bab73931 100644 --- a/spec/ruby/library/set/hash_spec.rb +++ b/spec/ruby/library/set/hash_spec.rb @@ -10,4 +10,9 @@ describe "Set#hash" do Set[].hash.should_not == Set[1, 2, 3].hash Set[1, 2, 3].hash.should_not == Set[:a, "b", ?c].hash end + + # see https://github.com/jruby/jruby/issues/8393 + it "is equal to nil.hash for an uninitialized Set" do + Set.allocate.hash.should == nil.hash + end end diff --git a/spec/ruby/library/set/merge_spec.rb b/spec/ruby/library/set/merge_spec.rb index a8e3ffc870..3ae0da827c 100644 --- a/spec/ruby/library/set/merge_spec.rb +++ b/spec/ruby/library/set/merge_spec.rb @@ -16,4 +16,16 @@ describe "Set#merge" do -> { Set[1, 2].merge(1) }.should raise_error(ArgumentError) -> { Set[1, 2].merge(Object.new) }.should raise_error(ArgumentError) end + + ruby_version_is ""..."3.3" do + it "accepts only a single argument" do + -> { Set[].merge([], []) }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 1)") + end + end + + ruby_version_is "3.3" do + it "accepts multiple arguments" do + Set[:a, :b].merge(Set[:b, :c], [:d]).should == Set[:a, :b, :c, :d] + end + end end diff --git a/spec/ruby/library/socket/addrinfo/initialize_spec.rb b/spec/ruby/library/socket/addrinfo/initialize_spec.rb index 83b204b575..d8885c5d62 100644 --- a/spec/ruby/library/socket/addrinfo/initialize_spec.rb +++ b/spec/ruby/library/socket/addrinfo/initialize_spec.rb @@ -335,7 +335,7 @@ describe "Addrinfo#initialize" do @sockaddr = ['AF_INET6', 80, 'hostname', '127.0.0.1'] end - it "raises SocketError when using any Socket constant except except AF_INET(6)/PF_INET(6)" do + it "raises SocketError when using any Socket constant except AF_INET(6)/PF_INET(6)" do Socket.constants.grep(/(^AF_|^PF_)(?!INET)/).each do |constant| value = Socket.const_get(constant) -> { diff --git a/spec/ruby/library/socket/basicsocket/send_spec.rb b/spec/ruby/library/socket/basicsocket/send_spec.rb index 86b5567026..1c028480e3 100644 --- a/spec/ruby/library/socket/basicsocket/send_spec.rb +++ b/spec/ruby/library/socket/basicsocket/send_spec.rb @@ -16,27 +16,27 @@ describe "BasicSocket#send" do @socket.close end - it "sends a message to another socket and returns the number of bytes sent" do - data = +"" - t = Thread.new do - client = @server.accept - loop do - got = client.recv(5) - break if got.nil? || got.empty? - data << got - end - client.close - end - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil + it "sends a message to another socket and returns the number of bytes sent" do + data = +"" + t = Thread.new do + client = @server.accept + loop do + got = client.recv(5) + break if got.nil? || got.empty? + data << got + end + client.close + end + Thread.pass while t.status and t.status != "sleep" + t.status.should_not be_nil - @socket.send('hello', 0).should == 5 - @socket.shutdown(1) # indicate, that we are done sending - @socket.recv(10) + @socket.send('hello', 0).should == 5 + @socket.shutdown(1) # indicate, that we are done sending + @socket.recv(10) - t.join - data.should == 'hello' - end + t.join + data.should == 'hello' + end platform_is_not :solaris, :windows do it "accepts flags to specify unusual sending behaviour" do diff --git a/spec/ruby/library/stringio/fixtures/classes.rb b/spec/ruby/library/stringio/fixtures/classes.rb index bb8dc354cc..832c5457d7 100644 --- a/spec/ruby/library/stringio/fixtures/classes.rb +++ b/spec/ruby/library/stringio/fixtures/classes.rb @@ -4,12 +4,12 @@ class StringSubclass < String; end module StringIOSpecs def self.build - str = <<-EOS + str = <<-EOS each peach pear plum - EOS + EOS StringIO.new(str) end end diff --git a/spec/ruby/library/stringio/set_encoding_by_bom_spec.rb b/spec/ruby/library/stringio/set_encoding_by_bom_spec.rb new file mode 100644 index 0000000000..1030aad042 --- /dev/null +++ b/spec/ruby/library/stringio/set_encoding_by_bom_spec.rb @@ -0,0 +1,237 @@ +require 'stringio' +require_relative '../../spec_helper' + +# Should be synced with specs for IO#set_encoding_by_bom +describe "StringIO#set_encoding_by_bom" do + it "returns nil if not readable" do + io = StringIO.new("".b, "wb") + + io.set_encoding_by_bom.should be_nil + io.external_encoding.should == Encoding::ASCII_8BIT + end + + it "returns the result encoding if found BOM UTF-8 sequence" do + io = StringIO.new("\u{FEFF}".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_8 + io.external_encoding.should == Encoding::UTF_8 + io.read.b.should == "".b + + io = StringIO.new("\u{FEFF}abc".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_8 + io.external_encoding.should == Encoding::UTF_8 + io.read.b.should == "abc".b + end + + it "returns the result encoding if found BOM UTF_16LE sequence" do + io = StringIO.new("\xFF\xFE".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_16LE + io.external_encoding.should == Encoding::UTF_16LE + io.read.b.should == "".b + + io = StringIO.new("\xFF\xFEabc".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_16LE + io.external_encoding.should == Encoding::UTF_16LE + io.read.b.should == "abc".b + end + + it "returns the result encoding if found BOM UTF_16BE sequence" do + io = StringIO.new("\xFE\xFF".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_16BE + io.external_encoding.should == Encoding::UTF_16BE + io.read.b.should == "".b + + io = StringIO.new("\xFE\xFFabc".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_16BE + io.external_encoding.should == Encoding::UTF_16BE + io.read.b.should == "abc".b + end + + it "returns the result encoding if found BOM UTF_32LE sequence" do + io = StringIO.new("\xFF\xFE\x00\x00".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_32LE + io.external_encoding.should == Encoding::UTF_32LE + io.read.b.should == "".b + + io = StringIO.new("\xFF\xFE\x00\x00abc".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_32LE + io.external_encoding.should == Encoding::UTF_32LE + io.read.b.should == "abc".b + end + + it "returns the result encoding if found BOM UTF_32BE sequence" do + io = StringIO.new("\x00\x00\xFE\xFF".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_32BE + io.external_encoding.should == Encoding::UTF_32BE + io.read.b.should == "".b + + io = StringIO.new("\x00\x00\xFE\xFFabc".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_32BE + io.external_encoding.should == Encoding::UTF_32BE + io.read.b.should == "abc".b + end + + it "returns nil if io is empty" do + io = StringIO.new("".b, "rb") + io.set_encoding_by_bom.should be_nil + io.external_encoding.should == Encoding::ASCII_8BIT + end + + it "returns nil if UTF-8 BOM sequence is incomplete" do + io = StringIO.new("\xEF".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xEF".b + + io = StringIO.new("\xEFa".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xEFa".b + + io = StringIO.new("\xEF\xBB".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xEF\xBB".b + + io = StringIO.new("\xEF\xBBa".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xEF\xBBa".b + end + + it "returns nil if UTF-16BE BOM sequence is incomplete" do + io = StringIO.new("\xFE".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xFE".b + + io = StringIO.new("\xFEa".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xFEa".b + end + + it "returns nil if UTF-16LE/UTF-32LE BOM sequence is incomplete" do + io = StringIO.new("\xFF".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xFF".b + + io = StringIO.new("\xFFa".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\xFFa".b + end + + it "returns UTF-16LE if UTF-32LE BOM sequence is incomplete" do + io = StringIO.new("\xFF\xFE".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_16LE + io.external_encoding.should == Encoding::UTF_16LE + io.read.b.should == "".b + + io = StringIO.new("\xFF\xFE\x00".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_16LE + io.external_encoding.should == Encoding::UTF_16LE + io.read.b.should == "\x00".b + + io = StringIO.new("\xFF\xFE\x00a".b, "rb") + + io.set_encoding_by_bom.should == Encoding::UTF_16LE + io.external_encoding.should == Encoding::UTF_16LE + io.read.b.should == "\x00a".b + end + + it "returns nil if UTF-32BE BOM sequence is incomplete" do + io = StringIO.new("\x00".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\x00".b + + io = StringIO.new("\x00a".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\x00a".b + + io = StringIO.new("\x00\x00".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\x00\x00".b + + io = StringIO.new("\x00\x00a".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\x00\x00a".b + + io = StringIO.new("\x00\x00\xFE".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\x00\x00\xFE".b + + io = StringIO.new("\x00\x00\xFEa".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read.b.should == "\x00\x00\xFEa".b + end + + it "returns nil if found BOM sequence not provided" do + io = StringIO.new("abc".b, "rb") + + io.set_encoding_by_bom.should == nil + io.external_encoding.should == Encoding::ASCII_8BIT + io.read(3).should == "abc".b + end + + it "does not raise exception if io not in binary mode" do + io = StringIO.new("", 'r') + io.set_encoding_by_bom.should == nil + end + + it "does not raise exception if encoding already set" do + io = StringIO.new("".b, "rb") + io.set_encoding("utf-8") + io.set_encoding_by_bom.should == nil + end + + it "does not raise exception if encoding conversion is already set" do + io = StringIO.new("".b, "rb") + io.set_encoding(Encoding::UTF_8, Encoding::UTF_16BE) + + io.set_encoding_by_bom.should == nil + end + + it "raises FrozenError when io is frozen" do + io = StringIO.new() + io.freeze + -> { io.set_encoding_by_bom }.should raise_error(FrozenError) + end + + it "does not raise FrozenError when initial string is frozen" do + io = StringIO.new("".freeze) + io.set_encoding_by_bom.should == nil + end +end diff --git a/spec/ruby/library/stringio/shared/sysread.rb b/spec/ruby/library/stringio/shared/sysread.rb index 937bac705c..3e23fbc233 100644 --- a/spec/ruby/library/stringio/shared/sysread.rb +++ b/spec/ruby/library/stringio/shared/sysread.rb @@ -10,6 +10,6 @@ describe :stringio_sysread_length, shared: true do it "raises an EOFError when passed length > 0 and no data remains" do @io.read.should == "example" - -> { @io.sysread(1) }.should raise_error(EOFError) + -> { @io.send(@method, 1) }.should raise_error(EOFError) end end diff --git a/spec/ruby/library/stringio/sysread_spec.rb b/spec/ruby/library/stringio/sysread_spec.rb index 8f78073f42..fabb06dd9a 100644 --- a/spec/ruby/library/stringio/sysread_spec.rb +++ b/spec/ruby/library/stringio/sysread_spec.rb @@ -1,6 +1,7 @@ require_relative '../../spec_helper' require "stringio" require_relative 'shared/read' +require_relative 'shared/sysread' describe "StringIO#sysread when passed length, buffer" do it_behaves_like :stringio_read, :sysread @@ -32,6 +33,10 @@ describe "StringIO#sysread when passed nil" do end end +describe "StringIO#sysread when passed length" do + it_behaves_like :stringio_sysread_length, :sysread +end + describe "StringIO#sysread when passed [length]" do before :each do @io = StringIO.new("example") diff --git a/spec/ruby/library/time/shared/rfc2822.rb b/spec/ruby/library/time/shared/rfc2822.rb index d99f1f76de..e460d655a6 100644 --- a/spec/ruby/library/time/shared/rfc2822.rb +++ b/spec/ruby/library/time/shared/rfc2822.rb @@ -1,33 +1,33 @@ describe :time_rfc2822, shared: true do it "parses RFC-822 strings" do t1 = (Time.utc(1976, 8, 26, 14, 30) + 4 * 3600) - t2 = Time.rfc2822("26 Aug 76 14:30 EDT") + t2 = Time.send(@method, "26 Aug 76 14:30 EDT") t1.should == t2 t3 = Time.utc(1976, 8, 27, 9, 32) + 7 * 3600 - t4 = Time.rfc2822("27 Aug 76 09:32 PDT") + t4 = Time.send(@method, "27 Aug 76 09:32 PDT") t3.should == t4 end it "parses RFC-2822 strings" do t1 = Time.utc(1997, 11, 21, 9, 55, 6) + 6 * 3600 - t2 = Time.rfc2822("Fri, 21 Nov 1997 09:55:06 -0600") + t2 = Time.send(@method, "Fri, 21 Nov 1997 09:55:06 -0600") t1.should == t2 t3 = Time.utc(2003, 7, 1, 10, 52, 37) - 2 * 3600 - t4 = Time.rfc2822("Tue, 1 Jul 2003 10:52:37 +0200") + t4 = Time.send(@method, "Tue, 1 Jul 2003 10:52:37 +0200") t3.should == t4 t5 = Time.utc(1997, 11, 21, 10, 1, 10) + 6 * 3600 - t6 = Time.rfc2822("Fri, 21 Nov 1997 10:01:10 -0600") + t6 = Time.send(@method, "Fri, 21 Nov 1997 10:01:10 -0600") t5.should == t6 t7 = Time.utc(1997, 11, 21, 11, 0, 0) + 6 * 3600 - t8 = Time.rfc2822("Fri, 21 Nov 1997 11:00:00 -0600") + t8 = Time.send(@method, "Fri, 21 Nov 1997 11:00:00 -0600") t7.should == t8 t9 = Time.utc(1997, 11, 24, 14, 22, 1) + 8 * 3600 - t10 = Time.rfc2822("Mon, 24 Nov 1997 14:22:01 -0800") + t10 = Time.send(@method, "Mon, 24 Nov 1997 14:22:01 -0800") t9.should == t10 begin @@ -36,11 +36,11 @@ describe :time_rfc2822, shared: true do # ignore else t11 = Time.utc(1969, 2, 13, 23, 32, 54) + 3 * 3600 + 30 * 60 - t12 = Time.rfc2822("Thu, 13 Feb 1969 23:32:54 -0330") + t12 = Time.send(@method, "Thu, 13 Feb 1969 23:32:54 -0330") t11.should == t12 t13 = Time.utc(1969, 2, 13, 23, 32, 0) + 3 * 3600 + 30 * 60 - t14 = Time.rfc2822(" Thu, + t14 = Time.send(@method, " Thu, 13 Feb 1969 @@ -50,16 +50,16 @@ describe :time_rfc2822, shared: true do end t15 = Time.utc(1997, 11, 21, 9, 55, 6) - t16 = Time.rfc2822("21 Nov 97 09:55:06 GMT") + t16 = Time.send(@method, "21 Nov 97 09:55:06 GMT") t15.should == t16 t17 = Time.utc(1997, 11, 21, 9, 55, 6) + 6 * 3600 - t18 = Time.rfc2822("Fri, 21 Nov 1997 09 : 55 : 06 -0600") + t18 = Time.send(@method, "Fri, 21 Nov 1997 09 : 55 : 06 -0600") t17.should == t18 -> { # inner comment is not supported. - Time.rfc2822("Fri, 21 Nov 1997 09(comment): 55 : 06 -0600") + Time.send(@method, "Fri, 21 Nov 1997 09(comment): 55 : 06 -0600") }.should raise_error(ArgumentError) end end diff --git a/spec/ruby/library/time/shared/xmlschema.rb b/spec/ruby/library/time/shared/xmlschema.rb index 831d8509a7..0002886ca5 100644 --- a/spec/ruby/library/time/shared/xmlschema.rb +++ b/spec/ruby/library/time/shared/xmlschema.rb @@ -2,23 +2,23 @@ describe :time_library_xmlschema, shared: true do it "parses ISO-8601 strings" do t = Time.utc(1985, 4, 12, 23, 20, 50, 520000) s = "1985-04-12T23:20:50.52Z" - t.should == Time.xmlschema(s) - #s.should == t.xmlschema(2) + t.should == Time.send(@method, s) + #s.should == t.send(@method, 2) t = Time.utc(1996, 12, 20, 0, 39, 57) s = "1996-12-19T16:39:57-08:00" - t.should == Time.xmlschema(s) + t.should == Time.send(@method, s) # There is no way to generate time string with arbitrary timezone. s = "1996-12-20T00:39:57Z" - t.should == Time.xmlschema(s) - #assert_equal(s, t.xmlschema) + t.should == Time.send(@method, s) + #assert_equal(s, t.send(@method)) t = Time.utc(1990, 12, 31, 23, 59, 60) s = "1990-12-31T23:59:60Z" - t.should == Time.xmlschema(s) + t.should == Time.send(@method, s) # leap second is representable only if timezone file has it. s = "1990-12-31T15:59:60-08:00" - t.should == Time.xmlschema(s) + t.should == Time.send(@method, s) begin Time.at(-1) @@ -27,27 +27,27 @@ describe :time_library_xmlschema, shared: true do else t = Time.utc(1937, 1, 1, 11, 40, 27, 870000) s = "1937-01-01T12:00:27.87+00:20" - t.should == Time.xmlschema(s) + t.should == Time.send(@method, s) end # more - # (Time.utc(1999, 5, 31, 13, 20, 0) + 5 * 3600).should == Time.xmlschema("1999-05-31T13:20:00-05:00") - # (Time.local(2000, 1, 20, 12, 0, 0)).should == Time.xmlschema("2000-01-20T12:00:00") - # (Time.utc(2000, 1, 20, 12, 0, 0)).should == Time.xmlschema("2000-01-20T12:00:00Z") - # (Time.utc(2000, 1, 20, 12, 0, 0) - 12 * 3600).should == Time.xmlschema("2000-01-20T12:00:00+12:00") - # (Time.utc(2000, 1, 20, 12, 0, 0) + 13 * 3600).should == Time.xmlschema("2000-01-20T12:00:00-13:00") - # (Time.utc(2000, 3, 4, 23, 0, 0) - 3 * 3600).should == Time.xmlschema("2000-03-04T23:00:00+03:00") - # (Time.utc(2000, 3, 4, 20, 0, 0)).should == Time.xmlschema("2000-03-04T20:00:00Z") - # (Time.local(2000, 1, 15, 0, 0, 0)).should == Time.xmlschema("2000-01-15T00:00:00") - # (Time.local(2000, 2, 15, 0, 0, 0)).should == Time.xmlschema("2000-02-15T00:00:00") - # (Time.local(2000, 1, 15, 12, 0, 0)).should == Time.xmlschema("2000-01-15T12:00:00") - # (Time.utc(2000, 1, 16, 12, 0, 0)).should == Time.xmlschema("2000-01-16T12:00:00Z") - # (Time.local(2000, 1, 1, 12, 0, 0)).should == Time.xmlschema("2000-01-01T12:00:00") - # (Time.utc(1999, 12, 31, 23, 0, 0)).should == Time.xmlschema("1999-12-31T23:00:00Z") - # (Time.local(2000, 1, 16, 12, 0, 0)).should == Time.xmlschema("2000-01-16T12:00:00") - # (Time.local(2000, 1, 16, 0, 0, 0)).should == Time.xmlschema("2000-01-16T00:00:00") - # (Time.utc(2000, 1, 12, 12, 13, 14)).should == Time.xmlschema("2000-01-12T12:13:14Z") - # (Time.utc(2001, 4, 17, 19, 23, 17, 300000)).should == Time.xmlschema("2001-04-17T19:23:17.3Z") + # (Time.utc(1999, 5, 31, 13, 20, 0) + 5 * 3600).should == Time.send(@method, "1999-05-31T13:20:00-05:00") + # (Time.local(2000, 1, 20, 12, 0, 0)).should == Time.send(@method, "2000-01-20T12:00:00") + # (Time.utc(2000, 1, 20, 12, 0, 0)).should == Time.send(@method, "2000-01-20T12:00:00Z") + # (Time.utc(2000, 1, 20, 12, 0, 0) - 12 * 3600).should == Time.send(@method, "2000-01-20T12:00:00+12:00") + # (Time.utc(2000, 1, 20, 12, 0, 0) + 13 * 3600).should == Time.send(@method, "2000-01-20T12:00:00-13:00") + # (Time.utc(2000, 3, 4, 23, 0, 0) - 3 * 3600).should == Time.send(@method, "2000-03-04T23:00:00+03:00") + # (Time.utc(2000, 3, 4, 20, 0, 0)).should == Time.send(@method, "2000-03-04T20:00:00Z") + # (Time.local(2000, 1, 15, 0, 0, 0)).should == Time.send(@method, "2000-01-15T00:00:00") + # (Time.local(2000, 2, 15, 0, 0, 0)).should == Time.send(@method, "2000-02-15T00:00:00") + # (Time.local(2000, 1, 15, 12, 0, 0)).should == Time.send(@method, "2000-01-15T12:00:00") + # (Time.utc(2000, 1, 16, 12, 0, 0)).should == Time.send(@method, "2000-01-16T12:00:00Z") + # (Time.local(2000, 1, 1, 12, 0, 0)).should == Time.send(@method, "2000-01-01T12:00:00") + # (Time.utc(1999, 12, 31, 23, 0, 0)).should == Time.send(@method, "1999-12-31T23:00:00Z") + # (Time.local(2000, 1, 16, 12, 0, 0)).should == Time.send(@method, "2000-01-16T12:00:00") + # (Time.local(2000, 1, 16, 0, 0, 0)).should == Time.send(@method, "2000-01-16T00:00:00") + # (Time.utc(2000, 1, 12, 12, 13, 14)).should == Time.send(@method, "2000-01-12T12:13:14Z") + # (Time.utc(2001, 4, 17, 19, 23, 17, 300000)).should == Time.send(@method, "2001-04-17T19:23:17.3Z") end end diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c index 04252b2848..e6bf4870ec 100644 --- a/spec/ruby/optional/capi/ext/kernel_spec.c +++ b/spec/ruby/optional/capi/ext/kernel_spec.c @@ -7,16 +7,12 @@ extern "C" { #endif -VALUE kernel_spec_call_proc(VALUE arg_array) { +static VALUE kernel_spec_call_proc(VALUE arg_array) { VALUE arg = rb_ary_pop(arg_array); VALUE proc = rb_ary_pop(arg_array); return rb_funcall(proc, rb_intern("call"), 1, arg); } -VALUE kernel_spec_call_proc_raise(VALUE arg_array, VALUE raised_exc) { - return kernel_spec_call_proc(arg_array); -} - static VALUE kernel_spec_rb_block_given_p(VALUE self) { return rb_block_given_p() ? Qtrue : Qfalse; } @@ -134,7 +130,16 @@ VALUE kernel_spec_rb_throw_obj(VALUE self, VALUE obj, VALUE result) { return ID2SYM(rb_intern("rb_throw_failed")); } -VALUE kernel_spec_call_proc_with_raised_exc(VALUE arg_array, VALUE raised_exc) { +VALUE kernel_spec_rb_errinfo(VALUE self) { + return rb_errinfo(); +} + +VALUE kernel_spec_rb_set_errinfo(VALUE self, VALUE exc) { + rb_set_errinfo(exc); + return Qnil; +} + +static VALUE kernel_spec_call_proc_with_raised_exc(VALUE arg_array, VALUE raised_exc) { VALUE argv[2]; int argc; @@ -181,7 +186,7 @@ VALUE kernel_spec_rb_rescue2(int argc, VALUE *args, VALUE self) { rb_ary_push(raise_array, args[3]); return rb_rescue2(kernel_spec_call_proc, main_array, - kernel_spec_call_proc_raise, raise_array, args[4], args[5], (VALUE)0); + kernel_spec_call_proc_with_raised_exc, raise_array, args[4], args[5], (VALUE)0); } static VALUE kernel_spec_rb_protect_yield(VALUE self, VALUE obj, VALUE ary) { @@ -195,7 +200,7 @@ static VALUE kernel_spec_rb_protect_yield(VALUE self, VALUE obj, VALUE ary) { return res; } -static VALUE kernel_spec_rb_protect_errinfo(VALUE self, VALUE obj, VALUE ary) { +static VALUE kernel_spec_rb_protect_ignore_status(VALUE self, VALUE obj, VALUE ary) { int status = 0; VALUE res = rb_protect(rb_yield, obj, &status); rb_ary_store(ary, 0, INT2NUM(23)); @@ -382,10 +387,13 @@ void Init_kernel_spec(void) { rb_define_method(cls, "rb_raise", kernel_spec_rb_raise, 1); rb_define_method(cls, "rb_throw", kernel_spec_rb_throw, 1); rb_define_method(cls, "rb_throw_obj", kernel_spec_rb_throw_obj, 2); + rb_define_method(cls, "rb_errinfo", kernel_spec_rb_errinfo, 0); + rb_define_method(cls, "rb_set_errinfo", kernel_spec_rb_set_errinfo, 1); + rb_define_method(cls, "rb_rescue", kernel_spec_rb_rescue, 4); rb_define_method(cls, "rb_rescue", kernel_spec_rb_rescue, 4); rb_define_method(cls, "rb_rescue2", kernel_spec_rb_rescue2, -1); rb_define_method(cls, "rb_protect_yield", kernel_spec_rb_protect_yield, 2); - rb_define_method(cls, "rb_protect_errinfo", kernel_spec_rb_protect_errinfo, 2); + rb_define_method(cls, "rb_protect_ignore_status", kernel_spec_rb_protect_ignore_status, 2); rb_define_method(cls, "rb_protect_null_status", kernel_spec_rb_protect_null_status, 1); rb_define_method(cls, "rb_eval_string_protect", kernel_spec_rb_eval_string_protect, 2); rb_define_method(cls, "rb_catch", kernel_spec_rb_catch, 2); diff --git a/spec/ruby/optional/capi/ext/mutex_spec.c b/spec/ruby/optional/capi/ext/mutex_spec.c index c2fdf917ac..d2c8f98e89 100644 --- a/spec/ruby/optional/capi/ext/mutex_spec.c +++ b/spec/ruby/optional/capi/ext/mutex_spec.c @@ -29,15 +29,34 @@ VALUE mutex_spec_rb_mutex_sleep(VALUE self, VALUE mutex, VALUE timeout) { return rb_mutex_sleep(mutex, timeout); } - VALUE mutex_spec_rb_mutex_callback(VALUE arg) { return rb_funcall(arg, rb_intern("call"), 0); } +VALUE mutex_spec_rb_mutex_naughty_callback(VALUE arg) { + int *result = (int *) arg; + return (VALUE) result; +} + +VALUE mutex_spec_rb_mutex_callback_basic(VALUE arg) { + return arg; +} + VALUE mutex_spec_rb_mutex_synchronize(VALUE self, VALUE mutex, VALUE value) { return rb_mutex_synchronize(mutex, mutex_spec_rb_mutex_callback, value); } +VALUE mutex_spec_rb_mutex_synchronize_with_naughty_callback(VALUE self, VALUE mutex) { + // a naughty callback accepts or returns not a Ruby object but arbitrary value + int arg = 42; + VALUE result = rb_mutex_synchronize(mutex, mutex_spec_rb_mutex_naughty_callback, (VALUE) &arg); + return INT2NUM(*((int *) result)); +} + +VALUE mutex_spec_rb_mutex_synchronize_with_native_callback(VALUE self, VALUE mutex, VALUE value) { + return rb_mutex_synchronize(mutex, mutex_spec_rb_mutex_callback_basic, value); +} + void Init_mutex_spec(void) { VALUE cls = rb_define_class("CApiMutexSpecs", rb_cObject); rb_define_method(cls, "rb_mutex_new", mutex_spec_rb_mutex_new, 0); @@ -47,6 +66,8 @@ void Init_mutex_spec(void) { rb_define_method(cls, "rb_mutex_unlock", mutex_spec_rb_mutex_unlock, 1); rb_define_method(cls, "rb_mutex_sleep", mutex_spec_rb_mutex_sleep, 2); rb_define_method(cls, "rb_mutex_synchronize", mutex_spec_rb_mutex_synchronize, 2); + rb_define_method(cls, "rb_mutex_synchronize_with_naughty_callback", mutex_spec_rb_mutex_synchronize_with_naughty_callback, 1); + rb_define_method(cls, "rb_mutex_synchronize_with_native_callback", mutex_spec_rb_mutex_synchronize_with_native_callback, 2); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c index cec3f65f45..94f412267f 100644 --- a/spec/ruby/optional/capi/ext/string_spec.c +++ b/spec/ruby/optional/capi/ext/string_spec.c @@ -117,6 +117,10 @@ VALUE string_spec_rb_str_cmp(VALUE self, VALUE str1, VALUE str2) { return INT2NUM(rb_str_cmp(str1, str2)); } +VALUE string_spec_rb_str_strlen(VALUE self, VALUE str) { + return LONG2NUM(rb_str_strlen(str)); +} + VALUE string_spec_rb_str_conv_enc(VALUE self, VALUE str, VALUE from, VALUE to) { rb_encoding* from_enc; rb_encoding* to_enc; @@ -600,6 +604,7 @@ void Init_string_spec(void) { rb_define_method(cls, "rb_str_cat_cstr", string_spec_rb_str_cat_cstr, 2); rb_define_method(cls, "rb_str_cat_cstr_constant", string_spec_rb_str_cat_cstr_constant, 1); rb_define_method(cls, "rb_str_cmp", string_spec_rb_str_cmp, 2); + rb_define_method(cls, "rb_str_strlen", string_spec_rb_str_strlen, 1); rb_define_method(cls, "rb_str_conv_enc", string_spec_rb_str_conv_enc, 3); rb_define_method(cls, "rb_str_conv_enc_opts", string_spec_rb_str_conv_enc_opts, 5); rb_define_method(cls, "rb_str_drop_bytes", string_spec_rb_str_drop_bytes, 2); diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb index 3b61d4f0f1..a169813cd5 100644 --- a/spec/ruby/optional/capi/kernel_spec.rb +++ b/spec/ruby/optional/capi/kernel_spec.rb @@ -3,11 +3,19 @@ require_relative 'fixtures/kernel' kernel_path = load_extension("kernel") +class CApiKernelSpecs::Exc < StandardError +end +exception_class = CApiKernelSpecs::Exc + describe "C-API Kernel function" do before :each do @s = CApiKernelSpecs.new end + after :each do + @s.rb_errinfo.should == nil + end + describe "rb_block_given_p" do it "returns false if no block is passed" do @s.should_not.rb_block_given_p @@ -78,6 +86,22 @@ describe "C-API Kernel function" do -> { @s.rb_raise(h) }.should raise_error(TypeError) h[:stage].should == :before end + + it "re-raises a rescued exception" do + -> do + begin + raise StandardError, "aaa" + rescue Exception + begin + @s.rb_raise({}) + rescue TypeError + end + + # should raise StandardError "aaa" + raise + end + end.should raise_error(StandardError, "aaa") + end end describe "rb_throw" do @@ -295,7 +319,7 @@ describe "C-API Kernel function" do it "will allow cleanup code to run after a raise" do proof = [] # Hold proof of work performed after the yield. -> do - @s.rb_protect_yield(77, proof) { |x| raise NameError} + @s.rb_protect_yield(77, proof) { |x| raise NameError } end.should raise_error(NameError) proof[0].should == 23 end @@ -303,7 +327,7 @@ describe "C-API Kernel function" do it "will return nil if an error was raised" do proof = [] # Hold proof of work performed after the yield. -> do - @s.rb_protect_yield(77, proof) { |x| raise NameError} + @s.rb_protect_yield(77, proof) { |x| raise NameError } end.should raise_error(NameError) proof[0].should == 23 proof[1].should == nil @@ -311,14 +335,21 @@ describe "C-API Kernel function" do it "accepts NULL as status and returns nil if it failed" do @s.rb_protect_null_status(42) { |x| x + 1 }.should == 43 - @s.rb_protect_null_status(42) { |x| raise }.should == nil + @s.rb_protect_null_status(42) { |x| raise NameError }.should == nil + @s.rb_errinfo().should.is_a? NameError + ensure + @s.rb_set_errinfo(nil) end - it "populates errinfo with the captured exception" do + it "populates rb_errinfo() with the captured exception" do proof = [] - @s.rb_protect_errinfo(77, proof) { |x| raise NameError }.class.should == NameError + @s.rb_protect_ignore_status(77, proof) { |x| raise NameError } + @s.rb_errinfo().should.is_a? NameError + # Note: on CRuby $! is the NameError here, but not clear if that is desirable or bug proof[0].should == 23 proof[1].should == nil + ensure + @s.rb_set_errinfo(nil) end end @@ -382,9 +413,21 @@ describe "C-API Kernel function" do -> { @s.rb_rescue(@std_error_proc, nil, @std_error_proc, nil) }.should raise_error(StandardError) end - it "makes $! available only during the 'rescue function' execution" do - @s.rb_rescue(@std_error_proc, nil, -> *_ { $! }, nil).class.should == StandardError + it "sets $! and rb_errinfo() during the 'rescue function' execution" do + @s.rb_rescue(-> *_ { raise exception_class, '' }, nil, -> _, exc { + exc.should.is_a?(exception_class) + $!.should.equal?(exc) + @s.rb_errinfo.should.equal?(exc) + }, nil) + + @s.rb_rescue(-> _ { @s.rb_raise({}) }, nil, -> _, exc { + exc.should.is_a?(TypeError) + $!.should.equal?(exc) + @s.rb_errinfo.should.equal?(exc) + }, nil) + $!.should == nil + @s.rb_errinfo.should == nil end it "returns the break value if the passed function yields to a block with a break" do @@ -402,7 +445,7 @@ describe "C-API Kernel function" do describe "rb_rescue2" do it "only rescues if one of the passed exceptions is raised" do - proc = -> x { x } + proc = -> x, _exc { x } arg_error_proc = -> *_ { raise ArgumentError, '' } run_error_proc = -> *_ { raise RuntimeError, '' } type_error_proc = -> *_ { raise Exception, 'custom error' } @@ -418,6 +461,23 @@ describe "C-API Kernel function" do @s.rb_rescue2(-> *_ { raise RuntimeError, "foo" }, :no_exc, -> x { x }, :exc, Object.new, 42) }.should raise_error(TypeError, /class or module required/) end + + it "sets $! and rb_errinfo() during the 'rescue function' execution" do + @s.rb_rescue2(-> *_ { raise exception_class, '' }, :no_exc, -> _, exc { + exc.should.is_a?(exception_class) + $!.should.equal?(exc) + @s.rb_errinfo.should.equal?(exc) + }, :exc, exception_class, ScriptError) + + @s.rb_rescue2(-> *_ { @s.rb_raise({}) }, :no_exc, -> _, exc { + exc.should.is_a?(TypeError) + $!.should.equal?(exc) + @s.rb_errinfo.should.equal?(exc) + }, :exc, TypeError, ArgumentError) + + $!.should == nil + @s.rb_errinfo.should == nil + end end describe "rb_catch" do @@ -486,12 +546,33 @@ describe "C-API Kernel function" do it "executes passed 'ensure function' when an exception is raised" do foo = nil - raise_proc = -> { raise '' } + raise_proc = -> _ { raise exception_class } ensure_proc = -> x { foo = x } - @s.rb_ensure(raise_proc, nil, ensure_proc, :foo) rescue nil + -> { + @s.rb_ensure(raise_proc, nil, ensure_proc, :foo) + }.should raise_error(exception_class) foo.should == :foo end + it "sets $! and rb_errinfo() during the 'ensure function' execution" do + -> { + @s.rb_ensure(-> _ { raise exception_class }, nil, -> _ { + $!.should.is_a?(exception_class) + @s.rb_errinfo.should.is_a?(exception_class) + }, nil) + }.should raise_error(exception_class) + + -> { + @s.rb_ensure(-> _ { @s.rb_raise({}) }, nil, -> _ { + $!.should.is_a?(TypeError) + @s.rb_errinfo.should.is_a?(TypeError) + }, nil) + }.should raise_error(TypeError) + + $!.should == nil + @s.rb_errinfo.should == nil + end + it "raises the same exception raised inside passed function" do raise_proc = -> *_ { raise RuntimeError, 'foo' } proc = -> *_ { } diff --git a/spec/ruby/optional/capi/mutex_spec.rb b/spec/ruby/optional/capi/mutex_spec.rb index 34659974f5..71a2212e36 100644 --- a/spec/ruby/optional/capi/mutex_spec.rb +++ b/spec/ruby/optional/capi/mutex_spec.rb @@ -85,5 +85,18 @@ describe "C-API Mutex functions" do callback = -> { @m.locked?.should be_true } @s.rb_mutex_synchronize(@m, callback) end + + it "returns a value returned from a callback" do + callback = -> { :foo } + @s.rb_mutex_synchronize(@m, callback).should == :foo + end + + it "calls a C-function that accepts and returns non-VALUE values" do + @s.rb_mutex_synchronize_with_naughty_callback(@m).should == 42 + end + + it "calls a native function" do + @s.rb_mutex_synchronize_with_native_callback(@m, 42).should == 42 + end end end diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb index 43b4b3f09b..8f2244bcea 100644 --- a/spec/ruby/optional/capi/string_spec.rb +++ b/spec/ruby/optional/capi/string_spec.rb @@ -449,6 +449,20 @@ describe "C-API String function" do end end + describe "rb_str_strlen" do + it 'returns 0 as the length of an empty string' do + @s.rb_str_strlen('').should == 0 + end + + it 'returns the number of characters in a string' do + @s.rb_str_strlen('hello').should == 5 + end + + it 'returns the number of characters in a string with multi-byte characters' do + @s.rb_str_strlen('こんにちは').should == 5 + end + end + describe "rb_str_split" do it "splits strings over a splitter" do @s.rb_str_split("Hello,Goodbye").should == ["Hello", "Goodbye"] @@ -888,16 +902,20 @@ describe "C-API String function" do end it "returns the original String if a transcoding error occurs" do - a = [0xEE].pack('C').force_encoding("utf-8") - @s.rb_str_conv_enc(a, Encoding::UTF_8, Encoding::EUC_JP).should equal(a) + a = [0xEE].pack('C').force_encoding(Encoding::UTF_8) + @s.rb_str_conv_enc(a, Encoding::UTF_8, Encoding::EUC_JP).should.equal?(a) + a.encoding.should == Encoding::UTF_8 + + a = "\x80".b + @s.rb_str_conv_enc(a, Encoding::BINARY, Encoding::UTF_8).should.equal?(a) + a.encoding.should == Encoding::BINARY end it "returns a transcoded String" do - a = "\xE3\x81\x82\xE3\x82\x8C".dup.force_encoding("utf-8") + a = "\xE3\x81\x82\xE3\x82\x8C".dup.force_encoding(Encoding::UTF_8) result = @s.rb_str_conv_enc(a, Encoding::UTF_8, Encoding::EUC_JP) - x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4').force_encoding('utf-8') - result.should == x.force_encoding("euc-jp") - result.encoding.should equal(Encoding::EUC_JP) + result.should == [0xA4, 0xA2, 0xA4, 0xEC].pack('C4').force_encoding(Encoding::EUC_JP) + result.encoding.should == Encoding::EUC_JP end describe "when the String encoding is equal to the destination encoding" do diff --git a/spec/ruby/shared/queue/freeze.rb b/spec/ruby/shared/queue/freeze.rb new file mode 100644 index 0000000000..4c506a4235 --- /dev/null +++ b/spec/ruby/shared/queue/freeze.rb @@ -0,0 +1,18 @@ +describe :queue_freeze, shared: true do + ruby_version_is ""..."3.3" do + it "can be frozen" do + queue = @object.call + queue.freeze + queue.should.frozen? + end + end + + ruby_version_is "3.3" do + it "raises an exception when freezing" do + queue = @object.call + -> { + queue.freeze + }.should raise_error(TypeError, "cannot freeze #{queue}") + end + end +end |