diff options
Diffstat (limited to 'spec/ruby')
418 files changed, 5855 insertions, 7639 deletions
diff --git a/spec/ruby/.mspec.constants b/spec/ruby/.mspec.constants index 6b70274c52..5dd477eb66 100644 --- a/spec/ruby/.mspec.constants +++ b/spec/ruby/.mspec.constants @@ -39,6 +39,8 @@ CodingUS_ASCII CodingUTF_8 ComparisonTest ConstantSpecsIncludedModule +ConstantSpecsTwo +ConstantSpecsThree ConstantVisibility Coverage CoverageSpecs @@ -73,6 +75,7 @@ EvalBindingProcA Exception2MessageMapper ExceptionForMatrix Fcntl +Fiddle FileStat FileUtils Find diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml index eab4c3c4a6..e807b59321 100644 --- a/spec/ruby/.rubocop.yml +++ b/spec/ruby/.rubocop.yml @@ -1,11 +1,12 @@ inherit_from: .rubocop_todo.yml AllCops: - TargetRubyVersion: 2.6 + TargetRubyVersion: 2.7 DisplayCopNames: true Exclude: - command_line/fixtures/bad_syntax.rb DisabledByDefault: true + NewCops: disable Layout/TrailingWhitespace: Enabled: true @@ -56,12 +57,52 @@ Lint/UnusedMethodArgument: Lint/UselessAssignment: Enabled: false -Lint/UselessComparison: +Lint/BinaryOperatorWithIdenticalOperands: Enabled: false +Lint/EmptyConditionalBody: + Enabled: false # buggy + Lint/Void: Enabled: false +Lint/ConstantDefinitionInBlock: + Enabled: false + +Lint/RaiseException: + Enabled: false + +Lint/FloatComparison: + Enabled: false + +Lint/DeprecatedClassMethods: + Enabled: false + +Lint/UnreachableLoop: + Enabled: false + +Lint/MissingSuper: + Enabled: false + +Lint/UselessMethodDefinition: + Enabled: false + +Lint/UselessTimes: + Enabled: false + +Lint/MixedRegexpCaptureTypes: + Enabled: false + +Lint/DuplicateElsifCondition: + Enabled: false + +Lint/OutOfRangeRegexpRef: + Enabled: false + +Lint/ElseLayout: + Exclude: + - 'language/if_spec.rb' + Lint/EmptyExpression: Exclude: - 'language/**/*.rb' diff --git a/spec/ruby/CONTRIBUTING.md b/spec/ruby/CONTRIBUTING.md index 30941677e0..20258e5c36 100644 --- a/spec/ruby/CONTRIBUTING.md +++ b/spec/ruby/CONTRIBUTING.md @@ -13,12 +13,14 @@ Spec are grouped in 5 separate top-level groups: * `optional/capi`: for functions available to the Ruby C-extension API The exact file for methods is decided by the `#owner` of a method, for instance for `#group_by`: + ```ruby > [].method(:group_by) => #<Method: Array(Enumerable)#group_by> > [].method(:group_by).owner => Enumerable ``` + Which should therefore be specified in `core/enumerable/group_by_spec.rb`. ### MkSpec - a tool to generate the spec structure @@ -178,7 +180,7 @@ First, file a bug at https://bugs.ruby-lang.org/. It is better to use a `ruby_version_is` guard if there was a release with the fix. ```ruby -ruby_bug '#13669', ''...'2.7' do +ruby_bug '#13669', ''...'3.2' do it "works like this" do # Specify the expected behavior here, not the bug end @@ -220,7 +222,7 @@ If an implementation does not support some feature, simply tag the related specs ### Shared Specs Often throughout Ruby, identical functionality is used by different methods and modules. In order -to avoid duplication of specs, we have shared specs that are re-used in other specs. The use is a +to avoid duplication of specs, we have shared specs that are re-used in other specs. The use is a bit tricky however, so let's go over it. Commonly, if a shared spec is only reused within its own module, the shared spec will live within a @@ -232,7 +234,7 @@ An example of this is the `shared/file/socket.rb` which is used by `core/file/so `core/filetest/socket_spec.rb`, and `core/file/state/socket_spec.rb` and so it lives in the root `shared/`. Defining a shared spec involves adding a `shared: true` option to the top-level `describe` block. This -will signal not to run the specs directly by the runner. Shared specs have access to two instance +will signal not to run the specs directly by the runner. Shared specs have access to two instance variables from the implementor spec: `@method` and `@object`, which the implementor spec will pass in. Here's an example of a snippet of a shared spec and two specs which integrates it: @@ -257,12 +259,12 @@ end ``` In the example, the first `describe` defines the shared spec `:hash_key_p`, which defines a spec that -calls the `@method` method with an expectation. In the implementor spec, we use `it_behaves_like` to -integrate the shared spec. `it_behaves_like` takes 3 parameters: the key of the shared spec, a method, -and an object. These last two parameters are accessible via `@method` and `@object` in the shared spec. +calls the `@method` method with an expectation. In the implementor spec, we use `it_behaves_like` to +integrate the shared spec. `it_behaves_like` takes 3 parameters: the key of the shared spec, a method, +and an object. These last two parameters are accessible via `@method` and `@object` in the shared spec. Sometimes, shared specs require more context from the implementor class than a simple object. We can address -this by passing a lambda as the method, which will have the scope of the implementor. Here's an example of +this by passing a lambda as the method, which will have the scope of the implementor. Here's an example of how this is used currently: ```ruby diff --git a/spec/ruby/README.md b/spec/ruby/README.md index e62ddc7dce..55b248a6c3 100644 --- a/spec/ruby/README.md +++ b/spec/ruby/README.md @@ -18,20 +18,21 @@ Every example code has a textual description, which presents several advantages: The specs are written with syntax similar to RSpec 2. They are run with MSpec, the purpose-built framework for running the Ruby Spec Suite. -For more information, see the [MSpec](http://github.com/ruby/mspec) project. +For more information, see the [MSpec](https://github.com/ruby/mspec) project. The specs describe the [language syntax](language/), the [core library](core/), the [standard library](library/), the [C API for extensions](optional/capi) and the [command line flags](command_line/). The language specs are grouped by keyword while the core and standard library specs are grouped by class and method. ruby/spec is known to be tested in these implementations for every commit: -* [MRI](http://rubyci.org/) on 30 platforms and 4 versions + +* [MRI](https://rubyci.org/) on 30 platforms and 4 versions * [JRuby](https://github.com/jruby/jruby/tree/master/spec/ruby) for both 1.7 and 9.x * [TruffleRuby](https://github.com/oracle/truffleruby/tree/master/spec/ruby) * [Opal](https://github.com/opal/opal/tree/master/spec) * [Artichoke](https://github.com/artichoke/spec/tree/artichoke-vendor) -ruby/spec describes the behavior of Ruby 2.6 and more recent Ruby versions. -More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (2.6.x, 2.7.x, 3.0.x, etc), and those are tested in CI. +ruby/spec describes the behavior of Ruby 2.7 and more recent Ruby versions. +More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (2.7.x, 3.0.x, 3.1.x, etc), and those are tested in CI. ### Synchronization with Ruby Implementations @@ -53,12 +54,14 @@ $ ../mspec/bin/mspec ### Specs for old Ruby versions For older specs try these commits: + * Ruby 2.0.0-p647 - [Suite](https://github.com/ruby/spec/commit/245862558761d5abc676843ef74f86c9bcc8ea8d) using [MSpec](https://github.com/ruby/mspec/commit/f90efa068791064f955de7a843e96e2d7d3041c2) (may encounter 2 failures) * Ruby 2.1.9 - [Suite](https://github.com/ruby/spec/commit/f029e65241374386077ac500add557ae65069b55) using [MSpec](https://github.com/ruby/mspec/commit/55568ea3918c6380e64db8c567d732fa5781efed) * Ruby 2.2.10 - [Suite](https://github.com/ruby/spec/commit/cbaa0e412270c944df0c2532fc500c920dba0e92) using [MSpec](https://github.com/ruby/mspec/commit/d84d7668449e96856c5f6bac8cb1526b6d357ce3) * Ruby 2.3.8 - [Suite](https://github.com/ruby/spec/commit/dc733114d8ae66a3368ba3a98422c50147a76ba5) using [MSpec](https://github.com/ruby/mspec/commit/4599bc195fb109f2a482a01c32a7d659518369ea) * Ruby 2.4.10 - [Suite](https://github.com/ruby/spec/commit/bce4f2b81d6c31db67cf4d023a0625ceadde59bd) using [MSpec](https://github.com/ruby/mspec/commit/e7eb8aa4c26495b7b461e687d950b96eb08b3ff2) * Ruby 2.5.9 - [Suite](https://github.com/ruby/spec/commit/c503335d3d9f6ec6ef24de60a0716c34af69b64f) using [MSpec](https://github.com/ruby/mspec/commit/0091e8a62e954717cd54641f935eaf1403692041) +* Ruby 2.6.10 - [Suite](https://github.com/ruby/spec/commit/aaf998fb8c92c4e63ad423a2e7ca6e6921818c6e) using [MSpec](https://github.com/ruby/mspec/commit/5e36c684e9e2b92b1187589bba1df22c640a8661) ### Running the specs @@ -70,7 +73,7 @@ Then move to it: $ cd spec -Clone [MSpec](http://github.com/ruby/mspec): +Clone [MSpec](https://github.com/ruby/mspec): $ git clone https://github.com/ruby/mspec.git ../mspec @@ -152,5 +155,5 @@ This project was originally born from [Rubinius](https://github.com/rubinius/rub The revision history of these specs is available [here](https://github.com/ruby/spec/blob/2b886623/CHANGES.before-2008-05-10). These specs were later extracted to their own project, RubySpec, with a specific vision and principles. At the end of 2014, Brian Shirai, the creator of RubySpec, decided to [end RubySpec](http://rubinius.com/2014/12/31/matz-s-ruby-developers-don-t-use-rubyspec/). -A couple months later, the different repositories were merged and [the project was revived](http://eregon.github.io/rubyspec/2015/07/29/rubyspec-is-reborn.html). +A couple months later, the different repositories were merged and [the project was revived](https://eregon.github.io/rubyspec/2015/07/29/rubyspec-is-reborn.html). On 12 January 2016, the name was changed to "The Ruby Spec Suite" for clarity and to let the RubySpec ideology rest in peace. diff --git a/spec/ruby/command_line/dash_upper_w_spec.rb b/spec/ruby/command_line/dash_upper_w_spec.rb index cbb040a8dd..4019510d42 100644 --- a/spec/ruby/command_line/dash_upper_w_spec.rb +++ b/spec/ruby/command_line/dash_upper_w_spec.rb @@ -19,29 +19,26 @@ describe "The -W command line option with 2" do it_behaves_like :command_line_verbose, "-W2" end -# Regarding the defaults, see core/warning/element_reference_spec.rb -ruby_version_is "2.7" do - describe "The -W command line option with :deprecated" do - it "enables deprecation warnings" do - ruby_exe('p Warning[:deprecated]', options: '-W:deprecated').should == "true\n" - end +describe "The -W command line option with :deprecated" do + it "enables deprecation warnings" do + ruby_exe('p Warning[:deprecated]', options: '-W:deprecated').should == "true\n" end +end - describe "The -W command line option with :no-deprecated" do - it "suppresses deprecation warnings" do - ruby_exe('p Warning[:deprecated]', options: '-w -W:no-deprecated').should == "false\n" - end +describe "The -W command line option with :no-deprecated" do + it "suppresses deprecation warnings" do + ruby_exe('p Warning[:deprecated]', options: '-w -W:no-deprecated').should == "false\n" end +end - describe "The -W command line option with :experimental" do - it "enables experimental warnings" do - ruby_exe('p Warning[:experimental]', options: '-W:experimental').should == "true\n" - end +describe "The -W command line option with :experimental" do + it "enables experimental warnings" do + ruby_exe('p Warning[:experimental]', options: '-W:experimental').should == "true\n" end +end - describe "The -W command line option with :no-experimental" do - it "suppresses experimental warnings" do - ruby_exe('p Warning[:experimental]', options: '-w -W:no-experimental').should == "false\n" - end +describe "The -W command line option with :no-experimental" do + it "suppresses experimental warnings" do + ruby_exe('p Warning[:experimental]', options: '-w -W:no-experimental').should == "false\n" end end diff --git a/spec/ruby/command_line/dash_v_spec.rb b/spec/ruby/command_line/dash_v_spec.rb index 89cef6c3bd..a4f4dcd051 100644 --- a/spec/ruby/command_line/dash_v_spec.rb +++ b/spec/ruby/command_line/dash_v_spec.rb @@ -7,6 +7,7 @@ describe "The -v command line option" do describe "when used alone" do it "prints version and ends" do ruby_exe(nil, args: '-v').should include(RUBY_DESCRIPTION) - end unless defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled? # pending. not sure why MJIT doesn't need anything to fix this. + end unless (defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?) || + (defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled?) end end diff --git a/spec/ruby/command_line/dash_w_spec.rb b/spec/ruby/command_line/dash_w_spec.rb index c262df12cc..f310dca3ed 100644 --- a/spec/ruby/command_line/dash_w_spec.rb +++ b/spec/ruby/command_line/dash_w_spec.rb @@ -4,9 +4,7 @@ require_relative 'shared/verbose' describe "The -w command line option" do it_behaves_like :command_line_verbose, "-w" - ruby_version_is "2.7" do - it "enables both deprecated and experimental warnings" do - ruby_exe('p Warning[:deprecated]; p Warning[:experimental]', options: '-w').should == "true\ntrue\n" - end + it "enables both deprecated and experimental warnings" do + ruby_exe('p Warning[:deprecated]; p Warning[:experimental]', options: '-w').should == "true\ntrue\n" end end diff --git a/spec/ruby/command_line/feature_spec.rb b/spec/ruby/command_line/feature_spec.rb index 1a9ea925c9..4a24cc6795 100644 --- a/spec/ruby/command_line/feature_spec.rb +++ b/spec/ruby/command_line/feature_spec.rb @@ -43,7 +43,9 @@ describe "The --enable and --disable flags" do ruby_exe("p 'foo'.frozen?", options: "--disable-frozen-string-literal").chomp.should == "false" end - platform_is_not :darwin do # frequently hangs for >60s on GitHub Actions macos-latest + # frequently hangs for >60s on GitHub Actions macos-latest + # MinGW's YJIT support seems broken + platform_is_not :darwin, :mingw do it "can be used with all for enable" do e = "p [defined?(Gem), defined?(DidYouMean), $VERBOSE, 'foo'.frozen?]" env = {'RUBYOPT' => '-w'} diff --git a/spec/ruby/command_line/fixtures/freeze_flag_two_literals.rb b/spec/ruby/command_line/fixtures/freeze_flag_two_literals.rb index 074092c9d9..f5547a5bae 100644 --- a/spec/ruby/command_line/fixtures/freeze_flag_two_literals.rb +++ b/spec/ruby/command_line/fixtures/freeze_flag_two_literals.rb @@ -1 +1 @@ -p "abc".object_id == "abc".object_id +p "abc".equal?("abc") diff --git a/spec/ruby/command_line/rubyopt_spec.rb b/spec/ruby/command_line/rubyopt_spec.rb index a2b817bad8..bbea4d557d 100644 --- a/spec/ruby/command_line/rubyopt_spec.rb +++ b/spec/ruby/command_line/rubyopt_spec.rb @@ -59,24 +59,22 @@ describe "Processing RUBYOPT" do ruby_exe("p $VERBOSE", escape: true).chomp.should == "true" end - ruby_version_is "2.7" do - it "suppresses deprecation warnings for '-W:no-deprecated'" do - ENV["RUBYOPT"] = '-W:no-deprecated' - result = ruby_exe('$; = ""', args: '2>&1') - result.should == "" - end + it "suppresses deprecation warnings for '-W:no-deprecated'" do + ENV["RUBYOPT"] = '-W:no-deprecated' + result = ruby_exe('$; = ""', args: '2>&1') + result.should == "" + end - it "suppresses experimental warnings for '-W:no-experimental'" do - ENV["RUBYOPT"] = '-W:no-experimental' - result = ruby_exe('case 0; in a; end', args: '2>&1') - result.should == "" - end + it "suppresses experimental warnings for '-W:no-experimental'" do + ENV["RUBYOPT"] = '-W:no-experimental' + result = ruby_exe('case 0; in a; end', args: '2>&1') + result.should == "" + end - it "suppresses deprecation and experimental warnings for '-W:no-deprecated -W:no-experimental'" do - ENV["RUBYOPT"] = '-W:no-deprecated -W:no-experimental' - result = ruby_exe('case ($; = ""); in a; end', args: '2>&1') - result.should == "" - end + it "suppresses deprecation and experimental warnings for '-W:no-deprecated -W:no-experimental'" do + ENV["RUBYOPT"] = '-W:no-deprecated -W:no-experimental' + result = ruby_exe('case ($; = ""); in a; end', args: '2>&1') + result.should == "" end it "requires the file for '-r'" do diff --git a/spec/ruby/core/array/clear_spec.rb b/spec/ruby/core/array/clear_spec.rb index bddc672d3b..81ba56e01e 100644 --- a/spec/ruby/core/array/clear_spec.rb +++ b/spec/ruby/core/array/clear_spec.rb @@ -20,30 +20,10 @@ describe "Array#clear" do a.size.should == 0 end - ruby_version_is ''...'2.7' do - it "keeps tainted status" do - a = [1] - a.taint - a.tainted?.should be_true - a.clear - a.tainted?.should be_true - end - end - it "does not accept any arguments" do -> { [1].clear(true) }.should raise_error(ArgumentError) end - ruby_version_is ''...'2.7' do - it "keeps untrusted status" do - a = [1] - a.untrust - a.untrusted?.should be_true - a.clear - a.untrusted?.should be_true - end - end - it "raises a FrozenError on a frozen array" do a = [1] a.freeze diff --git a/spec/ruby/core/array/compact_spec.rb b/spec/ruby/core/array/compact_spec.rb index aa3c1c0446..83b3fa2a89 100644 --- a/spec/ruby/core/array/compact_spec.rb +++ b/spec/ruby/core/array/compact_spec.rb @@ -21,20 +21,6 @@ describe "Array#compact" do it "does not return subclass instance for Array subclasses" do ArraySpecs::MyArray[1, 2, 3, nil].compact.should be_an_instance_of(Array) end - - ruby_version_is ''...'2.7' do - it "does not keep tainted status even if all elements are removed" do - a = [nil, nil] - a.taint - a.compact.tainted?.should be_false - end - - it "does not keep untrusted status even if all elements are removed" do - a = [nil, nil] - a.untrust - a.compact.untrusted?.should be_false - end - end end describe "Array#compact!" do @@ -59,22 +45,6 @@ describe "Array#compact!" do [1, 2, false, 3].compact!.should == nil end - ruby_version_is ''...'2.7' do - it "keeps tainted status even if all elements are removed" do - a = [nil, nil] - a.taint - a.compact! - a.tainted?.should be_true - end - - it "keeps untrusted status even if all elements are removed" do - a = [nil, nil] - a.untrust - a.compact! - a.untrusted?.should be_true - end - end - it "raises a FrozenError on a frozen array" do -> { ArraySpecs.frozen_array.compact! }.should raise_error(FrozenError) end diff --git a/spec/ruby/core/array/concat_spec.rb b/spec/ruby/core/array/concat_spec.rb index da6763bfd6..f3cab9c17c 100644 --- a/spec/ruby/core/array/concat_spec.rb +++ b/spec/ruby/core/array/concat_spec.rb @@ -41,64 +41,6 @@ describe "Array#concat" do -> { ArraySpecs.frozen_array.concat([]) }.should raise_error(FrozenError) end - ruby_version_is ''...'2.7' do - it "keeps tainted status" do - ary = [1, 2] - ary.taint - ary.concat([3]) - ary.tainted?.should be_true - ary.concat([]) - ary.tainted?.should be_true - end - - it "is not infected by the other" do - ary = [1,2] - other = [3]; other.taint - ary.tainted?.should be_false - ary.concat(other) - ary.tainted?.should be_false - end - - it "keeps the tainted status of elements" do - ary = [ Object.new, Object.new, Object.new ] - ary.each {|x| x.taint } - - ary.concat([ Object.new ]) - ary[0].tainted?.should be_true - ary[1].tainted?.should be_true - ary[2].tainted?.should be_true - ary[3].tainted?.should be_false - end - - it "keeps untrusted status" do - ary = [1, 2] - ary.untrust - ary.concat([3]) - ary.untrusted?.should be_true - ary.concat([]) - ary.untrusted?.should be_true - end - - it "is not infected untrustedness by the other" do - ary = [1,2] - other = [3]; other.untrust - ary.untrusted?.should be_false - ary.concat(other) - ary.untrusted?.should be_false - end - - it "keeps the untrusted status of elements" do - ary = [ Object.new, Object.new, Object.new ] - ary.each {|x| x.untrust } - - ary.concat([ Object.new ]) - ary[0].untrusted?.should be_true - ary[1].untrusted?.should be_true - ary[2].untrusted?.should be_true - ary[3].untrusted?.should be_false - end - end - it "appends elements to an Array with enough capacity that has been shifted" do ary = [1, 2, 3, 4, 5] 2.times { ary.shift } diff --git a/spec/ruby/core/array/deconstruct_spec.rb b/spec/ruby/core/array/deconstruct_spec.rb index 2b07152dfc..ad67abe47b 100644 --- a/spec/ruby/core/array/deconstruct_spec.rb +++ b/spec/ruby/core/array/deconstruct_spec.rb @@ -1,11 +1,9 @@ require_relative '../../spec_helper' -ruby_version_is "2.7" do - describe "Array#deconstruct" do - it "returns self" do - array = [1] +describe "Array#deconstruct" do + it "returns self" do + array = [1] - array.deconstruct.should equal array - end + array.deconstruct.should equal array end end diff --git a/spec/ruby/core/array/delete_at_spec.rb b/spec/ruby/core/array/delete_at_spec.rb index fc225a03f1..80ec643702 100644 --- a/spec/ruby/core/array/delete_at_spec.rb +++ b/spec/ruby/core/array/delete_at_spec.rb @@ -38,26 +38,4 @@ describe "Array#delete_at" do it "raises a FrozenError on a frozen array" do -> { [1,2,3].freeze.delete_at(0) }.should raise_error(FrozenError) end - - ruby_version_is ''...'2.7' do - it "keeps tainted status" do - ary = [1, 2] - ary.taint - ary.tainted?.should be_true - ary.delete_at(0) - ary.tainted?.should be_true - ary.delete_at(0) # now empty - ary.tainted?.should be_true - end - - it "keeps untrusted status" do - ary = [1, 2] - ary.untrust - ary.untrusted?.should be_true - ary.delete_at(0) - ary.untrusted?.should be_true - ary.delete_at(0) # now empty - ary.untrusted?.should be_true - end - end end diff --git a/spec/ruby/core/array/delete_if_spec.rb b/spec/ruby/core/array/delete_if_spec.rb index e1931220f5..1459cc8d04 100644 --- a/spec/ruby/core/array/delete_if_spec.rb +++ b/spec/ruby/core/array/delete_if_spec.rb @@ -47,22 +47,6 @@ describe "Array#delete_if" do -> { ArraySpecs.empty_frozen_array.delete_if {} }.should raise_error(FrozenError) end - ruby_version_is ''...'2.7' do - it "keeps tainted status" do - @a.taint - @a.tainted?.should be_true - @a.delete_if{ true } - @a.tainted?.should be_true - end - - it "keeps untrusted status" do - @a.untrust - @a.untrusted?.should be_true - @a.delete_if{ true } - @a.untrusted?.should be_true - end - end - it_behaves_like :enumeratorized_with_origin_size, :delete_if, [1,2,3] it_behaves_like :delete_if, :delete_if end diff --git a/spec/ruby/core/array/delete_spec.rb b/spec/ruby/core/array/delete_spec.rb index 5d53c74e47..dddbbe6bd3 100644 --- a/spec/ruby/core/array/delete_spec.rb +++ b/spec/ruby/core/array/delete_spec.rb @@ -43,26 +43,4 @@ describe "Array#delete" do it "raises a FrozenError on a frozen array" do -> { [1, 2, 3].freeze.delete(1) }.should raise_error(FrozenError) end - - ruby_version_is ''...'2.7' do - it "keeps tainted status" do - a = [1, 2] - a.taint - a.tainted?.should be_true - a.delete(2) - a.tainted?.should be_true - a.delete(1) # now empty - a.tainted?.should be_true - end - - it "keeps untrusted status" do - a = [1, 2] - a.untrust - a.untrusted?.should be_true - a.delete(2) - a.untrusted?.should be_true - a.delete(1) # now empty - a.untrusted?.should be_true - end - end end diff --git a/spec/ruby/core/array/each_spec.rb b/spec/ruby/core/array/each_spec.rb index 256647d61e..cf8e9da6d8 100644 --- a/spec/ruby/core/array/each_spec.rb +++ b/spec/ruby/core/array/each_spec.rb @@ -3,9 +3,10 @@ require_relative 'fixtures/classes' require_relative 'shared/enumeratorize' require_relative '../enumerable/shared/enumeratorized' -# Modifying a collection while the contents are being iterated -# gives undefined behavior. See -# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633 +# Mutating the array while it is being iterated is discouraged as it can result in confusing behavior. +# Yet a Ruby implementation must not crash in such a case, and following the simple CRuby behavior makes sense. +# CRuby simply reads the array storage and checks the size for every iteration; +# like `i = 0; while i < size; yield self[i]; end` describe "Array#each" do it "yields each element to the block" do @@ -15,6 +16,34 @@ describe "Array#each" do a.should == [1, 2, 3] end + it "yields each element to the block even if the array is changed during iteration" do + a = [1, 2, 3, 4, 5] + iterated = [] + a.each { |x| iterated << x; a << x+5 if x.even? } + iterated.should == [1, 2, 3, 4, 5, 7, 9] + end + + it "yields only elements that are still in the array" do + a = [0, 1, 2, 3, 4] + iterated = [] + a.each { |x| iterated << x; a.pop if x.even? } + iterated.should == [0, 1, 2] + end + + it "yields elements based on an internal index" do + a = [0, 1, 2, 3, 4] + iterated = [] + a.each { |x| iterated << x; a.shift if x.even? } + iterated.should == [0, 2, 4] + end + + it "yields the same element multiple times if inserting while iterating" do + a = [1, 2] + iterated = [] + a.each { |x| iterated << x; a.unshift(0) if a.size == 2 } + iterated.should == [1, 1, 2] + end + it "yields each element to a block that takes multiple arguments" do a = [[1, 2], :a, [3, 4]] b = [] diff --git a/spec/ruby/core/array/element_set_spec.rb b/spec/ruby/core/array/element_set_spec.rb index 1e192c100f..df5ca9582e 100644 --- a/spec/ruby/core/array/element_set_spec.rb +++ b/spec/ruby/core/array/element_set_spec.rb @@ -481,50 +481,48 @@ describe "Array#[]= with [m..]" do end end -ruby_version_is "2.7" do - describe "Array#[]= with [..n] and [...n]" do - it "just sets the section defined by range to nil even if the rhs is nil" do - a = [1, 2, 3, 4, 5] - a[eval("(..2)")] = nil - a.should == [nil, 4, 5] - a[eval("(...2)")] = nil - a.should == [nil, 5] - end +describe "Array#[]= with [..n] and [...n]" do + it "just sets the section defined by range to nil even if the rhs is nil" do + a = [1, 2, 3, 4, 5] + a[(..2)] = nil + a.should == [nil, 4, 5] + a[(...2)] = nil + a.should == [nil, 5] + end - it "just sets the section defined by range to nil if n < 0 and the rhs is nil" do - a = [1, 2, 3, 4, 5] - a[eval("(..-3)")] = nil - a.should == [nil, 4, 5] - a[eval("(...-1)")] = [nil, 5] - end + it "just sets the section defined by range to nil if n < 0 and the rhs is nil" do + a = [1, 2, 3, 4, 5] + a[(..-3)] = nil + a.should == [nil, 4, 5] + a[(...-1)] = [nil, 5] + end - it "replaces the section defined by range" do - a = [6, 5, 4, 3, 2, 1] - a[eval("(...3)")] = 9 - a.should == [9, 3, 2, 1] - a[eval("(..2)")] = [7, 7, 7, 7, 7] - a.should == [7, 7, 7, 7, 7, 1] - end + it "replaces the section defined by range" do + a = [6, 5, 4, 3, 2, 1] + a[(...3)] = 9 + a.should == [9, 3, 2, 1] + a[(..2)] = [7, 7, 7, 7, 7] + a.should == [7, 7, 7, 7, 7, 1] + end - it "replaces the section if n < 0" do - a = [1, 2, 3, 4, 5] - a[eval("(..-2)")] = [7, 8, 9] - a.should == [7, 8, 9, 5] - end + it "replaces the section if n < 0" do + a = [1, 2, 3, 4, 5] + a[(..-2)] = [7, 8, 9] + a.should == [7, 8, 9, 5] + end - it "replaces everything if n > the array size" do - a = [1, 2, 3] - a[eval("(...7)")] = [4] - a.should == [4] - end + it "replaces everything if n > the array size" do + a = [1, 2, 3] + a[(...7)] = [4] + a.should == [4] + end - it "inserts at the beginning if n < negative the array size" do - a = [1, 2, 3] - a[eval("(..-7)")] = [4] - a.should == [4, 1, 2, 3] - a[eval("(...-10)")] = [6] - a.should == [6, 4, 1, 2, 3] - end + it "inserts at the beginning if n < negative the array size" do + a = [1, 2, 3] + a[(..-7)] = [4] + a.should == [4, 1, 2, 3] + a[(...-10)] = [6] + a.should == [6, 4, 1, 2, 3] end end diff --git a/spec/ruby/core/array/fill_spec.rb b/spec/ruby/core/array/fill_spec.rb index bfa8db551b..6369f23544 100644 --- a/spec/ruby/core/array/fill_spec.rb +++ b/spec/ruby/core/array/fill_spec.rb @@ -323,10 +323,8 @@ describe "Array#fill with (filler, range)" do [1, 2, 3, 4].fill(eval("(3...)")) { |x| x + 2 }.should == [1, 2, 3, 5] end - ruby_version_is "2.7" do - it "works with beginless ranges" do - [1, 2, 3, 4].fill('x', eval("(..2)")).should == ["x", "x", "x", 4] - [1, 2, 3, 4].fill(eval("(...2)")) { |x| x + 2 }.should == [2, 3, 3, 4] - end + it "works with beginless ranges" do + [1, 2, 3, 4].fill('x', (..2)).should == ["x", "x", "x", 4] + [1, 2, 3, 4].fill((...2)) { |x| x + 2 }.should == [2, 3, 3, 4] end end diff --git a/spec/ruby/core/array/flatten_spec.rb b/spec/ruby/core/array/flatten_spec.rb index 2f9fb8a3ec..1770b5389a 100644 --- a/spec/ruby/core/array/flatten_spec.rb +++ b/spec/ruby/core/array/flatten_spec.rb @@ -147,16 +147,6 @@ describe "Array#flatten" do end end - ruby_version_is ''...'2.7' do - it "returns a tainted array if self is tainted" do - [].taint.flatten.tainted?.should be_true - end - - it "returns an untrusted array if self is untrusted" do - [].untrust.flatten.untrusted?.should be_true - end - end - it "performs respond_to? and method_missing-aware checks when coercing elements to array" do bo = BasicObject.new [bo].flatten.should == [bo] diff --git a/spec/ruby/core/array/intersection_spec.rb b/spec/ruby/core/array/intersection_spec.rb index 27d90f1e44..e01a68d389 100644 --- a/spec/ruby/core/array/intersection_spec.rb +++ b/spec/ruby/core/array/intersection_spec.rb @@ -6,16 +6,14 @@ describe "Array#&" do it_behaves_like :array_intersection, :& end -ruby_version_is "2.7" do - describe "Array#intersection" do - it_behaves_like :array_intersection, :intersection +describe "Array#intersection" do + it_behaves_like :array_intersection, :intersection - it "accepts multiple arguments" do - [1, 2, 3, 4].intersection([1, 2, 3], [2, 3, 4]).should == [2, 3] - end + it "accepts multiple arguments" do + [1, 2, 3, 4].intersection([1, 2, 3], [2, 3, 4]).should == [2, 3] + end - it "preserves elements order from original array" do - [1, 2, 3, 4].intersection([3, 2, 1]).should == [1, 2, 3] - end + it "preserves elements order from original array" do + [1, 2, 3, 4].intersection([3, 2, 1]).should == [1, 2, 3] end end diff --git a/spec/ruby/core/array/multiply_spec.rb b/spec/ruby/core/array/multiply_spec.rb index 16e407348b..23d5c99f3a 100644 --- a/spec/ruby/core/array/multiply_spec.rb +++ b/spec/ruby/core/array/multiply_spec.rb @@ -97,46 +97,6 @@ describe "Array#* with an integer" do ScratchPad.recorded.should be_nil end end - - ruby_version_is ''...'2.7' do - it "copies the taint status of the original array even if the passed count is 0" do - ary = [1, 2, 3] - ary.taint - (ary * 0).should.tainted? - end - - it "copies the taint status of the original array even if the array is empty" do - ary = [] - ary.taint - (ary * 3).should.tainted? - end - - it "copies the taint status of the original array if the passed count is not 0" do - ary = [1, 2, 3] - ary.taint - (ary * 1).should.tainted? - (ary * 2).should.tainted? - end - - it "copies the untrusted status of the original array even if the passed count is 0" do - ary = [1, 2, 3] - ary.untrust - (ary * 0).should.untrusted? - end - - it "copies the untrusted status of the original array even if the array is empty" do - ary = [] - ary.untrust - (ary * 3).should.untrusted? - end - - it "copies the untrusted status of the original array if the passed count is not 0" do - ary = [1, 2, 3] - ary.untrust - (ary * 1).should.untrusted? - (ary * 2).should.untrusted? - end - end end describe "Array#* with a string" do diff --git a/spec/ruby/core/array/pack/a_spec.rb b/spec/ruby/core/array/pack/a_spec.rb index 7af7a16c68..f4a40502c2 100644 --- a/spec/ruby/core/array/pack/a_spec.rb +++ b/spec/ruby/core/array/pack/a_spec.rb @@ -12,6 +12,17 @@ describe "Array#pack with format 'A'" do it_behaves_like :array_pack_string, 'A' it_behaves_like :array_pack_taint, 'A' + it "calls #to_str to convert an Object to a String" do + obj = mock("pack A string") + obj.should_receive(:to_str).and_return("``abcdef") + [obj].pack("A*").should == "``abcdef" + end + + it "will not implicitly convert a number to a string" do + -> { [0].pack('A') }.should raise_error(TypeError) + -> { [0].pack('a') }.should raise_error(TypeError) + end + it "adds all the bytes to the output when passed the '*' modifier" do ["abc"].pack("A*").should == "abc" end diff --git a/spec/ruby/core/array/pack/b_spec.rb b/spec/ruby/core/array/pack/b_spec.rb index 872c1b88d5..ec82b7d1ab 100644 --- a/spec/ruby/core/array/pack/b_spec.rb +++ b/spec/ruby/core/array/pack/b_spec.rb @@ -13,11 +13,16 @@ describe "Array#pack with format 'B'" do it_behaves_like :array_pack_taint, 'B' it "calls #to_str to convert an Object to a String" do - obj = mock("pack H string") + obj = mock("pack B string") obj.should_receive(:to_str).and_return("``abcdef") [obj].pack("B*").should == "\x2a" end + it "will not implicitly convert a number to a string" do + -> { [0].pack('B') }.should raise_error(TypeError) + -> { [0].pack('b') }.should raise_error(TypeError) + end + it "encodes one bit for each character starting with the most significant bit" do [ [["0"], "\x00"], [["1"], "\x80"] diff --git a/spec/ruby/core/array/pack/h_spec.rb b/spec/ruby/core/array/pack/h_spec.rb index 85a875fc8b..2c1dac8d4a 100644 --- a/spec/ruby/core/array/pack/h_spec.rb +++ b/spec/ruby/core/array/pack/h_spec.rb @@ -18,6 +18,11 @@ describe "Array#pack with format 'H'" do [obj].pack("H").should == "\xa0" end + it "will not implicitly convert a number to a string" do + -> { [0].pack('H') }.should raise_error(TypeError) + -> { [0].pack('h') }.should raise_error(TypeError) + end + it "encodes the first character as the most significant nibble when passed no count modifier" do ["ab"].pack("H").should == "\xa0" end diff --git a/spec/ruby/core/array/pack/p_spec.rb b/spec/ruby/core/array/pack/p_spec.rb index d7dff8a4da..b023bf9110 100644 --- a/spec/ruby/core/array/pack/p_spec.rb +++ b/spec/ruby/core/array/pack/p_spec.rb @@ -15,18 +15,6 @@ describe "Array#pack with format 'P'" do ["hello"].pack("P").unpack("P5").should == ["hello"] end - ruby_version_is ''...'2.7' do - it "taints the input string" do - input_string = "hello" - [input_string].pack("P") - input_string.tainted?.should be_true - end - - it "does not taint the output string in normal cases" do - ["hello"].pack("P").tainted?.should be_false - end - end - it "with nil gives a null pointer" do [nil].pack("P").unpack("J").should == [0] end @@ -44,18 +32,6 @@ describe "Array#pack with format 'p'" do ["hello"].pack("p").unpack("p").should == ["hello"] end - ruby_version_is ''...'2.7' do - it "taints the input string" do - input_string = "hello" - [input_string].pack("p") - input_string.tainted?.should be_true - end - - it "does not taint the output string in normal cases" do - ["hello"].pack("p").tainted?.should be_false - end - end - it "with nil gives a null pointer" do [nil].pack("p").unpack("J").should == [0] end diff --git a/spec/ruby/core/array/pack/shared/basic.rb b/spec/ruby/core/array/pack/shared/basic.rb index 9061273ad6..23e239d3de 100644 --- a/spec/ruby/core/array/pack/shared/basic.rb +++ b/spec/ruby/core/array/pack/shared/basic.rb @@ -32,12 +32,6 @@ describe :array_pack_basic_non_float, shared: true do d.should_receive(:to_str).and_return("x"+pack_format) [@obj, @obj].pack(d).should be_an_instance_of(String) end - - ruby_version_is ''...'2.7' do - it "taints the output string if the format string is tainted" do - [@obj, @obj].pack("x"+pack_format.taint).tainted?.should be_true - end - end end describe :array_pack_basic_float, shared: true do @@ -50,12 +44,6 @@ describe :array_pack_basic_float, shared: true do d.should_receive(:to_str).and_return("x"+pack_format) [1.2, 4.7].pack(d).should be_an_instance_of(String) end - - ruby_version_is ''...'2.7' do - it "taints the output string if the format string is tainted" do - [3.2, 2.8].pack("x"+pack_format.taint).tainted?.should be_true - end - end end describe :array_pack_no_platform, shared: true do diff --git a/spec/ruby/core/array/pack/shared/float.rb b/spec/ruby/core/array/pack/shared/float.rb index c6b194007f..ba174a071a 100644 --- a/spec/ruby/core/array/pack/shared/float.rb +++ b/spec/ruby/core/array/pack/shared/float.rb @@ -53,6 +53,14 @@ describe :array_pack_float_le, shared: true do it "encodes a negative Float outside the range of a single precision float" do [-1e150].pack(pack_format).should == "\x00\x00\x80\xff" end + + it "encodes a bignum as a float" do + [2 ** 65].pack(pack_format).should == [(2 ** 65).to_f].pack(pack_format) + end + + it "encodes a rational as a float" do + [Rational(3, 4)].pack(pack_format).should == [Rational(3, 4).to_f].pack(pack_format) + end end describe :array_pack_float_be, shared: true do diff --git a/spec/ruby/core/array/pack/shared/taint.rb b/spec/ruby/core/array/pack/shared/taint.rb index 565f04b8b9..2c2b011c34 100644 --- a/spec/ruby/core/array/pack/shared/taint.rb +++ b/spec/ruby/core/array/pack/shared/taint.rb @@ -1,35 +1,2 @@ describe :array_pack_taint, shared: true do - ruby_version_is ''...'2.7' do - it "returns a tainted string when a pack argument is tainted" do - ["abcd".taint, 0x20].pack(pack_format("3C")).tainted?.should be_true - end - - it "does not return a tainted string when the array is tainted" do - ["abcd", 0x20].taint.pack(pack_format("3C")).tainted?.should be_false - end - - it "returns a tainted string when the format is tainted" do - ["abcd", 0x20].pack(pack_format("3C").taint).tainted?.should be_true - end - - it "returns a tainted string when an empty format is tainted" do - ["abcd", 0x20].pack("".taint).tainted?.should be_true - end - - it "returns a untrusted string when the format is untrusted" do - ["abcd", 0x20].pack(pack_format("3C").untrust).untrusted?.should be_true - end - - it "returns a untrusted string when the empty format is untrusted" do - ["abcd", 0x20].pack("".untrust).untrusted?.should be_true - end - - it "returns a untrusted string when a pack argument is untrusted" do - ["abcd".untrust, 0x20].pack(pack_format("3C")).untrusted?.should be_true - end - - it "returns a trusted string when the array is untrusted" do - ["abcd", 0x20].untrust.pack(pack_format("3C")).untrusted?.should be_false - end - end end diff --git a/spec/ruby/core/array/pack/u_spec.rb b/spec/ruby/core/array/pack/u_spec.rb index fe969cbb2d..b20093a647 100644 --- a/spec/ruby/core/array/pack/u_spec.rb +++ b/spec/ruby/core/array/pack/u_spec.rb @@ -18,6 +18,16 @@ describe "Array#pack with format 'u'" do it_behaves_like :array_pack_arguments, 'u' it_behaves_like :array_pack_taint, 'u' + it "calls #to_str to convert an Object to a String" do + obj = mock("pack u string") + obj.should_receive(:to_str).and_return("``abcdef") + [obj].pack("u*").should == "(8&!A8F-D968`\n" + end + + it "will not implicitly convert a number to a string" do + -> { [0].pack('u') }.should raise_error(TypeError) + end + it "encodes an empty string as an empty string" do [""].pack("u").should == "" end diff --git a/spec/ruby/core/array/pack/x_spec.rb b/spec/ruby/core/array/pack/x_spec.rb index a28dd0bf21..86c3ad1aa4 100644 --- a/spec/ruby/core/array/pack/x_spec.rb +++ b/spec/ruby/core/array/pack/x_spec.rb @@ -30,6 +30,7 @@ describe "Array#pack with format 'x'" do it "does not add a NULL byte when passed the '*' modifier" do [].pack("x*").should == "" + [1, 2].pack("Cx*C").should == "\x01\x02" end end diff --git a/spec/ruby/core/array/pack/z_spec.rb b/spec/ruby/core/array/pack/z_spec.rb index 82ce7b4a1c..5ad3afd69e 100644 --- a/spec/ruby/core/array/pack/z_spec.rb +++ b/spec/ruby/core/array/pack/z_spec.rb @@ -12,6 +12,16 @@ describe "Array#pack with format 'Z'" do it_behaves_like :array_pack_string, 'Z' it_behaves_like :array_pack_taint, 'Z' + it "calls #to_str to convert an Object to a String" do + obj = mock("pack Z string") + obj.should_receive(:to_str).and_return("``abcdef") + [obj].pack("Z*").should == "``abcdef\x00" + end + + it "will not implicitly convert a number to a string" do + -> { [0].pack('Z') }.should raise_error(TypeError) + end + it "adds all the bytes and appends a NULL byte when passed the '*' modifier" do ["abc"].pack("Z*").should == "abc\x00" end diff --git a/spec/ruby/core/array/plus_spec.rb b/spec/ruby/core/array/plus_spec.rb index 45f8438208..3962b05c39 100644 --- a/spec/ruby/core/array/plus_spec.rb +++ b/spec/ruby/core/array/plus_spec.rb @@ -40,20 +40,4 @@ describe "Array#+" do it "does not call to_ary on array subclasses" do ([5, 6] + ArraySpecs::ToAryArray[1, 2]).should == [5, 6, 1, 2] end - - ruby_version_is ''...'2.7' do - it "does not get infected even if an original array is tainted" do - ([1, 2] + [3, 4]).tainted?.should be_false - ([1, 2].taint + [3, 4]).tainted?.should be_false - ([1, 2] + [3, 4].taint).tainted?.should be_false - ([1, 2].taint + [3, 4].taint).tainted?.should be_false - end - - it "does not infected even if an original array is untrusted" do - ([1, 2] + [3, 4]).untrusted?.should be_false - ([1, 2].untrust + [3, 4]).untrusted?.should be_false - ([1, 2] + [3, 4].untrust).untrusted?.should be_false - ([1, 2].untrust + [3, 4].untrust).untrusted?.should be_false - end - end end diff --git a/spec/ruby/core/array/pop_spec.rb b/spec/ruby/core/array/pop_spec.rb index 96ef78da32..2a19408660 100644 --- a/spec/ruby/core/array/pop_spec.rb +++ b/spec/ruby/core/array/pop_spec.rb @@ -30,16 +30,6 @@ describe "Array#pop" do array.pop.should == [1, 'two', 3.0, array, array, array, array] end - ruby_version_is ''...'2.7' do - it "keeps taint status" do - a = [1, 2].taint - a.pop - a.tainted?.should be_true - a.pop - a.tainted?.should be_true - end - end - it "raises a FrozenError on a frozen array" do -> { ArraySpecs.frozen_array.pop }.should raise_error(FrozenError) end @@ -48,16 +38,6 @@ describe "Array#pop" do -> { ArraySpecs.empty_frozen_array.pop }.should raise_error(FrozenError) end - ruby_version_is ''...'2.7' do - it "keeps untrusted status" do - a = [1, 2].untrust - a.pop - a.untrusted?.should be_true - a.pop - a.untrusted?.should be_true - end - end - describe "passed a number n as an argument" do it "removes and returns an array with the last n elements of the array" do a = [1, 2, 3, 4, 5, 6] @@ -136,41 +116,9 @@ describe "Array#pop" do ArraySpecs::MyArray[1, 2, 3].pop(2).should be_an_instance_of(Array) end - ruby_version_is ''...'2.7' do - it "returns an untainted array even if the array is tainted" do - ary = [1, 2].taint - ary.pop(2).tainted?.should be_false - ary.pop(0).tainted?.should be_false - end - - it "keeps taint status" do - a = [1, 2].taint - a.pop(2) - a.tainted?.should be_true - a.pop(2) - a.tainted?.should be_true - end - - it "returns a trusted array even if the array is untrusted" do - ary = [1, 2].untrust - ary.pop(2).untrusted?.should be_false - ary.pop(0).untrusted?.should be_false - end - end - it "raises a FrozenError on a frozen array" do -> { ArraySpecs.frozen_array.pop(2) }.should raise_error(FrozenError) -> { ArraySpecs.frozen_array.pop(0) }.should raise_error(FrozenError) end - - ruby_version_is ''...'2.7' do - it "keeps untrusted status" do - a = [1, 2].untrust - a.pop(2) - a.untrusted?.should be_true - a.pop(2) - a.untrusted?.should be_true - end - end end end diff --git a/spec/ruby/core/array/sample_spec.rb b/spec/ruby/core/array/sample_spec.rb index 565d7ff7f9..755b46f126 100644 --- a/spec/ruby/core/array/sample_spec.rb +++ b/spec/ruby/core/array/sample_spec.rb @@ -19,10 +19,18 @@ describe "Array#sample" do [].sample.should be_nil end + it "returns nil for an empty array when called without n and a Random is given" do + [].sample(random: Random.new(42)).should be_nil + end + it "returns a single value when not passed a count" do [4].sample.should equal(4) end + it "returns a single value when not passed a count and a Random is given" do + [4].sample(random: Random.new(42)).should equal(4) + end + it "returns an empty Array when passed zero" do [4].sample(0).should == [] end diff --git a/spec/ruby/core/array/shared/clone.rb b/spec/ruby/core/array/shared/clone.rb index 3c17b1f10f..035b45ec99 100644 --- a/spec/ruby/core/array/shared/clone.rb +++ b/spec/ruby/core/array/shared/clone.rb @@ -17,28 +17,4 @@ describe :array_clone, shared: true do b.should == a b.__id__.should_not == a.__id__ end - - ruby_version_is ''...'2.7' do - it "copies taint status from the original" do - a = [1, 2, 3, 4] - b = [1, 2, 3, 4] - a.taint - aa = a.send @method - bb = b.send @method - - aa.should.tainted? - bb.should_not.tainted? - end - - it "copies untrusted status from the original" do - a = [1, 2, 3, 4] - b = [1, 2, 3, 4] - a.untrust - aa = a.send @method - bb = b.send @method - - aa.should.untrusted? - bb.should_not.untrusted? - end - end end diff --git a/spec/ruby/core/array/shared/collect.rb b/spec/ruby/core/array/shared/collect.rb index d84432734a..8d75f7db9a 100644 --- a/spec/ruby/core/array/shared/collect.rb +++ b/spec/ruby/core/array/shared/collect.rb @@ -42,20 +42,6 @@ describe :array_collect, shared: true do }.should raise_error(ArgumentError) end - ruby_version_is ''...'2.7' do - it "does not copy tainted status" do - a = [1, 2, 3] - a.taint - a.send(@method){|x| x}.tainted?.should be_false - end - - it "does not copy untrusted status" do - a = [1, 2, 3] - a.untrust - a.send(@method){|x| x}.untrusted?.should be_false - end - end - before :all do @object = [1, 2, 3, 4] end @@ -96,23 +82,6 @@ describe :array_collect_b, shared: true do a.should == ["1!", "2!", "3!"] end - ruby_version_is ''...'2.7' do - it "keeps tainted status" do - a = [1, 2, 3] - a.taint - a.tainted?.should be_true - a.send(@method){|x| x} - a.tainted?.should be_true - end - - it "keeps untrusted status" do - a = [1, 2, 3] - a.untrust - a.send(@method){|x| x} - a.untrusted?.should be_true - end - end - describe "when frozen" do it "raises a FrozenError" do -> { ArraySpecs.frozen_array.send(@method) {} }.should raise_error(FrozenError) diff --git a/spec/ruby/core/array/shared/inspect.rb b/spec/ruby/core/array/shared/inspect.rb index 736f8d946b..a2b43d4959 100644 --- a/spec/ruby/core/array/shared/inspect.rb +++ b/spec/ruby/core/array/shared/inspect.rb @@ -64,32 +64,6 @@ describe :array_inspect, shared: true do ArraySpecs.empty_recursive_array.send(@method).should == "[[...]]" end - ruby_version_is ''...'2.7' do - it "taints the result if the Array is non-empty and tainted" do - [1, 2].taint.send(@method).tainted?.should be_true - end - - it "does not taint the result if the Array is tainted but empty" do - [].taint.send(@method).tainted?.should be_false - end - - it "taints the result if an element is tainted" do - ["str".taint].send(@method).tainted?.should be_true - end - - it "untrusts the result if the Array is untrusted" do - [1, 2].untrust.send(@method).untrusted?.should be_true - end - - it "does not untrust the result if the Array is untrusted but empty" do - [].untrust.send(@method).untrusted?.should be_false - end - - it "untrusts the result if an element is untrusted" do - ["str".untrust].send(@method).untrusted?.should be_true - end - end - describe "with encoding" do before :each do @default_external_encoding = Encoding.default_external diff --git a/spec/ruby/core/array/shared/join.rb b/spec/ruby/core/array/shared/join.rb index dfdb4ae1e4..507b13e3c8 100644 --- a/spec/ruby/core/array/shared/join.rb +++ b/spec/ruby/core/array/shared/join.rb @@ -58,36 +58,6 @@ describe :array_join_with_default_separator, shared: true do -> { ArraySpecs.empty_recursive_array.send(@method) }.should raise_error(ArgumentError) end - ruby_version_is ''...'2.7' do - it "taints the result if the Array is tainted and non-empty" do - [1, 2].taint.send(@method).tainted?.should be_true - end - - it "does not taint the result if the Array is tainted but empty" do - [].taint.send(@method).tainted?.should be_false - end - - it "taints the result if the result of coercing an element is tainted" do - s = mock("taint") - s.should_receive(:to_s).and_return("str".taint) - [s].send(@method).tainted?.should be_true - end - - it "untrusts the result if the Array is untrusted and non-empty" do - [1, 2].untrust.send(@method).untrusted?.should be_true - end - - it "does not untrust the result if the Array is untrusted but empty" do - [].untrust.send(@method).untrusted?.should be_false - end - - it "untrusts the result if the result of coercing an element is untrusted" do - s = mock("untrust") - s.should_receive(:to_s).and_return("str".untrust) - [s].send(@method).untrusted?.should be_true - end - end - it "uses the first encoding when other strings are compatible" do ary1 = ArraySpecs.array_with_7bit_utf8_and_usascii_strings ary2 = ArraySpecs.array_with_usascii_and_7bit_utf8_strings @@ -114,18 +84,16 @@ describe :array_join_with_default_separator, shared: true do -> { ary_utf8_bad_binary.send(@method) }.should raise_error(EncodingError) end - ruby_version_is "2.7" do - context "when $, is not nil" do - before do - suppress_warning do - $, = '*' - end + context "when $, is not nil" do + before do + suppress_warning do + $, = '*' end + end - it "warns" do - -> { [].join }.should complain(/warning: \$, is set to non-nil value/) - -> { [].join(nil) }.should complain(/warning: \$, is set to non-nil value/) - end + it "warns" do + -> { [].join }.should complain(/warning: \$, is set to non-nil value/) + -> { [].join(nil) }.should complain(/warning: \$, is set to non-nil value/) end end end @@ -141,42 +109,4 @@ describe :array_join_with_string_separator, shared: true do [1, [2, [3, 4], 5], 6].send(@method, ":").should == "1:2:3:4:5:6" [1, [2, ArraySpecs::MyArray[3, 4], 5], 6].send(@method, ":").should == "1:2:3:4:5:6" end - - ruby_version_is ''...'2.7' do - describe "with a tainted separator" do - before :each do - @sep = ":".taint - end - - it "does not taint the result if the array is empty" do - [].send(@method, @sep).tainted?.should be_false - end - - it "does not taint the result if the array has only one element" do - [1].send(@method, @sep).tainted?.should be_false - end - - it "taints the result if the array has two or more elements" do - [1, 2].send(@method, @sep).tainted?.should be_true - end - end - - describe "with an untrusted separator" do - before :each do - @sep = ":".untrust - end - - it "does not untrust the result if the array is empty" do - [].send(@method, @sep).untrusted?.should be_false - end - - it "does not untrust the result if the array has only one element" do - [1].send(@method, @sep).untrusted?.should be_false - end - - it "untrusts the result if the array has two or more elements" do - [1, 2].send(@method, @sep).untrusted?.should be_true - end - end - end end diff --git a/spec/ruby/core/array/shared/slice.rb b/spec/ruby/core/array/shared/slice.rb index 540a050130..3b09fdcbc6 100644 --- a/spec/ruby/core/array/shared/slice.rb +++ b/spec/ruby/core/array/shared/slice.rb @@ -556,34 +556,34 @@ describe :array_slice, shared: true do it "has beginless range and positive steps" do # end with zero index - @array.send(@method, eval("(..0).step(1)")).should == [0] - @array.send(@method, eval("(...0).step(1)")).should == [] + @array.send(@method, (..0).step(1)).should == [0] + @array.send(@method, (...0).step(1)).should == [] - @array.send(@method, eval("(..0).step(2)")).should == [0] - @array.send(@method, eval("(...0).step(2)")).should == [] + @array.send(@method, (..0).step(2)).should == [0] + @array.send(@method, (...0).step(2)).should == [] - @array.send(@method, eval("(..0).step(10)")).should == [0] - @array.send(@method, eval("(...0).step(10)")).should == [] + @array.send(@method, (..0).step(10)).should == [0] + @array.send(@method, (...0).step(10)).should == [] # end with positive index - @array.send(@method, eval("(..3).step(1)")).should == [0, 1, 2, 3] - @array.send(@method, eval("(...3).step(1)")).should == [0, 1, 2] + @array.send(@method, (..3).step(1)).should == [0, 1, 2, 3] + @array.send(@method, (...3).step(1)).should == [0, 1, 2] - @array.send(@method, eval("(..3).step(2)")).should == [0, 2] - @array.send(@method, eval("(...3).step(2)")).should == [0, 2] + @array.send(@method, (..3).step(2)).should == [0, 2] + @array.send(@method, (...3).step(2)).should == [0, 2] - @array.send(@method, eval("(..3).step(10)")).should == [0] - @array.send(@method, eval("(...3).step(10)")).should == [0] + @array.send(@method, (..3).step(10)).should == [0] + @array.send(@method, (...3).step(10)).should == [0] # end with negative index - @array.send(@method, eval("(..-2).step(1)")).should == [0, 1, 2, 3, 4,] - @array.send(@method, eval("(...-2).step(1)")).should == [0, 1, 2, 3] + @array.send(@method, (..-2).step(1)).should == [0, 1, 2, 3, 4,] + @array.send(@method, (...-2).step(1)).should == [0, 1, 2, 3] - @array.send(@method, eval("(..-2).step(2)")).should == [0, 2, 4] - @array.send(@method, eval("(...-2).step(2)")).should == [0, 2] + @array.send(@method, (..-2).step(2)).should == [0, 2, 4] + @array.send(@method, (...-2).step(2)).should == [0, 2] - @array.send(@method, eval("(..-2).step(10)")).should == [0] - @array.send(@method, eval("(...-2).step(10)")).should == [0] + @array.send(@method, (..-2).step(10)).should == [0] + @array.send(@method, (...-2).step(10)).should == [0] end it "has endless range and negative steps" do @@ -770,26 +770,24 @@ describe :array_slice, shared: true do end end - ruby_version_is "2.7" do - it "can accept beginless ranges" do - a = [0, 1, 2, 3, 4, 5] - a.send(@method, eval("(..3)")).should == [0, 1, 2, 3] - a.send(@method, eval("(...3)")).should == [0, 1, 2] - a.send(@method, eval("(..-3)")).should == [0, 1, 2, 3] - a.send(@method, eval("(...-3)")).should == [0, 1, 2] - a.send(@method, eval("(..0)")).should == [0] - a.send(@method, eval("(...0)")).should == [] - a.send(@method, eval("(..9)")).should == [0, 1, 2, 3, 4, 5] - a.send(@method, eval("(...9)")).should == [0, 1, 2, 3, 4, 5] - a.send(@method, eval("(..-9)")).should == [] - a.send(@method, eval("(...-9)")).should == [] - end - - it "can accept nil...nil ranges" do - a = [0, 1, 2, 3, 4, 5] - a.send(@method, eval("(nil...nil)")).should == a - a.send(@method, eval("(...nil)")).should == a - a.send(@method, eval("(nil..)")).should == a - end + it "can accept beginless ranges" do + a = [0, 1, 2, 3, 4, 5] + a.send(@method, (..3)).should == [0, 1, 2, 3] + a.send(@method, (...3)).should == [0, 1, 2] + a.send(@method, (..-3)).should == [0, 1, 2, 3] + a.send(@method, (...-3)).should == [0, 1, 2] + a.send(@method, (..0)).should == [0] + a.send(@method, (...0)).should == [] + a.send(@method, (..9)).should == [0, 1, 2, 3, 4, 5] + a.send(@method, (...9)).should == [0, 1, 2, 3, 4, 5] + a.send(@method, (..-9)).should == [] + a.send(@method, (...-9)).should == [] + end + + it "can accept nil...nil ranges" do + a = [0, 1, 2, 3, 4, 5] + a.send(@method, eval("(nil...nil)")).should == a + a.send(@method, (...nil)).should == a + a.send(@method, eval("(nil..)")).should == a end end diff --git a/spec/ruby/core/array/shift_spec.rb b/spec/ruby/core/array/shift_spec.rb index b998e45d28..6b4ef39f77 100644 --- a/spec/ruby/core/array/shift_spec.rb +++ b/spec/ruby/core/array/shift_spec.rb @@ -116,21 +116,5 @@ describe "Array#shift" do it "does not return subclass instances with Array subclass" do ArraySpecs::MyArray[1, 2, 3].shift(2).should be_an_instance_of(Array) end - - ruby_version_is ''...'2.7' do - it "returns an untainted array even if the array is tainted" do - ary = [1, 2].taint - ary.shift(2).tainted?.should be_false - ary.shift(0).tainted?.should be_false - end - - it "keeps taint status" do - a = [1, 2].taint - a.shift(2) - a.tainted?.should be_true - a.shift(2) - a.tainted?.should be_true - end - end end end diff --git a/spec/ruby/core/array/slice_spec.rb b/spec/ruby/core/array/slice_spec.rb index 8c276f9084..8e1499855a 100644 --- a/spec/ruby/core/array/slice_spec.rb +++ b/spec/ruby/core/array/slice_spec.rb @@ -172,16 +172,14 @@ describe "Array#slice!" do a.should == [1, 2] end - ruby_version_is "2.7" do - it "works with beginless ranges" do - a = [0,1,2,3,4] - a.slice!(eval("(..3)")).should == [0, 1, 2, 3] - a.should == [4] - - a = [0,1,2,3,4] - a.slice!(eval("(...-2)")).should == [0, 1, 2] - a.should == [3, 4] - end + it "works with beginless ranges" do + a = [0,1,2,3,4] + a.slice!((..3)).should == [0, 1, 2, 3] + a.should == [4] + + a = [0,1,2,3,4] + a.slice!((...-2)).should == [0, 1, 2] + a.should == [3, 4] end describe "with a subclass of Array" do diff --git a/spec/ruby/core/array/uniq_spec.rb b/spec/ruby/core/array/uniq_spec.rb index 5911c23e6a..4461cae16b 100644 --- a/spec/ruby/core/array/uniq_spec.rb +++ b/spec/ruby/core/array/uniq_spec.rb @@ -39,76 +39,32 @@ describe "Array#uniq" do [x, y].uniq.should == [x, y] end - ruby_version_is '2.7' do - it "compares elements with matching hash codes with #eql?" do - a = Array.new(2) do - obj = mock('0') - obj.should_receive(:hash).at_least(1).and_return(0) - - def obj.eql?(o) - false - end - - obj - end - - a.uniq.should == a + it "compares elements with matching hash codes with #eql?" do + a = Array.new(2) do + obj = mock('0') + obj.should_receive(:hash).at_least(1).and_return(0) - a = Array.new(2) do - obj = mock('0') - obj.should_receive(:hash).at_least(1).and_return(0) - - def obj.eql?(o) - true - end - - obj + def obj.eql?(o) + false end - a.uniq.size.should == 1 + obj end - end - ruby_version_is ''...'2.7' do - it "compares elements with matching hash codes with #eql?" do - a = Array.new(2) do - obj = mock('0') - obj.should_receive(:hash).at_least(1).and_return(0) - - def obj.eql?(o) - # It's undefined whether the impl does a[0].eql?(a[1]) or - # a[1].eql?(a[0]) so we taint both. - taint - o.taint - false - end - - obj - end - - a.uniq.should == a - a[0].should.tainted? - a[1].should.tainted? + a.uniq.should == a - a = Array.new(2) do - obj = mock('0') - obj.should_receive(:hash).at_least(1).and_return(0) + a = Array.new(2) do + obj = mock('0') + obj.should_receive(:hash).at_least(1).and_return(0) - def obj.eql?(o) - # It's undefined whether the impl does a[0].eql?(a[1]) or - # a[1].eql?(a[0]) so we taint both. - taint - o.taint - true - end - - obj + def obj.eql?(o) + true end - a.uniq.size.should == 1 - a[0].should.tainted? - a[1].should.tainted? + obj end + + a.uniq.size.should == 1 end it "compares elements based on the value returned from the block" do diff --git a/spec/ruby/core/array/values_at_spec.rb b/spec/ruby/core/array/values_at_spec.rb index f1522e0bfe..2c6fd16947 100644 --- a/spec/ruby/core/array/values_at_spec.rb +++ b/spec/ruby/core/array/values_at_spec.rb @@ -66,10 +66,8 @@ describe "Array#values_at" do [1, 2, 3, 4].values_at(eval("(3...)")).should == [4] end - ruby_version_is "2.7" do - it "works when given beginless ranges" do - [1, 2, 3, 4].values_at(eval("(..2)")).should == [1, 2, 3] - [1, 2, 3, 4].values_at(eval("(...2)")).should == [1, 2] - end + it "works when given beginless ranges" do + [1, 2, 3, 4].values_at((..2)).should == [1, 2, 3] + [1, 2, 3, 4].values_at((...2)).should == [1, 2] end end diff --git a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb index 7c87a970d7..b0b86030e2 100644 --- a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb +++ b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb @@ -49,15 +49,7 @@ describe "RUBY_RELEASE_DATE" do end describe "RUBY_REVISION" do - ruby_version_is ""..."2.7" do - it "is an Integer" do - RUBY_REVISION.should be_kind_of(Integer) - end - end - - ruby_version_is "2.7" do - it "is a String" do - RUBY_REVISION.should be_kind_of(String) - end + it "is a String" do + RUBY_REVISION.should be_kind_of(String) end end diff --git a/spec/ruby/core/class/descendants_spec.rb b/spec/ruby/core/class/descendants_spec.rb deleted file mode 100644 index f87cd68be8..0000000000 --- a/spec/ruby/core/class/descendants_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -require_relative '../../spec_helper' -require_relative '../module/fixtures/classes' - -ruby_version_is '3.1' do - describe "Class#descendants" do - it "returns a list of classes descended from self (excluding self)" do - assert_descendants(ModuleSpecs::Parent, [ModuleSpecs::Child, ModuleSpecs::Child2, ModuleSpecs::Grandchild]) - end - - it "does not return included modules" do - parent = Class.new - child = Class.new(parent) - mod = Module.new - parent.include(mod) - - assert_descendants(parent, [child]) - end - - it "does not return singleton classes" do - a = Class.new - - a_obj = a.new - def a_obj.force_singleton_class - 42 - end - - a.descendants.should_not include(a_obj.singleton_class) - end - - it "has 1 entry per module or class" do - ModuleSpecs::Parent.descendants.should == ModuleSpecs::Parent.descendants.uniq - end - - def assert_descendants(mod, descendants) - mod.descendants.sort_by(&:inspect).should == descendants.sort_by(&:inspect) - end - end -end diff --git a/spec/ruby/core/comparable/clamp_spec.rb b/spec/ruby/core/comparable/clamp_spec.rb index 393496fc76..796d4a18c1 100644 --- a/spec/ruby/core/comparable/clamp_spec.rb +++ b/spec/ruby/core/comparable/clamp_spec.rb @@ -2,14 +2,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe 'Comparable#clamp' do - ruby_version_is ""..."2.7" do - it 'raises an Argument error unless given 2 parameters' do - c = ComparableSpecs::Weird.new(0) - -> { c.clamp(c) }.should raise_error(ArgumentError) - -> { c.clamp(c, c, c) }.should raise_error(ArgumentError) - end - end - it 'raises an Argument error unless the 2 parameters are correctly ordered' do one = ComparableSpecs::WithOnlyCompareDefined.new(1) two = ComparableSpecs::WithOnlyCompareDefined.new(2) @@ -48,41 +40,39 @@ describe 'Comparable#clamp' do c.clamp(one, two).should equal(two) end - ruby_version_is "2.7" do - it 'returns self if within the given range parameters' do - one = ComparableSpecs::WithOnlyCompareDefined.new(1) - two = ComparableSpecs::WithOnlyCompareDefined.new(2) - three = ComparableSpecs::WithOnlyCompareDefined.new(3) - c = ComparableSpecs::Weird.new(2) - - c.clamp(one..two).should equal(c) - c.clamp(two..two).should equal(c) - c.clamp(one..three).should equal(c) - c.clamp(two..three).should equal(c) - end - - it 'returns the minimum value of the range parameters if smaller than it' do - one = ComparableSpecs::WithOnlyCompareDefined.new(1) - two = ComparableSpecs::WithOnlyCompareDefined.new(2) - c = ComparableSpecs::Weird.new(0) - - c.clamp(one..two).should equal(one) - end - - it 'returns the maximum value of the range parameters if greater than it' do - one = ComparableSpecs::WithOnlyCompareDefined.new(1) - two = ComparableSpecs::WithOnlyCompareDefined.new(2) - c = ComparableSpecs::Weird.new(3) - - c.clamp(one..two).should equal(two) - end - - it 'raises an Argument error if the range parameter is exclusive' do - one = ComparableSpecs::WithOnlyCompareDefined.new(1) - two = ComparableSpecs::WithOnlyCompareDefined.new(2) - c = ComparableSpecs::Weird.new(3) - - -> { c.clamp(one...two) }.should raise_error(ArgumentError) - end + it 'returns self if within the given range parameters' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + two = ComparableSpecs::WithOnlyCompareDefined.new(2) + three = ComparableSpecs::WithOnlyCompareDefined.new(3) + c = ComparableSpecs::Weird.new(2) + + c.clamp(one..two).should equal(c) + c.clamp(two..two).should equal(c) + c.clamp(one..three).should equal(c) + c.clamp(two..three).should equal(c) + end + + it 'returns the minimum value of the range parameters if smaller than it' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + two = ComparableSpecs::WithOnlyCompareDefined.new(2) + c = ComparableSpecs::Weird.new(0) + + c.clamp(one..two).should equal(one) + end + + it 'returns the maximum value of the range parameters if greater than it' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + two = ComparableSpecs::WithOnlyCompareDefined.new(2) + c = ComparableSpecs::Weird.new(3) + + c.clamp(one..two).should equal(two) + end + + it 'raises an Argument error if the range parameter is exclusive' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + two = ComparableSpecs::WithOnlyCompareDefined.new(2) + c = ComparableSpecs::Weird.new(3) + + -> { c.clamp(one...two) }.should raise_error(ArgumentError) end end diff --git a/spec/ruby/core/complex/comparison_spec.rb b/spec/ruby/core/complex/comparison_spec.rb index 2a437afb71..3a3142f234 100644 --- a/spec/ruby/core/complex/comparison_spec.rb +++ b/spec/ruby/core/complex/comparison_spec.rb @@ -1,27 +1,25 @@ require_relative '../../spec_helper' describe "Complex#<=>" do - ruby_version_is "2.7" do - it "returns nil if either self or argument has imaginary part" do - (Complex(5, 1) <=> Complex(2)).should be_nil - (Complex(1) <=> Complex(2, 1)).should be_nil - (5 <=> Complex(2, 1)).should be_nil - end + it "returns nil if either self or argument has imaginary part" do + (Complex(5, 1) <=> Complex(2)).should be_nil + (Complex(1) <=> Complex(2, 1)).should be_nil + (5 <=> Complex(2, 1)).should be_nil + end - it "returns nil if argument is not numeric" do - (Complex(5, 1) <=> "cmp").should be_nil - (Complex(1) <=> "cmp").should be_nil - (Complex(1) <=> Object.new).should be_nil - end + it "returns nil if argument is not numeric" do + (Complex(5, 1) <=> "cmp").should be_nil + (Complex(1) <=> "cmp").should be_nil + (Complex(1) <=> Object.new).should be_nil + end - it "returns 0, 1, or -1 if self and argument do not have imaginary part" do - (Complex(5) <=> Complex(2)).should == 1 - (Complex(2) <=> Complex(3)).should == -1 - (Complex(2) <=> Complex(2)).should == 0 + it "returns 0, 1, or -1 if self and argument do not have imaginary part" do + (Complex(5) <=> Complex(2)).should == 1 + (Complex(2) <=> Complex(3)).should == -1 + (Complex(2) <=> Complex(2)).should == 0 - (Complex(5) <=> 2).should == 1 - (Complex(2) <=> 3).should == -1 - (Complex(2) <=> 2).should == 0 - end + (Complex(5) <=> 2).should == 1 + (Complex(2) <=> 3).should == -1 + (Complex(2) <=> 2).should == 0 end end diff --git a/spec/ruby/core/dir/children_spec.rb b/spec/ruby/core/dir/children_spec.rb index 986c8f38c0..03698cc246 100644 --- a/spec/ruby/core/dir/children_spec.rb +++ b/spec/ruby/core/dir/children_spec.rb @@ -105,14 +105,6 @@ describe "Dir#children" do dirs.each { |d| d.encoding.should == Encoding::UTF_8 } end - ruby_version_is ""..."2.7" do - it "accepts nil options" do - @dir = Dir.new("#{DirSpecs.mock_dir}/deeply/nested", nil) - dirs = @dir.to_a.sort - dirs.each { |d| d.encoding.should == Encoding.find("filesystem") } - end - end - it "returns children encoded with the filesystem encoding by default" do # This spec depends on the locale not being US-ASCII because if it is, the # children that are not ascii_only? will be BINARY encoded. diff --git a/spec/ruby/core/dir/each_child_spec.rb b/spec/ruby/core/dir/each_child_spec.rb index f7980991e5..520186e79e 100644 --- a/spec/ruby/core/dir/each_child_spec.rb +++ b/spec/ruby/core/dir/each_child_spec.rb @@ -15,13 +15,6 @@ describe "Dir.each_child" do dirs.each {|dir| dir.encoding.should == Encoding::UTF_8} end - ruby_version_is ""..."2.7" do - it "accepts nil options" do - dirs = Dir.each_child("#{DirSpecs.mock_dir}/deeply/nested", nil).to_a.sort - dirs.each {|dir| dir.encoding.should == Encoding.find("filesystem")} - end - end - it "yields all names in an existing directory to the provided block" do a, b = [], [] diff --git a/spec/ruby/core/dir/entries_spec.rb b/spec/ruby/core/dir/entries_spec.rb index 9aa58657db..91c30fccae 100644 --- a/spec/ruby/core/dir/entries_spec.rb +++ b/spec/ruby/core/dir/entries_spec.rb @@ -40,13 +40,6 @@ describe "Dir.entries" do dirs.each {|dir| dir.encoding.should == Encoding::UTF_8} end - ruby_version_is ""..."2.7" do - it "accepts nil options" do - dirs = Dir.entries("#{DirSpecs.mock_dir}/deeply/nested", nil).to_a.sort - dirs.each {|dir| dir.encoding.should == Encoding.find("filesystem")} - end - end - it "returns entries encoded with the filesystem encoding by default" do # This spec depends on the locale not being US-ASCII because if it is, the # entries that are not ascii_only? will be BINARY encoded. diff --git a/spec/ruby/core/dir/fixtures/common.rb b/spec/ruby/core/dir/fixtures/common.rb index c32b056819..a8d6e69c44 100644 --- a/spec/ruby/core/dir/fixtures/common.rb +++ b/spec/ruby/core/dir/fixtures/common.rb @@ -94,18 +94,37 @@ module DirSpecs special/こんにちは.txt special/\a ] + @mock_dir_files << "special/_\u{1f60e}.erb" end end @mock_dir_files end + def self.mock_dir_links + unless @mock_dir_links + @mock_dir_links = [] + platform_is_not :windows do + @mock_dir_links += [ + ['special/ln', 'subdir_one'] + ] + end + end + @mock_dir_links + end + def self.create_mock_dirs mock_dir_files.each do |name| file = File.join mock_dir, name mkdir_p File.dirname(file) touch file end + mock_dir_links.each do |link, target| + full_link = File.join mock_dir, link + full_target = File.join mock_dir, target + + File.symlink full_target, full_link + end end def self.delete_mock_dirs diff --git a/spec/ruby/core/dir/foreach_spec.rb b/spec/ruby/core/dir/foreach_spec.rb index c3ddb27a84..b0e18afeb5 100644 --- a/spec/ruby/core/dir/foreach_spec.rb +++ b/spec/ruby/core/dir/foreach_spec.rb @@ -42,12 +42,12 @@ describe "Dir.foreach" do it "accepts an encoding keyword for the encoding of the entries" do dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: "utf-8").to_a.sort dirs.each {|dir| dir.encoding.should == Encoding::UTF_8} - end - ruby_version_is ""..."2.7" do - it "accepts nil options" do - dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", nil).to_a.sort - dirs.each {|dir| dir.encoding.should == Encoding.find("filesystem")} + dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::UTF_16LE).to_a.sort + dirs.each {|dir| dir.encoding.should == Encoding::UTF_16LE} + + Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::UTF_16LE) do |f| + f.encoding.should == Encoding::UTF_16LE end end diff --git a/spec/ruby/core/dir/glob_spec.rb b/spec/ruby/core/dir/glob_spec.rb index 295a7ab920..43dac73eee 100644 --- a/spec/ruby/core/dir/glob_spec.rb +++ b/spec/ruby/core/dir/glob_spec.rb @@ -222,5 +222,30 @@ describe "Dir.glob" do Dir.rmdir('no_permission') end end + + it "will follow symlinks when processing a `*/` pattern." do + expected = ['special/ln/nondotfile'] + Dir.glob('special/*/nondotfile').should == expected + end + + it "will not follow symlinks when recursively traversing directories" do + expected = %w[ + deeply/nondotfile + nondotfile + subdir_one/nondotfile + subdir_two/nondotfile + ] + Dir.glob('**/nondotfile').sort.should == expected + end + + it "will follow symlinks when testing directory after recursive directory in pattern" do + expected = %w[ + deeply/nondotfile + special/ln/nondotfile + subdir_one/nondotfile + subdir_two/nondotfile + ] + Dir.glob('**/*/nondotfile').sort.should == expected + end end end diff --git a/spec/ruby/core/dir/home_spec.rb b/spec/ruby/core/dir/home_spec.rb index 713ba9db9a..8377f1dc97 100644 --- a/spec/ruby/core/dir/home_spec.rb +++ b/spec/ruby/core/dir/home_spec.rb @@ -28,7 +28,7 @@ describe "Dir.home" do end end - platform_is_not :windows, :solaris, :android do + platform_is_not :windows, :solaris, :android, :wasi do it "returns the named user's home directory, from the user database" do Dir.home(ENV['USER']).should == `echo ~#{ENV['USER']}`.chomp end diff --git a/spec/ruby/core/dir/read_spec.rb b/spec/ruby/core/dir/read_spec.rb index 59de2e81cf..276930c6b7 100644 --- a/spec/ruby/core/dir/read_spec.rb +++ b/spec/ruby/core/dir/read_spec.rb @@ -39,5 +39,38 @@ describe "Dir#read" do entries.sort.should == DirSpecs.expected_paths end + platform_is_not :windows do + it "returns all directory entries even when encoding conversion will fail" do + dir = Dir.open(File.join(DirSpecs.mock_dir, 'special')) + utf8_entries = [] + begin + while entry = dir.read + utf8_entries << entry + end + ensure + dir.close + end + old_internal_encoding = Encoding::default_internal + old_external_encoding = Encoding::default_external + Encoding.default_internal = Encoding::UTF_8 + Encoding.default_external = Encoding::SHIFT_JIS + shift_jis_entries = [] + begin + Dir.open(File.join(DirSpecs.mock_dir, 'special')) do |d| + -> { + while entry = d.read + shift_jis_entries << entry + end + }.should_not raise_error + end + ensure + Encoding.default_internal = old_internal_encoding + Encoding.default_external = old_external_encoding + end + shift_jis_entries.size.should == utf8_entries.size + shift_jis_entries.filter { |f| f.encoding == Encoding::SHIFT_JIS }.size.should == 1 + end + end + it_behaves_like :dir_closed, :read end diff --git a/spec/ruby/core/dir/shared/glob.rb b/spec/ruby/core/dir/shared/glob.rb index a38ff8aa68..60d4a8c97a 100644 --- a/spec/ruby/core/dir/shared/glob.rb +++ b/spec/ruby/core/dir/shared/glob.rb @@ -23,19 +23,8 @@ describe :dir_glob, shared: true do Dir.send(@method, obj).should == %w[file_one.ext] end - ruby_version_is ""..."2.7" do - it "splits the string on \\0 if there is only one string given and warns" do - -> { - Dir.send(@method, "file_o*\0file_t*").should == - %w!file_one.ext file_two.ext! - }.should complain(/warning: use glob patterns list instead of nul-separated patterns/) - end - end - - ruby_version_is "2.7" do - it "raises an ArgumentError if the string contains \\0" do - -> {Dir.send(@method, "file_o*\0file_t*")}.should raise_error ArgumentError, /nul-separated/ - end + it "raises an ArgumentError if the string contains \\0" do + -> {Dir.send(@method, "file_o*\0file_t*")}.should raise_error ArgumentError, /nul-separated/ end ruby_version_is "3.0" do diff --git a/spec/ruby/core/encoding/list_spec.rb b/spec/ruby/core/encoding/list_spec.rb index 8efd94ab9c..bd3d5b7bc0 100644 --- a/spec/ruby/core/encoding/list_spec.rb +++ b/spec/ruby/core/encoding/list_spec.rb @@ -40,10 +40,8 @@ describe "Encoding.list" do Encoding.list.should.include?(Encoding::UTF_8) end - ruby_version_is "2.7" do - it 'includes CESU-8 encoding' do - Encoding.list.should.include?(Encoding::CESU_8) - end + it 'includes CESU-8 encoding' do + Encoding.list.should.include?(Encoding::CESU_8) end # TODO: Find example that illustrates this diff --git a/spec/ruby/core/enumerable/all_spec.rb b/spec/ruby/core/enumerable/all_spec.rb index b782f94a3e..0ded1e8eba 100644 --- a/spec/ruby/core/enumerable/all_spec.rb +++ b/spec/ruby/core/enumerable/all_spec.rb @@ -131,7 +131,6 @@ describe "Enumerable#all?" do pattern.yielded.should == [[0], [1], [2], [-1]] end - # may raise an exception in future versions it "always returns true on empty enumeration" do @empty.all?(Integer).should == true [].all?(Integer).should == true diff --git a/spec/ruby/core/enumerable/any_spec.rb b/spec/ruby/core/enumerable/any_spec.rb index 636b1fa450..355cd0c290 100644 --- a/spec/ruby/core/enumerable/any_spec.rb +++ b/spec/ruby/core/enumerable/any_spec.rb @@ -145,7 +145,6 @@ describe "Enumerable#any?" do pattern.yielded.should == [[0], [1], [2]] end - # may raise an exception in future versions it "always returns false on empty enumeration" do @empty.any?(Integer).should == false [].any?(Integer).should == false diff --git a/spec/ruby/core/enumerable/filter_map_spec.rb b/spec/ruby/core/enumerable/filter_map_spec.rb index 31acc277b4..aa4894230b 100644 --- a/spec/ruby/core/enumerable/filter_map_spec.rb +++ b/spec/ruby/core/enumerable/filter_map_spec.rb @@ -1,26 +1,24 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is '2.7' do - describe 'Enumerable#filter_map' do - before :each do - @numerous = EnumerableSpecs::Numerous.new(*(1..8).to_a) - end +describe 'Enumerable#filter_map' do + before :each do + @numerous = EnumerableSpecs::Numerous.new(*(1..8).to_a) + end - it 'returns an empty array if there are no elements' do - EnumerableSpecs::Empty.new.filter_map { true }.should == [] - end + it 'returns an empty array if there are no elements' do + EnumerableSpecs::Empty.new.filter_map { true }.should == [] + end - it 'returns an array with truthy results of passing each element to block' do - @numerous.filter_map { |i| i * 2 if i.even? }.should == [4, 8, 12, 16] - @numerous.filter_map { |i| i * 2 }.should == [2, 4, 6, 8, 10, 12, 14, 16] - @numerous.filter_map { 0 }.should == [0, 0, 0, 0, 0, 0, 0, 0] - @numerous.filter_map { false }.should == [] - @numerous.filter_map { nil }.should == [] - end + it 'returns an array with truthy results of passing each element to block' do + @numerous.filter_map { |i| i * 2 if i.even? }.should == [4, 8, 12, 16] + @numerous.filter_map { |i| i * 2 }.should == [2, 4, 6, 8, 10, 12, 14, 16] + @numerous.filter_map { 0 }.should == [0, 0, 0, 0, 0, 0, 0, 0] + @numerous.filter_map { false }.should == [] + @numerous.filter_map { nil }.should == [] + end - it 'returns an enumerator when no block given' do - @numerous.filter_map.should be_an_instance_of(Enumerator) - end + it 'returns an enumerator when no block given' do + @numerous.filter_map.should be_an_instance_of(Enumerator) end end diff --git a/spec/ruby/core/enumerable/group_by_spec.rb b/spec/ruby/core/enumerable/group_by_spec.rb index 52b5a68d64..4fd1603819 100644 --- a/spec/ruby/core/enumerable/group_by_spec.rb +++ b/spec/ruby/core/enumerable/group_by_spec.rb @@ -33,15 +33,5 @@ describe "Enumerable#group_by" do [3, 4, 5] => [[3, 4, 5]] } end - ruby_version_is ''...'2.7' do - it "returns a tainted hash if self is tainted" do - EnumerableSpecs::Empty.new.taint.group_by {}.tainted?.should be_true - end - - it "returns an untrusted hash if self is untrusted" do - EnumerableSpecs::Empty.new.untrust.group_by {}.untrusted?.should be_true - end - end - it_behaves_like :enumerable_enumeratorized_with_origin_size, :group_by end diff --git a/spec/ruby/core/enumerable/none_spec.rb b/spec/ruby/core/enumerable/none_spec.rb index b898d00063..99bb7f7a4e 100644 --- a/spec/ruby/core/enumerable/none_spec.rb +++ b/spec/ruby/core/enumerable/none_spec.rb @@ -100,7 +100,6 @@ describe "Enumerable#none?" do pattern.yielded.should == [[0], [1], [2], [-1]] end - # may raise an exception in future versions it "always returns true on empty enumeration" do @empty.none?(Integer).should == true [].none?(Integer).should == true diff --git a/spec/ruby/core/enumerable/one_spec.rb b/spec/ruby/core/enumerable/one_spec.rb index d54dd4a527..47bfd65a0f 100644 --- a/spec/ruby/core/enumerable/one_spec.rb +++ b/spec/ruby/core/enumerable/one_spec.rb @@ -91,7 +91,6 @@ describe "Enumerable#one?" do pattern.yielded.should == [[0], [1], [2], [-1]] end - # may raise an exception in future versions it "always returns false on empty enumeration" do @empty.one?(Integer).should == false [].one?(Integer).should == false diff --git a/spec/ruby/core/enumerable/shared/entries.rb b/spec/ruby/core/enumerable/shared/entries.rb index 590ce73bcf..e32eb23d2a 100644 --- a/spec/ruby/core/enumerable/shared/entries.rb +++ b/spec/ruby/core/enumerable/shared/entries.rb @@ -13,14 +13,4 @@ describe :enumerable_entries, shared: true do count.send(@method, :hello, "world").should == [1, 2, 3] count.arguments_passed.should == [:hello, "world"] end - - ruby_version_is ''...'2.7' do - it "returns a tainted array if self is tainted" do - EnumerableSpecs::Empty.new.taint.send(@method).tainted?.should be_true - end - - it "returns an untrusted array if self is untrusted" do - EnumerableSpecs::Empty.new.untrust.send(@method).untrusted?.should be_true - end - end end diff --git a/spec/ruby/core/enumerable/shared/inject.rb b/spec/ruby/core/enumerable/shared/inject.rb index 12e0665dda..c5907f92d8 100644 --- a/spec/ruby/core/enumerable/shared/inject.rb +++ b/spec/ruby/core/enumerable/shared/inject.rb @@ -17,7 +17,8 @@ describe :enumerable_inject, shared: true do end it "ignores the block if two arguments" do - EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, :-){ raise "we never get here"}.should == 4 + EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, :-) { raise "we never get here"}.should == 4 + [].send(@method, 3, :+) { raise "we never get here"}.should == 3 end it "can take a symbol argument" do @@ -66,4 +67,11 @@ describe :enumerable_inject, shared: true do it "returns nil when fails(legacy rubycon)" do EnumerableSpecs::EachDefiner.new().send(@method) {|acc,x| 999 }.should == nil end + + ruby_bug '#18635', ''...'3.2' do + it "raises an ArgumentError when no parameters or block is given" do + -> { [1,2].send(@method) }.should raise_error(ArgumentError) + -> { {one: 1, two: 2}.send(@method) }.should raise_error(ArgumentError) + end + end end diff --git a/spec/ruby/core/enumerable/tally_spec.rb b/spec/ruby/core/enumerable/tally_spec.rb index 92aac507ff..f09a8f533a 100644 --- a/spec/ruby/core/enumerable/tally_spec.rb +++ b/spec/ruby/core/enumerable/tally_spec.rb @@ -1,36 +1,34 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "2.7" do - describe "Enumerable#tally" do - before :each do - ScratchPad.record [] - end +describe "Enumerable#tally" do + before :each do + ScratchPad.record [] + end - it "returns a hash with counts according to the value" do - enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz') - enum.tally.should == { 'foo' => 2, 'bar' => 1, 'baz' => 1} - end + it "returns a hash with counts according to the value" do + enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz') + enum.tally.should == { 'foo' => 2, 'bar' => 1, 'baz' => 1} + end - it "returns a hash without default" do - hash = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz').tally - hash.default_proc.should be_nil - hash.default.should be_nil - end + it "returns a hash without default" do + hash = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz').tally + hash.default_proc.should be_nil + hash.default.should be_nil + end - it "returns an empty hash for empty enumerables" do - EnumerableSpecs::Empty.new.tally.should == {} - end + it "returns an empty hash for empty enumerables" do + EnumerableSpecs::Empty.new.tally.should == {} + end - it "counts values as gathered array when yielded with multiple arguments" do - EnumerableSpecs::YieldsMixed2.new.tally.should == EnumerableSpecs::YieldsMixed2.gathered_yields.group_by(&:itself).transform_values(&:size) - end + it "counts values as gathered array when yielded with multiple arguments" do + EnumerableSpecs::YieldsMixed2.new.tally.should == EnumerableSpecs::YieldsMixed2.gathered_yields.group_by(&:itself).transform_values(&:size) + end - it "does not call given block" do - enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz') - enum.tally { |v| ScratchPad << v } - ScratchPad.recorded.should == [] - end + it "does not call given block" do + enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz') + enum.tally { |v| ScratchPad << v } + ScratchPad.recorded.should == [] end end diff --git a/spec/ruby/core/enumerable/uniq_spec.rb b/spec/ruby/core/enumerable/uniq_spec.rb index e58dd36366..a1ed44796f 100644 --- a/spec/ruby/core/enumerable/uniq_spec.rb +++ b/spec/ruby/core/enumerable/uniq_spec.rb @@ -31,76 +31,32 @@ describe 'Enumerable#uniq' do [x, y].to_enum.uniq.should == [x, y] end - ruby_version_is '2.7' do - it "compares elements with matching hash codes with #eql?" do - a = Array.new(2) do - obj = mock('0') - obj.should_receive(:hash).at_least(1).and_return(0) - - def obj.eql?(o) - false - end - - obj - end - - a.uniq.should == a + it "compares elements with matching hash codes with #eql?" do + a = Array.new(2) do + obj = mock('0') + obj.should_receive(:hash).at_least(1).and_return(0) - a = Array.new(2) do - obj = mock('0') - obj.should_receive(:hash).at_least(1).and_return(0) - - def obj.eql?(o) - true - end - - obj + def obj.eql?(o) + false end - a.to_enum.uniq.size.should == 1 + obj end - end - ruby_version_is ''...'2.7' do - it "compares elements with matching hash codes with #eql?" do - a = Array.new(2) do - obj = mock('0') - obj.should_receive(:hash).at_least(1).and_return(0) - - def obj.eql?(o) - # It's undefined whether the impl does a[0].eql?(a[1]) or - # a[1].eql?(a[0]) so we taint both. - taint - o.taint - false - end - - obj - end - - a.uniq.should == a - a[0].should.tainted? - a[1].should.tainted? + a.uniq.should == a - a = Array.new(2) do - obj = mock('0') - obj.should_receive(:hash).at_least(1).and_return(0) + a = Array.new(2) do + obj = mock('0') + obj.should_receive(:hash).at_least(1).and_return(0) - def obj.eql?(o) - # It's undefined whether the impl does a[0].eql?(a[1]) or - # a[1].eql?(a[0]) so we taint both. - taint - o.taint - true - end - - obj + def obj.eql?(o) + true end - a.to_enum.uniq.size.should == 1 - a[0].should.tainted? - a[1].should.tainted? + obj end + + a.to_enum.uniq.size.should == 1 end context 'when yielded with multiple arguments' do diff --git a/spec/ruby/core/enumerator/arithmetic_sequence/begin_spec.rb b/spec/ruby/core/enumerator/arithmetic_sequence/begin_spec.rb index 1837a4f246..bd243fa0b5 100644 --- a/spec/ruby/core/enumerator/arithmetic_sequence/begin_spec.rb +++ b/spec/ruby/core/enumerator/arithmetic_sequence/begin_spec.rb @@ -7,12 +7,10 @@ describe "Enumerator::ArithmeticSequence#begin" do (1...10).step.begin.should == 1 end - ruby_version_is "2.7" do - context "with beginless" do - it "returns nil as begin of the sequence" do - eval("(..10).step(1)").begin.should == nil - eval("(...10).step(1)").begin.should == nil - end + context "with beginless" do + it "returns nil as begin of the sequence" do + (..10).step(1).begin.should == nil + (...10).step(1).begin.should == nil end end end diff --git a/spec/ruby/core/enumerator/lazy/eager_spec.rb b/spec/ruby/core/enumerator/lazy/eager_spec.rb index 30ba2dfe0e..592da4fd8c 100644 --- a/spec/ruby/core/enumerator/lazy/eager_spec.rb +++ b/spec/ruby/core/enumerator/lazy/eager_spec.rb @@ -1,29 +1,27 @@ require_relative '../../../spec_helper' -ruby_version_is "2.7" do - describe "Enumerator::Lazy#eager" do - it "returns a non-lazy Enumerator converted from the lazy enumerator" do - enum = [1, 2, 3].lazy +describe "Enumerator::Lazy#eager" do + it "returns a non-lazy Enumerator converted from the lazy enumerator" do + enum = [1, 2, 3].lazy - enum.class.should == Enumerator::Lazy - enum.eager.class.should == Enumerator - end + enum.class.should == Enumerator::Lazy + enum.eager.class.should == Enumerator + end - it "does not enumerate an enumerator" do - ScratchPad.record [] + it "does not enumerate an enumerator" do + ScratchPad.record [] - sequence = [1, 2, 3] - enum_lazy = Enumerator::Lazy.new(sequence) do |yielder, value| - yielder << value - ScratchPad << value - end + sequence = [1, 2, 3] + enum_lazy = Enumerator::Lazy.new(sequence) do |yielder, value| + yielder << value + ScratchPad << value + end - ScratchPad.recorded.should == [] - enum = enum_lazy.eager - ScratchPad.recorded.should == [] + ScratchPad.recorded.should == [] + enum = enum_lazy.eager + ScratchPad.recorded.should == [] - enum.map { |i| i }.should == [1, 2, 3] - ScratchPad.recorded.should == [1, 2, 3] - end + enum.map { |i| i }.should == [1, 2, 3] + ScratchPad.recorded.should == [1, 2, 3] end end diff --git a/spec/ruby/core/enumerator/lazy/filter_map_spec.rb b/spec/ruby/core/enumerator/lazy/filter_map_spec.rb index 3480af0865..99dd59cebe 100644 --- a/spec/ruby/core/enumerator/lazy/filter_map_spec.rb +++ b/spec/ruby/core/enumerator/lazy/filter_map_spec.rb @@ -3,14 +3,12 @@ require_relative '../../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "2.7" do - describe "Enumerator::Lazy#filter_map" do - it "maps only truthy results" do - (1..Float::INFINITY).lazy.filter_map { |i| i if i.odd? }.first(4).should == [1, 3, 5, 7] - end +describe "Enumerator::Lazy#filter_map" do + it "maps only truthy results" do + (1..Float::INFINITY).lazy.filter_map { |i| i if i.odd? }.first(4).should == [1, 3, 5, 7] + end - it "does not map false results" do - (1..Float::INFINITY).lazy.filter_map { |i| i.odd? ? i : false }.first(4).should == [1, 3, 5, 7] - end + it "does not map false results" do + (1..Float::INFINITY).lazy.filter_map { |i| i.odd? ? i : false }.first(4).should == [1, 3, 5, 7] end end diff --git a/spec/ruby/core/enumerator/lazy/with_index_spec.rb b/spec/ruby/core/enumerator/lazy/with_index_spec.rb index 3a59ba4116..a6b5c38777 100644 --- a/spec/ruby/core/enumerator/lazy/with_index_spec.rb +++ b/spec/ruby/core/enumerator/lazy/with_index_spec.rb @@ -3,28 +3,34 @@ require_relative '../../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "2.7" do - describe "Enumerator::Lazy#with_index" do - it "enumerates with an index" do - (0..Float::INFINITY).lazy.with_index.map { |i, idx| [i, idx] }.first(3).should == [[0, 0], [1, 1], [2, 2]] - end +describe "Enumerator::Lazy#with_index" do + it "enumerates with an index" do + (0..Float::INFINITY).lazy.with_index.map { |i, idx| [i, idx] }.first(3).should == [[0, 0], [1, 1], [2, 2]] + end + + it "enumerates with an index starting at a given offset" do + (0..Float::INFINITY).lazy.with_index(3).map { |i, idx| [i, idx] }.first(3).should == [[0, 3], [1, 4], [2, 5]] + end - it "enumerates with an index starting at a given offset" do - (0..Float::INFINITY).lazy.with_index(3).map { |i, idx| [i, idx] }.first(3).should == [[0, 3], [1, 4], [2, 5]] - end + it "enumerates with an index starting at 0 when offset is nil" do + (0..Float::INFINITY).lazy.with_index(nil).map { |i, idx| [i, idx] }.first(3).should == [[0, 0], [1, 1], [2, 2]] + end - it "enumerates with an index starting at 0 when offset is nil" do - (0..Float::INFINITY).lazy.with_index(nil).map { |i, idx| [i, idx] }.first(3).should == [[0, 0], [1, 1], [2, 2]] - end + it "raises TypeError when offset does not convert to Integer" do + -> { (0..Float::INFINITY).lazy.with_index(false).map { |i, idx| i }.first(3) }.should raise_error(TypeError) + end - it "raises TypeError when offset does not convert to Integer" do - -> { (0..Float::INFINITY).lazy.with_index(false).map { |i, idx| i }.first(3) }.should raise_error(TypeError) - end + it "enumerates with a given block" do + result = [] + (0..Float::INFINITY).lazy.with_index { |i, idx| result << [i * 2, idx] }.first(3) + result.should == [[0,0],[2,1],[4,2]] + end - it "enumerates with a given block" do - result = [] - (0..Float::INFINITY).lazy.with_index { |i, idx| result << [i * 2, idx] }.first(3) - result.should == [[0,0],[2,1],[4,2]] - end + it "resets after a new call to each" do + enum = (0..2).lazy.with_index.map { |i, idx| [i, idx] } + result = [] + enum.each { |i, idx| result << [i, idx] } + enum.each { |i, idx| result << [i, idx] } + result.should == [[0,0], [1,1], [2,2], [0,0], [1,1], [2,2]] end end diff --git a/spec/ruby/core/enumerator/new_spec.rb b/spec/ruby/core/enumerator/new_spec.rb index 5cc0b3ff2e..c439469525 100644 --- a/spec/ruby/core/enumerator/new_spec.rb +++ b/spec/ruby/core/enumerator/new_spec.rb @@ -77,14 +77,12 @@ describe "Enumerator.new" do enum.take(3).should == [1, 2, 3] end - ruby_version_is "2.7" do - it "defines iteration with block, yielder argument and treating it as a proc" do - enum = Enumerator.new do |yielder| - "a\nb\nc".each_line(&yielder) - end - - enum.to_a.should == ["a\n", "b\n", "c"] + it "defines iteration with block, yielder argument and treating it as a proc" do + enum = Enumerator.new do |yielder| + "a\nb\nc".each_line(&yielder) end + + enum.to_a.should == ["a\n", "b\n", "c"] end describe 'yielded values' do diff --git a/spec/ruby/core/enumerator/produce_spec.rb b/spec/ruby/core/enumerator/produce_spec.rb index f6f1dcd429..c69fb49303 100644 --- a/spec/ruby/core/enumerator/produce_spec.rb +++ b/spec/ruby/core/enumerator/produce_spec.rb @@ -1,36 +1,34 @@ require_relative '../../spec_helper' -ruby_version_is "2.7" do - describe "Enumerator.produce" do - it "creates an infinite enumerator" do - enum = Enumerator.produce(0) { |prev| prev + 1 } - enum.take(5).should == [0, 1, 2, 3, 4] - end - - it "terminates iteration when block raises StopIteration exception" do - enum = Enumerator.produce(0) do | prev| - raise StopIteration if prev >= 2 - prev + 1 - end +describe "Enumerator.produce" do + it "creates an infinite enumerator" do + enum = Enumerator.produce(0) { |prev| prev + 1 } + enum.take(5).should == [0, 1, 2, 3, 4] + end - enum.to_a.should == [0, 1, 2] + it "terminates iteration when block raises StopIteration exception" do + enum = Enumerator.produce(0) do | prev| + raise StopIteration if prev >= 2 + prev + 1 end - context "when initial value skipped" do - it "uses nil instead" do - ScratchPad.record [] - enum = Enumerator.produce { |prev| ScratchPad << prev; (prev || 0) + 1 } + enum.to_a.should == [0, 1, 2] + end + + context "when initial value skipped" do + it "uses nil instead" do + ScratchPad.record [] + enum = Enumerator.produce { |prev| ScratchPad << prev; (prev || 0) + 1 } - enum.take(3).should == [1, 2, 3] - ScratchPad.recorded.should == [nil, 1, 2] - end + enum.take(3).should == [1, 2, 3] + ScratchPad.recorded.should == [nil, 1, 2] + end - it "starts enumerable from result of first block call" do - array = "a\nb\nc\nd".lines - lines = Enumerator.produce { array.shift }.take_while { |s| s } + it "starts enumerable from result of first block call" do + array = "a\nb\nc\nd".lines + lines = Enumerator.produce { array.shift }.take_while { |s| s } - lines.should == ["a\n", "b\n", "c\n", "d"] - end + lines.should == ["a\n", "b\n", "c\n", "d"] end end end diff --git a/spec/ruby/core/enumerator/yielder/to_proc_spec.rb b/spec/ruby/core/enumerator/yielder/to_proc_spec.rb index 0ed1645853..1d3681ab50 100644 --- a/spec/ruby/core/enumerator/yielder/to_proc_spec.rb +++ b/spec/ruby/core/enumerator/yielder/to_proc_spec.rb @@ -1,18 +1,16 @@ require_relative '../../../spec_helper' -ruby_version_is "2.7" do - describe "Enumerator::Yielder#to_proc" do - it "returns a Proc object that takes an argument and yields it to the block" do - ScratchPad.record [] - y = Enumerator::Yielder.new { |*args| ScratchPad << args; "foobar" } +describe "Enumerator::Yielder#to_proc" do + it "returns a Proc object that takes an argument and yields it to the block" do + ScratchPad.record [] + y = Enumerator::Yielder.new { |*args| ScratchPad << args; "foobar" } - callable = y.to_proc - callable.class.should == Proc + callable = y.to_proc + callable.class.should == Proc - result = callable.call(1, 2) - ScratchPad.recorded.should == [[1, 2]] + result = callable.call(1, 2) + ScratchPad.recorded.should == [[1, 2]] - result.should == "foobar" - end + result.should == "foobar" end end diff --git a/spec/ruby/core/env/merge_spec.rb b/spec/ruby/core/env/merge_spec.rb index b418cd11f4..f10662cf79 100644 --- a/spec/ruby/core/env/merge_spec.rb +++ b/spec/ruby/core/env/merge_spec.rb @@ -1,8 +1,6 @@ require_relative '../../spec_helper' require_relative 'shared/update' -ruby_version_is "2.7" do - describe "ENV.merge!" do - it_behaves_like :env_update, :merge! - end +describe "ENV.merge!" do + it_behaves_like :env_update, :merge! end diff --git a/spec/ruby/core/env/shared/update.rb b/spec/ruby/core/env/shared/update.rb index 129a56544c..2746e86545 100644 --- a/spec/ruby/core/env/shared/update.rb +++ b/spec/ruby/core/env/shared/update.rb @@ -39,23 +39,21 @@ describe :env_update, shared: true do ENV["bar"].should == "5" end - ruby_version_is "2.7" do - # BUG: https://bugs.ruby-lang.org/issues/16192 - it "does not evaluate the block when the name is new" do - ENV.delete("bar") - ENV.send @method, {"foo" => "0"} - ENV.send(@method, "bar" => "1") { |key, old, new| fail "Should not get here" } - ENV["bar"].should == "1" - end + # BUG: https://bugs.ruby-lang.org/issues/16192 + it "does not evaluate the block when the name is new" do + ENV.delete("bar") + ENV.send @method, {"foo" => "0"} + ENV.send(@method, "bar" => "1") { |key, old, new| fail "Should not get here" } + ENV["bar"].should == "1" + end - # BUG: https://bugs.ruby-lang.org/issues/16192 - it "does not use the block's return value as the value when the name is new" do - ENV.delete("bar") - ENV.send @method, {"foo" => "0"} - ENV.send(@method, "bar" => "1") { |key, old, new| "Should not use this value" } - ENV["foo"].should == "0" - ENV["bar"].should == "1" - end + # BUG: https://bugs.ruby-lang.org/issues/16192 + it "does not use the block's return value as the value when the name is new" do + ENV.delete("bar") + ENV.send @method, {"foo" => "0"} + ENV.send(@method, "bar" => "1") { |key, old, new| "Should not use this value" } + ENV["foo"].should == "0" + ENV["bar"].should == "1" end it "returns ENV when block given" do diff --git a/spec/ruby/core/exception/frozen_error_spec.rb b/spec/ruby/core/exception/frozen_error_spec.rb index f27b33295c..2efdc239d8 100644 --- a/spec/ruby/core/exception/frozen_error_spec.rb +++ b/spec/ruby/core/exception/frozen_error_spec.rb @@ -1,26 +1,22 @@ require_relative '../../spec_helper' describe "FrozenError.new" do - ruby_version_is "2.7" do - it "should take optional receiver argument" do - o = Object.new - FrozenError.new("msg", receiver: o).receiver.should equal(o) - end + it "should take optional receiver argument" do + o = Object.new + FrozenError.new("msg", receiver: o).receiver.should equal(o) end end describe "FrozenError#receiver" do - ruby_version_is "2.7" do - it "should return frozen object that modification was attempted on" do - o = Object.new.freeze - begin - def o.x; end - rescue => e - e.should be_kind_of(FrozenError) - e.receiver.should equal(o) - else - raise - end + it "should return frozen object that modification was attempted on" do + o = Object.new.freeze + begin + def o.x; end + rescue => e + e.should be_kind_of(FrozenError) + e.receiver.should equal(o) + else + raise end end end diff --git a/spec/ruby/core/exception/full_message_spec.rb b/spec/ruby/core/exception/full_message_spec.rb index 4cece9ebf9..9757a2f407 100644 --- a/spec/ruby/core/exception/full_message_spec.rb +++ b/spec/ruby/core/exception/full_message_spec.rb @@ -15,13 +15,19 @@ describe "Exception#full_message" do it "supports :highlight option and adds escape sequences to highlight some strings" do e = RuntimeError.new("Some runtime error") - full_message = e.full_message(highlight: true, order: :bottom) - full_message.should include "\e[1mTraceback\e[m (most recent call last)" - full_message.should include "\e[1mSome runtime error (\e[1;4mRuntimeError\e[m\e[1m)" + full_message = e.full_message(highlight: true, order: :top).lines + full_message[0].should.end_with? "\e[1mSome runtime error (\e[1;4mRuntimeError\e[m\e[1m)\e[m\n" - full_message = e.full_message(highlight: false, order: :bottom) - full_message.should include "Traceback (most recent call last)" - full_message.should include "Some runtime error (RuntimeError)" + 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[1mSome runtime error (\e[1;4mRuntimeError\e[m\e[1m)\e[m\n" + + full_message = e.full_message(highlight: false, order: :top).lines + full_message[0].should.end_with? "Some runtime error (RuntimeError)\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? "Some runtime error (RuntimeError)\n" end it "supports :order option and places the error message and the backtrace at the top or the bottom" do @@ -35,9 +41,9 @@ describe "Exception#full_message" do it "shows the caller if the exception has no backtrace" do e = RuntimeError.new("Some runtime error") e.backtrace.should == nil - full_message = e.full_message(highlight: false, order: :top) - full_message.should include("#{__FILE__}:#{__LINE__-1}:in `") - full_message.should include("': Some runtime error (RuntimeError)\n") + full_message = e.full_message(highlight: false, order: :top).lines + full_message[0].should.start_with?("#{__FILE__}:#{__LINE__-1}:in `") + full_message[0].should.end_with?("': Some runtime error (RuntimeError)\n") end it "shows the exception class at the end of the first line of the message when the message contains multiple lines" do @@ -45,12 +51,24 @@ describe "Exception#full_message" do line = __LINE__; raise "first line\nsecond line" rescue => e full_message = e.full_message(highlight: false, order: :top).lines - full_message[0].should include("#{__FILE__}:#{line}:in `") - full_message[0].should include(": first line (RuntimeError)\n") + full_message[0].should.start_with?("#{__FILE__}:#{line}:in `") + full_message[0].should.end_with?(": first line (RuntimeError)\n") full_message[1].should == "second line\n" end end + it "highlights the entire message when the message contains multiple lines" do + begin + line = __LINE__; raise "first line\nsecond line\nthird line" + rescue => e + full_message = e.full_message(highlight: true, order: :top).lines + full_message[0].should.start_with?("#{__FILE__}:#{line}:in `") + full_message[0].should.end_with?(": \e[1mfirst line (\e[1;4mRuntimeError\e[m\e[1m)\e[m\n") + full_message[1].should == "\e[1msecond line\e[m\n" + full_message[2].should == "\e[1mthird line\e[m\n" + end + end + it "contains cause of exception" do begin begin diff --git a/spec/ruby/core/exception/interrupt_spec.rb b/spec/ruby/core/exception/interrupt_spec.rb index a7501efadc..299b5b81f3 100644 --- a/spec/ruby/core/exception/interrupt_spec.rb +++ b/spec/ruby/core/exception/interrupt_spec.rb @@ -48,4 +48,13 @@ describe "Interrupt" do RUBY out.should == "Interrupt: #{Signal.list["INT"]}\n" end + + platform_is_not :windows do + it "shows the backtrace and has a signaled exit status" do + err = IO.popen([*ruby_exe, '-e', 'Process.kill :INT, Process.pid; sleep'], err: [:child, :out], &:read) + $?.termsig.should == Signal.list.fetch('INT') + err.should.include? ': Interrupt' + err.should.include? "from -e:1:in `<main>'" + end + end end diff --git a/spec/ruby/core/exception/system_exit_spec.rb b/spec/ruby/core/exception/system_exit_spec.rb index eef9faf271..d899844c4e 100644 --- a/spec/ruby/core/exception/system_exit_spec.rb +++ b/spec/ruby/core/exception/system_exit_spec.rb @@ -1,6 +1,48 @@ require_relative '../../spec_helper' describe "SystemExit" do + describe "#initialize" do + it "accepts a status and message" do + exc = SystemExit.new(42, "message") + exc.status.should == 42 + exc.message.should == "message" + + exc = SystemExit.new(true, "message") + exc.status.should == 0 + exc.message.should == "message" + + exc = SystemExit.new(false, "message") + exc.status.should == 1 + exc.message.should == "message" + end + + it "accepts a status only" do + exc = SystemExit.new(42) + exc.status.should == 42 + exc.message.should == "SystemExit" + + exc = SystemExit.new(true) + exc.status.should == 0 + exc.message.should == "SystemExit" + + exc = SystemExit.new(false) + exc.status.should == 1 + exc.message.should == "SystemExit" + end + + it "accepts a message only" do + exc = SystemExit.new("message") + exc.status.should == 0 + exc.message.should == "message" + end + + it "accepts no arguments" do + exc = SystemExit.new + exc.status.should == 0 + exc.message.should == "SystemExit" + end + end + it "sets the exit status and exits silently when raised" do code = 'raise SystemExit.new(7)' result = ruby_exe(code, args: "2>&1", exit_status: 7) diff --git a/spec/ruby/core/false/to_s_spec.rb b/spec/ruby/core/false/to_s_spec.rb index 4cae278891..62f67f6f55 100644 --- a/spec/ruby/core/false/to_s_spec.rb +++ b/spec/ruby/core/false/to_s_spec.rb @@ -5,13 +5,11 @@ describe "FalseClass#to_s" do false.to_s.should == "false" end - ruby_version_is "2.7" do - it "returns a frozen string" do - false.to_s.should.frozen? - end + it "returns a frozen string" do + false.to_s.should.frozen? + end - it "always returns the same string" do - false.to_s.should equal(false.to_s) - end + it "always returns the same string" do + false.to_s.should equal(false.to_s) end end diff --git a/spec/ruby/core/fiber/raise_spec.rb b/spec/ruby/core/fiber/raise_spec.rb index 2a465c8bfa..09c4c1b524 100644 --- a/spec/ruby/core/fiber/raise_spec.rb +++ b/spec/ruby/core/fiber/raise_spec.rb @@ -2,101 +2,99 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative '../../shared/kernel/raise' -ruby_version_is "2.7" do - describe "Fiber#raise" do - it_behaves_like :kernel_raise, :raise, FiberSpecs::NewFiberToRaise +describe "Fiber#raise" do + it_behaves_like :kernel_raise, :raise, FiberSpecs::NewFiberToRaise +end + +describe "Fiber#raise" do + it 'raises RuntimeError by default' do + -> { FiberSpecs::NewFiberToRaise.raise }.should raise_error(RuntimeError) end - describe "Fiber#raise" do - it 'raises RuntimeError by default' do - -> { FiberSpecs::NewFiberToRaise.raise }.should raise_error(RuntimeError) - end + it "raises FiberError if Fiber is not born" do + fiber = Fiber.new { true } + -> { fiber.raise }.should raise_error(FiberError, "cannot raise exception on unborn fiber") + end - it "raises FiberError if Fiber is not born" do - fiber = Fiber.new { true } - -> { fiber.raise }.should raise_error(FiberError, "cannot raise exception on unborn fiber") - end + it "raises FiberError if Fiber is dead" do + fiber = Fiber.new { true } + fiber.resume + -> { fiber.raise }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/) + end - it "raises FiberError if Fiber is dead" do - fiber = Fiber.new { true } - fiber.resume - -> { fiber.raise }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/) - end + it 'accepts error class' do + -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError }.should raise_error(FiberSpecs::CustomError) + end - it 'accepts error class' do - -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError }.should raise_error(FiberSpecs::CustomError) - end + it 'accepts error message' do + -> { FiberSpecs::NewFiberToRaise.raise "error message" }.should raise_error(RuntimeError, "error message") + end - it 'accepts error message' do - -> { FiberSpecs::NewFiberToRaise.raise "error message" }.should raise_error(RuntimeError, "error message") - end + it 'does not accept array of backtrace information only' do + -> { FiberSpecs::NewFiberToRaise.raise ['foo'] }.should raise_error(TypeError) + end - it 'does not accept array of backtrace information only' do - -> { FiberSpecs::NewFiberToRaise.raise ['foo'] }.should raise_error(TypeError) - end + it 'does not accept integer' do + -> { FiberSpecs::NewFiberToRaise.raise 100 }.should raise_error(TypeError) + end - it 'does not accept integer' do - -> { FiberSpecs::NewFiberToRaise.raise 100 }.should raise_error(TypeError) - end + it 'accepts error class with error message' do + -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error' }.should raise_error(FiberSpecs::CustomError, 'test error') + end - it 'accepts error class with error message' 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 + -> { + FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error', ['foo', 'boo'] + }.should raise_error(FiberSpecs::CustomError) { |e| + e.message.should == 'test error' + e.backtrace.should == ['foo', 'boo'] + } + end - it 'accepts error class with with error message and backtrace information' do - -> { - FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error', ['foo', 'boo'] - }.should raise_error(FiberSpecs::CustomError) { |e| - e.message.should == 'test error' - e.backtrace.should == ['foo', 'boo'] - } - end + it 'does not accept only error message and backtrace information' do + -> { FiberSpecs::NewFiberToRaise.raise 'test error', ['foo', 'boo'] }.should raise_error(TypeError) + end - it 'does not accept only error message and backtrace information' do - -> { FiberSpecs::NewFiberToRaise.raise 'test error', ['foo', 'boo'] }.should raise_error(TypeError) - end + it "raises a FiberError if invoked from a different Thread" do + fiber = Fiber.new { Fiber.yield } + fiber.resume + Thread.new do + -> { + fiber.raise + }.should raise_error(FiberError, "fiber called across threads") + end.join + end - it "raises a FiberError if invoked from a different Thread" do - fiber = Fiber.new { Fiber.yield } - fiber.resume - Thread.new do - -> { - fiber.raise - }.should raise_error(FiberError, "fiber called across threads") - end.join - end + it "kills Fiber" do + fiber = Fiber.new { Fiber.yield :first; :second } + fiber.resume + -> { fiber.raise }.should raise_error + -> { fiber.resume }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/) + end - it "kills Fiber" do - fiber = Fiber.new { Fiber.yield :first; :second } - fiber.resume - -> { fiber.raise }.should raise_error - -> { fiber.resume }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/) + it "returns to calling fiber after raise" do + fiber_one = Fiber.new do + Fiber.yield :yield_one + :unreachable end - it "returns to calling fiber after raise" do - fiber_one = Fiber.new do - Fiber.yield :yield_one - :unreachable - end - - fiber_two = Fiber.new do - results = [] - results << fiber_one.resume - begin - fiber_one.raise - rescue - results << :rescued - end - results + fiber_two = Fiber.new do + results = [] + results << fiber_one.resume + begin + fiber_one.raise + rescue + results << :rescued end - - fiber_two.resume.should == [:yield_one, :rescued] + results end - end + fiber_two.resume.should == [:yield_one, :rescued] + end end -ruby_version_is "2.7"..."3.0" do + +ruby_version_is ""..."3.0" do describe "Fiber#raise" do it "raises a FiberError if invoked on a transferring Fiber" do require "fiber" diff --git a/spec/ruby/core/file/absolute_path_spec.rb b/spec/ruby/core/file/absolute_path_spec.rb index 9f39923472..e35c80ec3c 100644 --- a/spec/ruby/core/file/absolute_path_spec.rb +++ b/spec/ruby/core/file/absolute_path_spec.rb @@ -1,54 +1,52 @@ require_relative '../../spec_helper' -ruby_version_is "2.7" do - describe "File.absolute_path?" do - before :each do - @abs = File.expand_path(__FILE__) - end +describe "File.absolute_path?" do + before :each do + @abs = File.expand_path(__FILE__) + end - it "returns true if it's an absolute pathname" do - File.absolute_path?(@abs).should be_true - end + it "returns true if it's an absolute pathname" do + File.absolute_path?(@abs).should be_true + end - it "returns false if it's a relative path" do - File.absolute_path?(File.basename(__FILE__)).should be_false - end + it "returns false if it's a relative path" do + File.absolute_path?(File.basename(__FILE__)).should be_false + end - it "returns false if it's a tricky relative path" do - File.absolute_path?("C:foo\\bar").should be_false - end + it "returns false if it's a tricky relative path" do + File.absolute_path?("C:foo\\bar").should be_false + end - it "does not expand '~' to a home directory." do - File.absolute_path?('~').should be_false - end + it "does not expand '~' to a home directory." do + File.absolute_path?('~').should be_false + end - it "does not expand '~user' to a home directory." do - path = File.dirname(@abs) - Dir.chdir(path) do - File.absolute_path?('~user').should be_false - end + it "does not expand '~user' to a home directory." do + path = File.dirname(@abs) + Dir.chdir(path) do + File.absolute_path?('~user').should be_false end + end - it "calls #to_path on its argument" do - mock = mock_to_path(File.expand_path(__FILE__)) + it "calls #to_path on its argument" do + mock = mock_to_path(File.expand_path(__FILE__)) - File.absolute_path?(mock).should be_true - end + File.absolute_path?(mock).should be_true + end - platform_is_not :windows do - it "takes into consideration the platform's root" do - File.absolute_path?("C:\\foo\\bar").should be_false - File.absolute_path?("C:/foo/bar").should be_false - File.absolute_path?("/foo/bar\\baz").should be_true - end + platform_is_not :windows do + it "takes into consideration the platform's root" do + File.absolute_path?("C:\\foo\\bar").should be_false + File.absolute_path?("C:/foo/bar").should be_false + File.absolute_path?("/foo/bar\\baz").should be_true end + end - platform_is :windows do - it "takes into consideration the platform path separator(s)" do - File.absolute_path?("C:\\foo\\bar").should be_true - File.absolute_path?("C:/foo/bar").should be_true - File.absolute_path?("/foo/bar\\baz").should be_false - end + platform_is :windows do + it "takes into consideration the platform path separator(s)" do + File.absolute_path?("C:\\foo\\bar").should be_true + File.absolute_path?("C:/foo/bar").should be_true + File.absolute_path?("/foo/bar\\baz").should be_false end end end diff --git a/spec/ruby/core/file/extname_spec.rb b/spec/ruby/core/file/extname_spec.rb index e182ed44f2..d20cf813d9 100644 --- a/spec/ruby/core/file/extname_spec.rb +++ b/spec/ruby/core/file/extname_spec.rb @@ -33,14 +33,14 @@ describe "File.extname" do end describe "for a filename ending with a dot" do - guard -> { platform_is :windows or ruby_version_is ""..."2.7" } do + platform_is :windows do it "returns ''" do File.extname(".foo.").should == "" File.extname("foo.").should == "" end end - guard -> { platform_is_not :windows and ruby_version_is "2.7" } do + platform_is_not :windows do it "returns '.'" do File.extname(".foo.").should == "." File.extname("foo.").should == "." diff --git a/spec/ruby/core/file/shared/fnmatch.rb b/spec/ruby/core/file/shared/fnmatch.rb index a8488fd30a..00682bb64c 100644 --- a/spec/ruby/core/file/shared/fnmatch.rb +++ b/spec/ruby/core/file/shared/fnmatch.rb @@ -75,6 +75,14 @@ describe :file_fnmatch, shared: true do File.send(@method, 'c*t', 'c/a/b/t').should == true end + it "does not match unterminated range of characters" do + File.send(@method, 'abc[de', 'abcd').should == false + end + + it "does not match unterminated range of characters as a literal" do + File.send(@method, 'abc[de', 'abc[de').should == false + end + it "matches ranges of characters using bracket expression (e.g. [a-z])" do File.send(@method, 'ca[a-z]', 'cat').should == true end diff --git a/spec/ruby/core/file/utime_spec.rb b/spec/ruby/core/file/utime_spec.rb index 59eef20c66..a191e29240 100644 --- a/spec/ruby/core/file/utime_spec.rb +++ b/spec/ruby/core/file/utime_spec.rb @@ -77,6 +77,10 @@ describe "File.utime" do File.mtime(@file1).nsec.should.between?(0, 123500000) end + it "returns the number of filenames in the arguments" do + File.utime(@atime.to_f, @mtime.to_f, @file1, @file2).should == 2 + end + platform_is :linux do platform_is wordsize: 64 do it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19)" do diff --git a/spec/ruby/core/float/coerce_spec.rb b/spec/ruby/core/float/coerce_spec.rb index ea108f3303..baa831dcf6 100644 --- a/spec/ruby/core/float/coerce_spec.rb +++ b/spec/ruby/core/float/coerce_spec.rb @@ -9,10 +9,10 @@ describe "Float#coerce" do 1.0.coerce(3.14).should == [3.14, 1.0] a, b = -0.0.coerce(bignum_value) - a.should be_close(9223372036854775808.0, TOLERANCE) + a.should be_close(18446744073709551616.0, TOLERANCE) b.should be_close(-0.0, TOLERANCE) a, b = 1.0.coerce(bignum_value) - a.should be_close(9223372036854775808.0, TOLERANCE) + a.should be_close(18446744073709551616.0, TOLERANCE) b.should be_close(1.0, TOLERANCE) end end diff --git a/spec/ruby/core/float/divmod_spec.rb b/spec/ruby/core/float/divmod_spec.rb index ec55dd3681..523217ac1f 100644 --- a/spec/ruby/core/float/divmod_spec.rb +++ b/spec/ruby/core/float/divmod_spec.rb @@ -10,7 +10,7 @@ describe "Float#divmod" do values[1].should be_close(2.8284, TOLERANCE) values = -1.0.divmod(bignum_value) values[0].should eql(-1) - values[1].should be_close(9223372036854775808.000, TOLERANCE) + values[1].should be_close(18446744073709551616.0, TOLERANCE) values = -1.0.divmod(1) values[0].should eql(-1) values[1].should eql(0.0) diff --git a/spec/ruby/core/float/minus_spec.rb b/spec/ruby/core/float/minus_spec.rb index 5626cbdac2..a4281a397b 100644 --- a/spec/ruby/core/float/minus_spec.rb +++ b/spec/ruby/core/float/minus_spec.rb @@ -6,7 +6,7 @@ describe "Float#-" do it "returns self minus other" do (9_237_212.5280 - 5_280).should be_close(9231932.528, TOLERANCE) - (2_560_496.1691 - bignum_value).should be_close(-9223372036852215808.000, TOLERANCE) + (2_560_496.1691 - bignum_value).should be_close(-18446744073706991616.0, TOLERANCE) (5.5 - 5.5).should be_close(0.0,TOLERANCE) end end diff --git a/spec/ruby/core/float/multiply_spec.rb b/spec/ruby/core/float/multiply_spec.rb index eca0b52c4f..2adb8796cd 100644 --- a/spec/ruby/core/float/multiply_spec.rb +++ b/spec/ruby/core/float/multiply_spec.rb @@ -7,7 +7,7 @@ describe "Float#*" do it "returns self multiplied by other" do (4923.98221 * 2).should be_close(9847.96442, TOLERANCE) (6712.5 * 0.25).should be_close(1678.125, TOLERANCE) - (256.4096 * bignum_value).should be_close(2364961134621118431232.000, TOLERANCE) + (256.4096 * bignum_value).should be_close(4729922269242236862464.0, TOLERANCE) end it "raises a TypeError when given a non-Numeric" do diff --git a/spec/ruby/core/float/plus_spec.rb b/spec/ruby/core/float/plus_spec.rb index 06b136a06b..e3e19d7f39 100644 --- a/spec/ruby/core/float/plus_spec.rb +++ b/spec/ruby/core/float/plus_spec.rb @@ -6,7 +6,7 @@ describe "Float#+" do it "returns self plus other" do (491.213 + 2).should be_close(493.213, TOLERANCE) - (9.99 + bignum_value).should be_close(9223372036854775808.000, TOLERANCE) + (9.99 + bignum_value).should be_close(18446744073709551616.0, TOLERANCE) (1001.99 + 5.219).should be_close(1007.209, TOLERANCE) end end diff --git a/spec/ruby/core/hash/constructor_spec.rb b/spec/ruby/core/hash/constructor_spec.rb index ad67274802..8fba47958f 100644 --- a/spec/ruby/core/hash/constructor_spec.rb +++ b/spec/ruby/core/hash/constructor_spec.rb @@ -42,26 +42,13 @@ describe "Hash.[]" do Hash[ary].should == { a: :b } end - ruby_version_is "" ... "2.7" do - it "ignores elements that are not arrays" do - -> { - Hash[[:a]].should == {} - }.should complain(/ignoring wrong elements/) - -> { - Hash[[:nil]].should == {} - }.should complain(/ignoring wrong elements/) - end - end - - ruby_version_is "2.7" do - it "raises for elements that are not arrays" do - -> { - Hash[[:a]].should == {} - }.should raise_error(ArgumentError) - -> { - Hash[[:nil]].should == {} - }.should raise_error(ArgumentError) - end + it "raises for elements that are not arrays" do + -> { + Hash[[:a]].should == {} + }.should raise_error(ArgumentError) + -> { + Hash[[:nil]].should == {} + }.should raise_error(ArgumentError) end it "raises an ArgumentError for arrays of more than 2 elements" do diff --git a/spec/ruby/core/hash/deconstruct_keys_spec.rb b/spec/ruby/core/hash/deconstruct_keys_spec.rb index b265732616..bbcd8932e5 100644 --- a/spec/ruby/core/hash/deconstruct_keys_spec.rb +++ b/spec/ruby/core/hash/deconstruct_keys_spec.rb @@ -1,25 +1,23 @@ require_relative '../../spec_helper' -ruby_version_is "2.7" do - describe "Hash#deconstruct_keys" do - it "returns self" do - hash = {a: 1, b: 2} +describe "Hash#deconstruct_keys" do + it "returns self" do + hash = {a: 1, b: 2} - hash.deconstruct_keys([:a, :b]).should equal hash - end + hash.deconstruct_keys([:a, :b]).should equal hash + end - it "requires one argument" do - -> { - {a: 1}.deconstruct_keys - }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/) - end + it "requires one argument" do + -> { + {a: 1}.deconstruct_keys + }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/) + end - it "ignores argument" do - hash = {a: 1, b: 2} + it "ignores argument" do + hash = {a: 1, b: 2} - hash.deconstruct_keys([:a]).should == {a: 1, b: 2} - hash.deconstruct_keys(0 ).should == {a: 1, b: 2} - hash.deconstruct_keys('' ).should == {a: 1, b: 2} - end + hash.deconstruct_keys([:a]).should == {a: 1, b: 2} + hash.deconstruct_keys(0 ).should == {a: 1, b: 2} + hash.deconstruct_keys('' ).should == {a: 1, b: 2} end end diff --git a/spec/ruby/core/hash/reject_spec.rb b/spec/ruby/core/hash/reject_spec.rb index 397000ab67..dd8e817237 100644 --- a/spec/ruby/core/hash/reject_spec.rb +++ b/spec/ruby/core/hash/reject_spec.rb @@ -31,13 +31,6 @@ describe "Hash#reject" do HashSpecs::MyHash[1 => 2, 3 => 4].reject { false }.should be_kind_of(Hash) HashSpecs::MyHash[1 => 2, 3 => 4].reject { true }.should be_kind_of(Hash) end - - ruby_version_is ''...'2.7' do - it "does not taint the resulting hash" do - h = { a: 1 }.taint - h.reject {false}.should_not.tainted? - end - end end it "processes entries with the same order as reject!" do diff --git a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb index 005886a482..e9337b9d1c 100644 --- a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb +++ b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb @@ -1,47 +1,59 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "2.7" do - describe "Hash.ruby2_keywords_hash?" do - it "returns false if the Hash is not a keywords Hash" do - Hash.ruby2_keywords_hash?({}).should == false - end - - it "returns true if the Hash is a keywords Hash marked by Module#ruby2_keywords" do - obj = Class.new { - ruby2_keywords def m(*args) - args.last - end - }.new - Hash.ruby2_keywords_hash?(obj.m(a: 1)).should == true - end - - it "raises TypeError for non-Hash" do - -> { Hash.ruby2_keywords_hash?(nil) }.should raise_error(TypeError) - end - end - - describe "Hash.ruby2_keywords_hash" do - it "returns a copy of a Hash and marks the copy as a keywords Hash" do - h = {a: 1}.freeze - kw = Hash.ruby2_keywords_hash(h) - Hash.ruby2_keywords_hash?(h).should == false - Hash.ruby2_keywords_hash?(kw).should == true - kw.should == h - end - - it "returns an instance of the subclass if called on an instance of a subclass of Hash" do - h = HashSpecs::MyHash.new - h[:a] = 1 - kw = Hash.ruby2_keywords_hash(h) - kw.class.should == HashSpecs::MyHash - Hash.ruby2_keywords_hash?(h).should == false - Hash.ruby2_keywords_hash?(kw).should == true - kw.should == h - end - - it "raises TypeError for non-Hash" do - -> { Hash.ruby2_keywords_hash(nil) }.should raise_error(TypeError) - end +describe "Hash.ruby2_keywords_hash?" do + it "returns false if the Hash is not a keywords Hash" do + Hash.ruby2_keywords_hash?({}).should == false + end + + it "returns true if the Hash is a keywords Hash marked by Module#ruby2_keywords" do + obj = Class.new { + ruby2_keywords def m(*args) + args.last + end + }.new + Hash.ruby2_keywords_hash?(obj.m(a: 1)).should == true + end + + it "raises TypeError for non-Hash" do + -> { Hash.ruby2_keywords_hash?(nil) }.should raise_error(TypeError) + end +end + +describe "Hash.ruby2_keywords_hash" do + it "returns a copy of a Hash and marks the copy as a keywords Hash" do + h = {a: 1}.freeze + kw = Hash.ruby2_keywords_hash(h) + Hash.ruby2_keywords_hash?(h).should == false + Hash.ruby2_keywords_hash?(kw).should == true + kw.should == h + end + + it "returns an instance of the subclass if called on an instance of a subclass of Hash" do + h = HashSpecs::MyHash.new + h[:a] = 1 + kw = Hash.ruby2_keywords_hash(h) + kw.class.should == HashSpecs::MyHash + Hash.ruby2_keywords_hash?(h).should == false + Hash.ruby2_keywords_hash?(kw).should == true + kw.should == h + end + + it "copies instance variables" do + h = {a: 1} + h.instance_variable_set(:@foo, 42) + kw = Hash.ruby2_keywords_hash(h) + kw.instance_variable_get(:@foo).should == 42 + end + + it "copies the hash internals" do + h = {a: 1} + kw = Hash.ruby2_keywords_hash(h) + h[:a] = 2 + kw[:a].should == 1 + end + + it "raises TypeError for non-Hash" do + -> { Hash.ruby2_keywords_hash(nil) }.should raise_error(TypeError) end end diff --git a/spec/ruby/core/hash/shared/eql.rb b/spec/ruby/core/hash/shared/eql.rb index e294edd764..68db49f76d 100644 --- a/spec/ruby/core/hash/shared/eql.rb +++ b/spec/ruby/core/hash/shared/eql.rb @@ -149,80 +149,34 @@ describe :hash_eql_additional, shared: true do h.send(@method, HashSpecs::MyHash[h]).should be_true end - ruby_version_is '2.7' do - # Why isn't this true of eql? too ? - it "compares keys with matching hash codes via eql?" do - a = Array.new(2) do - obj = mock('0') - obj.should_receive(:hash).at_least(1).and_return(0) - - def obj.eql?(o) - return true if self.equal?(o) - false - end - - obj + # Why isn't this true of eql? too ? + it "compares keys with matching hash codes via eql?" do + a = Array.new(2) do + obj = mock('0') + obj.should_receive(:hash).at_least(1).and_return(0) + + def obj.eql?(o) + return true if self.equal?(o) + false end - { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_false - - a = Array.new(2) do - obj = mock('0') - obj.should_receive(:hash).at_least(1).and_return(0) - - def obj.eql?(o) - true - end - - obj - end - - { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_true + obj end - end - ruby_version_is ''...'2.7' do - # Why isn't this true of eql? too ? - it "compares keys with matching hash codes via eql?" do - a = Array.new(2) do - obj = mock('0') - obj.should_receive(:hash).at_least(1).and_return(0) + { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_false - # It's undefined whether the impl does a[0].eql?(a[1]) or - # a[1].eql?(a[0]) so we taint both. - def obj.eql?(o) - return true if self.equal?(o) - taint - o.taint - false - end + a = Array.new(2) do + obj = mock('0') + obj.should_receive(:hash).at_least(1).and_return(0) - obj + def obj.eql?(o) + true end - { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_false - a[0].tainted?.should be_true - a[1].tainted?.should be_true - - a = Array.new(2) do - obj = mock('0') - obj.should_receive(:hash).at_least(1).and_return(0) - - def obj.eql?(o) - # It's undefined whether the impl does a[0].send(@method, a[1]) or - # a[1].send(@method, a[0]) so we taint both. - taint - o.taint - true - end - - obj - end - - { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_true - a[0].tainted?.should be_true - a[1].tainted?.should be_true + obj end + + { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_true end it "compares the values in self to values in other hash" do diff --git a/spec/ruby/core/hash/shared/to_s.rb b/spec/ruby/core/hash/shared/to_s.rb index b0e3705d01..2db3a96583 100644 --- a/spec/ruby/core/hash/shared/to_s.rb +++ b/spec/ruby/core/hash/shared/to_s.rb @@ -2,7 +2,6 @@ require_relative '../../../spec_helper' require_relative '../fixtures/classes' describe :hash_to_s, shared: true do - it "returns a string representation with same order as each()" do h = { a: [1, 2], b: -2, d: -6, nil => nil } @@ -77,22 +76,14 @@ describe :hash_to_s, shared: true do y.send(@method).should == "{1=>{0=>{...}}}" end - ruby_version_is ''...'2.7' do - it "returns a tainted string if self is tainted and not empty" do - {}.taint.send(@method).tainted?.should be_false - { nil => nil }.taint.send(@method).tainted?.should be_true - end - - it "returns an untrusted string if self is untrusted and not empty" do - {}.untrust.send(@method).untrusted?.should be_false - { nil => nil }.untrust.send(@method).untrusted?.should be_true - end - end - it "does not raise if inspected result is not default external encoding" do utf_16be = mock("utf_16be") utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode!(Encoding::UTF_16BE)) {a: utf_16be}.send(@method).should == '{:a=>"utf_16be \u3042"}' end + + it "works for keys and values whose #inspect return a frozen String" do + { true => false }.to_s.should == "{true=>false}" + end end diff --git a/spec/ruby/core/hash/shift_spec.rb b/spec/ruby/core/hash/shift_spec.rb index 9d43e640f5..ea36488a04 100644 --- a/spec/ruby/core/hash/shift_spec.rb +++ b/spec/ruby/core/hash/shift_spec.rb @@ -30,23 +30,45 @@ describe "Hash#shift" do h.should == {} end - it "calls #default with nil if the Hash is empty" do - h = {} - def h.default(key) - key.should == nil - :foo + ruby_version_is '3.2' do + it "returns nil if the Hash is empty" do + h = {} + def h.default(key) + raise + end + h.shift.should == nil + end + end + + ruby_version_is ''...'3.2' do + it "calls #default with nil if the Hash is empty" do + h = {} + def h.default(key) + key.should == nil + :foo + end + h.shift.should == :foo end - h.shift.should == :foo end it "returns nil from an empty hash" do {}.shift.should == nil end - it "returns (computed) default for empty hashes" do - Hash.new(5).shift.should == 5 - h = Hash.new { |*args| args } - h.shift.should == [h, nil] + ruby_version_is '3.2' do + it "returns nil for empty hashes with defaults and default procs" do + Hash.new(5).shift.should == nil + h = Hash.new { |*args| args } + h.shift.should == nil + end + end + + ruby_version_is ''...'3.2' do + it "returns (computed) default for empty hashes" do + Hash.new(5).shift.should == 5 + h = Hash.new { |*args| args } + h.shift.should == [h, nil] + end end it "preserves Hash invariants when removing the last item" do diff --git a/spec/ruby/core/hash/to_a_spec.rb b/spec/ruby/core/hash/to_a_spec.rb index 46f871389a..8b7894a2ba 100644 --- a/spec/ruby/core/hash/to_a_spec.rb +++ b/spec/ruby/core/hash/to_a_spec.rb @@ -27,13 +27,13 @@ describe "Hash#to_a" do ent.should == pairs end - ruby_version_is ''...'2.7' do - it "returns a tainted array if self is tainted" do - {}.taint.to_a.tainted?.should be_true + ruby_version_is ''...'3.0' do + it "returns a not tainted array if self is tainted" do + {}.taint.to_a.tainted?.should be_false end - it "returns an untrusted array if self is untrusted" do - {}.untrust.to_a.untrusted?.should be_true + it "returns a trusted array if self is untrusted" do + {}.untrust.to_a.untrusted?.should be_false end end end diff --git a/spec/ruby/core/hash/transform_keys_spec.rb b/spec/ruby/core/hash/transform_keys_spec.rb index 8ee1a2cd6d..361089ca97 100644 --- a/spec/ruby/core/hash/transform_keys_spec.rb +++ b/spec/ruby/core/hash/transform_keys_spec.rb @@ -73,14 +73,13 @@ describe "Hash#transform_keys!" do @hash.should == { 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4 } end - # https://bugs.ruby-lang.org/issues/14380 it "prevents conflicts between new keys and old ones" do @hash.transform_keys!(&:succ) @hash.should == { b: 1, c: 2, d: 3, e: 4 } end ruby_version_is ""..."3.0.2" do # https://bugs.ruby-lang.org/issues/17735 - it "returns the processed keys if we broke from the block" do + it "returns the processed keys if we break from the block" do @hash.transform_keys! do |v| break if v == :c v.succ @@ -90,7 +89,7 @@ describe "Hash#transform_keys!" do end ruby_version_is "3.0.2" do - it "returns the processed keys and non evaluated keys if we broke from the block" do + it "returns the processed keys and non evaluated keys if we break from the block" do @hash.transform_keys! do |v| break if v == :c v.succ diff --git a/spec/ruby/core/integer/bit_and_spec.rb b/spec/ruby/core/integer/bit_and_spec.rb index 15a8026855..8de5a14aaa 100644 --- a/spec/ruby/core/integer/bit_and_spec.rb +++ b/spec/ruby/core/integer/bit_and_spec.rb @@ -55,24 +55,24 @@ describe "Integer#&" do @bignum = bignum_value(5) (@bignum & 3).should == 1 (@bignum & 52).should == 4 - (@bignum & bignum_value(9921)).should == 9223372036854775809 + (@bignum & bignum_value(9921)).should == 18446744073709551617 ((2*bignum_value) & 1).should == 0 - ((2*bignum_value) & (2*bignum_value)).should == 18446744073709551616 + ((2*bignum_value) & (2*bignum_value)).should == 36893488147419103232 end it "returns self bitwise AND other when one operand is negative" do ((2*bignum_value) & -1).should == (2*bignum_value) ((4*bignum_value) & -1).should == (4*bignum_value) - (@bignum & -0xffffffffffffff5).should == 9223372036854775809 + (@bignum & -0xffffffffffffff5).should == 18446744073709551617 (@bignum & -@bignum).should == 1 - (@bignum & -0x8000000000000000).should == 9223372036854775808 + (@bignum & -0x8000000000000000).should == 18446744073709551616 end it "returns self bitwise AND other when both operands are negative" do - (-@bignum & -0x4000000000000005).should == -13835058055282163717 - (-@bignum & -@bignum).should == -9223372036854775813 - (-@bignum & -0x4000000000000000).should == -13835058055282163712 + (-@bignum & -0x4000000000000005).should == -23058430092136939525 + (-@bignum & -@bignum).should == -18446744073709551621 + (-@bignum & -0x4000000000000000).should == -23058430092136939520 end it "returns self bitwise AND other when both are negative and a multiple in bitsize of Fixnum::MIN" do diff --git a/spec/ruby/core/integer/bit_or_spec.rb b/spec/ruby/core/integer/bit_or_spec.rb index e486eeec10..6f4279c170 100644 --- a/spec/ruby/core/integer/bit_or_spec.rb +++ b/spec/ruby/core/integer/bit_or_spec.rb @@ -7,13 +7,34 @@ describe "Integer#|" do (5 | 4).should == 5 (5 | 6).should == 7 (248 | 4096).should == 4344 - (0xffff | bignum_value + 0xf0f0).should == 0x8000_0000_0000_ffff + (0xffff | bignum_value + 0xf0f0).should == 0x1_0000_0000_0000_ffff + end + + it "returns self bitwise OR other when one operand is negative" do + ((1 << 33) | -1).should == -1 + (-1 | (1 << 33)).should == -1 + + ((-(1<<33)-1) | 5).should == -8589934593 + (5 | (-(1<<33)-1)).should == -8589934593 + end + + it "returns self bitwise OR other when both operands are negative" do + (-5 | -1).should == -1 + (-3 | -4).should == -3 + (-12 | -13).should == -9 + (-13 | -12).should == -9 end it "returns self bitwise OR a bignum" do (-1 | 2**64).should == -1 end + it "coerces the rhs and calls #coerce" do + obj = mock("fixnum bit and") + obj.should_receive(:coerce).with(6).and_return([3, 6]) + (6 & obj).should == 2 + end + it "raises a TypeError when passed a Float" do -> { (3 | 3.4) }.should raise_error(TypeError) end @@ -32,20 +53,20 @@ describe "Integer#|" do end it "returns self bitwise OR other" do - (@bignum | 2).should == 9223372036854775819 - (@bignum | 9).should == 9223372036854775819 - (@bignum | bignum_value).should == 9223372036854775819 + (@bignum | 2).should == 18446744073709551627 + (@bignum | 9).should == 18446744073709551627 + (@bignum | bignum_value).should == 18446744073709551627 end it "returns self bitwise OR other when one operand is negative" do - (@bignum | -0x40000000000000000).should == -64563604257983430645 + (@bignum | -0x40000000000000000).should == -55340232221128654837 (@bignum | -@bignum).should == -1 (@bignum | -0x8000000000000000).should == -9223372036854775797 end it "returns self bitwise OR other when both operands are negative" do (-@bignum | -0x4000000000000005).should == -1 - (-@bignum | -@bignum).should == -9223372036854775819 + (-@bignum | -@bignum).should == -18446744073709551627 (-@bignum | -0x4000000000000000).should == -11 end diff --git a/spec/ruby/core/integer/bit_xor_spec.rb b/spec/ruby/core/integer/bit_xor_spec.rb index ac8826a52f..f1150a20d5 100644 --- a/spec/ruby/core/integer/bit_xor_spec.rb +++ b/spec/ruby/core/integer/bit_xor_spec.rb @@ -5,13 +5,34 @@ describe "Integer#^" do it "returns self bitwise EXCLUSIVE OR other" do (3 ^ 5).should == 6 (-2 ^ -255).should == 255 - (5 ^ bignum_value + 0xffff_ffff).should == 0x8000_0000_ffff_fffa + (5 ^ bignum_value + 0xffff_ffff).should == 0x1_0000_0000_ffff_fffa + end + + it "returns self bitwise XOR other when one operand is negative" do + ((1 << 33) ^ -1).should == -8589934593 + (-1 ^ (1 << 33)).should == -8589934593 + + ((-(1<<33)-1) ^ 5).should == -8589934598 + (5 ^ (-(1<<33)-1)).should == -8589934598 + end + + it "returns self bitwise XOR other when both operands are negative" do + (-5 ^ -1).should == 4 + (-3 ^ -4).should == 1 + (-12 ^ -13).should == 7 + (-13 ^ -12).should == 7 end it "returns self bitwise EXCLUSIVE OR a bignum" do (-1 ^ 2**64).should == -18446744073709551617 end + it "coerces the rhs and calls #coerce" do + obj = mock("fixnum bit and") + obj.should_receive(:coerce).with(6).and_return([3, 6]) + (6 ^ obj).should == 5 + end + it "raises a TypeError when passed a Float" do -> { (3 ^ 3.4) }.should raise_error(TypeError) end @@ -30,21 +51,21 @@ describe "Integer#^" do end it "returns self bitwise EXCLUSIVE OR other" do - (@bignum ^ 2).should == 9223372036854775824 + (@bignum ^ 2).should == 18446744073709551632 (@bignum ^ @bignum).should == 0 - (@bignum ^ 14).should == 9223372036854775836 + (@bignum ^ 14).should == 18446744073709551644 end it "returns self bitwise EXCLUSIVE OR other when one operand is negative" do - (@bignum ^ -0x40000000000000000).should == -64563604257983430638 + (@bignum ^ -0x40000000000000000).should == -55340232221128654830 (@bignum ^ -@bignum).should == -4 - (@bignum ^ -0x8000000000000000).should == -18446744073709551598 + (@bignum ^ -0x8000000000000000).should == -27670116110564327406 end it "returns self bitwise EXCLUSIVE OR other when both operands are negative" do - (-@bignum ^ -0x40000000000000000).should == 64563604257983430638 + (-@bignum ^ -0x40000000000000000).should == 55340232221128654830 (-@bignum ^ -@bignum).should == 0 - (-@bignum ^ -0x4000000000000000).should == 13835058055282163694 + (-@bignum ^ -0x4000000000000000).should == 23058430092136939502 end it "returns self bitwise EXCLUSIVE OR other when all bits are 1 and other value is negative" do diff --git a/spec/ruby/core/integer/chr_spec.rb b/spec/ruby/core/integer/chr_spec.rb index 9f105e4241..3e13f45480 100644 --- a/spec/ruby/core/integer/chr_spec.rb +++ b/spec/ruby/core/integer/chr_spec.rb @@ -11,7 +11,11 @@ describe "Integer#chr without argument" do it "raises a RangeError is self is less than 0" do -> { -1.chr }.should raise_error(RangeError) - -> { -bignum_value.chr }.should raise_error(RangeError) + -> { (-bignum_value).chr }.should raise_error(RangeError) + end + + it "raises a RangeError if self is too large" do + -> { 2206368128.chr(Encoding::UTF_8) }.should raise_error(RangeError) end describe "when Encoding.default_internal is nil" do @@ -162,7 +166,7 @@ describe "Integer#chr with an encoding argument" do # http://redmine.ruby-lang.org/issues/4869 it "raises a RangeError is self is less than 0" do -> { -1.chr(Encoding::UTF_8) }.should raise_error(RangeError) - -> { -bignum_value.chr(Encoding::EUC_JP) }.should raise_error(RangeError) + -> { (-bignum_value).chr(Encoding::EUC_JP) }.should raise_error(RangeError) end it "raises a RangeError if self is too large" do @@ -241,16 +245,14 @@ describe "Integer#chr with an encoding argument" do end end - ruby_version_is "2.7" do - it 'returns a String encoding self interpreted as a codepoint in the CESU-8 encoding' do - # see more details here https://en.wikipedia.org/wiki/CESU-8 - # code points from U+0000 to U+FFFF is encoded in the same way as in UTF-8 - 0x0045.chr(Encoding::CESU_8).bytes.should == 0x0045.chr(Encoding::UTF_8).bytes + it 'returns a String encoding self interpreted as a codepoint in the CESU-8 encoding' do + # see more details here https://en.wikipedia.org/wiki/CESU-8 + # code points from U+0000 to U+FFFF is encoded in the same way as in UTF-8 + 0x0045.chr(Encoding::CESU_8).bytes.should == 0x0045.chr(Encoding::UTF_8).bytes - # code points in range from U+10000 to U+10FFFF is CESU-8 data containing a 6-byte surrogate pair, - # which decodes to a 4-byte UTF-8 string - 0x10400.chr(Encoding::CESU_8).bytes.should != 0x10400.chr(Encoding::UTF_8).bytes - 0x10400.chr(Encoding::CESU_8).bytes.to_a.should == [0xED, 0xA0, 0x81, 0xED, 0xB0, 0x80] - end + # code points in range from U+10000 to U+10FFFF is CESU-8 data containing a 6-byte surrogate pair, + # which decodes to a 4-byte UTF-8 string + 0x10400.chr(Encoding::CESU_8).bytes.should != 0x10400.chr(Encoding::UTF_8).bytes + 0x10400.chr(Encoding::CESU_8).bytes.to_a.should == [0xED, 0xA0, 0x81, 0xED, 0xB0, 0x80] end end diff --git a/spec/ruby/core/integer/complement_spec.rb b/spec/ruby/core/integer/complement_spec.rb index eafa5c263f..baf5e6c457 100644 --- a/spec/ruby/core/integer/complement_spec.rb +++ b/spec/ruby/core/integer/complement_spec.rb @@ -12,9 +12,9 @@ describe "Integer#~" do context "bignum" do it "returns self with each bit flipped" do - (~bignum_value(48)).should == -9223372036854775857 - (~(-bignum_value(21))).should == 9223372036854775828 - (~bignum_value(1)).should == -9223372036854775810 + (~bignum_value(48)).should == -18446744073709551665 + (~(-bignum_value(21))).should == 18446744073709551636 + (~bignum_value(1)).should == -18446744073709551618 end end end diff --git a/spec/ruby/core/integer/constants_spec.rb b/spec/ruby/core/integer/constants_spec.rb index 3b8b01e330..2077ad451e 100644 --- a/spec/ruby/core/integer/constants_spec.rb +++ b/spec/ruby/core/integer/constants_spec.rb @@ -1,25 +1,41 @@ require_relative '../../spec_helper' describe "Fixnum" do - it "is unified into Integer" do - suppress_warning do - Fixnum.should equal(Integer) + ruby_version_is ""..."3.2" do + it "is unified into Integer" do + suppress_warning do + Fixnum.should equal(Integer) + end + end + + it "is deprecated" do + -> { Fixnum }.should complain(/constant ::Fixnum is deprecated/) end end - it "is deprecated" do - -> { Fixnum }.should complain(/constant ::Fixnum is deprecated/) + ruby_version_is "3.2" do + it "is no longer defined" do + Object.should_not.const_defined?(:Fixnum) + end end end describe "Bignum" do - it "is unified into Integer" do - suppress_warning do - Bignum.should equal(Integer) + ruby_version_is ""..."3.2" do + it "is unified into Integer" do + suppress_warning do + Bignum.should equal(Integer) + end + end + + it "is deprecated" do + -> { Bignum }.should complain(/constant ::Bignum is deprecated/) end end - it "is deprecated" do - -> { Bignum }.should complain(/constant ::Bignum is deprecated/) + ruby_version_is "3.2" do + it "is no longer defined" do + Object.should_not.const_defined?(:Bignum) + end end end diff --git a/spec/ruby/core/integer/div_spec.rb b/spec/ruby/core/integer/div_spec.rb index bc1c4363d4..344e095179 100644 --- a/spec/ruby/core/integer/div_spec.rb +++ b/spec/ruby/core/integer/div_spec.rb @@ -70,8 +70,8 @@ describe "Integer#div" do end it "returns self divided by other" do - @bignum.div(4).should == 2305843009213693974 - @bignum.div(Rational(4, 1)).should == 2305843009213693974 + @bignum.div(4).should == 4611686018427387926 + @bignum.div(Rational(4, 1)).should == 4611686018427387926 @bignum.div(bignum_value(2)).should == 1 (-(10**50)).div(-(10**40 + 1)).should == 9999999999 @@ -124,11 +124,11 @@ describe "Integer#div" do end it "returns a result of integer division of self by a float argument" do - @bignum.div(4294967295.5).should eql(2147483648) + @bignum.div(4294967295.5).should eql(4294967296) not_supported_on :opal do - @bignum.div(4294967295.0).should eql(2147483648) + @bignum.div(4294967295.0).should eql(4294967297) @bignum.div(bignum_value(88).to_f).should eql(1) - @bignum.div(-bignum_value(88).to_f).should eql(-1) + @bignum.div((-bignum_value(88)).to_f).should eql(-1) end end diff --git a/spec/ruby/core/integer/divide_spec.rb b/spec/ruby/core/integer/divide_spec.rb index 5ac2dc538d..a878c4668c 100644 --- a/spec/ruby/core/integer/divide_spec.rb +++ b/spec/ruby/core/integer/divide_spec.rb @@ -47,7 +47,7 @@ describe "Integer#/" do end it "returns self divided by other" do - (@bignum / 4).should == 2305843009213693974 + (@bignum / 4).should == 4611686018427387926 (@bignum / bignum_value(2)).should == 1 @@ -60,15 +60,15 @@ describe "Integer#/" do it "returns self divided by Float" do not_supported_on :opal do - (bignum_value(88) / 4294967295.0).should be_close(2147483648.5, TOLERANCE) + (bignum_value(88) / 4294967295.0).should be_close(4294967297.0, TOLERANCE) end - (bignum_value(88) / 4294967295.5).should be_close(2147483648.25, TOLERANCE) + (bignum_value(88) / 4294967295.5).should be_close(4294967296.5, TOLERANCE) end it "returns result the same class as the argument" do - (@bignum / 4).should == 2305843009213693974 - (@bignum / 4.0).should be_close(2305843009213693974, TOLERANCE) - (@bignum / Rational(4, 1)).should == Rational(2305843009213693974, 1) + (@bignum / 4).should == 4611686018427387926 + (@bignum / 4.0).should be_close(4611686018427387926, TOLERANCE) + (@bignum / Rational(4, 1)).should == Rational(4611686018427387926, 1) end it "does NOT raise ZeroDivisionError if other is zero and is a Float" do diff --git a/spec/ruby/core/integer/divmod_spec.rb b/spec/ruby/core/integer/divmod_spec.rb index d88925caad..7a489e9344 100644 --- a/spec/ruby/core/integer/divmod_spec.rb +++ b/spec/ruby/core/integer/divmod_spec.rb @@ -46,16 +46,16 @@ describe "Integer#divmod" do # assert(0 < b ? (0 <= r && r < b) : (b < r && r <= 0)) # So, r is always between 0 and b. it "returns an Array containing quotient and modulus obtained from dividing self by the given argument" do - @bignum.divmod(4).should == [2305843009213693965, 3] - @bignum.divmod(13).should == [709490156681136604, 11] + @bignum.divmod(4).should == [4611686018427387917, 3] + @bignum.divmod(13).should == [1418980313362273205, 6] - @bignum.divmod(4.5).should == [2049638230412172288, 3.5] + @bignum.divmod(4.5).should == [4099276460824344576, 2.5] not_supported_on :opal do - @bignum.divmod(4.0).should == [2305843009213693952, 0.0] - @bignum.divmod(13.0).should == [709490156681136640, 8.0] + @bignum.divmod(4.0).should == [4611686018427387904, 0.0] + @bignum.divmod(13.0).should == [1418980313362273280, 3.0] - @bignum.divmod(2.0).should == [4611686018427387904, 0.0] + @bignum.divmod(2.0).should == [9223372036854775808, 0.0] end @bignum.divmod(bignum_value).should == [1, 55] diff --git a/spec/ruby/core/integer/element_reference_spec.rb b/spec/ruby/core/integer/element_reference_spec.rb index 7197ecdc03..cb7e0dc9b0 100644 --- a/spec/ruby/core/integer/element_reference_spec.rb +++ b/spec/ruby/core/integer/element_reference_spec.rb @@ -79,81 +79,79 @@ describe "Integer#[]" do 3[bignum_value.to_f].should == 0 end - ruby_version_is "2.7" do - context "when index and length passed" do - it "returns specified number of bits from specified position" do - 0b101001101[2, 4].should == 0b0011 - 0b101001101[2, 5].should == 0b10011 - 0b101001101[2, 7].should == 0b1010011 - end + context "when index and length passed" do + it "returns specified number of bits from specified position" do + 0b101001101[2, 4].should == 0b0011 + 0b101001101[2, 5].should == 0b10011 + 0b101001101[2, 7].should == 0b1010011 + end - it "ensures n[i, len] equals to (n >> i) & ((1 << len) - 1)" do - n = 0b101001101; i = 2; len = 4 - n[i, len].should == (n >> i) & ((1 << len) - 1) - end + it "ensures n[i, len] equals to (n >> i) & ((1 << len) - 1)" do + n = 0b101001101; i = 2; len = 4 + n[i, len].should == (n >> i) & ((1 << len) - 1) + end - it "moves start position to the most significant bits when negative index passed" do - 0b000001[-1, 4].should == 0b10 - 0b000001[-2, 4].should == 0b100 - 0b000001[-3, 4].should == 0b1000 - end + it "moves start position to the most significant bits when negative index passed" do + 0b000001[-1, 4].should == 0b10 + 0b000001[-2, 4].should == 0b100 + 0b000001[-3, 4].should == 0b1000 + end - it "ignores negative length" do - 0b101001101[1, -1].should == 0b10100110 - 0b101001101[2, -1].should == 0b1010011 - 0b101001101[3, -1].should == 0b101001 + it "ignores negative length" do + 0b101001101[1, -1].should == 0b10100110 + 0b101001101[2, -1].should == 0b1010011 + 0b101001101[3, -1].should == 0b101001 - 0b101001101[3, -5].should == 0b101001 - 0b101001101[3, -15].should == 0b101001 - 0b101001101[3, -125].should == 0b101001 - end + 0b101001101[3, -5].should == 0b101001 + 0b101001101[3, -15].should == 0b101001 + 0b101001101[3, -125].should == 0b101001 end + end - context "when range passed" do - it "returns bits specified by range" do - 0b101001101[2..5].should == 0b0011 - 0b101001101[2..6].should == 0b10011 - 0b101001101[2..8].should == 0b1010011 - end + context "when range passed" do + it "returns bits specified by range" do + 0b101001101[2..5].should == 0b0011 + 0b101001101[2..6].should == 0b10011 + 0b101001101[2..8].should == 0b1010011 + end - it "ensures n[i..j] equals to (n >> i) & ((1 << (j - i + 1)) - 1)" do - n = 0b101001101; i = 2; j = 5 - n[i..j].should == (n >> i) & ((1 << (j - i + 1)) - 1) - end + it "ensures n[i..j] equals to (n >> i) & ((1 << (j - i + 1)) - 1)" do + n = 0b101001101; i = 2; j = 5 + n[i..j].should == (n >> i) & ((1 << (j - i + 1)) - 1) + end - it "ensures n[i..] equals to (n >> i)" do - eval("0b101001101[3..]").should == 0b101001101 >> 3 - end + it "ensures n[i..] equals to (n >> i)" do + eval("0b101001101[3..]").should == 0b101001101 >> 3 + end - it "moves lower boundary to the most significant bits when negative value passed" do - 0b000001[-1, 4].should == 0b10 - 0b000001[-2, 4].should == 0b100 - 0b000001[-3, 4].should == 0b1000 - end + it "moves lower boundary to the most significant bits when negative value passed" do + 0b000001[-1, 4].should == 0b10 + 0b000001[-2, 4].should == 0b100 + 0b000001[-3, 4].should == 0b1000 + end - it "ignores upper boundary smaller than lower boundary" do - 0b101001101[4..1].should == 0b10100 - 0b101001101[4..2].should == 0b10100 - 0b101001101[-4..-5].should == 0b1010011010000 - end + it "ignores upper boundary smaller than lower boundary" do + 0b101001101[4..1].should == 0b10100 + 0b101001101[4..2].should == 0b10100 + 0b101001101[-4..-5].should == 0b1010011010000 + end + + it "raises FloatDomainError if any boundary is infinity" do + -> { 0x0001[3..Float::INFINITY] }.should raise_error(FloatDomainError, /Infinity/) + -> { 0x0001[-Float::INFINITY..3] }.should raise_error(FloatDomainError, /-Infinity/) + end - it "raises FloatDomainError if any boundary is infinity" do - -> { 0x0001[3..Float::INFINITY] }.should raise_error(FloatDomainError, /Infinity/) - -> { 0x0001[-Float::INFINITY..3] }.should raise_error(FloatDomainError, /-Infinity/) + context "when passed (..i)" do + it "returns 0 if all i bits equal 0" do + eval("0b10000[..1]").should == 0 + eval("0b10000[..2]").should == 0 + eval("0b10000[..3]").should == 0 end - context "when passed (..i)" do - it "returns 0 if all i bits equal 0" do - eval("0b10000[..1]").should == 0 - eval("0b10000[..2]").should == 0 - eval("0b10000[..3]").should == 0 - end - - it "raises ArgumentError if any of i bit equals 1" do - -> { - eval("0b111110[..3]") - }.should raise_error(ArgumentError, /The beginless range for Integer#\[\] results in infinity/) - end + it "raises ArgumentError if any of i bit equals 1" do + -> { + eval("0b111110[..3]") + }.should raise_error(ArgumentError, /The beginless range for Integer#\[\] results in infinity/) end end end diff --git a/spec/ruby/core/integer/fdiv_spec.rb b/spec/ruby/core/integer/fdiv_spec.rb index 6de170278f..d99a19eb0f 100644 --- a/spec/ruby/core/integer/fdiv_spec.rb +++ b/spec/ruby/core/integer/fdiv_spec.rb @@ -9,6 +9,52 @@ describe "Integer#fdiv" do 8.fdiv(bignum_value).should be_close(8.673617379884035e-19, TOLERANCE) end + it "performs floating-point division between self bignum and a bignum" do + num = 1000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146010000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146010000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146009 + den = 2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + num.fdiv(den).should == 500.0 + end + + it "rounds to the correct value for bignums" do + den = 9 * 10**342 + + num = 1 * 10**344 + num.fdiv(den).should == 11.11111111111111 + + num = 1 * 10**343 + num.fdiv(den).should == 1.1111111111111112 + + num = 1 * 10**342 + num.fdiv(den).should == 0.1111111111111111 + + num = 2 * 10**342 + num.fdiv(den).should == 0.2222222222222222 + + num = 3 * 10**342 + num.fdiv(den).should == 0.3333333333333333 + + num = 4 * 10**342 + num.fdiv(den).should == 0.4444444444444444 + + num = 5 * 10**342 + num.fdiv(den).should == 0.5555555555555556 + + num = 6 * 10**342 + num.fdiv(den).should == 0.6666666666666666 + + num = 7 * 10**342 + num.fdiv(den).should == 0.7777777777777778 + + num = 8 * 10**342 + num.fdiv(den).should == 0.8888888888888888 + + num = 9 * 10**342 + num.fdiv(den).should == 1.0 + + num = -5 * 10**342 + num.fdiv(den).should == -0.5555555555555556 + end + it "performs floating-point division between self and a Float" do 8.fdiv(9.0).should be_close(0.888888888888889, TOLERANCE) end diff --git a/spec/ruby/core/integer/left_shift_spec.rb b/spec/ruby/core/integer/left_shift_spec.rb index 4efcbef334..135af90421 100644 --- a/spec/ruby/core/integer/left_shift_spec.rb +++ b/spec/ruby/core/integer/left_shift_spec.rb @@ -56,13 +56,13 @@ describe "Integer#<< (with n << m)" do (3 << -bignum_value).should == 0 end - it "returns an Bignum == fixnum_max * 2 when fixnum_max << 1 and n > 0" do + it "returns a Bignum == fixnum_max * 2 when fixnum_max << 1 and n > 0" do result = fixnum_max << 1 result.should be_an_instance_of(Integer) result.should == fixnum_max * 2 end - it "returns an Bignum == fixnum_min * 2 when fixnum_min << 1 and n < 0" do + it "returns a Bignum == fixnum_min * 2 when fixnum_min << 1 and n < 0" do result = fixnum_min << 1 result.should be_an_instance_of(Integer) result.should == fixnum_min * 2 @@ -96,7 +96,7 @@ describe "Integer#<< (with n << m)" do context "bignum" do before :each do - @bignum = bignum_value * 16 + @bignum = bignum_value * 8 # 2 ** 67 end it "returns n shifted left m bits when n > 0, m > 0" do @@ -127,10 +127,6 @@ describe "Integer#<< (with n << m)" do (@bignum << -68).should == 0 end - it "returns 0 when m < 0 and m is a Bignum" do - (@bignum << -bignum_value).should == 0 - end - it "returns a Fixnum == fixnum_max when (fixnum_max * 2) << -1 and n > 0" do result = (fixnum_max * 2) << -1 result.should be_an_instance_of(Integer) @@ -165,4 +161,51 @@ describe "Integer#<< (with n << m)" do -> { @bignum << "4" }.should raise_error(TypeError) end end + + context "when m is a bignum or larger than int" do + it "returns -1 when m < 0 and n < 0" do + (-1 << -bignum_value).should == -1 + (-1 << -(2**40)).should == -1 + + (-bignum_value << -bignum_value).should == -1 + (-bignum_value << -(2**40)).should == -1 + end + + it "returns 0 when m < 0 and n >= 0" do + (0 << -bignum_value).should == 0 + (1 << -bignum_value).should == 0 + (bignum_value << -bignum_value).should == 0 + + (0 << -(2**40)).should == 0 + (1 << -(2**40)).should == 0 + (bignum_value << -(2**40)).should == 0 + end + + ruby_bug "#18517", ""..."3.2" do + it "returns 0 when m > 0 long and n == 0" do + (0 << (2**40)).should == 0 + end + end + + it "returns 0 when m > 0 bignum and n == 0" do + (0 << bignum_value).should == 0 + end + + ruby_bug "#18518", ""..."3.3" do + it "raises NoMemoryError when m > 0 and n != 0" do + coerce_long = mock("long") + coerce_long.stub!(:to_int).and_return(2**40) + coerce_bignum = mock("bignum") + coerce_bignum.stub!(:to_int).and_return(bignum_value) + exps = [2**40, bignum_value, coerce_long, coerce_bignum] + + exps.each { |exp| + -> { (1 << exp) }.should raise_error(NoMemoryError) + -> { (-1 << exp) }.should raise_error(NoMemoryError) + -> { (bignum_value << exp) }.should raise_error(NoMemoryError) + -> { (-bignum_value << exp) }.should raise_error(NoMemoryError) + } + end + end + end end diff --git a/spec/ruby/core/integer/minus_spec.rb b/spec/ruby/core/integer/minus_spec.rb index ce50c8752f..aadf416a05 100644 --- a/spec/ruby/core/integer/minus_spec.rb +++ b/spec/ruby/core/integer/minus_spec.rb @@ -10,7 +10,7 @@ describe "Integer#-" do (9237212 - 5_280).should == 9231932 (781 - 0.5).should == 780.5 - (2_560_496 - bignum_value).should == -9223372036852215312 + (2_560_496 - bignum_value).should == -18446744073706991120 end it "raises a TypeError when given a non-Integer" do @@ -29,8 +29,8 @@ describe "Integer#-" do end it "returns self minus the given Integer" do - (@bignum - 9).should == 9223372036854776113 - (@bignum - 12.57).should be_close(9223372036854776109.43, TOLERANCE) + (@bignum - 9).should == 18446744073709551921 + (@bignum - 12.57).should be_close(18446744073709551917.43, TOLERANCE) (@bignum - bignum_value(42)).should == 272 end diff --git a/spec/ruby/core/integer/multiply_spec.rb b/spec/ruby/core/integer/multiply_spec.rb index d1e9c2640d..5037d27458 100644 --- a/spec/ruby/core/integer/multiply_spec.rb +++ b/spec/ruby/core/integer/multiply_spec.rb @@ -10,7 +10,7 @@ describe "Integer#*" do (1342177 * 800).should == 1073741600 (65536 * 65536).should == 4294967296 - (256 * bignum_value).should == 2361183241434822606848 + (256 * bignum_value).should == 4722366482869645213696 (6712 * 0.25).should == 1678.0 end @@ -32,8 +32,8 @@ describe "Integer#*" do it "returns self multiplied by the given Integer" do (@bignum * (1/bignum_value(0xffff).to_f)).should be_close(1.0, TOLERANCE) (@bignum * (1/bignum_value(0xffff).to_f)).should be_close(1.0, TOLERANCE) - (@bignum * 10).should == 92233720368547765800 - (@bignum * (@bignum - 40)).should == 85070591730234629737795195287525433200 + (@bignum * 10).should == 184467440737095523880 + (@bignum * (@bignum - 40)).should == 340282366920938491207277694290934407024 end it "raises a TypeError when given a non-Integer" do diff --git a/spec/ruby/core/integer/plus_spec.rb b/spec/ruby/core/integer/plus_spec.rb index 511a436872..d01a76ab58 100644 --- a/spec/ruby/core/integer/plus_spec.rb +++ b/spec/ruby/core/integer/plus_spec.rb @@ -9,7 +9,7 @@ describe "Integer#+" do (491 + 2).should == 493 (90210 + 10).should == 90220 - (9 + bignum_value).should == 9223372036854775817 + (9 + bignum_value).should == 18446744073709551625 (1001 + 5.219).should == 1006.219 end @@ -29,9 +29,9 @@ describe "Integer#+" do end it "returns self plus the given Integer" do - (@bignum + 4).should == 9223372036854775888 - (@bignum + 4.2).should be_close(9223372036854775888.2, TOLERANCE) - (@bignum + bignum_value(3)).should == 18446744073709551695 + (@bignum + 4).should == 18446744073709551696 + (@bignum + 4.2).should be_close(18446744073709551696.2, TOLERANCE) + (@bignum + bignum_value(3)).should == 36893488147419103311 end it "raises a TypeError when given a non-Integer" do diff --git a/spec/ruby/core/integer/remainder_spec.rb b/spec/ruby/core/integer/remainder_spec.rb index cd10dad6f2..96268b3af5 100644 --- a/spec/ruby/core/integer/remainder_spec.rb +++ b/spec/ruby/core/integer/remainder_spec.rb @@ -33,7 +33,7 @@ describe "Integer#remainder" do it "returns the remainder of dividing self by other" do a = bignum_value(79) a.remainder(2).should == 1 - a.remainder(97.345).should be_close(46.5674996147722, TOLERANCE) + a.remainder(97.345).should be_close(93.1349992295444, TOLERANCE) a.remainder(bignum_value).should == 79 end diff --git a/spec/ruby/core/integer/right_shift_spec.rb b/spec/ruby/core/integer/right_shift_spec.rb index 6abcd8d714..81405667b2 100644 --- a/spec/ruby/core/integer/right_shift_spec.rb +++ b/spec/ruby/core/integer/right_shift_spec.rb @@ -52,17 +52,13 @@ describe "Integer#>> (with n >> m)" do (-7 >> 64).should == -1 end - it "returns 0 when m is a bignum" do - (3 >> bignum_value).should == 0 - end - - it "returns an Bignum == fixnum_max * 2 when fixnum_max >> -1 and n > 0" do + it "returns a Bignum == fixnum_max * 2 when fixnum_max >> -1 and n > 0" do result = fixnum_max >> -1 result.should be_an_instance_of(Integer) result.should == fixnum_max * 2 end - it "returns an Bignum == fixnum_min * 2 when fixnum_min >> -1 and n < 0" do + it "returns a Bignum == fixnum_min * 2 when fixnum_min >> -1 and n < 0" do result = fixnum_min >> -1 result.should be_an_instance_of(Integer) result.should == fixnum_min * 2 @@ -96,7 +92,7 @@ describe "Integer#>> (with n >> m)" do context "bignum" do before :each do - @bignum = bignum_value * 16 + @bignum = bignum_value * 8 # 2 ** 67 end it "returns n shifted right m bits when n > 0, m > 0" do @@ -153,10 +149,6 @@ describe "Integer#>> (with n >> m)" do (@bignum >> 68).should == 0 end - it "returns 0 when m is a Bignum" do - (@bignum >> bignum_value).should == 0 - end - it "returns a Fixnum == fixnum_max when (fixnum_max * 2) >> 1 and n > 0" do result = (fixnum_max * 2) >> 1 result.should be_an_instance_of(Integer) @@ -191,4 +183,51 @@ describe "Integer#>> (with n >> m)" do -> { @bignum >> "4" }.should raise_error(TypeError) end end + + context "when m is a bignum or larger than int" do + it "returns -1 when m > 0 and n < 0" do + (-1 >> bignum_value).should == -1 + (-1 >> (2**40)).should == -1 + + (-bignum_value >> bignum_value).should == -1 + (-bignum_value >> (2**40)).should == -1 + end + + it "returns 0 when m > 0 and n >= 0" do + (0 >> bignum_value).should == 0 + (1 >> bignum_value).should == 0 + (bignum_value >> bignum_value).should == 0 + + (0 >> (2**40)).should == 0 + (1 >> (2**40)).should == 0 + (bignum_value >> (2**40)).should == 0 + end + + ruby_bug "#18517", ""..."3.2" do + it "returns 0 when m < 0 long and n == 0" do + (0 >> -(2**40)).should == 0 + end + end + + it "returns 0 when m < 0 bignum and n == 0" do + (0 >> -bignum_value).should == 0 + end + + ruby_bug "#18518", ""..."3.3" do + it "raises NoMemoryError when m < 0 and n != 0" do + coerce_long = mock("long") + coerce_long.stub!(:to_int).and_return(-(2**40)) + coerce_bignum = mock("bignum") + coerce_bignum.stub!(:to_int).and_return(-bignum_value) + exps = [-(2**40), -bignum_value, coerce_long, coerce_bignum] + + exps.each { |exp| + -> { (1 >> exp) }.should raise_error(NoMemoryError) + -> { (-1 >> exp) }.should raise_error(NoMemoryError) + -> { (bignum_value >> exp) }.should raise_error(NoMemoryError) + -> { (-bignum_value >> exp) }.should raise_error(NoMemoryError) + } + end + end + end end diff --git a/spec/ruby/core/integer/shared/abs.rb b/spec/ruby/core/integer/shared/abs.rb index 946aa21864..43844c9065 100644 --- a/spec/ruby/core/integer/shared/abs.rb +++ b/spec/ruby/core/integer/shared/abs.rb @@ -11,8 +11,8 @@ describe :integer_abs, shared: true do context "bignum" do it "returns the absolute bignum value" do - bignum_value(39).send(@method).should == 9223372036854775847 - (-bignum_value(18)).send(@method).should == 9223372036854775826 + bignum_value(39).send(@method).should == 18446744073709551655 + (-bignum_value(18)).send(@method).should == 18446744073709551634 end end end diff --git a/spec/ruby/core/integer/shared/exponent.rb b/spec/ruby/core/integer/shared/exponent.rb index f949c514c8..15df518b7e 100644 --- a/spec/ruby/core/integer/shared/exponent.rb +++ b/spec/ruby/core/integer/shared/exponent.rb @@ -30,11 +30,13 @@ describe :integer_exponent, shared: true do (-2).send(@method, 30).should eql(1073741824) (-2).send(@method, 31).should eql(-2147483648) (-2).send(@method, 32).should eql(4294967296) + (-2).send(@method, 33).should eql(-8589934592) (-2).send(@method, 61).should eql(-2305843009213693952) (-2).send(@method, 62).should eql(4611686018427387904) (-2).send(@method, 63).should eql(-9223372036854775808) (-2).send(@method, 64).should eql(18446744073709551616) + (-2).send(@method, 65).should eql(-36893488147419103232) end it "can raise 1 to a bignum safely" do @@ -96,8 +98,8 @@ describe :integer_exponent, shared: true do end it "returns self raised to other power" do - (@bignum.send(@method, 4)).should == 7237005577332262361485077344629993318496048279512298547155833600056910050625 - (@bignum.send(@method, 1.2)).should be_close(57262152889751597425762.57804, TOLERANCE) + (@bignum.send(@method, 4)).should == 115792089237316196603666111261383895964500887398800252671052694326794607293761 + (@bignum.send(@method, 1.3)).should be_close(11109528802438156839288832.0, TOLERANCE) end it "raises a TypeError when given a non-Integer" do @@ -116,8 +118,9 @@ describe :integer_exponent, shared: true do end it "returns a complex number when negative and raised to a fractional power" do - ((-@bignum).send(@method, (1.0/3))) .should be_close(Complex(1048576,1816186.907597341), TOLERANCE) - ((-@bignum).send(@method, Rational(1,3))).should be_close(Complex(1048576,1816186.907597341), TOLERANCE) + (-bignum_value).send(@method, (1.0/2)).should be_close(Complex(0.0, 4294967296.0), TOLERANCE) + (-@bignum).send(@method, (1.0/3)) .should be_close(Complex(1321122.9748145656, 2288252.1154253655), TOLERANCE) + (-@bignum).send(@method, Rational(1,3)).should be_close(Complex(1321122.9748145656, 2288252.1154253655), TOLERANCE) end end end diff --git a/spec/ruby/core/integer/shared/modulo.rb b/spec/ruby/core/integer/shared/modulo.rb index b06d81e17d..f678a10806 100644 --- a/spec/ruby/core/integer/shared/modulo.rb +++ b/spec/ruby/core/integer/shared/modulo.rb @@ -48,11 +48,11 @@ describe :integer_modulo, shared: true do end it "returns the modulus obtained from dividing self by the given argument" do - @bignum.send(@method, 5).should == 3 - @bignum.send(@method, -5).should == -2 - @bignum.send(@method, -100).should == -92 - @bignum.send(@method, 2.22).should be_close(0.780180180180252, TOLERANCE) - @bignum.send(@method, bignum_value(10)).should == 9223372036854775808 + @bignum.send(@method, 5).should == 1 + @bignum.send(@method, -5).should == -4 + @bignum.send(@method, -100).should == -84 + @bignum.send(@method, 2.22).should be_close(1.5603603603605034, TOLERANCE) + @bignum.send(@method, bignum_value(10)).should == 18446744073709551616 end it "raises a ZeroDivisionError when the given argument is 0" do diff --git a/spec/ruby/core/integer/to_f_spec.rb b/spec/ruby/core/integer/to_f_spec.rb index 06092eaa92..9f1df9ada9 100644 --- a/spec/ruby/core/integer/to_f_spec.rb +++ b/spec/ruby/core/integer/to_f_spec.rb @@ -11,9 +11,9 @@ describe "Integer#to_f" do context "bignum" do it "returns self converted to a Float" do - bignum_value(0x4000_0aa0_0bb0_0000).to_f.should eql(13_835_069_737_789_292_544.00) - bignum_value(0x8000_0000_0000_0ccc).to_f.should eql(18_446_744_073_709_555_712.00) - (-bignum_value(99)).to_f.should eql(-9_223_372_036_854_775_808.00) + bignum_value(0x4000_0aa0_0bb0_0000).to_f.should eql(23_058_441_774_644_068_352.0) + bignum_value(0x8000_0000_0000_0ccc).to_f.should eql(27_670_116_110_564_330_700.0) + (-bignum_value(99)).to_f.should eql(-18_446_744_073_709_551_715.0) end it "converts number close to Float::MAX without exceeding MAX or producing NaN" do diff --git a/spec/ruby/core/integer/to_s_spec.rb b/spec/ruby/core/integer/to_s_spec.rb index 7988bfde7a..ca08dad95c 100644 --- a/spec/ruby/core/integer/to_s_spec.rb +++ b/spec/ruby/core/integer/to_s_spec.rb @@ -68,9 +68,9 @@ describe "Integer#to_s" do describe "when given no base" do it "returns self converted to a String using base 10" do - bignum_value(9).to_s.should == "9223372036854775817" - bignum_value.to_s.should == "9223372036854775808" - (-bignum_value(675)).to_s.should == "-9223372036854776483" + bignum_value(9).to_s.should == "18446744073709551625" + bignum_value.to_s.should == "18446744073709551616" + (-bignum_value(675)).to_s.should == "-18446744073709552291" end end diff --git a/spec/ruby/core/integer/uminus_spec.rb b/spec/ruby/core/integer/uminus_spec.rb index b6b110dec4..7a9cfe89bf 100644 --- a/spec/ruby/core/integer/uminus_spec.rb +++ b/spec/ruby/core/integer/uminus_spec.rb @@ -20,11 +20,11 @@ describe "Integer#-@" do context "bignum" do it "returns self as a negative value" do - bignum_value.send(:-@).should == -9223372036854775808 - (-bignum_value).send(:-@).should == 9223372036854775808 + bignum_value.send(:-@).should == -18446744073709551616 + (-bignum_value).send(:-@).should == 18446744073709551616 - bignum_value(921).send(:-@).should == -9223372036854776729 - (-bignum_value(921).send(:-@)).should == 9223372036854776729 + bignum_value(921).send(:-@).should == -18446744073709552537 + (-bignum_value(921).send(:-@)).should == 18446744073709552537 end end end diff --git a/spec/ruby/core/io/close_spec.rb b/spec/ruby/core/io/close_spec.rb index eb560eaf67..3a44cc8b17 100644 --- a/spec/ruby/core/io/close_spec.rb +++ b/spec/ruby/core/io/close_spec.rb @@ -44,6 +44,12 @@ describe "IO#close" do @io.close.should be_nil end + it "does not call the #flush method but flushes the stream internally" do + @io.should_not_receive(:flush) + @io.close + @io.should.closed? + end + it 'raises an IOError with a clear message' do matching_exception = nil diff --git a/spec/ruby/core/io/flush_spec.rb b/spec/ruby/core/io/flush_spec.rb index 8de373a0bd..34cf42c425 100644 --- a/spec/ruby/core/io/flush_spec.rb +++ b/spec/ruby/core/io/flush_spec.rb @@ -23,7 +23,7 @@ describe "IO#flush" do # For instance, MJIT creates a worker before @r.close with fork(), @r.close happens, # and the MJIT worker keeps the pipe open until the worker execve(). # TODO: consider acquiring GVL from MJIT worker. - guard_not -> { defined?(RubyVM::JIT) && RubyVM::JIT.enabled? } do + guard_not -> { defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? } do it "raises Errno::EPIPE if sync=false and the read end is closed" do @w.sync = false @w.write "foo" diff --git a/spec/ruby/core/io/gets_spec.rb b/spec/ruby/core/io/gets_spec.rb index a3cd180b66..42238f6201 100644 --- a/spec/ruby/core/io/gets_spec.rb +++ b/spec/ruby/core/io/gets_spec.rb @@ -38,14 +38,6 @@ describe "IO#gets" do IOSpecs.lines.each { |line| line.should == @io.gets } end - ruby_version_is ''...'2.7' do - it "returns tainted strings" do - while line = @io.gets - line.should.tainted? - end - end - end - it "updates lineno with each invocation" do while @io.gets @io.lineno.should == @count += 1 @@ -64,14 +56,6 @@ describe "IO#gets" do @io.gets(nil).should == IOSpecs.lines.join("") end - ruby_version_is ''...'2.7' do - it "returns tainted strings" do - while line = @io.gets(nil) - line.should.tainted? - end - end - end - it "updates lineno with each invocation" do while @io.gets(nil) @io.lineno.should == @count += 1 @@ -100,14 +84,6 @@ describe "IO#gets" do @io.gets.should == IOSpecs.lines[4] end - ruby_version_is ''...'2.7' do - it "returns tainted strings" do - while line = @io.gets("") - line.should.tainted? - end - end - end - it "updates lineno with each invocation" do while @io.gets("") @io.lineno.should == @count += 1 @@ -126,14 +102,6 @@ describe "IO#gets" do @io.gets("la linea").should == "Voici la ligne une.\nQui \303\250 la linea" end - ruby_version_is ''...'2.7' do - it "returns tainted strings" do - while line = @io.gets("la") - line.should.tainted? - end - end - end - it "updates lineno with each invocation" do while (@io.gets("la")) @io.lineno.should == @count += 1 diff --git a/spec/ruby/core/io/set_encoding_by_bom_spec.rb b/spec/ruby/core/io/set_encoding_by_bom_spec.rb index 7368ec7677..b52d3a943a 100644 --- a/spec/ruby/core/io/set_encoding_by_bom_spec.rb +++ b/spec/ruby/core/io/set_encoding_by_bom_spec.rb @@ -12,66 +12,64 @@ describe "IO#set_encoding_by_bom" do rm_r @name end - ruby_version_is "2.7" do - it "returns the result encoding if found BOM UTF-8 sequence" do - File.binwrite(@name, "\u{FEFF}abc") + it "returns the result encoding if found BOM UTF-8 sequence" do + File.binwrite(@name, "\u{FEFF}abc") - @io.set_encoding_by_bom.should == Encoding::UTF_8 - @io.external_encoding.should == Encoding::UTF_8 - end + @io.set_encoding_by_bom.should == Encoding::UTF_8 + @io.external_encoding.should == Encoding::UTF_8 + end - it "returns the result encoding if found BOM UTF_16LE sequence" do - File.binwrite(@name, "\xFF\xFEabc") + it "returns the result encoding if found BOM UTF_16LE sequence" do + File.binwrite(@name, "\xFF\xFEabc") - @io.set_encoding_by_bom.should == Encoding::UTF_16LE - @io.external_encoding.should == Encoding::UTF_16LE - end + @io.set_encoding_by_bom.should == Encoding::UTF_16LE + @io.external_encoding.should == Encoding::UTF_16LE + end - it "returns the result encoding if found BOM UTF_16BE sequence" do - File.binwrite(@name, "\xFE\xFFabc") + it "returns the result encoding if found BOM UTF_16BE sequence" do + File.binwrite(@name, "\xFE\xFFabc") - @io.set_encoding_by_bom.should == Encoding::UTF_16BE - @io.external_encoding.should == Encoding::UTF_16BE - end + @io.set_encoding_by_bom.should == Encoding::UTF_16BE + @io.external_encoding.should == Encoding::UTF_16BE + end - it "returns the result encoding if found BOM UTF_32LE sequence" do - File.binwrite(@name, "\xFF\xFE\x00\x00abc") + it "returns the result encoding if found BOM UTF_32LE sequence" do + File.binwrite(@name, "\xFF\xFE\x00\x00abc") - @io.set_encoding_by_bom.should == Encoding::UTF_32LE - @io.external_encoding.should == Encoding::UTF_32LE - end + @io.set_encoding_by_bom.should == Encoding::UTF_32LE + @io.external_encoding.should == Encoding::UTF_32LE + end - it "returns the result encoding if found BOM UTF_32BE sequence" do - File.binwrite(@name, "\x00\x00\xFE\xFFabc") + it "returns the result encoding if found BOM UTF_32BE sequence" do + File.binwrite(@name, "\x00\x00\xFE\xFFabc") - @io.set_encoding_by_bom.should == Encoding::UTF_32BE - @io.external_encoding.should == Encoding::UTF_32BE - end + @io.set_encoding_by_bom.should == Encoding::UTF_32BE + @io.external_encoding.should == Encoding::UTF_32BE + end - it "returns nil if found BOM sequence not provided" do - File.write(@name, "abc") + it "returns nil if found BOM sequence not provided" do + File.write(@name, "abc") - @io.set_encoding_by_bom.should == nil - end + @io.set_encoding_by_bom.should == nil + end - it 'returns exception if io not in binary mode' do - not_binary_io = new_io(@name, 'r') + it 'returns exception if io not in binary mode' do + not_binary_io = new_io(@name, 'r') - -> { not_binary_io.set_encoding_by_bom }.should raise_error(ArgumentError, 'ASCII incompatible encoding needs binmode') - ensure - not_binary_io.close - end + -> { not_binary_io.set_encoding_by_bom }.should raise_error(ArgumentError, 'ASCII incompatible encoding needs binmode') + ensure + not_binary_io.close + end - it 'returns exception if encoding already set' do - @io.set_encoding("utf-8") + it 'returns exception if encoding already set' do + @io.set_encoding("utf-8") - -> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding is set to UTF-8 already') - end + -> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding is set to UTF-8 already') + end - it 'returns exception if encoding conversion is already set' do - @io.set_encoding(Encoding::UTF_8, Encoding::UTF_16BE) + it 'returns exception if encoding conversion is already set' do + @io.set_encoding(Encoding::UTF_8, Encoding::UTF_16BE) - -> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding conversion is set') - end + -> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding conversion is set') end end diff --git a/spec/ruby/core/io/shared/readlines.rb b/spec/ruby/core/io/shared/readlines.rb index 8e4a73bb98..52b20364ef 100644 --- a/spec/ruby/core/io/shared/readlines.rb +++ b/spec/ruby/core/io/shared/readlines.rb @@ -73,6 +73,11 @@ describe :io_readlines_options_19, shared: true do result = IO.send(@method, @name, 10, &@object) (result ? result : ScratchPad.recorded).should == IOSpecs.lines_limit end + + it "ignores the object as a limit if it is negative" do + result = IO.send(@method, @name, -2, &@object) + (result ? result : ScratchPad.recorded).should == IOSpecs.lines + end end describe "when the object is a String" do diff --git a/spec/ruby/core/io/shared/write.rb b/spec/ruby/core/io/shared/write.rb index 5e53d981c5..270b84ac39 100644 --- a/spec/ruby/core/io/shared/write.rb +++ b/spec/ruby/core/io/shared/write.rb @@ -99,7 +99,7 @@ describe :io_write, shared: true do # For instance, MJIT creates a worker before @r.close with fork(), @r.close happens, # and the MJIT worker keeps the pipe open until the worker execve(). # TODO: consider acquiring GVL from MJIT worker. - guard_not -> { defined?(RubyVM::JIT) && RubyVM::JIT.enabled? } do + guard_not -> { defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? } do it "raises Errno::EPIPE if the read end is closed and does not die from SIGPIPE" do @r.close -> { @w.send(@method, "foo") }.should raise_error(Errno::EPIPE, /Broken pipe/) diff --git a/spec/ruby/core/io/ungetbyte_spec.rb b/spec/ruby/core/io/ungetbyte_spec.rb index 776707205a..716743a6af 100644 --- a/spec/ruby/core/io/ungetbyte_spec.rb +++ b/spec/ruby/core/io/ungetbyte_spec.rb @@ -36,20 +36,10 @@ describe "IO#ungetbyte" do @io.getbyte.should == 97 end - ruby_version_is ''...'2.6.1' do - it "is an RangeError if the integer is not in 8bit" do - for i in [4095, 0x4f7574206f6620636861722072616e6765] do - -> { @io.ungetbyte(i) }.should raise_error(RangeError) - end - end - end - - ruby_version_is '2.6.1' do - it "never raises RangeError" do - for i in [4095, 0x4f7574206f6620636861722072616e67ff] do - @io.ungetbyte(i).should be_nil - @io.getbyte.should == 255 - end + it "never raises RangeError" do + for i in [4095, 0x4f7574206f6620636861722072616e67ff] do + @io.ungetbyte(i).should be_nil + @io.getbyte.should == 255 end end diff --git a/spec/ruby/core/io/ungetc_spec.rb b/spec/ruby/core/io/ungetc_spec.rb index a05d80ee9c..41a455c836 100644 --- a/spec/ruby/core/io/ungetc_spec.rb +++ b/spec/ruby/core/io/ungetc_spec.rb @@ -103,7 +103,7 @@ describe "IO#ungetc" do -> { @io.sysread(1) }.should raise_error(IOError) end - ruby_version_is "0"..."3.0" do + ruby_version_is ""..."3.0" do it "does not affect the stream and returns nil when passed nil" do @io.getc.should == ?V @io.ungetc(nil) diff --git a/spec/ruby/core/io/write_spec.rb b/spec/ruby/core/io/write_spec.rb index 60e66e998f..f29fdf3a01 100644 --- a/spec/ruby/core/io/write_spec.rb +++ b/spec/ruby/core/io/write_spec.rb @@ -168,3 +168,27 @@ platform_is :windows do end end end + +ruby_version_is "3.0" do + describe "IO#write on STDOUT" do + # https://bugs.ruby-lang.org/issues/14413 + platform_is_not :windows do + it "raises SignalException SIGPIPE if the stream is closed instead of Errno::EPIPE like other IOs" do + stderr_file = tmp("stderr") + begin + IO.popen([*ruby_exe, "-e", "loop { puts :ok }"], "r", err: stderr_file) do |io| + io.gets.should == "ok\n" + io.close + end + status = $? + status.should_not.success? + status.should.signaled? + Signal.signame(status.termsig).should == 'PIPE' + File.read(stderr_file).should.empty? + ensure + rm_r stderr_file + end + end + end + end +end diff --git a/spec/ruby/core/kernel/caller_locations_spec.rb b/spec/ruby/core/kernel/caller_locations_spec.rb index 3ec8f0f432..5994b28fa3 100644 --- a/spec/ruby/core/kernel/caller_locations_spec.rb +++ b/spec/ruby/core/kernel/caller_locations_spec.rb @@ -34,12 +34,10 @@ describe 'Kernel#caller_locations' do locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s) end - ruby_version_is "2.7" do - it "works with beginless ranges" do - locations1 = caller_locations(0) - locations2 = caller_locations(eval("(...5)")) - locations2.map(&:to_s)[eval("(2..)")].should == locations1[eval("(...5)")].map(&:to_s)[eval("(2..)")] - end + it "works with beginless ranges" do + locations1 = caller_locations(0) + locations2 = caller_locations((...5)) + locations2.map(&:to_s)[eval("(2..)")].should == locations1[(...5)].map(&:to_s)[eval("(2..)")] end it "can be called with a range whose end is negative" do diff --git a/spec/ruby/core/kernel/caller_spec.rb b/spec/ruby/core/kernel/caller_spec.rb index dba65ddcb0..f1ff7044b8 100644 --- a/spec/ruby/core/kernel/caller_spec.rb +++ b/spec/ruby/core/kernel/caller_spec.rb @@ -50,12 +50,10 @@ describe 'Kernel#caller' do locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s) end - ruby_version_is "2.7" do - it "works with beginless ranges" do - locations1 = KernelSpecs::CallerTest.locations(0) - locations2 = KernelSpecs::CallerTest.locations(eval("(..5)")) - locations2.map(&:to_s)[eval("(2..)")].should == locations1[eval("(..5)")].map(&:to_s)[eval("(2..)")] - end + it "works with beginless ranges" do + locations1 = KernelSpecs::CallerTest.locations(0) + locations2 = KernelSpecs::CallerTest.locations((..5)) + locations2.map(&:to_s)[eval("(2..)")].should == locations1[(..5)].map(&:to_s)[eval("(2..)")] end guard -> { Kernel.instance_method(:tap).source_location } do diff --git a/spec/ruby/core/kernel/clone_spec.rb b/spec/ruby/core/kernel/clone_spec.rb index 38ae1984c0..a87c7544fe 100644 --- a/spec/ruby/core/kernel/clone_spec.rb +++ b/spec/ruby/core/kernel/clone_spec.rb @@ -206,11 +206,4 @@ describe "Kernel#clone" do cloned.bar.should == ['a'] end - - ruby_version_is ''...'2.7' do - it 'copies tainted?' do - o = ''.taint.clone - o.tainted?.should be_true - end - end end diff --git a/spec/ruby/core/kernel/define_singleton_method_spec.rb b/spec/ruby/core/kernel/define_singleton_method_spec.rb index dc77c3e6f8..2d8b1bf413 100644 --- a/spec/ruby/core/kernel/define_singleton_method_spec.rb +++ b/spec/ruby/core/kernel/define_singleton_method_spec.rb @@ -96,4 +96,19 @@ describe "Kernel#define_singleton_method" do o.define(:foo) { raise "not used" } }.should raise_error(ArgumentError) end + + it "always defines the method with public visibility" do + cls = Class.new + def cls.define(name, &block) + private + define_singleton_method(name, &block) + end + + -> { + suppress_warning do + cls.define(:foo) { :ok } + end + cls.foo.should == :ok + }.should_not raise_error(NoMethodError) + end end diff --git a/spec/ruby/core/kernel/inspect_spec.rb b/spec/ruby/core/kernel/inspect_spec.rb index e6fca8bf6f..1f9ce834ab 100644 --- a/spec/ruby/core/kernel/inspect_spec.rb +++ b/spec/ruby/core/kernel/inspect_spec.rb @@ -6,16 +6,6 @@ describe "Kernel#inspect" do Object.new.inspect.should be_an_instance_of(String) end - ruby_version_is ''...'2.7' do - it "returns a tainted string if self is tainted" do - Object.new.taint.inspect.tainted?.should be_true - end - - it "returns an untrusted string if self is untrusted" do - Object.new.untrust.inspect.untrusted?.should be_true - end - end - it "does not call #to_s if it is defined" do # We must use a bare Object here obj = Object.new diff --git a/spec/ruby/core/kernel/instance_variable_set_spec.rb b/spec/ruby/core/kernel/instance_variable_set_spec.rb index 7fda30f72c..dbd257f7b9 100644 --- a/spec/ruby/core/kernel/instance_variable_set_spec.rb +++ b/spec/ruby/core/kernel/instance_variable_set_spec.rb @@ -89,5 +89,11 @@ describe "Kernel#instance_variable_set" do it "raises a FrozenError when passed replacement is different from stored object" do -> { @frozen.instance_variable_set(:@ivar, :replacement) }.should raise_error(FrozenError) end + + it "accepts unicode instance variable names" do + o = Object.new + o.instance_variable_set(:@💙, 42) + o.instance_variable_get(:@💙).should == 42 + end end end diff --git a/spec/ruby/core/kernel/match_spec.rb b/spec/ruby/core/kernel/match_spec.rb index fbfc77f959..aa25006163 100644 --- a/spec/ruby/core/kernel/match_spec.rb +++ b/spec/ruby/core/kernel/match_spec.rb @@ -1,22 +1,30 @@ require_relative '../../spec_helper' describe "Kernel#=~" do - it "returns nil matching any object" do - o = Object.new + ruby_version_is ''...'3.2' do + it "returns nil matching any object" do + o = Object.new - suppress_warning do - (o =~ /Object/).should be_nil - (o =~ 'Object').should be_nil - (o =~ Object).should be_nil - (o =~ Object.new).should be_nil - (o =~ nil).should be_nil - (o =~ true).should be_nil + suppress_warning do + (o =~ /Object/).should be_nil + (o =~ 'Object').should be_nil + (o =~ Object).should be_nil + (o =~ Object.new).should be_nil + (o =~ nil).should be_nil + (o =~ true).should be_nil + end + end + + it "is deprecated" do + -> do + Object.new =~ /regexp/ + end.should complain(/deprecated Object#=~ is called on Object/, verbose: true) end end - it "is deprecated" do - -> do - Object.new =~ /regexp/ - end.should complain(/deprecated Object#=~ is called on Object/, verbose: true) + ruby_version_is '3.2' do + it "is no longer defined" do + Object.new.should_not.respond_to?(:=~) + end end end diff --git a/spec/ruby/core/kernel/method_spec.rb b/spec/ruby/core/kernel/method_spec.rb index 25c6691e10..caf2ec948b 100644 --- a/spec/ruby/core/kernel/method_spec.rb +++ b/spec/ruby/core/kernel/method_spec.rb @@ -34,4 +34,28 @@ describe "Kernel#method" do m.should be_an_instance_of(Method) m.call(1, 2, 3).should == "Done handled_privately([1, 2, 3])" end + + it "can call a #method_missing accepting zero or one arguments" do + cls = Class.new do + def respond_to_missing?(name, *) + name == :foo or super + end + def method_missing + :no_args + end + end + m = cls.new.method(:foo) + -> { m.call }.should raise_error(ArgumentError) + + cls = Class.new do + def respond_to_missing?(name, *) + name == :bar or super + end + def method_missing(m) + m + end + end + m = cls.new.method(:bar) + m.call.should == :bar + end end diff --git a/spec/ruby/core/kernel/open_spec.rb b/spec/ruby/core/kernel/open_spec.rb index 569f2f6a7f..fa9299f9d4 100644 --- a/spec/ruby/core/kernel/open_spec.rb +++ b/spec/ruby/core/kernel/open_spec.rb @@ -27,7 +27,7 @@ describe "Kernel#open" do open(@name, "r") { |f| f.gets }.should == @content end - platform_is_not :windows do + platform_is_not :windows, :wasi do it "opens an io when path starts with a pipe" do @io = open("|date") begin diff --git a/spec/ruby/core/kernel/proc_spec.rb b/spec/ruby/core/kernel/proc_spec.rb index dfe178420b..231c1f0dfb 100644 --- a/spec/ruby/core/kernel/proc_spec.rb +++ b/spec/ruby/core/kernel/proc_spec.rb @@ -40,15 +40,7 @@ describe "Kernel#proc" do proc end - ruby_version_is ""..."2.7" do - it "uses the implicit block from an enclosing method" do - prc = some_method { "hello" } - - prc.call.should == "hello" - end - end - - ruby_version_is "2.7"..."3.0" do + ruby_version_is ""..."3.0" do it "can be created when called with no block" do -> { some_method { "hello" } diff --git a/spec/ruby/core/kernel/rand_spec.rb b/spec/ruby/core/kernel/rand_spec.rb index c52faee2c4..355e425792 100644 --- a/spec/ruby/core/kernel/rand_spec.rb +++ b/spec/ruby/core/kernel/rand_spec.rb @@ -1,7 +1,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -describe "Kernel.rand" do +describe "Kernel#rand" do it "is a private method" do Kernel.should have_private_instance_method(:rand) end @@ -192,6 +192,6 @@ describe "Kernel.rand" do end end -describe "Kernel#rand" do +describe "Kernel.rand" do it "needs to be reviewed for spec completeness" end diff --git a/spec/ruby/core/kernel/require_relative_spec.rb b/spec/ruby/core/kernel/require_relative_spec.rb index d4146eb3c8..5999855de6 100644 --- a/spec/ruby/core/kernel/require_relative_spec.rb +++ b/spec/ruby/core/kernel/require_relative_spec.rb @@ -207,7 +207,7 @@ describe "Kernel#require_relative with a relative path" do $LOADED_FEATURES.should include(@abs_path) end - platform_is_not :windows do + platform_is_not :windows, :wasi do describe "with symlinks" do before :each do @symlink_to_code_dir = tmp("codesymlink") diff --git a/spec/ruby/core/kernel/shared/dup_clone.rb b/spec/ruby/core/kernel/shared/dup_clone.rb index 84ad49cbde..4fac6006e1 100644 --- a/spec/ruby/core/kernel/shared/dup_clone.rb +++ b/spec/ruby/core/kernel/shared/dup_clone.rb @@ -52,18 +52,6 @@ describe :kernel_dup_clone, shared: true do o2.original.should equal(o) end - ruby_version_is ''...'2.7' do - it "preserves tainted state from the original" do - o = ObjectSpecDupInitCopy.new - o2 = o.send(@method) - o.taint - o3 = o.send(@method) - - o2.should_not.tainted? - o3.should.tainted? - end - end - it "does not preserve the object_id" do o1 = ObjectSpecDupInitCopy.new old_object_id = o1.object_id @@ -71,18 +59,6 @@ describe :kernel_dup_clone, shared: true do o2.object_id.should_not == old_object_id end - ruby_version_is ''...'2.7' do - it "preserves untrusted state from the original" do - o = ObjectSpecDupInitCopy.new - o2 = o.send(@method) - o.untrust - o3 = o.send(@method) - - o2.should_not.untrusted? - o3.should.untrusted? - end - end - it "returns nil for NilClass" do nil.send(@method).should == nil end diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb index 9a2c38be1a..cf01b9dc52 100644 --- a/spec/ruby/core/kernel/shared/require.rb +++ b/spec/ruby/core/kernel/shared/require.rb @@ -251,7 +251,7 @@ describe :kernel_require, shared: true do ScratchPad.recorded.should == [:loaded] end - ruby_bug "#16926", "2.7"..."3.0" do + ruby_bug "#16926", ""..."3.0" do it "does not load a feature twice when $LOAD_PATH has been modified" do $LOAD_PATH.replace [CODE_LOADING_DIR] @object.require("load_fixture").should be_true @@ -547,9 +547,7 @@ describe :kernel_require, shared: true do end provided = %w[complex enumerator rational thread] - ruby_version_is "2.7" do - provided << 'ruby2_keywords' - end + provided << 'ruby2_keywords' it "#{provided.join(', ')} are already required" do features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems') diff --git a/spec/ruby/core/kernel/srand_spec.rb b/spec/ruby/core/kernel/srand_spec.rb index 6774d19284..95bb406f46 100644 --- a/spec/ruby/core/kernel/srand_spec.rb +++ b/spec/ruby/core/kernel/srand_spec.rb @@ -1,7 +1,15 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -describe "Kernel.srand" do +describe "Kernel#srand" do + before :each do + @seed = srand + end + + after :each do + srand(@seed) + end + it "is a private method" do Kernel.should have_private_instance_method(:srand) end @@ -11,8 +19,8 @@ describe "Kernel.srand" do srand(20).should == 10 end - it "returns the previous seed value on the first call" do - ruby_exe('p srand(10)', options: '--disable-gems').chomp.should =~ /\A\d+\z/ + it "returns the system-initialized seed value on the first call" do + ruby_exe('print srand(10)', options: '--disable-gems').should =~ /\A\d+\z/ end it "seeds the RNG correctly and repeatably" do @@ -60,6 +68,6 @@ describe "Kernel.srand" do end end -describe "Kernel#srand" do +describe "Kernel.srand" do it "needs to be reviewed for spec completeness" end diff --git a/spec/ruby/core/kernel/taint_spec.rb b/spec/ruby/core/kernel/taint_spec.rb index 8ba9869af2..9a58bb5f04 100644 --- a/spec/ruby/core/kernel/taint_spec.rb +++ b/spec/ruby/core/kernel/taint_spec.rb @@ -2,50 +2,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Kernel#taint" do - ruby_version_is ''...'2.7' do - it "returns self" do - o = Object.new - o.taint.should equal(o) - end - - it "sets the tainted bit" do - o = Object.new - o.taint - o.should.tainted? - end - - it "raises FrozenError on an untainted, frozen object" do - o = Object.new.freeze - -> { o.taint }.should raise_error(FrozenError) - end - - it "does not raise an error on a tainted, frozen object" do - o = Object.new.taint.freeze - o.taint.should equal(o) - end - - it "has no effect on immediate values" do - [nil, true, false].each do |v| - v.taint - v.should_not.tainted? - end - end - - it "no raises a RuntimeError on symbols" do - v = :sym - -> { v.taint }.should_not raise_error(RuntimeError) - v.should_not.tainted? - end - - it "no raises error on integer values" do - [1].each do |v| - -> { v.taint }.should_not raise_error(RuntimeError) - v.should_not.tainted? - end - end - end - - ruby_version_is "2.7"..."3.0" do + ruby_version_is ""..."3.0" do it "is a no-op" do o = Object.new o.taint diff --git a/spec/ruby/core/kernel/tainted_spec.rb b/spec/ruby/core/kernel/tainted_spec.rb index 022938bfc1..7511c730c9 100644 --- a/spec/ruby/core/kernel/tainted_spec.rb +++ b/spec/ruby/core/kernel/tainted_spec.rb @@ -2,17 +2,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Kernel#tainted?" do - ruby_version_is ''...'2.7' do - it "returns true if Object is tainted" do - o = mock('o') - p = mock('p') - p.taint - o.should_not.tainted? - p.should.tainted? - end - end - - ruby_version_is "2.7"..."3.0" do + ruby_version_is ""..."3.0" do it "is a no-op" do o = mock('o') p = mock('p') diff --git a/spec/ruby/core/kernel/to_s_spec.rb b/spec/ruby/core/kernel/to_s_spec.rb index 64b40f46e5..ea4b00151e 100644 --- a/spec/ruby/core/kernel/to_s_spec.rb +++ b/spec/ruby/core/kernel/to_s_spec.rb @@ -5,14 +5,4 @@ describe "Kernel#to_s" do it "returns a String containing the name of self's class" do Object.new.to_s.should =~ /Object/ end - - ruby_version_is ''...'2.7' do - it "returns a tainted result if self is tainted" do - Object.new.taint.to_s.tainted?.should be_true - end - - it "returns an untrusted result if self is untrusted" do - Object.new.untrust.to_s.untrusted?.should be_true - end - end end diff --git a/spec/ruby/core/kernel/trust_spec.rb b/spec/ruby/core/kernel/trust_spec.rb index 399983f74d..4665036da6 100644 --- a/spec/ruby/core/kernel/trust_spec.rb +++ b/spec/ruby/core/kernel/trust_spec.rb @@ -2,30 +2,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Kernel#trust" do - ruby_version_is ''...'2.7' do - it "returns self" do - o = Object.new - o.trust.should equal(o) - end - - it "clears the untrusted bit" do - o = Object.new.untrust - o.trust - o.should_not.untrusted? - end - - it "raises FrozenError on an untrusted, frozen object" do - o = Object.new.untrust.freeze - -> { o.trust }.should raise_error(FrozenError) - end - - it "does not raise an error on a trusted, frozen object" do - o = Object.new.freeze - o.trust.should equal(o) - end - end - - ruby_version_is "2.7"..."3.0" do + ruby_version_is ""..."3.0" do it "is a no-op" do o = Object.new.untrust o.should_not.untrusted? diff --git a/spec/ruby/core/kernel/untaint_spec.rb b/spec/ruby/core/kernel/untaint_spec.rb index 44d87da5d5..42fe8a4239 100644 --- a/spec/ruby/core/kernel/untaint_spec.rb +++ b/spec/ruby/core/kernel/untaint_spec.rb @@ -2,30 +2,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Kernel#untaint" do - ruby_version_is ''...'2.7' do - it "returns self" do - o = Object.new - o.untaint.should equal(o) - end - - it "clears the tainted bit" do - o = Object.new.taint - o.untaint - o.should_not.tainted? - end - - it "raises FrozenError on a tainted, frozen object" do - o = Object.new.taint.freeze - -> { o.untaint }.should raise_error(FrozenError) - end - - it "does not raise an error on an untainted, frozen object" do - o = Object.new.freeze - o.untaint.should equal(o) - end - end - - ruby_version_is "2.7"..."3.0" do + ruby_version_is ""..."3.0" do it "is a no-op" do o = Object.new.taint o.should_not.tainted? diff --git a/spec/ruby/core/kernel/untrust_spec.rb b/spec/ruby/core/kernel/untrust_spec.rb index aff0fec57b..ba0e073cf0 100644 --- a/spec/ruby/core/kernel/untrust_spec.rb +++ b/spec/ruby/core/kernel/untrust_spec.rb @@ -2,30 +2,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Kernel#untrust" do - ruby_version_is ''...'2.7' do - it "returns self" do - o = Object.new - o.untrust.should equal(o) - end - - it "sets the untrusted bit" do - o = Object.new - o.untrust - o.should.untrusted? - end - - it "raises FrozenError on a trusted, frozen object" do - o = Object.new.freeze - -> { o.untrust }.should raise_error(FrozenError) - end - - it "does not raise an error on an untrusted, frozen object" do - o = Object.new.untrust.freeze - o.untrust.should equal(o) - end - end - - ruby_version_is "2.7"..."3.0" do + ruby_version_is ""..."3.0" do it "is a no-op" do o = Object.new o.untrust diff --git a/spec/ruby/core/kernel/untrusted_spec.rb b/spec/ruby/core/kernel/untrusted_spec.rb index 5347c90093..517bd4711b 100644 --- a/spec/ruby/core/kernel/untrusted_spec.rb +++ b/spec/ruby/core/kernel/untrusted_spec.rb @@ -2,33 +2,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Kernel#untrusted?" do - ruby_version_is ''...'2.7' do - it "returns the untrusted status of an object" do - o = mock('o') - o.should_not.untrusted? - o.untrust - o.should.untrusted? - end - - it "has no effect on immediate values" do - a = nil - b = true - c = false - a.untrust - b.untrust - c.untrust - a.should_not.untrusted? - b.should_not.untrusted? - c.should_not.untrusted? - end - - it "has effect on immediate values" do - d = 1 - -> { d.untrust }.should_not raise_error(RuntimeError) - end - end - - ruby_version_is "2.7"..."3.0" do + ruby_version_is ""..."3.0" do it "is a no-op" do o = mock('o') o.should_not.untrusted? diff --git a/spec/ruby/core/main/ruby2_keywords_spec.rb b/spec/ruby/core/main/ruby2_keywords_spec.rb index 0999cddeed..27ceae3253 100644 --- a/spec/ruby/core/main/ruby2_keywords_spec.rb +++ b/spec/ruby/core/main/ruby2_keywords_spec.rb @@ -1,11 +1,9 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "2.7" do - describe "main.ruby2_keywords" do - it "is the same as Object.ruby2_keywords" do - main = TOPLEVEL_BINDING.receiver - main.should have_private_method(:ruby2_keywords) - end +describe "main.ruby2_keywords" do + it "is the same as Object.ruby2_keywords" do + main = TOPLEVEL_BINDING.receiver + main.should have_private_method(:ruby2_keywords) end end diff --git a/spec/ruby/core/marshal/dump_spec.rb b/spec/ruby/core/marshal/dump_spec.rb index a54a4c6735..079010e554 100644 --- a/spec/ruby/core/marshal/dump_spec.rb +++ b/spec/ruby/core/marshal/dump_spec.rb @@ -604,30 +604,4 @@ describe "Marshal.dump" do m = Mutex.new -> { Marshal.dump(m) }.should raise_error(TypeError) end - - ruby_version_is ''...'2.7' do - it "returns an untainted string if object is untainted" do - Marshal.dump(Object.new).tainted?.should be_false - end - - it "returns a tainted string if object is tainted" do - Marshal.dump(Object.new.taint).tainted?.should be_true - end - - it "returns a tainted string if nested object is tainted" do - Marshal.dump([[Object.new.taint]]).tainted?.should be_true - end - - it "returns a trusted string if object is trusted" do - Marshal.dump(Object.new).untrusted?.should be_false - end - - it "returns an untrusted string if object is untrusted" do - Marshal.dump(Object.new.untrust).untrusted?.should be_true - end - - it "returns an untrusted string if nested object is untrusted" do - Marshal.dump([[Object.new.untrust]]).untrusted?.should be_true - end - end end diff --git a/spec/ruby/core/marshal/shared/load.rb b/spec/ruby/core/marshal/shared/load.rb index b70bca55bf..98fae44296 100644 --- a/spec/ruby/core/marshal/shared/load.rb +++ b/spec/ruby/core/marshal/shared/load.rb @@ -306,89 +306,6 @@ describe :marshal_load, shared: true do end end - ruby_version_is ''...'2.7' do - it "returns an untainted object if source is untainted" do - x = Object.new - y = Marshal.send(@method, Marshal.dump(x)) - y.tainted?.should be_false - end - - describe "when source is tainted" do - it "returns a tainted object" do - x = Object.new - x.taint - s = Marshal.dump(x) - y = Marshal.send(@method, s) - y.tainted?.should be_true - - # note that round-trip via Marshal does not preserve - # the taintedness at each level of the nested structure - y = Marshal.send(@method, Marshal.dump([[x]])) - y.tainted?.should be_true - y.first.tainted?.should be_true - y.first.first.tainted?.should be_true - end - - it "does not taint Symbols" do - x = [:x] - y = Marshal.send(@method, Marshal.dump(x).taint) - y.tainted?.should be_true - y.first.tainted?.should be_false - end - - it "does not taint Fixnums" do - x = [1] - y = Marshal.send(@method, Marshal.dump(x).taint) - y.tainted?.should be_true - y.first.tainted?.should be_false - end - - it "does not taint Bignums" do - x = [bignum_value] - y = Marshal.send(@method, Marshal.dump(x).taint) - y.tainted?.should be_true - y.first.tainted?.should be_false - end - - it "does not taint Floats" do - x = [1.2] - y = Marshal.send(@method, Marshal.dump(x).taint) - y.tainted?.should be_true - y.first.tainted?.should be_false - end - end - - it "preserves taintedness of nested structure" do - x = Object.new - a = [[x]] - x.taint - y = Marshal.send(@method, Marshal.dump(a)) - y.tainted?.should be_true - y.first.tainted?.should be_true - y.first.first.tainted?.should be_true - end - - it "returns a trusted object if source is trusted" do - x = Object.new - y = Marshal.send(@method, Marshal.dump(x)) - y.untrusted?.should be_false - end - - it "returns an untrusted object if source is untrusted" do - x = Object.new - x.untrust - y = Marshal.send(@method, Marshal.dump(x)) - y.untrusted?.should be_true - - # note that round-trip via Marshal does not preserve - # the untrustedness at each level of the nested structure - y = Marshal.send(@method, Marshal.dump([[x]])) - y.untrusted?.should be_true - y.first.untrusted?.should be_true - y.first.first.untrusted?.should be_true - end - end - # Note: Ruby 1.9 should be compatible with older marshal format MarshalSpec::DATA.each do |description, (object, marshal, attributes)| it "loads a #{description}" do diff --git a/spec/ruby/core/matchdata/allocate_spec.rb b/spec/ruby/core/matchdata/allocate_spec.rb index 9f3ada4018..142ce639c2 100644 --- a/spec/ruby/core/matchdata/allocate_spec.rb +++ b/spec/ruby/core/matchdata/allocate_spec.rb @@ -1,10 +1,8 @@ require_relative '../../spec_helper' describe "MatchData.allocate" do - ruby_version_is "2.7" do - it "is undefined" do - # https://bugs.ruby-lang.org/issues/16294 - -> { MatchData.allocate }.should raise_error(NoMethodError) - end + it "is undefined" do + # https://bugs.ruby-lang.org/issues/16294 + -> { MatchData.allocate }.should raise_error(NoMethodError) end end diff --git a/spec/ruby/core/matchdata/element_reference_spec.rb b/spec/ruby/core/matchdata/element_reference_spec.rb index 3b976cb1c4..8965f902a0 100644 --- a/spec/ruby/core/matchdata/element_reference_spec.rb +++ b/spec/ruby/core/matchdata/element_reference_spec.rb @@ -16,6 +16,12 @@ describe "MatchData#[]" do it "supports accessors [start, length]" do /(.)(.)(\d+)(\d)/.match("THX1138.")[1, 2].should == %w|H X| /(.)(.)(\d+)(\d)/.match("THX1138.")[-3, 2].should == %w|X 113| + + # negative index is larger than the number of match values + /(.)(.)(\d+)(\d)/.match("THX1138.")[-30, 2].should == nil + + # length argument larger than number of match values is capped to match value length + /(.)(.)(\d+)(\d)/.match("THX1138.")[3, 10].should == %w|113 8| end it "supports ranges [start..end]" do diff --git a/spec/ruby/core/matchdata/post_match_spec.rb b/spec/ruby/core/matchdata/post_match_spec.rb index 1a4ca0a83f..d3aa4c8900 100644 --- a/spec/ruby/core/matchdata/post_match_spec.rb +++ b/spec/ruby/core/matchdata/post_match_spec.rb @@ -7,24 +7,6 @@ describe "MatchData#post_match" do $'.should == ': The Movie' end - ruby_version_is ''...'2.7' do - it "keeps taint status from the source string" do - str = "THX1138: The Movie" - str.taint - res = /(.)(.)(\d+)(\d)/.match(str).post_match - res.tainted?.should be_true - $'.tainted?.should be_true - end - - it "keeps untrusted status from the source string" do - str = "THX1138: The Movie" - str.untrust - res = /(.)(.)(\d+)(\d)/.match(str).post_match - res.untrusted?.should be_true - $'.untrusted?.should be_true - end - end - it "sets the encoding to the encoding of the source String" do str = "abc".force_encoding Encoding::EUC_JP str.match(/b/).post_match.encoding.should equal(Encoding::EUC_JP) diff --git a/spec/ruby/core/matchdata/pre_match_spec.rb b/spec/ruby/core/matchdata/pre_match_spec.rb index 9b50336c7d..b43be5fb41 100644 --- a/spec/ruby/core/matchdata/pre_match_spec.rb +++ b/spec/ruby/core/matchdata/pre_match_spec.rb @@ -7,24 +7,6 @@ describe "MatchData#pre_match" do $`.should == 'T' end - ruby_version_is ''...'2.7' do - it "keeps taint status from the source string" do - str = "THX1138: The Movie" - str.taint - res = /(.)(.)(\d+)(\d)/.match(str).pre_match - res.tainted?.should be_true - $`.tainted?.should be_true - end - - it "keeps untrusted status from the source string" do - str = "THX1138: The Movie" - str.untrust - res = /(.)(.)(\d+)(\d)/.match(str).pre_match - res.untrusted?.should be_true - $`.untrusted?.should be_true - end - end - it "sets the encoding to the encoding of the source String" do str = "abc".force_encoding Encoding::EUC_JP str.match(/b/).pre_match.encoding.should equal(Encoding::EUC_JP) diff --git a/spec/ruby/core/math/log2_spec.rb b/spec/ruby/core/math/log2_spec.rb index 1594f2d7af..3d4d41d130 100644 --- a/spec/ruby/core/math/log2_spec.rb +++ b/spec/ruby/core/math/log2_spec.rb @@ -15,7 +15,7 @@ describe "Math.log2" do Math.log2((2**301+45677544234809571)).should == 301.0 end - it "raises an Errno::EDOM if the argument is less than 0" do + it "raises Math::DomainError if the argument is less than 0" do -> { Math.log2(-1e-15) }.should raise_error( Math::DomainError) end diff --git a/spec/ruby/core/math/sqrt_spec.rb b/spec/ruby/core/math/sqrt_spec.rb index 779aea2a0a..918e7c3a17 100644 --- a/spec/ruby/core/math/sqrt_spec.rb +++ b/spec/ruby/core/math/sqrt_spec.rb @@ -27,6 +27,10 @@ describe "Math.sqrt" do it "accepts any argument that can be coerced with Float()" do Math.sqrt(MathSpecs::Float.new).should be_close(1.0, TOLERANCE) end + + it "raises a Math::DomainError when given a negative number" do + -> { Math.sqrt(-1) }.should raise_error(Math::DomainError) + end end describe "Math#sqrt" do diff --git a/spec/ruby/core/method/parameters_spec.rb b/spec/ruby/core/method/parameters_spec.rb index 3fdaf9ce6f..e6d51d1b4d 100644 --- a/spec/ruby/core/method/parameters_spec.rb +++ b/spec/ruby/core/method/parameters_spec.rb @@ -222,9 +222,18 @@ describe "Method#parameters" do m.method(:handled_via_method_missing).parameters.should == [[:rest]] end - it "adds nameless rest arg for \"star\" argument" do - m = MethodSpecs::Methods.new - m.method(:one_unnamed_splat).parameters.should == [[:rest]] + ruby_version_is '3.2' do + it "adds * rest arg for \"star\" argument" do + m = MethodSpecs::Methods.new + m.method(:one_unnamed_splat).parameters.should == [[:rest, :*]] + end + end + + ruby_version_is ''...'3.2' do + it "adds nameless rest arg for \"star\" argument" do + m = MethodSpecs::Methods.new + m.method(:one_unnamed_splat).parameters.should == [[:rest]] + end end it "returns the args and block for a splat and block argument" do diff --git a/spec/ruby/core/method/shared/to_s.rb b/spec/ruby/core/method/shared/to_s.rb index 0dcae41b59..6fdeaaf99c 100644 --- a/spec/ruby/core/method/shared/to_s.rb +++ b/spec/ruby/core/method/shared/to_s.rb @@ -24,19 +24,17 @@ describe :method_to_s, shared: true do @string.should =~ /\#bar/ end - ruby_version_is "2.7" do - it "returns a String containing method arguments" do - obj = MethodSpecs::Methods.new - obj.method(:zero).send(@method).should.include?("()") - obj.method(:one_req).send(@method).should.include?("(a)") - obj.method(:one_req_named).send(@method).should.include?("(a:)") - obj.method(:zero_with_block).send(@method).should.include?("(&blk)") - obj.method(:one_opt).send(@method).should.include?("(a=...)") - obj.method(:one_opt_named).send(@method).should.include?("(a: ...)") - obj.method(:zero_with_splat).send(@method).should.include?("(*a)") - obj.method(:zero_with_double_splat).send(@method).should.include?("(**a)") - obj.method(:one_req_one_opt_with_splat_and_block).send(@method).should.include?("(a, b=..., *c, &blk)") - end + it "returns a String containing method arguments" do + obj = MethodSpecs::Methods.new + obj.method(:zero).send(@method).should.include?("()") + obj.method(:one_req).send(@method).should.include?("(a)") + obj.method(:one_req_named).send(@method).should.include?("(a:)") + obj.method(:zero_with_block).send(@method).should.include?("(&blk)") + obj.method(:one_opt).send(@method).should.include?("(a=...)") + obj.method(:one_opt_named).send(@method).should.include?("(a: ...)") + obj.method(:zero_with_splat).send(@method).should.include?("(*a)") + obj.method(:zero_with_double_splat).send(@method).should.include?("(**a)") + obj.method(:one_req_one_opt_with_splat_and_block).send(@method).should.include?("(a, b=..., *c, &blk)") end it "returns a String containing the Module the method is defined in" do @@ -79,11 +77,9 @@ describe :method_to_s, shared: true do @string.should.start_with? "#<Method: #<MethodSpecs::MySub:0xXXXXXX>.bar" end - ruby_version_is '2.7' do - ruby_bug '#17428', '2.7'...'3.0' do - it "shows the metaclass and the owner for a Module instance method retrieved from a class" do - String.method(:include).inspect.should.start_with?("#<Method: #<Class:String>(Module)#include") - end + ruby_bug '#17428', ''...'3.0' do + it "shows the metaclass and the owner for a Module instance method retrieved from a class" do + String.method(:include).inspect.should.start_with?("#<Method: #<Class:String>(Module)#include") end end end diff --git a/spec/ruby/core/module/append_features_spec.rb b/spec/ruby/core/module/append_features_spec.rb index d960798eef..1724cde5d6 100644 --- a/spec/ruby/core/module/append_features_spec.rb +++ b/spec/ruby/core/module/append_features_spec.rb @@ -47,20 +47,6 @@ describe "Module#append_features" do end - ruby_version_is ''...'2.7' do - it "copies own tainted status to the given module" do - other = Module.new - Module.new.taint.send :append_features, other - other.tainted?.should be_true - end - - it "copies own untrusted status to the given module" do - other = Module.new - Module.new.untrust.send :append_features, other - other.untrusted?.should be_true - end - end - describe "when other is frozen" do before :each do @receiver = Module.new diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb index 1d61646db5..7e7e7a2139 100644 --- a/spec/ruby/core/module/autoload_spec.rb +++ b/spec/ruby/core/module/autoload_spec.rb @@ -18,16 +18,14 @@ describe "Module#autoload?" do ModuleSpecs::Autoload::Child.autoload?(:AnotherAutoload).should == "another_autoload.rb" end - ruby_version_is "2.7" do - it "returns nil if an ancestor defined that autoload but recursion is disabled" do - ModuleSpecs::Autoload::Parent.autoload :InheritedAutoload, "inherited_autoload.rb" - ModuleSpecs::Autoload::Child.autoload?(:InheritedAutoload, false).should be_nil - end + it "returns nil if an ancestor defined that autoload but recursion is disabled" do + ModuleSpecs::Autoload::Parent.autoload :InheritedAutoload, "inherited_autoload.rb" + ModuleSpecs::Autoload::Child.autoload?(:InheritedAutoload, false).should be_nil + end - it "returns the name of the file that will be loaded if recursion is disabled but the autoload is defined on the class itself" do - ModuleSpecs::Autoload::Child.autoload :ChildAutoload, "child_autoload.rb" - ModuleSpecs::Autoload::Child.autoload?(:ChildAutoload, false).should == "child_autoload.rb" - end + it "returns the name of the file that will be loaded if recursion is disabled but the autoload is defined on the class itself" do + ModuleSpecs::Autoload::Child.autoload :ChildAutoload, "child_autoload.rb" + ModuleSpecs::Autoload::Child.autoload?(:ChildAutoload, false).should == "child_autoload.rb" end end @@ -514,9 +512,7 @@ describe "Module#autoload" do it "does not load the file when accessing the constants table of the module" do ModuleSpecs::Autoload.autoload :P, @non_existent ModuleSpecs::Autoload.const_defined?(:P).should be_true - ruby_bug "[Bug #15780]", ""..."2.7" do - ModuleSpecs::Autoload.const_defined?("P").should be_true - end + ModuleSpecs::Autoload.const_defined?("P").should be_true end it "loads the file when opening a module that is the autoloaded constant" do diff --git a/spec/ruby/core/module/const_added_spec.rb b/spec/ruby/core/module/const_added_spec.rb new file mode 100644 index 0000000000..31ac6eb105 --- /dev/null +++ b/spec/ruby/core/module/const_added_spec.rb @@ -0,0 +1,125 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe "Module#const_added" do + ruby_version_is "3.2" do + it "is a private instance method" do + Module.should have_private_instance_method(:const_added) + end + + it "returns nil in the default implementation" do + Module.new do + const_added(:TEST).should == nil + end + end + + it "is called when a new constant is assigned on self" do + ScratchPad.record [] + + mod = Module.new do + def self.const_added(name) + ScratchPad << name + end + end + + mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1) + TEST = 1 + RUBY + + ScratchPad.recorded.should == [:TEST] + end + + it "is called when a new constant is assigned on self through const_set" do + ScratchPad.record [] + + mod = Module.new do + def self.const_added(name) + ScratchPad << name + end + end + + mod.const_set(:TEST, 1) + + ScratchPad.recorded.should == [:TEST] + end + + it "is called when a new module is defined under self" do + ScratchPad.record [] + + mod = Module.new do + def self.const_added(name) + ScratchPad << name + end + end + + mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1) + module SubModule + end + + module SubModule + end + RUBY + + ScratchPad.recorded.should == [:SubModule] + end + + it "is called when a new class is defined under self" do + ScratchPad.record [] + + mod = Module.new do + def self.const_added(name) + ScratchPad << name + end + end + + mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1) + class SubClass + end + + class SubClass + end + RUBY + + ScratchPad.recorded.should == [:SubClass] + end + + it "is called when an autoload is defined" do + ScratchPad.record [] + + mod = Module.new do + def self.const_added(name) + ScratchPad << name + end + end + + mod.autoload :Autoload, "foo" + ScratchPad.recorded.should == [:Autoload] + end + + it "is called with a precise caller location with the line of definition" do + ScratchPad.record [] + + mod = Module.new do + def self.const_added(name) + location = caller_locations(1, 1)[0] + ScratchPad << location.lineno + end + end + + line = __LINE__ + mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1) + TEST = 1 + + module SubModule + end + + class SubClass + end + RUBY + + mod.const_set(:CONST_SET, 1) + + ScratchPad.recorded.should == [line + 2, line + 4, line + 7, line + 11] + end + end +end diff --git a/spec/ruby/core/module/const_get_spec.rb b/spec/ruby/core/module/const_get_spec.rb index 9f9fafe5bb..69f181cf51 100644 --- a/spec/ruby/core/module/const_get_spec.rb +++ b/spec/ruby/core/module/const_get_spec.rb @@ -100,6 +100,16 @@ describe "Module#const_get" do ConstantSpecs.const_get("::CS_CONST1").should == :const1 end + it "accepts a toplevel scope qualifier when inherit is false" do + ConstantSpecs.const_get("::CS_CONST1", false).should == :const1 + -> { ConstantSpecs.const_get("CS_CONST1", false) }.should raise_error(NameError) + end + + it "returns a constant whose module is defined the the toplevel" do + ConstantSpecs.const_get("ConstantSpecsTwo::Foo").should == :cs_two_foo + ConstantSpecsThree.const_get("ConstantSpecsTwo::Foo").should == :cs_three_foo + end + it "accepts a scoped constant name" do ConstantSpecs.const_get("ClassA::CS_CONST10").should == :const10_10 end @@ -140,6 +150,10 @@ describe "Module#const_get" do Object.const_get('CSAutoloadD::InnerModule').name.should == 'CSAutoloadD::InnerModule' end + it "raises a NameError when the nested constant does not exist on the module but exists in Object" do + -> { Object.const_get('ConstantSpecs::CS_CONST1') }.should raise_error(NameError) + end + describe "with statically assigned constants" do it "searches the immediate class or module first" do ConstantSpecs::ClassA.const_get(:CS_CONST10).should == :const10_10 diff --git a/spec/ruby/core/module/const_source_location_spec.rb b/spec/ruby/core/module/const_source_location_spec.rb index 9e1f2c1c49..11a2e74756 100644 --- a/spec/ruby/core/module/const_source_location_spec.rb +++ b/spec/ruby/core/module/const_source_location_spec.rb @@ -6,215 +6,220 @@ describe "Module#const_source_location" do @constants_fixture_path = File.expand_path('../../fixtures/constants.rb', __dir__) end - ruby_version_is "2.7" do - describe "with dynamically assigned constants" do - it "searches a path in the immediate class or module first" do - ConstantSpecs::ClassA::CSL_CONST301 = :const301_1 - ConstantSpecs::ClassA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1] - - ConstantSpecs::ModuleA::CSL_CONST301 = :const301_2 - ConstantSpecs::ModuleA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1] + describe "with dynamically assigned constants" do + it "searches a path in the immediate class or module first" do + ConstantSpecs::ClassA::CSL_CONST301 = :const301_1 + ConstantSpecs::ClassA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1] - ConstantSpecs::ParentA::CSL_CONST301 = :const301_3 - ConstantSpecs::ParentA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1] + ConstantSpecs::ModuleA::CSL_CONST301 = :const301_2 + ConstantSpecs::ModuleA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1] - ConstantSpecs::ContainerA::ChildA::CSL_CONST301 = :const301_5 - ConstantSpecs::ContainerA::ChildA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1] - end + ConstantSpecs::ParentA::CSL_CONST301 = :const301_3 + ConstantSpecs::ParentA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1] - it "searches a path in a module included in the immediate class before the superclass" do - ConstantSpecs::ParentB::CSL_CONST302 = :const302_1 - ConstantSpecs::ModuleF::CSL_CONST302 = :const302_2 - ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST302).should == [__FILE__, __LINE__ - 1] - end - - it "searches a path in the superclass before a module included in the superclass" do - ConstantSpecs::ModuleE::CSL_CONST303 = :const303_1 - ConstantSpecs::ParentB::CSL_CONST303 = :const303_2 - ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST303).should == [__FILE__, __LINE__ - 1] - end - - it "searches a path in a module included in the superclass" do - ConstantSpecs::ModuleA::CSL_CONST304 = :const304_1 - ConstantSpecs::ModuleE::CSL_CONST304 = :const304_2 - ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST304).should == [__FILE__, __LINE__ - 1] - end - - it "searches a path in the superclass chain" do - ConstantSpecs::ModuleA::CSL_CONST305 = :const305 - ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST305).should == [__FILE__, __LINE__ - 1] - end - - it "returns path to a toplevel constant when the receiver is a Class" do - Object::CSL_CONST306 = :const306 - ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST306).should == [__FILE__, __LINE__ - 1] - end - - it "returns path to a toplevel constant when the receiver is a Module" do - Object::CSL_CONST308 = :const308 - ConstantSpecs.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 1] - ConstantSpecs::ModuleA.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 2] - end - - it "returns path to the updated value of a constant" do - ConstantSpecs::ClassB::CSL_CONST309 = :const309_1 - ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 1] + ConstantSpecs::ContainerA::ChildA::CSL_CONST301 = :const301_5 + ConstantSpecs::ContainerA::ChildA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1] + end - -> { - ConstantSpecs::ClassB::CSL_CONST309 = :const309_2 - }.should complain(/already initialized constant/) - ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 2] - end + it "searches a path in a module included in the immediate class before the superclass" do + ConstantSpecs::ParentB::CSL_CONST302 = :const302_1 + ConstantSpecs::ModuleF::CSL_CONST302 = :const302_2 + ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST302).should == [__FILE__, __LINE__ - 1] end - describe "with statically assigned constants" do - it "searches location path the immediate class or module first" do - ConstantSpecs::ClassA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_LINE] - ConstantSpecs::ModuleA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ModuleA::CS_CONST10_LINE] - ConstantSpecs::ParentA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST10_LINE] - ConstantSpecs::ContainerA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ContainerA::CS_CONST10_LINE] - ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ContainerA::ChildA::CS_CONST10_LINE] - end + it "searches a path in the superclass before a module included in the superclass" do + ConstantSpecs::ModuleE::CSL_CONST303 = :const303_1 + ConstantSpecs::ParentB::CSL_CONST303 = :const303_2 + ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST303).should == [__FILE__, __LINE__ - 1] + end - it "searches location path a module included in the immediate class before the superclass" do - ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST15).should == [@constants_fixture_path, ConstantSpecs::ModuleC::CS_CONST15_LINE] - end + it "searches a path in a module included in the superclass" do + ConstantSpecs::ModuleA::CSL_CONST304 = :const304_1 + ConstantSpecs::ModuleE::CSL_CONST304 = :const304_2 + ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST304).should == [__FILE__, __LINE__ - 1] + end - it "searches location path the superclass before a module included in the superclass" do - ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST11).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST11_LINE] - end + it "searches a path in the superclass chain" do + ConstantSpecs::ModuleA::CSL_CONST305 = :const305 + ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST305).should == [__FILE__, __LINE__ - 1] + end - it "searches location path a module included in the superclass" do - ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST12).should == [@constants_fixture_path, ConstantSpecs::ModuleB::CS_CONST12_LINE] - end + it "returns path to a toplevel constant when the receiver is a Class" do + Object::CSL_CONST306 = :const306 + ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST306).should == [__FILE__, __LINE__ - 1] + end - it "searches location path the superclass chain" do - ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST13).should == [@constants_fixture_path, ConstantSpecs::ModuleA::CS_CONST13_LINE] - end + it "returns path to a toplevel constant when the receiver is a Module" do + Object::CSL_CONST308 = :const308 + ConstantSpecs.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 1] + ConstantSpecs::ModuleA.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 2] + end - it "returns location path a toplevel constant when the receiver is a Class" do - ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE] - end + it "returns path to the updated value of a constant" do + ConstantSpecs::ClassB::CSL_CONST309 = :const309_1 + ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 1] - it "returns location path a toplevel constant when the receiver is a Module" do - ConstantSpecs.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE] - ConstantSpecs::ModuleA.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE] - end + -> { + ConstantSpecs::ClassB::CSL_CONST309 = :const309_2 + }.should complain(/already initialized constant/) + ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 2] end + end - it "return empty path if constant defined in C code" do - Object.const_source_location(:String).should == [] + describe "with statically assigned constants" do + it "searches location path the immediate class or module first" do + ConstantSpecs::ClassA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_LINE] + ConstantSpecs::ModuleA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ModuleA::CS_CONST10_LINE] + ConstantSpecs::ParentA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST10_LINE] + ConstantSpecs::ContainerA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ContainerA::CS_CONST10_LINE] + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ContainerA::ChildA::CS_CONST10_LINE] end - it "accepts a String or Symbol name" do - Object.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE] - Object.const_source_location("CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE] + it "searches location path a module included in the immediate class before the superclass" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST15).should == [@constants_fixture_path, ConstantSpecs::ModuleC::CS_CONST15_LINE] end - it "returns nil if no constant is defined in the search path" do - ConstantSpecs.const_source_location(:CS_CONSTX).should == nil + it "searches location path the superclass before a module included in the superclass" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST11).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST11_LINE] end - it "raises a NameError if the name does not start with a capital letter" do - -> { ConstantSpecs.const_source_location "name" }.should raise_error(NameError) + it "searches location path a module included in the superclass" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST12).should == [@constants_fixture_path, ConstantSpecs::ModuleB::CS_CONST12_LINE] end - it "raises a NameError if the name starts with a non-alphabetic character" do - -> { ConstantSpecs.const_source_location "__CONSTX__" }.should raise_error(NameError) - -> { ConstantSpecs.const_source_location "@CS_CONST1" }.should raise_error(NameError) - -> { ConstantSpecs.const_source_location "!CS_CONST1" }.should raise_error(NameError) + it "searches location path the superclass chain" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST13).should == [@constants_fixture_path, ConstantSpecs::ModuleA::CS_CONST13_LINE] end - it "raises a NameError if the name contains non-alphabetic characters except '_'" do - Object.const_source_location("CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE] - -> { ConstantSpecs.const_source_location "CS_CONST1=" }.should raise_error(NameError) - -> { ConstantSpecs.const_source_location "CS_CONST1?" }.should raise_error(NameError) + it "returns location path a toplevel constant when the receiver is a Class" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE] end - it "calls #to_str to convert the given name to a String" do - name = mock("ClassA") - name.should_receive(:to_str).and_return("ClassA") - ConstantSpecs.const_source_location(name).should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CLASS_A_LINE] + it "returns location path a toplevel constant when the receiver is a Module" do + ConstantSpecs.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE] + ConstantSpecs::ModuleA.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE] end + end - it "raises a TypeError if conversion to a String by calling #to_str fails" do - name = mock('123') - -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError) + it "return empty path if constant defined in C code" do + Object.const_source_location(:String).should == [] + end - name.should_receive(:to_str).and_return(123) - -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError) - end + it "accepts a String or Symbol name" do + Object.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE] + Object.const_source_location("CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE] + end - it "does not search the singleton class of a Class or Module" do - ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST14).should == nil - ConstantSpecs.const_source_location(:CS_CONST14).should == nil - end + it "returns nil if no constant is defined in the search path" do + ConstantSpecs.const_source_location(:CS_CONSTX).should == nil + end - it "does not search the containing scope" do - ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST20).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST20_LINE] - ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST5) == nil - end + it "raises a NameError if the name does not start with a capital letter" do + -> { ConstantSpecs.const_source_location "name" }.should raise_error(NameError) + end - it "returns nil if the constant is defined in the receiver's superclass and the inherit flag is false" do - ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST4, false).should == nil - end + it "raises a NameError if the name starts with a non-alphabetic character" do + -> { ConstantSpecs.const_source_location "__CONSTX__" }.should raise_error(NameError) + -> { ConstantSpecs.const_source_location "@CS_CONST1" }.should raise_error(NameError) + -> { ConstantSpecs.const_source_location "!CS_CONST1" }.should raise_error(NameError) + end - it "searches into the receiver superclasses if the inherit flag is true" do - ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST4, true).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST4_LINE] - end + it "raises a NameError if the name contains non-alphabetic characters except '_'" do + Object.const_source_location("CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE] + -> { ConstantSpecs.const_source_location "CS_CONST1=" }.should raise_error(NameError) + -> { ConstantSpecs.const_source_location "CS_CONST1?" }.should raise_error(NameError) + end - it "returns nil when the receiver is a Module, the constant is defined at toplevel and the inherit flag is false" do - ConstantSpecs::ModuleA.const_source_location(:CS_CONST1, false).should == nil - end + it "calls #to_str to convert the given name to a String" do + name = mock("ClassA") + name.should_receive(:to_str).and_return("ClassA") + ConstantSpecs.const_source_location(name).should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CLASS_A_LINE] + end - it "returns nil when the receiver is a Class, the constant is defined at toplevel and the inherit flag is false" do - ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST1, false).should == nil - end + it "raises a TypeError if conversion to a String by calling #to_str fails" do + name = mock('123') + -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError) - it "accepts a toplevel scope qualifier" do - ConstantSpecs.const_source_location("::CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE] - end + name.should_receive(:to_str).and_return(123) + -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError) + end - it "accepts a scoped constant name" do - ConstantSpecs.const_source_location("ClassA::CS_CONST10").should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_LINE] - end + it "does not search the singleton class of a Class or Module" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST14).should == nil + ConstantSpecs.const_source_location(:CS_CONST14).should == nil + end - it "raises a NameError if the name includes two successive scope separators" do - -> { ConstantSpecs.const_source_location("ClassA::::CS_CONST10") }.should raise_error(NameError) - end + it "does not search the containing scope" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST20).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST20_LINE] + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST5) == nil + end - it "raises a NameError if only '::' is passed" do - -> { ConstantSpecs.const_source_location("::") }.should raise_error(NameError) - end + it "returns nil if the constant is defined in the receiver's superclass and the inherit flag is false" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST4, false).should == nil + end - it "raises a NameError if a Symbol has a toplevel scope qualifier" do - -> { ConstantSpecs.const_source_location(:'::CS_CONST1') }.should raise_error(NameError) - end + it "searches into the receiver superclasses if the inherit flag is true" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST4, true).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST4_LINE] + end - it "raises a NameError if a Symbol is a scoped constant name" do - -> { ConstantSpecs.const_source_location(:'ClassA::CS_CONST10') }.should raise_error(NameError) - end + it "returns nil when the receiver is a Module, the constant is defined at toplevel and the inherit flag is false" do + ConstantSpecs::ModuleA.const_source_location(:CS_CONST1, false).should == nil + end - it "does search private constants path" do - ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE] - end + it "returns nil when the receiver is a Class, the constant is defined at toplevel and the inherit flag is false" do + ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST1, false).should == nil + end + + it "accepts a toplevel scope qualifier" do + ConstantSpecs.const_source_location("::CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE] + end + + it "accepts a scoped constant name" do + ConstantSpecs.const_source_location("ClassA::CS_CONST10").should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_LINE] + end + + it "returns updated location from const_set" do + mod = Module.new + const_line = __LINE__ + 1 + mod.const_set :Foo, 1 + mod.const_source_location(:Foo).should == [__FILE__, const_line] + end + + it "raises a NameError if the name includes two successive scope separators" do + -> { ConstantSpecs.const_source_location("ClassA::::CS_CONST10") }.should raise_error(NameError) + end + + it "raises a NameError if only '::' is passed" do + -> { ConstantSpecs.const_source_location("::") }.should raise_error(NameError) + end - context 'autoload' do - before :all do - ConstantSpecs.autoload :CSL_CONST1, "#{__dir__}/notexisting.rb" - @line = __LINE__ - 1 - end + it "raises a NameError if a Symbol has a toplevel scope qualifier" do + -> { ConstantSpecs.const_source_location(:'::CS_CONST1') }.should raise_error(NameError) + end - it 'returns the autoload location while not resolved' do - ConstantSpecs.const_source_location('CSL_CONST1').should == [__FILE__, @line] - end + it "raises a NameError if a Symbol is a scoped constant name" do + -> { ConstantSpecs.const_source_location(:'ClassA::CS_CONST10') }.should raise_error(NameError) + end + + it "does search private constants path" do + ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE] + end + + context 'autoload' do + before :all do + ConstantSpecs.autoload :CSL_CONST1, "#{__dir__}/notexisting.rb" + @line = __LINE__ - 1 + end + + it 'returns the autoload location while not resolved' do + ConstantSpecs.const_source_location('CSL_CONST1').should == [__FILE__, @line] + end - it 'returns where the constant was resolved when resolved' do - file = fixture(__FILE__, 'autoload_location.rb') - ConstantSpecs.autoload :CONST_LOCATION, file - line = ConstantSpecs::CONST_LOCATION - ConstantSpecs.const_source_location('CONST_LOCATION').should == [file, line] - end + it 'returns where the constant was resolved when resolved' do + file = fixture(__FILE__, 'autoload_location.rb') + ConstantSpecs.autoload :CONST_LOCATION, file + line = ConstantSpecs::CONST_LOCATION + ConstantSpecs.const_source_location('CONST_LOCATION').should == [file, line] end end end diff --git a/spec/ruby/core/module/deprecate_constant_spec.rb b/spec/ruby/core/module/deprecate_constant_spec.rb index faacbea03e..aabef934c4 100644 --- a/spec/ruby/core/module/deprecate_constant_spec.rb +++ b/spec/ruby/core/module/deprecate_constant_spec.rb @@ -31,17 +31,15 @@ describe "Module#deprecate_constant" do -> { @module.const_get :PRIVATE }.should complain(/warning: constant .+::PRIVATE is deprecated/) end - ruby_version_is '2.7' do - it "does not warn if Warning[:deprecated] is false" do - @module.deprecate_constant :PUBLIC1 - - deprecated = Warning[:deprecated] - begin - Warning[:deprecated] = false - -> { @module::PUBLIC1 }.should_not complain - ensure - Warning[:deprecated] = deprecated - end + it "does not warn if Warning[:deprecated] is false" do + @module.deprecate_constant :PUBLIC1 + + deprecated = Warning[:deprecated] + begin + Warning[:deprecated] = false + -> { @module::PUBLIC1 }.should_not complain + ensure + Warning[:deprecated] = deprecated end end end diff --git a/spec/ruby/core/module/extend_object_spec.rb b/spec/ruby/core/module/extend_object_spec.rb index e66b87efef..1fd1abc0b5 100644 --- a/spec/ruby/core/module/extend_object_spec.rb +++ b/spec/ruby/core/module/extend_object_spec.rb @@ -42,20 +42,6 @@ describe "Module#extend_object" do ScratchPad.recorded.should == :extended end - ruby_version_is ''...'2.7' do - it "does not copy own tainted status to the given object" do - other = Object.new - Module.new.taint.send :extend_object, other - other.tainted?.should be_false - end - - it "does not copy own untrusted status to the given object" do - other = Object.new - Module.new.untrust.send :extend_object, other - other.untrusted?.should be_false - end - end - describe "when given a frozen object" do before :each do @receiver = Module.new diff --git a/spec/ruby/core/module/include_spec.rb b/spec/ruby/core/module/include_spec.rb index 128b9af2bf..c47e052d22 100644 --- a/spec/ruby/core/module/include_spec.rb +++ b/spec/ruby/core/module/include_spec.rb @@ -532,6 +532,27 @@ describe "Module#include" do B.foo.should == 'n' end end + + it "overrides a previous super method call" do + c1 = Class.new do + def foo + [:c1] + end + end + c2 = Class.new(c1) do + def foo + [:c2] + super + end + end + c2.new.foo.should == [:c2, :c1] + m = Module.new do + def foo + [:m1] + end + end + c2.include(m) + c2.new.foo.should == [:c2, :m1] + 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 ca9106a973..b78bbfcc80 100644 --- a/spec/ruby/core/module/name_spec.rb +++ b/spec/ruby/core/module/name_spec.rb @@ -118,27 +118,13 @@ describe "Module#name" do m::N.name.should == "ModuleSpecs::Anonymous::E::N" end - ruby_version_is ""..."2.7" do - it "returns a mutable string" do - ModuleSpecs.name.frozen?.should be_false - end - - it "returns a mutable string that when mutated does not modify the original module name" do - ModuleSpecs.name << "foo" - - ModuleSpecs.name.should == "ModuleSpecs" - end + it "returns a frozen String" do + ModuleSpecs.name.should.frozen? end - ruby_version_is "2.7" do - it "returns a frozen String" do - ModuleSpecs.name.should.frozen? - end - - it "always returns the same String for a given Module" do - s1 = ModuleSpecs.name - s2 = ModuleSpecs.name - s1.should equal(s2) - end + it "always returns the same String for a given Module" do + s1 = ModuleSpecs.name + s2 = ModuleSpecs.name + s1.should equal(s2) end end diff --git a/spec/ruby/core/module/prepend_features_spec.rb b/spec/ruby/core/module/prepend_features_spec.rb index 2d1fa713b7..09c15c5c15 100644 --- a/spec/ruby/core/module/prepend_features_spec.rb +++ b/spec/ruby/core/module/prepend_features_spec.rb @@ -28,20 +28,6 @@ describe "Module#prepend_features" do }.should raise_error(ArgumentError) end - ruby_version_is ''...'2.7' do - it "copies own tainted status to the given module" do - other = Module.new - Module.new.taint.send :prepend_features, other - other.tainted?.should be_true - end - - it "copies own untrusted status to the given module" do - other = Module.new - Module.new.untrust.send :prepend_features, other - other.untrusted?.should be_true - end - end - it "clears caches of the given module" do parent = Class.new do def bar; :bar; end diff --git a/spec/ruby/core/module/prepend_spec.rb b/spec/ruby/core/module/prepend_spec.rb index 04cc27d472..d636e023ed 100644 --- a/spec/ruby/core/module/prepend_spec.rb +++ b/spec/ruby/core/module/prepend_spec.rb @@ -499,7 +499,7 @@ describe "Module#prepend" do c.dup.new.should be_kind_of(m) end - ruby_version_is '0'...'3.0' do + ruby_version_is ''...'3.0' do it "keeps the module in the chain when dupping an intermediate module" do m1 = Module.new { def calc(x) x end } m2 = Module.new { prepend(m1) } diff --git a/spec/ruby/core/module/refine_spec.rb b/spec/ruby/core/module/refine_spec.rb index f6751a42da..841900cf87 100644 --- a/spec/ruby/core/module/refine_spec.rb +++ b/spec/ruby/core/module/refine_spec.rb @@ -243,28 +243,30 @@ describe "Module#refine" do result.should == "foo from singleton class" end - it "looks in the included modules for builtin methods" do - result = ruby_exe(<<-RUBY) - a = Module.new do - def /(other) quo(other) end - end + ruby_version_is ""..."3.2" do + it "looks in the included modules for builtin methods" do + result = ruby_exe(<<-RUBY) + a = Module.new do + def /(other) quo(other) end + end - refinement = Module.new do - refine Integer do - include a + refinement = Module.new do + refine Integer do + include a + end end - end - result = nil - Module.new do - using refinement - result = 1 / 2 - end + result = nil + Module.new do + using refinement + result = 1 / 2 + end - print result.class - RUBY + print result.class + RUBY - result.should == 'Rational' + result.should == 'Rational' + end end it "looks in later included modules of the refined module first" do @@ -516,115 +518,55 @@ describe "Module#refine" do result.should == "hello from refinement" end - ruby_version_is "" ... "2.7" do - it "is not honored by Kernel#method" do - klass = Class.new - refinement = Module.new do - refine klass do - def foo; end - end + it "is honored by Kernel#method" do + klass = Class.new + refinement = Module.new do + refine klass do + def foo; end end - - -> { - Module.new do - using refinement - klass.new.method(:foo) - end - }.should raise_error(NameError, /undefined method `foo'/) end - end - - ruby_version_is "2.7" do - it "is honored by Kernel#method" do - klass = Class.new - refinement = Module.new do - refine klass do - def foo; end - end - end - result = nil - Module.new do - using refinement - result = klass.new.method(:foo).class - end - - result.should == Method + result = nil + Module.new do + using refinement + result = klass.new.method(:foo).class end - end - ruby_version_is "" ... "2.7" do - it "is not honored by Kernel#public_method" do - klass = Class.new - refinement = Module.new do - refine klass do - def foo; end - end - end - - -> { - Module.new do - using refinement - klass.new.public_method(:foo) - end - }.should raise_error(NameError, /undefined method `foo'/) - end + result.should == Method end - ruby_version_is "2.7" do - it "is honored by Kernel#public_method" do - klass = Class.new - refinement = Module.new do - refine klass do - def foo; end - end - end - - result = nil - Module.new do - using refinement - result = klass.new.public_method(:foo).class + it "is honored by Kernel#public_method" do + klass = Class.new + refinement = Module.new do + refine klass do + def foo; end end - - result.should == Method end - end - ruby_version_is "" ... "2.7" do - it "is not honored by Kernel#instance_method" do - klass = Class.new - refinement = Module.new do - refine klass do - def foo; end - end - end - - -> { - Module.new do - using refinement - klass.instance_method(:foo) - end - }.should raise_error(NameError, /undefined method `foo'/) + result = nil + Module.new do + using refinement + result = klass.new.public_method(:foo).class end - end - ruby_version_is "2.7" do - it "is honored by Kernel#instance_method" do - klass = Class.new - refinement = Module.new do - refine klass do - def foo; end - end - end + result.should == Method + end - result = nil - Module.new do - using refinement - result = klass.instance_method(:foo).class + it "is honored by Kernel#instance_method" do + klass = Class.new + refinement = Module.new do + refine klass do + def foo; end end + end - result.should == UnboundMethod + result = nil + Module.new do + using refinement + result = klass.instance_method(:foo).class end + + result.should == UnboundMethod end it "is honored by Kernel#respond_to?" do diff --git a/spec/ruby/core/module/ruby2_keywords_spec.rb b/spec/ruby/core/module/ruby2_keywords_spec.rb index 34c45cb1bc..80a99e2624 100644 --- a/spec/ruby/core/module/ruby2_keywords_spec.rb +++ b/spec/ruby/core/module/ruby2_keywords_spec.rb @@ -1,112 +1,319 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is "2.7" do - describe "Module#ruby2_keywords" do - it "marks the final hash argument as keyword hash" do - obj = Object.new +describe "Module#ruby2_keywords" do + class << self + ruby2_keywords def mark(*args) + args + end + end - obj.singleton_class.class_exec do - def foo(*a) a.last end - ruby2_keywords :foo + it "marks the final hash argument as keyword hash" do + last = mark(1, 2, a: "a").last + Hash.ruby2_keywords_hash?(last).should == true + end + + it "makes a copy of the hash and only marks the copy as keyword hash" do + obj = Object.new + obj.singleton_class.class_exec do + def regular(*args) + args.last end + end - last = obj.foo(1, 2, a: "a") - Hash.ruby2_keywords_hash?(last).should == true + h = {a: 1} + ruby_version_is "3.0" do + obj.regular(**h).should.equal?(h) end - ruby_version_is "2.7" ... "3.0" do - it "fixes delegation warnings when calling a method accepting keywords" do - obj = Object.new + last = mark(**h).last + Hash.ruby2_keywords_hash?(last).should == true + Hash.ruby2_keywords_hash?(h).should == false - obj.singleton_class.class_exec do - def foo(*a) bar(*a) end - def bar(*a, **b) end - end + last2 = mark(**last).last # last is already marked + Hash.ruby2_keywords_hash?(last2).should == true + Hash.ruby2_keywords_hash?(last).should == true + last2.should_not.equal?(last) + Hash.ruby2_keywords_hash?(h).should == false + end - -> { obj.foo(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/) + it "makes a copy and unmark the Hash when calling a method taking (arg)" do + obj = Object.new + obj.singleton_class.class_exec do + def single(arg) + arg + end + end - obj.singleton_class.class_exec do - ruby2_keywords :foo - end + h = { a: 1 } + args = mark(**h) + marked = args.last + Hash.ruby2_keywords_hash?(marked).should == true + + after_usage = obj.single(*args) + after_usage.should == h + after_usage.should_not.equal?(h) + after_usage.should_not.equal?(marked) + Hash.ruby2_keywords_hash?(after_usage).should == false + Hash.ruby2_keywords_hash?(marked).should == true + end - -> { obj.foo(1, 2, {a: "a"}) }.should_not complain + it "makes a copy and unmark the Hash when calling a method taking (**kw)" do + obj = Object.new + obj.singleton_class.class_exec do + def kwargs(**kw) + kw end end - it "returns nil" do - obj = Object.new + h = { a: 1 } + args = mark(**h) + marked = args.last + Hash.ruby2_keywords_hash?(marked).should == true + + after_usage = obj.kwargs(*args) + after_usage.should == h + after_usage.should_not.equal?(h) + after_usage.should_not.equal?(marked) + Hash.ruby2_keywords_hash?(after_usage).should == false + Hash.ruby2_keywords_hash?(marked).should == true + end + ruby_version_is "3.2" do + it "makes a copy and unmark the Hash when calling a method taking (*args)" do + obj = Object.new obj.singleton_class.class_exec do - def foo(*a) end + def splat(*args) + args.last + end - ruby2_keywords(:foo).should == nil + def splat1(arg, *args) + args.last + end + + def proc_call(*args) + -> *a { a.last }.call(*args) + end end + + h = { a: 1 } + args = mark(**h) + marked = args.last + Hash.ruby2_keywords_hash?(marked).should == true + + after_usage = obj.splat(*args) + after_usage.should == h + after_usage.should_not.equal?(h) + after_usage.should_not.equal?(marked) + Hash.ruby2_keywords_hash?(after_usage).should == false + Hash.ruby2_keywords_hash?(marked).should == true + + args = mark(1, **h) + marked = args.last + after_usage = obj.splat1(*args) + after_usage.should == h + after_usage.should_not.equal?(h) + after_usage.should_not.equal?(marked) + Hash.ruby2_keywords_hash?(after_usage).should == false + Hash.ruby2_keywords_hash?(marked).should == true + + args = mark(**h) + marked = args.last + after_usage = obj.proc_call(*args) + after_usage.should == h + after_usage.should_not.equal?(h) + after_usage.should_not.equal?(marked) + Hash.ruby2_keywords_hash?(after_usage).should == false + Hash.ruby2_keywords_hash?(marked).should == true + + args = mark(**h) + marked = args.last + after_usage = obj.send(:splat, *args) + after_usage.should == h + after_usage.should_not.equal?(h) + after_usage.should_not.equal?(marked) + Hash.ruby2_keywords_hash?(after_usage).should == false + Hash.ruby2_keywords_hash?(marked).should == true end + end - it "raises NameError when passed not existing method name" do + ruby_version_is ""..."3.2" do + # https://bugs.ruby-lang.org/issues/18625 + it "does NOT copy the Hash when calling a method taking (*args)" do obj = Object.new + obj.singleton_class.class_exec do + def splat(*args) + args.last + end + + def splat1(arg, *args) + args.last + end - -> { - obj.singleton_class.class_exec do - ruby2_keywords :not_existing + def proc_call(*args) + -> *a { a.last }.call(*args) end - }.should raise_error(NameError, /undefined method `not_existing'/) + end + + h = { a: 1 } + args = mark(**h) + marked = args.last + Hash.ruby2_keywords_hash?(marked).should == true + + after_usage = obj.splat(*args) + after_usage.should == h + after_usage.should_not.equal?(h) + after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625 + Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625 + Hash.ruby2_keywords_hash?(marked).should == true + + args = mark(1, **h) + marked = args.last + after_usage = obj.splat1(*args) + after_usage.should == h + after_usage.should_not.equal?(h) + after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625 + Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625 + Hash.ruby2_keywords_hash?(marked).should == true + + args = mark(**h) + marked = args.last + after_usage = obj.proc_call(*args) + after_usage.should == h + after_usage.should_not.equal?(h) + after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625 + Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625 + Hash.ruby2_keywords_hash?(marked).should == true + + args = mark(**h) + marked = args.last + after_usage = obj.send(:splat, *args) + after_usage.should == h + after_usage.should_not.equal?(h) + send_copies = RUBY_ENGINE == "ruby" # inconsistent with Proc#call above for CRuby + after_usage.equal?(marked).should == !send_copies + Hash.ruby2_keywords_hash?(after_usage).should == !send_copies + Hash.ruby2_keywords_hash?(marked).should == true end + end + + it "applies to the underlying method and applies across aliasing" do + obj = Object.new + + obj.singleton_class.class_exec do + def foo(*a) a.last end + alias_method :bar, :foo + ruby2_keywords :foo + + def baz(*a) a.last end + ruby2_keywords :baz + alias_method :bob, :baz + end + + last = obj.foo(1, 2, a: "a") + Hash.ruby2_keywords_hash?(last).should == true + + last = obj.bar(1, 2, a: "a") + Hash.ruby2_keywords_hash?(last).should == true - it "acceps String as well" do + last = obj.baz(1, 2, a: "a") + Hash.ruby2_keywords_hash?(last).should == true + + last = obj.bob(1, 2, a: "a") + Hash.ruby2_keywords_hash?(last).should == true + end + + ruby_version_is ""..."3.0" do + it "fixes delegation warnings when calling a method accepting keywords" do obj = Object.new obj.singleton_class.class_exec do - def foo(*a) a.last end - ruby2_keywords "foo" + def foo(*a) bar(*a) end + def bar(*a, **b) end end - last = obj.foo(1, 2, a: "a") - Hash.ruby2_keywords_hash?(last).should == true - end + -> { obj.foo(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/) - it "raises TypeError when passed not Symbol or String" do - obj = Object.new + obj.singleton_class.class_exec do + ruby2_keywords :foo + end - -> { - obj.singleton_class.class_exec do - ruby2_keywords Object.new - end - }.should raise_error(TypeError, /is not a symbol nor a string/) + -> { obj.foo(1, 2, {a: "a"}) }.should_not complain end + end - it "prints warning when a method does not accept argument splat" do - obj = Object.new - def obj.foo(a, b, c) end + it "returns nil" do + obj = Object.new - -> { - obj.singleton_class.class_exec do - ruby2_keywords :foo - end - }.should complain(/Skipping set of ruby2_keywords flag for/) + obj.singleton_class.class_exec do + def foo(*a) end + + ruby2_keywords(:foo).should == nil end + end - it "prints warning when a method accepts keywords" do - obj = Object.new - def obj.foo(a:, b:) end + it "raises NameError when passed not existing method name" do + obj = Object.new - -> { - obj.singleton_class.class_exec do - ruby2_keywords :foo - end - }.should complain(/Skipping set of ruby2_keywords flag for/) - end + -> { + obj.singleton_class.class_exec do + ruby2_keywords :not_existing + end + }.should raise_error(NameError, /undefined method `not_existing'/) + end - it "prints warning when a method accepts keyword splat" do - obj = Object.new - def obj.foo(**a) end + it "accepts String as well" do + obj = Object.new - -> { - obj.singleton_class.class_exec do - ruby2_keywords :foo - end - }.should complain(/Skipping set of ruby2_keywords flag for/) + obj.singleton_class.class_exec do + def foo(*a) a.last end + ruby2_keywords "foo" end + + last = obj.foo(1, 2, a: "a") + Hash.ruby2_keywords_hash?(last).should == true + end + + it "raises TypeError when passed not Symbol or String" do + obj = Object.new + + -> { + obj.singleton_class.class_exec do + ruby2_keywords Object.new + end + }.should raise_error(TypeError, /is not a symbol nor a string/) + end + + it "prints warning when a method does not accept argument splat" do + obj = Object.new + def obj.foo(a, b, c) end + + -> { + obj.singleton_class.class_exec do + ruby2_keywords :foo + end + }.should complain(/Skipping set of ruby2_keywords flag for/) + end + + it "prints warning when a method accepts keywords" do + obj = Object.new + def obj.foo(a:, b:) end + + -> { + obj.singleton_class.class_exec do + ruby2_keywords :foo + end + }.should complain(/Skipping set of ruby2_keywords flag for/) + end + + it "prints warning when a method accepts keyword splat" do + obj = Object.new + def obj.foo(**a) end + + -> { + obj.singleton_class.class_exec do + ruby2_keywords :foo + end + }.should complain(/Skipping set of ruby2_keywords flag for/) end end diff --git a/spec/ruby/core/nil/match_spec.rb b/spec/ruby/core/nil/match_spec.rb index 2e2b5d1c1b..bc1c591793 100644 --- a/spec/ruby/core/nil/match_spec.rb +++ b/spec/ruby/core/nil/match_spec.rb @@ -2,7 +2,7 @@ require_relative '../../spec_helper' describe "NilClass#=~" do it "returns nil matching any object" do - o = Object.new + o = nil suppress_warning do (o =~ /Object/).should be_nil diff --git a/spec/ruby/core/nil/to_s_spec.rb b/spec/ruby/core/nil/to_s_spec.rb index 283d26477a..fa0b929677 100644 --- a/spec/ruby/core/nil/to_s_spec.rb +++ b/spec/ruby/core/nil/to_s_spec.rb @@ -5,13 +5,11 @@ describe "NilClass#to_s" do nil.to_s.should == "" end - ruby_version_is "2.7" do - it "returns a frozen string" do - nil.to_s.should.frozen? - end + it "returns a frozen string" do + nil.to_s.should.frozen? + end - it "always returns the same string" do - nil.to_s.should equal(nil.to_s) - end + it "always returns the same string" do + nil.to_s.should equal(nil.to_s) end end diff --git a/spec/ruby/core/numeric/quo_spec.rb b/spec/ruby/core/numeric/quo_spec.rb index b4a23fd476..67bacee9b5 100644 --- a/spec/ruby/core/numeric/quo_spec.rb +++ b/spec/ruby/core/numeric/quo_spec.rb @@ -20,7 +20,7 @@ describe "Numeric#quo" do -> { 10.quo(0) }.should raise_error(ZeroDivisionError) -> { -10.quo(0) }.should raise_error(ZeroDivisionError) -> { bignum_value.quo(0) }.should raise_error(ZeroDivisionError) - -> { -bignum_value.quo(0) }.should raise_error(ZeroDivisionError) + -> { (-bignum_value).quo(0) }.should raise_error(ZeroDivisionError) end it "calls #to_r to convert the object to a Rational" do diff --git a/spec/ruby/core/numeric/shared/step.rb b/spec/ruby/core/numeric/shared/step.rb index a4fe74f9db..8b1a7bf307 100644 --- a/spec/ruby/core/numeric/shared/step.rb +++ b/spec/ruby/core/numeric/shared/step.rb @@ -256,7 +256,6 @@ describe :numeric_step, :shared => true do end describe "when no block is given" do - step_enum_class = Enumerator step_enum_class = Enumerator::ArithmeticSequence ruby_version_is ""..."3.0" do diff --git a/spec/ruby/core/numeric/step_spec.rb b/spec/ruby/core/numeric/step_spec.rb index 03af8b0e4d..095c474fec 100644 --- a/spec/ruby/core/numeric/step_spec.rb +++ b/spec/ruby/core/numeric/step_spec.rb @@ -21,7 +21,6 @@ describe "Numeric#step" do it_behaves_like :numeric_step, :step describe "when no block is given" do - step_enum_class = Enumerator step_enum_class = Enumerator::ArithmeticSequence ruby_version_is ""..."3.0" do @@ -61,7 +60,6 @@ describe "Numeric#step" do end end end - end describe 'with keyword arguments' do diff --git a/spec/ruby/core/objectspace/weakmap/element_set_spec.rb b/spec/ruby/core/objectspace/weakmap/element_set_spec.rb index 2b53650148..8588877158 100644 --- a/spec/ruby/core/objectspace/weakmap/element_set_spec.rb +++ b/spec/ruby/core/objectspace/weakmap/element_set_spec.rb @@ -17,45 +17,22 @@ describe "ObjectSpace::WeakMap#[]=" do map[key1].should == ref1 end - ruby_version_is ""..."2.7" do - it "does not accept primitive or frozen keys or values" do - map = ObjectSpace::WeakMap.new - x = Object.new - -> { map[true] = x }.should raise_error(ArgumentError) - -> { map[false] = x }.should raise_error(ArgumentError) - -> { map[nil] = x }.should raise_error(ArgumentError) - -> { map[42] = x }.should raise_error(ArgumentError) - -> { map[:foo] = x }.should raise_error(ArgumentError) - -> { map[x] = true }.should raise_error(ArgumentError) - -> { map[x] = false }.should raise_error(ArgumentError) - -> { map[x] = nil }.should raise_error(ArgumentError) - -> { map[x] = 42 }.should raise_error(ArgumentError) - -> { map[x] = :foo }.should raise_error(ArgumentError) - - y = Object.new.freeze - -> { map[x] = y}.should raise_error(FrozenError) - -> { map[y] = x}.should raise_error(FrozenError) - end - end - - ruby_version_is "2.7" do - it "accepts primitive or frozen keys or values" do - map = ObjectSpace::WeakMap.new - x = Object.new - should_accept(map, true, x) - should_accept(map, false, x) - should_accept(map, nil, x) - should_accept(map, 42, x) - should_accept(map, :foo, x) + it "accepts primitive or frozen keys or values" do + map = ObjectSpace::WeakMap.new + x = Object.new + should_accept(map, true, x) + should_accept(map, false, x) + should_accept(map, nil, x) + should_accept(map, 42, x) + should_accept(map, :foo, x) - should_accept(map, x, true) - should_accept(map, x, false) - should_accept(map, x, 42) - should_accept(map, x, :foo) + should_accept(map, x, true) + should_accept(map, x, false) + should_accept(map, x, 42) + should_accept(map, x, :foo) - y = Object.new.freeze - should_accept(map, x, y) - should_accept(map, y, x) - end + y = Object.new.freeze + should_accept(map, x, y) + should_accept(map, y, x) end end diff --git a/spec/ruby/core/objectspace/weakmap/shared/include.rb b/spec/ruby/core/objectspace/weakmap/shared/include.rb index f9c174b6d1..1770eeac8b 100644 --- a/spec/ruby/core/objectspace/weakmap/shared/include.rb +++ b/spec/ruby/core/objectspace/weakmap/shared/include.rb @@ -20,15 +20,11 @@ describe :weakmap_include?, shared: true do map.send(@method, key2).should == false end - ruby_version_is "2.7" do - ruby_bug "#16826", "2.7.0"..."2.7.2" do - it "reports true if the pair exists and the value is nil" do - map = ObjectSpace::WeakMap.new - key = Object.new - map[key] = nil - map.size.should == 1 - map.send(@method, key).should == true - end - end + it "reports true if the pair exists and the value is nil" do + map = ObjectSpace::WeakMap.new + key = Object.new + map[key] = nil + map.size.should == 1 + map.send(@method, key).should == true end end diff --git a/spec/ruby/core/proc/block_pass_spec.rb b/spec/ruby/core/proc/block_pass_spec.rb index 99255139d4..411c0bf3db 100644 --- a/spec/ruby/core/proc/block_pass_spec.rb +++ b/spec/ruby/core/proc/block_pass_spec.rb @@ -19,25 +19,3 @@ describe "Proc as a block pass argument" do p.should == p2 end end - -ruby_version_is ""..."2.7" do - describe "Proc as an implicit block pass argument" do - def revivify - Proc.new - end - - it "remains the same object if re-vivified by the target method" do - p = Proc.new {} - p2 = revivify(&p) - p.should equal p2 - p.should == p2 - end - - it "remains the same object if reconstructed with Proc.new" do - p = Proc.new {} - p2 = Proc.new(&p) - p.should equal p2 - p.should == p2 - end - end -end diff --git a/spec/ruby/core/proc/compose_spec.rb b/spec/ruby/core/proc/compose_spec.rb index 803a32af7b..94814d11bc 100644 --- a/spec/ruby/core/proc/compose_spec.rb +++ b/spec/ruby/core/proc/compose_spec.rb @@ -61,9 +61,17 @@ describe "Proc#<<" do g = proc { |x| x + x } lambda_proc = -> x { x } + # lambda << proc (f << g).is_a?(Proc).should == true (f << g).should_not.lambda? + + # lambda << lambda + (f << lambda_proc).is_a?(Proc).should == true (f << lambda_proc).should.lambda? + + # proc << lambda + (g << f).is_a?(Proc).should == true + (g << f).should.lambda? end end diff --git a/spec/ruby/core/proc/eql_spec.rb b/spec/ruby/core/proc/eql_spec.rb index 5f38af72d9..06aee272e5 100644 --- a/spec/ruby/core/proc/eql_spec.rb +++ b/spec/ruby/core/proc/eql_spec.rb @@ -2,7 +2,7 @@ require_relative '../../spec_helper' require_relative 'shared/equal' describe "Proc#eql?" do - ruby_version_is "0"..."3.0" do + ruby_version_is ""..."3.0" do it_behaves_like :proc_equal_undefined, :eql? end diff --git a/spec/ruby/core/proc/equal_value_spec.rb b/spec/ruby/core/proc/equal_value_spec.rb index 4c336331d7..ee88c0537d 100644 --- a/spec/ruby/core/proc/equal_value_spec.rb +++ b/spec/ruby/core/proc/equal_value_spec.rb @@ -2,7 +2,7 @@ require_relative '../../spec_helper' require_relative 'shared/equal' describe "Proc#==" do - ruby_version_is "0"..."3.0" do + ruby_version_is ""..."3.0" do it_behaves_like :proc_equal_undefined, :== end diff --git a/spec/ruby/core/proc/new_spec.rb b/spec/ruby/core/proc/new_spec.rb index 6d5eb67a4b..cb52e94f44 100644 --- a/spec/ruby/core/proc/new_spec.rb +++ b/spec/ruby/core/proc/new_spec.rb @@ -94,20 +94,6 @@ describe "Proc.new with an associated block" do obj.first.should == :a obj.second.should == 2 end - - ruby_version_is ""..."2.7" do - it "returns a new Proc instance from the block passed to the containing method" do - prc = ProcSpecs.new_proc_in_method { "hello" } - prc.should be_an_instance_of(Proc) - prc.call.should == "hello" - end - - it "returns a new Proc instance from the block passed to the containing method" do - prc = ProcSpecs.new_proc_subclass_in_method { "hello" } - prc.should be_an_instance_of(ProcSpecs::ProcSubclass) - prc.call.should == "hello" - end - end end describe "Proc.new with a block argument" do @@ -180,30 +166,7 @@ describe "Proc.new without a block" do -> { ProcSpecs.new_proc_subclass_in_method }.should raise_error(ArgumentError) end - ruby_version_is ""..."2.7" do - it "uses the implicit block from an enclosing method" do - def some_method - Proc.new - end - - prc = some_method { "hello" } - - prc.call.should == "hello" - end - - it "uses the implicit block from an enclosing method when called inside a block" do - def some_method - proc do |&block| - Proc.new - end.call { "failing" } - end - prc = some_method { "hello" } - - prc.call.should == "hello" - end - end - - ruby_version_is "2.7"..."3.0" do + ruby_version_is ""..."3.0" do it "can be created if invoked from within a method with a block" do -> { ProcSpecs.new_proc_in_method { "hello" } }.should complain(/Capturing the given block using Proc.new is deprecated/) end diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb index 5fb5cf418d..3a56b613cd 100644 --- a/spec/ruby/core/proc/parameters_spec.rb +++ b/spec/ruby/core/proc/parameters_spec.rb @@ -20,6 +20,21 @@ describe "Proc#parameters" do proc {|x| }.parameters.first.first.should == :opt end + ruby_version_is "3.2" do + it "sets the first element of each sub-Array to :req if argument would be required if a lambda if lambda keyword used" do + proc {|x| }.parameters(lambda: true).first.first.should == :req + proc {|y,*x| }.parameters(lambda: true).first.first.should == :req + end + + it "regards named parameters in procs as required if lambda keyword used" do + proc {|x| }.parameters(lambda: true).first.first.should == :req + end + + it "regards named parameters in lambda as optional if lambda: false keyword used" do + -> x { }.parameters(lambda: false).first.first.should == :opt + end + end + it "regards optional keyword parameters in procs as optional" do proc {|x: :y| }.parameters.first.first.should == :key end @@ -80,8 +95,16 @@ describe "Proc#parameters" do -> x {}.parameters.should == [[:req, :x]] end - it "adds nameless rest arg for \"star\" argument" do - -> x, * {}.parameters.should == [[:req, :x], [:rest]] + ruby_version_is '3.2' do + it "adds * rest arg for \"star\" argument" do + -> x, * {}.parameters.should == [[:req, :x], [:rest, :*]] + end + end + + ruby_version_is ''...'3.2' do + it "adds nameless rest arg for \"star\" argument" do + -> x, * {}.parameters.should == [[:req, :x], [:rest]] + end end it "does not add locals as block options with a block and splat" do diff --git a/spec/ruby/core/proc/ruby2_keywords_spec.rb b/spec/ruby/core/proc/ruby2_keywords_spec.rb index 4f6bc151b6..c6eb03e693 100644 --- a/spec/ruby/core/proc/ruby2_keywords_spec.rb +++ b/spec/ruby/core/proc/ruby2_keywords_spec.rb @@ -1,64 +1,78 @@ require_relative '../../spec_helper' -ruby_version_is "2.7" do - describe "Proc#ruby2_keywords" do - it "marks the final hash argument as keyword hash" do - f = -> *a { a.last } - f.ruby2_keywords +describe "Proc#ruby2_keywords" do + it "marks the final hash argument as keyword hash" do + f = -> *a { a.last } + f.ruby2_keywords - last = f.call(1, 2, a: "a") - Hash.ruby2_keywords_hash?(last).should == true - end + last = f.call(1, 2, a: "a") + Hash.ruby2_keywords_hash?(last).should == true + end - ruby_version_is "2.7" ... "3.0" do - it "fixes delegation warnings when calling a method accepting keywords" do - obj = Object.new - def obj.foo(*a, **b) end + it "applies to the underlying method and applies across duplication" do + f1 = -> *a { a.last } + f1.ruby2_keywords + f2 = f1.dup - f = -> *a { obj.foo(*a) } + Hash.ruby2_keywords_hash?(f1.call(1, 2, a: "a")).should == true + Hash.ruby2_keywords_hash?(f2.call(1, 2, a: "a")).should == true - -> { f.call(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/) - f.ruby2_keywords - -> { f.call(1, 2, {a: "a"}) }.should_not complain - end + f3 = -> *a { a.last } + f4 = f3.dup + f3.ruby2_keywords - it "fixes delegation warnings when calling a proc accepting keywords" do - g = -> *a, **b { } - f = -> *a { g.call(*a) } + Hash.ruby2_keywords_hash?(f3.call(1, 2, a: "a")).should == true + Hash.ruby2_keywords_hash?(f4.call(1, 2, a: "a")).should == true + end - -> { f.call(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/) - f.ruby2_keywords - -> { f.call(1, 2, {a: "a"}) }.should_not complain - end - end + ruby_version_is ""..."3.0" do + it "fixes delegation warnings when calling a method accepting keywords" do + obj = Object.new + def obj.foo(*a, **b) end - it "returns self" do - f = -> *a { } - f.ruby2_keywords.should equal f + f = -> *a { obj.foo(*a) } + + -> { f.call(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/) + f.ruby2_keywords + -> { f.call(1, 2, {a: "a"}) }.should_not complain end - it "prints warning when a proc does not accept argument splat" do - f = -> a, b, c { } + it "fixes delegation warnings when calling a proc accepting keywords" do + g = -> *a, **b { } + f = -> *a { g.call(*a) } - -> { - f.ruby2_keywords - }.should complain(/Skipping set of ruby2_keywords flag for/) + -> { f.call(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/) + f.ruby2_keywords + -> { f.call(1, 2, {a: "a"}) }.should_not complain end + end + + it "returns self" do + f = -> *a { } + f.ruby2_keywords.should equal f + end - it "prints warning when a proc accepts keywords" do - f = -> a:, b: { } + it "prints warning when a proc does not accept argument splat" do + f = -> a, b, c { } - -> { - f.ruby2_keywords - }.should complain(/Skipping set of ruby2_keywords flag for/) - end + -> { + f.ruby2_keywords + }.should complain(/Skipping set of ruby2_keywords flag for/) + end - it "prints warning when a proc accepts keyword splat" do - f = -> **a { } + it "prints warning when a proc accepts keywords" do + f = -> a:, b: { } - -> { - f.ruby2_keywords - }.should complain(/Skipping set of ruby2_keywords flag for/) - end + -> { + f.ruby2_keywords + }.should complain(/Skipping set of ruby2_keywords flag for/) + end + + it "prints warning when a proc accepts keyword splat" do + f = -> **a { } + + -> { + f.ruby2_keywords + }.should complain(/Skipping set of ruby2_keywords flag for/) end end diff --git a/spec/ruby/core/proc/shared/compose.rb b/spec/ruby/core/proc/shared/compose.rb index e3ae7f76b8..3d3f3b310d 100644 --- a/spec/ruby/core/proc/shared/compose.rb +++ b/spec/ruby/core/proc/shared/compose.rb @@ -1,47 +1,22 @@ describe :proc_compose, shared: true do - ruby_version_is ""..."2.7" do - it "raises NoMethodError when called if passed not callable object" do - not_callable = Object.new - composed = @object.call.send(@method, not_callable) + it "raises TypeError if passed not callable object" do + lhs = @object.call + not_callable = Object.new - -> { - composed.call('a') - }.should raise_error(NoMethodError, /undefined method `call' for/) + -> { + lhs.send(@method, not_callable) + }.should raise_error(TypeError, "callable object is expected") - end - - it "when called does not try to coerce argument with #to_proc" do - succ = Object.new - def succ.to_proc(s); s.succ; end - - composed = @object.call.send(@method, succ) - - -> { - composed.call('a') - }.should raise_error(NoMethodError, /undefined method `call' for/) - end end - ruby_version_is "2.7" do # https://bugs.ruby-lang.org/issues/15428 - it "raises TypeError if passed not callable object" do - lhs = @object.call - not_callable = Object.new - - -> { - lhs.send(@method, not_callable) - }.should raise_error(TypeError, "callable object is expected") - - end - - it "does not try to coerce argument with #to_proc" do - lhs = @object.call + it "does not try to coerce argument with #to_proc" do + lhs = @object.call - succ = Object.new - def succ.to_proc(s); s.succ; end + succ = Object.new + def succ.to_proc(s); s.succ; end - -> { - lhs.send(@method, succ) - }.should raise_error(TypeError, "callable object is expected") - end + -> { + lhs.send(@method, succ) + }.should raise_error(TypeError, "callable object is expected") end end diff --git a/spec/ruby/core/proc/shared/to_s.rb b/spec/ruby/core/proc/shared/to_s.rb index 7f167a3d9d..f1e2f416fc 100644 --- a/spec/ruby/core/proc/shared/to_s.rb +++ b/spec/ruby/core/proc/shared/to_s.rb @@ -1,9 +1,7 @@ describe :proc_to_s, shared: true do - sep = ruby_version_is("2.7") ? " " : "@" - describe "for a proc created with Proc.new" do it "returns a description including file and line number" do - Proc.new { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{__LINE__ }>$/ + Proc.new { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ }>$/ end it "has a binary encoding" do @@ -13,7 +11,7 @@ describe :proc_to_s, shared: true do describe "for a proc created with lambda" do it "returns a description including '(lambda)' and including file and line number" do - -> { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{__LINE__ } \(lambda\)>$/ + -> { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ } \(lambda\)>$/ end it "has a binary encoding" do @@ -23,7 +21,7 @@ describe :proc_to_s, shared: true do describe "for a proc created with proc" do it "returns a description including file and line number" do - proc { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{__LINE__ }>$/ + proc { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ }>$/ end it "has a binary encoding" do @@ -36,7 +34,7 @@ describe :proc_to_s, shared: true do def hello; end s = method("hello").to_proc.send(@method) if s.include? __FILE__ - s.should =~ /^#<Proc:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{__LINE__ - 3} \(lambda\)>$/ + s.should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ - 3} \(lambda\)>$/ else s.should =~ /^#<Proc:([^ ]*?) \(lambda\)>$/ end diff --git a/spec/ruby/core/process/wait2_spec.rb b/spec/ruby/core/process/wait2_spec.rb index 6eb7fc6d06..673d3cdb9d 100644 --- a/spec/ruby/core/process/wait2_spec.rb +++ b/spec/ruby/core/process/wait2_spec.rb @@ -33,4 +33,13 @@ describe "Process.wait2" do -> { Process.wait2 }.should raise_error(Errno::ECHILD) -> { Process.wait2 }.should raise_error(StandardError) end + + it "returns nil if the child process is still running when given the WNOHANG flag" do + IO.popen(ruby_cmd('STDIN.getbyte'), "w") do |io| + pid, status = Process.wait2(io.pid, Process::WNOHANG) + pid.should be_nil + status.should be_nil + io.write('a') + end + end end diff --git a/spec/ruby/core/random/bytes_spec.rb b/spec/ruby/core/random/bytes_spec.rb index 06e84d03bd..ed1b3a7b41 100644 --- a/spec/ruby/core/random/bytes_spec.rb +++ b/spec/ruby/core/random/bytes_spec.rb @@ -18,7 +18,7 @@ describe "Random#bytes" do end it "returns the same numeric output for a given huge seed across all implementations and platforms" do - rnd = Random.new(bignum_value ** 4) + rnd = Random.new(2 ** (63 * 4)) rnd.bytes(2).should == "_\x91" rnd.bytes(1000) # skip some rnd.bytes(2).should == "\x17\x12" diff --git a/spec/ruby/core/random/default_spec.rb b/spec/ruby/core/random/default_spec.rb index db444d203d..b4ffcb81f4 100644 --- a/spec/ruby/core/random/default_spec.rb +++ b/spec/ruby/core/random/default_spec.rb @@ -1,37 +1,45 @@ require_relative '../../spec_helper' describe "Random::DEFAULT" do - it "returns a random number generator" do - suppress_warning do - Random::DEFAULT.should respond_to(:rand) - end - end - - ruby_version_is ''...'3.0' do - it "returns a Random instance" do + ruby_version_is ''...'3.2' do + it "returns a random number generator" do suppress_warning do - Random::DEFAULT.should be_an_instance_of(Random) + Random::DEFAULT.should respond_to(:rand) end end - end - ruby_version_is '3.0' do - it "refers to the Random class" do - suppress_warning do - Random::DEFAULT.should.equal?(Random) + it "changes seed on reboot" do + seed1 = ruby_exe('p Random::DEFAULT.seed', options: '--disable-gems') + seed2 = ruby_exe('p Random::DEFAULT.seed', options: '--disable-gems') + seed1.should != seed2 + end + + ruby_version_is ''...'3.0' do + it "returns a Random instance" do + suppress_warning do + Random::DEFAULT.should be_an_instance_of(Random) + end end end - it "is deprecated" do - -> { - Random::DEFAULT.should.equal?(Random) - }.should complain(/constant Random::DEFAULT is deprecated/) + ruby_version_is '3.0' do + it "refers to the Random class" do + suppress_warning do + Random::DEFAULT.should.equal?(Random) + end + end + + it "is deprecated" do + -> { + Random::DEFAULT.should.equal?(Random) + }.should complain(/constant Random::DEFAULT is deprecated/) + end end end - it "changes seed on reboot" do - seed1 = ruby_exe('p Random::DEFAULT.seed', options: '--disable-gems') - seed2 = ruby_exe('p Random::DEFAULT.seed', options: '--disable-gems') - seed1.should != seed2 + ruby_version_is '3.2' do + it "is no longer defined" do + Random.should_not.const_defined?(:DEFAULT) + end end end diff --git a/spec/ruby/core/random/rand_spec.rb b/spec/ruby/core/random/rand_spec.rb index 6ea7eece5f..9244177ab5 100644 --- a/spec/ruby/core/random/rand_spec.rb +++ b/spec/ruby/core/random/rand_spec.rb @@ -205,6 +205,11 @@ describe "Random#rand with Range" do Random.new(42).rand(0..1.0).should be_kind_of(Float) end + it "returns a float within a given float range" do + Random.new(42).rand(0.0...100.0).should == 37.454011884736246 + Random.new(42).rand(-100.0...0.0).should == -62.545988115263754 + end + it "raises an ArgumentError when the startpoint lacks #+ and #- methods" do -> do Random.new.rand(Object.new..67) diff --git a/spec/ruby/core/random/raw_seed_spec.rb b/spec/ruby/core/random/raw_seed_spec.rb deleted file mode 100644 index 0e40ed0796..0000000000 --- a/spec/ruby/core/random/raw_seed_spec.rb +++ /dev/null @@ -1,6 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'shared/urandom' - -describe "Random.urandom" do - it_behaves_like :random_urandom, :urandom -end diff --git a/spec/ruby/core/random/shared/urandom.rb b/spec/ruby/core/random/shared/urandom.rb deleted file mode 100644 index 159716075c..0000000000 --- a/spec/ruby/core/random/shared/urandom.rb +++ /dev/null @@ -1,23 +0,0 @@ -describe :random_urandom, shared: true do - it "returns a String" do - Random.send(@method, 1).should be_an_instance_of(String) - end - - it "returns a String of the length given as argument" do - Random.send(@method, 15).length.should == 15 - end - - it "raises an ArgumentError on a negative size" do - -> { - Random.send(@method, -1) - }.should raise_error(ArgumentError) - end - - it "returns a binary String" do - Random.send(@method, 15).encoding.should == Encoding::BINARY - end - - it "returns a random binary String" do - Random.send(@method, 12).should_not == Random.send(@method, 12) - end -end diff --git a/spec/ruby/core/random/urandom_spec.rb b/spec/ruby/core/random/urandom_spec.rb new file mode 100644 index 0000000000..6f180e54ac --- /dev/null +++ b/spec/ruby/core/random/urandom_spec.rb @@ -0,0 +1,25 @@ +require_relative '../../spec_helper' + +describe "Random.urandom" do + it "returns a String" do + Random.urandom(1).should be_an_instance_of(String) + end + + it "returns a String of the length given as argument" do + Random.urandom(15).length.should == 15 + end + + it "raises an ArgumentError on a negative size" do + -> { + Random.urandom(-1) + }.should raise_error(ArgumentError) + end + + it "returns a binary String" do + Random.urandom(15).encoding.should == Encoding::BINARY + end + + it "returns a random binary String" do + Random.urandom(12).should_not == Random.urandom(12) + end +end diff --git a/spec/ruby/core/range/bsearch_spec.rb b/spec/ruby/core/range/bsearch_spec.rb index 438c7ce314..9c93671d85 100644 --- a/spec/ruby/core/range/bsearch_spec.rb +++ b/spec/ruby/core/range/bsearch_spec.rb @@ -330,108 +330,106 @@ describe "Range#bsearch" do end - ruby_version_is "2.7" do - context "with beginless ranges and Integer values" do - context "with a block returning true or false" do - it "returns the smallest element for which block returns true" do - eval("(..10)").bsearch { |x| x >= 2 }.should == 2 - eval("(...-1)").bsearch { |x| x >= -10 }.should == -10 - end - end - - context "with a block returning negative, zero, positive numbers" do - it "returns nil if the block returns greater than zero for every element" do - eval("(..0)").bsearch { |x| 1 }.should be_nil - end - - it "returns nil if the block never returns zero" do - eval("(..0)").bsearch { |x| x > 5 ? -1 : 1 }.should be_nil - end - - it "accepts Float::INFINITY from the block" do - eval("(..0)").bsearch { |x| Float::INFINITY }.should be_nil - end - - it "returns an element at an index for which block returns 0.0" do - result = eval("(..10)").bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 } - result.should == 2 - end - - it "returns an element at an index for which block returns 0" do - result = eval("(...10)").bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 } - [1, 2, 3].should include(result) - end + context "with beginless ranges and Integer values" do + context "with a block returning true or false" do + it "returns the smallest element for which block returns true" do + (..10).bsearch { |x| x >= 2 }.should == 2 + (...-1).bsearch { |x| x >= -10 }.should == -10 + end + end + + context "with a block returning negative, zero, positive numbers" do + it "returns nil if the block returns greater than zero for every element" do + (..0).bsearch { |x| 1 }.should be_nil + end + + it "returns nil if the block never returns zero" do + (..0).bsearch { |x| x > 5 ? -1 : 1 }.should be_nil + end + + it "accepts Float::INFINITY from the block" do + (..0).bsearch { |x| Float::INFINITY }.should be_nil + end + + it "returns an element at an index for which block returns 0.0" do + result = (..10).bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 } + result.should == 2 + end + + it "returns an element at an index for which block returns 0" do + result = (...10).bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 } + [1, 2, 3].should include(result) end end + end + + context "with beginless ranges and Float values" do + context "with a block returning true or false" do + it "returns nil if the block returns true for every element" do + (..-0.1).bsearch { |x| x > 0.0 }.should be_nil + (...-0.1).bsearch { |x| x > 0.0 }.should be_nil + end + + it "returns nil if the block returns nil for every element" do + (..-0.1).bsearch { |x| nil }.should be_nil + (...-0.1).bsearch { |x| nil }.should be_nil + end + + it "returns the smallest element for which block returns true" do + (..10).bsearch { |x| x >= 2 }.should == 2 + (..10).bsearch { |x| x >= 1 }.should == 1 + end - context "with beginless ranges and Float values" do - context "with a block returning true or false" do - it "returns nil if the block returns true for every element" do - eval("(..-0.1)").bsearch { |x| x > 0.0 }.should be_nil - eval("(...-0.1)").bsearch { |x| x > 0.0 }.should be_nil - end - - it "returns nil if the block returns nil for every element" do - eval("(..-0.1)").bsearch { |x| nil }.should be_nil - eval("(...-0.1)").bsearch { |x| nil }.should be_nil - end - - it "returns the smallest element for which block returns true" do - eval("(..10)").bsearch { |x| x >= 2 }.should == 2 - eval("(..10)").bsearch { |x| x >= 1 }.should == 1 - end - - it "works with infinity bounds" do - inf = Float::INFINITY - eval("(..inf)").bsearch { |x| true }.should == -inf - eval("(...inf)").bsearch { |x| true }.should == -inf - eval("(..-inf)").bsearch { |x| true }.should == -inf - eval("(...-inf)").bsearch { |x| true }.should == nil - end - end - - context "with a block returning negative, zero, positive numbers" do - it "returns nil if the block returns less than zero for every element" do - eval("(..5.0)").bsearch { |x| -1 }.should be_nil - eval("(...5.0)").bsearch { |x| -1 }.should be_nil - end - - it "returns nil if the block returns greater than zero for every element" do - eval("(..1.1)").bsearch { |x| 1 }.should be_nil - eval("(...1.1)").bsearch { |x| 1 }.should be_nil - end - - it "returns nil if the block never returns zero" do - eval("(..6.3)").bsearch { |x| x < 2 ? 1 : -1 }.should be_nil - end - - it "accepts (+/-)Float::INFINITY from the block" do - eval("(..5.0)").bsearch { |x| Float::INFINITY }.should be_nil - eval("(..7.0)").bsearch { |x| -Float::INFINITY }.should be_nil - end - - it "returns an element at an index for which block returns 0.0" do - result = eval("(..8.0)").bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 } - result.should == 2 - end - - it "returns an element at an index for which block returns 0" do - result = eval("(..8.0)").bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 } - result.should >= 1 - result.should <= 3 - end - - it "works with infinity bounds" do - inf = Float::INFINITY - eval("(..-inf)").bsearch { |x| 1 }.should == nil - eval("(...-inf)").bsearch { |x| 1 }.should == nil - eval("(..inf)").bsearch { |x| x == inf ? 0 : 1 }.should == inf - eval("(...inf)").bsearch { |x| x == inf ? 0 : 1 }.should == nil - eval("(..-inf)").bsearch { |x| x == -inf ? 0 : -1 }.should == -inf - eval("(...-inf)").bsearch { |x| x == -inf ? 0 : -1 }.should == nil - eval("(..inf)").bsearch { |x| 3 - x }.should == 3 - eval("(...inf)").bsearch { |x| 3 - x }.should == 3 - end + it "works with infinity bounds" do + inf = Float::INFINITY + (..inf).bsearch { |x| true }.should == -inf + (...inf).bsearch { |x| true }.should == -inf + (..-inf).bsearch { |x| true }.should == -inf + (...-inf).bsearch { |x| true }.should == nil + end + end + + context "with a block returning negative, zero, positive numbers" do + it "returns nil if the block returns less than zero for every element" do + (..5.0).bsearch { |x| -1 }.should be_nil + (...5.0).bsearch { |x| -1 }.should be_nil + end + + it "returns nil if the block returns greater than zero for every element" do + (..1.1).bsearch { |x| 1 }.should be_nil + (...1.1).bsearch { |x| 1 }.should be_nil + end + + it "returns nil if the block never returns zero" do + (..6.3).bsearch { |x| x < 2 ? 1 : -1 }.should be_nil + end + + it "accepts (+/-)Float::INFINITY from the block" do + (..5.0).bsearch { |x| Float::INFINITY }.should be_nil + (..7.0).bsearch { |x| -Float::INFINITY }.should be_nil + end + + it "returns an element at an index for which block returns 0.0" do + result = (..8.0).bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 } + result.should == 2 + end + + it "returns an element at an index for which block returns 0" do + result = (..8.0).bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 } + result.should >= 1 + result.should <= 3 + end + + it "works with infinity bounds" do + inf = Float::INFINITY + (..-inf).bsearch { |x| 1 }.should == nil + (...-inf).bsearch { |x| 1 }.should == nil + (..inf).bsearch { |x| x == inf ? 0 : 1 }.should == inf + (...inf).bsearch { |x| x == inf ? 0 : 1 }.should == nil + (..-inf).bsearch { |x| x == -inf ? 0 : -1 }.should == -inf + (...-inf).bsearch { |x| x == -inf ? 0 : -1 }.should == nil + (..inf).bsearch { |x| 3 - x }.should == 3 + (...inf).bsearch { |x| 3 - x }.should == 3 end end end diff --git a/spec/ruby/core/range/case_compare_spec.rb b/spec/ruby/core/range/case_compare_spec.rb index e795026230..4a3faa3163 100644 --- a/spec/ruby/core/range/case_compare_spec.rb +++ b/spec/ruby/core/range/case_compare_spec.rb @@ -8,8 +8,6 @@ describe "Range#===" do (range === RangeSpecs::WithoutSucc.new(2)).should == true end - ruby_version_is "2.7" do - it_behaves_like :range_cover_and_include, :=== - it_behaves_like :range_cover, :=== - end + it_behaves_like :range_cover_and_include, :=== + it_behaves_like :range_cover, :=== end diff --git a/spec/ruby/core/range/count_spec.rb b/spec/ruby/core/range/count_spec.rb index f6f60fa054..24d4a9caf3 100644 --- a/spec/ruby/core/range/count_spec.rb +++ b/spec/ruby/core/range/count_spec.rb @@ -1,14 +1,12 @@ require_relative '../../spec_helper' describe "Range#count" do - ruby_version_is "2.7" do - it "returns Infinity for beginless ranges without arguments or blocks" do - inf = Float::INFINITY - eval("('a'...)").count.should == inf - eval("(7..)").count.should == inf - eval("(...'a')").count.should == inf - eval("(...nil)").count.should == inf - eval("(..10.0)").count.should == inf - end + it "returns Infinity for beginless ranges without arguments or blocks" do + inf = Float::INFINITY + eval("('a'...)").count.should == inf + eval("(7..)").count.should == inf + (...'a').count.should == inf + (...nil).count.should == inf + (..10.0).count.should == inf end end diff --git a/spec/ruby/core/range/dup_spec.rb b/spec/ruby/core/range/dup_spec.rb index 6c9d0c954a..976d4fd1d0 100644 --- a/spec/ruby/core/range/dup_spec.rb +++ b/spec/ruby/core/range/dup_spec.rb @@ -12,4 +12,10 @@ describe "Range#dup" do copy.end.should == "z" copy.should.exclude_end? end + + it "creates an unfrozen range" do + (1..2).dup.should_not.frozen? + (1..).dup.should_not.frozen? + Range.new(1, 2).dup.should_not.frozen? + end end diff --git a/spec/ruby/core/range/each_spec.rb b/spec/ruby/core/range/each_spec.rb index 6b33f57737..ecae17c881 100644 --- a/spec/ruby/core/range/each_spec.rb +++ b/spec/ruby/core/range/each_spec.rb @@ -58,10 +58,8 @@ describe "Range#each" do a.should == ["A", "B", "C", "D"] end - ruby_version_is "2.7" do - it "raises a TypeError beginless ranges" do - -> { eval("(..2)").each { |x| x } }.should raise_error(TypeError) - end + it "raises a TypeError beginless ranges" do + -> { (..2).each { |x| x } }.should raise_error(TypeError) end it "raises a TypeError if the first element does not respond to #succ" do diff --git a/spec/ruby/core/range/equal_value_spec.rb b/spec/ruby/core/range/equal_value_spec.rb index 0aaebfb59a..83dcf5cec8 100644 --- a/spec/ruby/core/range/equal_value_spec.rb +++ b/spec/ruby/core/range/equal_value_spec.rb @@ -12,9 +12,7 @@ describe "Range#==" do eval("(1.0..)").should == eval("(1.0..)") end - ruby_version_is "2.7" do - it "returns true if the endpoints are == for beginless ranges" do - eval("(...10)").should == eval("(...10)") - end + it "returns true if the endpoints are == for beginless ranges" do + (...10).should == (...10) end end diff --git a/spec/ruby/core/range/first_spec.rb b/spec/ruby/core/range/first_spec.rb index c5c90800ac..2af935f439 100644 --- a/spec/ruby/core/range/first_spec.rb +++ b/spec/ruby/core/range/first_spec.rb @@ -47,9 +47,7 @@ describe "Range#first" do -> { (2..3).first("1") }.should raise_error(TypeError) end - ruby_version_is "2.7" do - it "raises a RangeError when called on an beginless range" do - -> { eval("(..1)").first }.should raise_error(RangeError) - end + it "raises a RangeError when called on an beginless range" do + -> { (..1).first }.should raise_error(RangeError) end end diff --git a/spec/ruby/core/range/frozen_spec.rb b/spec/ruby/core/range/frozen_spec.rb new file mode 100644 index 0000000000..298ffc87cb --- /dev/null +++ b/spec/ruby/core/range/frozen_spec.rb @@ -0,0 +1,27 @@ +require_relative '../../spec_helper' + +# There is no Range#frozen? method but this feels like the best place for these specs +describe "Range#frozen?" do + ruby_version_is "3.0" do + it "is true for literal ranges" do + (1..2).should.frozen? + (1..).should.frozen? + (..1).should.frozen? + end + + it "is true for Range.new" do + Range.new(1, 2).should.frozen? + Range.new(1, nil).should.frozen? + Range.new(nil, 1).should.frozen? + end + + it "is false for instances of a subclass of Range" do + sub_range = Class.new(Range).new(1, 2) + sub_range.should_not.frozen? + end + + it "is false for Range.allocate" do + Range.allocate.should_not.frozen? + end + end +end diff --git a/spec/ruby/core/range/inspect_spec.rb b/spec/ruby/core/range/inspect_spec.rb index f49882e6ce..072de123b7 100644 --- a/spec/ruby/core/range/inspect_spec.rb +++ b/spec/ruby/core/range/inspect_spec.rb @@ -17,29 +17,13 @@ describe "Range#inspect" do eval("(0.1...)").inspect.should == "0.1..." end - ruby_version_is '2.7' do - it "works for beginless ranges" do - eval("(..1)").inspect.should == "..1" - eval("(...0.1)").inspect.should == "...0.1" - end - - it "works for nil ... nil ranges" do - eval("(..nil)").inspect.should == "nil..nil" - eval("(nil...)").inspect.should == "nil...nil" - end + it "works for beginless ranges" do + (..1).inspect.should == "..1" + (...0.1).inspect.should == "...0.1" end - ruby_version_is ''...'2.7' do - it "returns a tainted string if either end is tainted" do - (("a".taint)..."c").inspect.tainted?.should be_true - ("a"...("c".taint)).inspect.tainted?.should be_true - ("a"..."c").taint.inspect.tainted?.should be_true - end - - it "returns a untrusted string if either end is untrusted" do - (("a".untrust)..."c").inspect.untrusted?.should be_true - ("a"...("c".untrust)).inspect.untrusted?.should be_true - ("a"..."c").untrust.inspect.untrusted?.should be_true - end + it "works for nil ... nil ranges" do + (..nil).inspect.should == "nil..nil" + eval("(nil...)").inspect.should == "nil...nil" end end diff --git a/spec/ruby/core/range/max_spec.rb b/spec/ruby/core/range/max_spec.rb index a970144d66..6c9ada2a3c 100644 --- a/spec/ruby/core/range/max_spec.rb +++ b/spec/ruby/core/range/max_spec.rb @@ -52,13 +52,13 @@ describe "Range#max" do ruby_version_is "3.0" do it "returns the end point for beginless ranges" do - eval("(..1)").max.should == 1 - eval("(..1.0)").max.should == 1.0 + (..1).max.should == 1 + (..1.0).max.should == 1.0 end it "raises for an exclusive beginless range" do -> { - eval("(...1)").max + (...1).max }.should raise_error(TypeError, 'cannot exclude end value with non Integer begin value') end end @@ -97,9 +97,7 @@ describe "Range#max given a block" do (5...5).max {|x,y| x <=> y}.should be_nil end - ruby_version_is "2.7" do - it "raises RangeError when called with custom comparison method on an beginless range" do - -> { eval("(..1)").max {|a, b| a} }.should raise_error(RangeError) - end + it "raises RangeError when called with custom comparison method on an beginless range" do + -> { (..1).max {|a, b| a} }.should raise_error(RangeError) end end diff --git a/spec/ruby/core/range/min_spec.rb b/spec/ruby/core/range/min_spec.rb index 6e56cc733b..89310ee589 100644 --- a/spec/ruby/core/range/min_spec.rb +++ b/spec/ruby/core/range/min_spec.rb @@ -44,10 +44,8 @@ describe "Range#min" do eval("(1.0...)").min.should == 1.0 end - ruby_version_is "2.7" do - it "raises RangeError when called on an beginless range" do - -> { eval("(..1)").min }.should raise_error(RangeError) - end + it "raises RangeError when called on an beginless range" do + -> { (..1).min }.should raise_error(RangeError) end end diff --git a/spec/ruby/core/range/minmax_spec.rb b/spec/ruby/core/range/minmax_spec.rb index 1db9bfce38..b2b4fd61a1 100644 --- a/spec/ruby/core/range/minmax_spec.rb +++ b/spec/ruby/core/range/minmax_spec.rb @@ -1,6 +1,5 @@ require_relative '../../spec_helper' -# These specs use Range.new instead of the literal notation for beginless Ranges so they parse fine on Ruby < 2.7 describe 'Range#minmax' do before(:each) do @x = mock('x') @@ -13,37 +12,26 @@ describe 'Range#minmax' do end describe 'on an inclusive range' do - ruby_version_is ''...'2.7' do - it 'should try to iterate endlessly on an endless range' do - @x.should_receive(:succ).once.and_return(@y) - range = (@x..) - - -> { range.minmax }.should raise_error(NoMethodError, /^undefined method `succ' for/) - end - end - - ruby_version_is '2.7' do - it 'should raise RangeError on an endless range without iterating the range' do - @x.should_not_receive(:succ) + it 'should raise RangeError on an endless range without iterating the range' do + @x.should_not_receive(:succ) - range = (@x..) + range = (@x..) - -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range') - end + -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range') + end - it 'raises RangeError or ArgumentError on a beginless range' do - range = Range.new(nil, @x) - - -> { range.minmax }.should raise_error(StandardError) { |e| - if RangeError === e - # error from #min - -> { raise e }.should raise_error(RangeError, 'cannot get the minimum of beginless range') - else - # error from #max - -> { raise e }.should raise_error(ArgumentError, 'comparison of NilClass with MockObject failed') - end - } - end + it 'raises RangeError or ArgumentError on a beginless range' do + range = (..@x) + + -> { range.minmax }.should raise_error(StandardError) { |e| + if RangeError === e + # error from #min + -> { raise e }.should raise_error(RangeError, 'cannot get the minimum of beginless range') + else + # error from #max + -> { raise e }.should raise_error(ArgumentError, 'comparison of NilClass with MockObject failed') + end + } end it 'should return beginning of range if beginning and end are equal without iterating the range' do @@ -58,34 +46,22 @@ describe 'Range#minmax' do (@y..@x).minmax.should == [nil, nil] end - ruby_version_is ''...'2.7' do - it 'should return the minimum and maximum values for a non-numeric range by iterating the range' do - @x.should_receive(:succ).once.and_return(@y) - - (@x..@y).minmax.should == [@x, @y] - end - end - - ruby_version_is '2.7' do - it 'should return the minimum and maximum values for a non-numeric range without iterating the range' do - @x.should_not_receive(:succ) + it 'should return the minimum and maximum values for a non-numeric range without iterating the range' do + @x.should_not_receive(:succ) - (@x..@y).minmax.should == [@x, @y] - end + (@x..@y).minmax.should == [@x, @y] end it 'should return the minimum and maximum values for a numeric range' do (1..3).minmax.should == [1, 3] end - ruby_version_is '2.7' do - it 'should return the minimum and maximum values for a numeric range without iterating the range' do - # We cannot set expectations on integers, - # so we "prevent" iteration by picking a value that would iterate until the spec times out. - range_end = Float::INFINITY + it 'should return the minimum and maximum values for a numeric range without iterating the range' do + # We cannot set expectations on integers, + # so we "prevent" iteration by picking a value that would iterate until the spec times out. + range_end = Float::INFINITY - (1..range_end).minmax.should == [1, range_end] - end + (1..range_end).minmax.should == [1, range_end] end it 'should return the minimum and maximum values according to the provided block by iterating the range' do @@ -96,33 +72,21 @@ describe 'Range#minmax' do end describe 'on an exclusive range' do - ruby_version_is ''...'2.7' do - # Endless ranges introduced in 2.6 - it 'should try to iterate endlessly on an endless range' do - @x.should_receive(:succ).once.and_return(@y) - range = (@x...) + it 'should raise RangeError on an endless range' do + @x.should_not_receive(:succ) + range = (@x...) - -> { range.minmax }.should raise_error(NoMethodError, /^undefined method `succ' for/) - end + -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range') end - ruby_version_is '2.7' do - it 'should raise RangeError on an endless range' do - @x.should_not_receive(:succ) - range = (@x...) + it 'should raise RangeError on a beginless range' do + range = (...@x) - -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range') - end - - it 'should raise RangeError on a beginless range' do - range = Range.new(nil, @x, true) - - -> { range.minmax }.should raise_error(RangeError, - /cannot get the maximum of beginless range with custom comparison method|cannot get the minimum of beginless range/) - end + -> { range.minmax }.should raise_error(RangeError, + /cannot get the maximum of beginless range with custom comparison method|cannot get the minimum of beginless range/) end - ruby_bug "#17014", "2.7.0"..."3.0" do + ruby_bug "#17014", ""..."3.0" do it 'should return nil pair if beginning and end are equal without iterating the range' do @x.should_not_receive(:succ) @@ -146,19 +110,17 @@ describe 'Range#minmax' do (1...3).minmax.should == [1, 2] end - ruby_version_is '2.7' do - it 'should return the minimum and maximum values for a numeric range without iterating the range' do - # We cannot set expectations on integers, - # so we "prevent" iteration by picking a value that would iterate until the spec times out. - range_end = bignum_value + it 'should return the minimum and maximum values for a numeric range without iterating the range' do + # We cannot set expectations on integers, + # so we "prevent" iteration by picking a value that would iterate until the spec times out. + range_end = bignum_value - (1...range_end).minmax.should == [1, range_end - 1] - end + (1...range_end).minmax.should == [1, range_end - 1] + end - it 'raises TypeError if the end value is not an integer' do - range = (0...Float::INFINITY) - -> { range.minmax }.should raise_error(TypeError, 'cannot exclude non Integer end value') - end + it 'raises TypeError if the end value is not an integer' do + range = (0...Float::INFINITY) + -> { range.minmax }.should raise_error(TypeError, 'cannot exclude non Integer end value') end it 'should return the minimum and maximum values according to the provided block by iterating the range' do diff --git a/spec/ruby/core/range/new_spec.rb b/spec/ruby/core/range/new_spec.rb index a4de4963e7..85e99babff 100644 --- a/spec/ruby/core/range/new_spec.rb +++ b/spec/ruby/core/range/new_spec.rb @@ -42,24 +42,16 @@ describe "Range.new" do end describe "beginless/endless range" do - ruby_version_is ""..."2.7" do - it "does not allow range without left boundary" do - -> { Range.new(nil, 1) }.should raise_error(ArgumentError, /bad value for range/) - end + it "allows beginless left boundary" do + range = Range.new(nil, 1) + range.begin.should == nil end - ruby_version_is "2.7" do - it "allows beginless left boundary" do - range = Range.new(nil, 1) - range.begin.should == nil - end - - it "distinguishes ranges with included and excluded right boundary" do - range_exclude = Range.new(nil, 1, true) - range_include = Range.new(nil, 1, false) + it "distinguishes ranges with included and excluded right boundary" do + range_exclude = Range.new(nil, 1, true) + range_include = Range.new(nil, 1, false) - range_exclude.should_not == range_include - end + range_exclude.should_not == range_include end it "allows endless right boundary" do diff --git a/spec/ruby/core/range/shared/cover.rb b/spec/ruby/core/range/shared/cover.rb index f3c7d22668..0b41a26455 100644 --- a/spec/ruby/core/range/shared/cover.rb +++ b/spec/ruby/core/range/shared/cover.rb @@ -151,45 +151,43 @@ describe :range_cover_subrange, shared: true do end end - ruby_version_is "2.7" do - it "allows self to be a beginless range" do - eval("(...10)").send(@method, (3..7)).should be_true - eval("(...10)").send(@method, (3..15)).should be_false + it "allows self to be a beginless range" do + (...10).send(@method, (3..7)).should be_true + (...10).send(@method, (3..15)).should be_false - eval("(..7.9)").send(@method, (2.5..6.5)).should be_true - eval("(..7.9)").send(@method, (2.5..8.5)).should be_false + (..7.9).send(@method, (2.5..6.5)).should be_true + (..7.9).send(@method, (2.5..8.5)).should be_false - eval("(..'i')").send(@method, ('d'..'f')).should be_true - eval("(..'i')").send(@method, ('d'..'z')).should be_false - end + (..'i').send(@method, ('d'..'f')).should be_true + (..'i').send(@method, ('d'..'z')).should be_false + end - it "allows self to be a endless range" do - eval("(0...)").send(@method, (3..7)).should be_true - eval("(5...)").send(@method, (3..15)).should be_false + it "allows self to be a endless range" do + eval("(0...)").send(@method, (3..7)).should be_true + eval("(5...)").send(@method, (3..15)).should be_false - eval("(1.1..)").send(@method, (2.5..6.5)).should be_true - eval("(3.3..)").send(@method, (2.5..8.5)).should be_false + eval("(1.1..)").send(@method, (2.5..6.5)).should be_true + eval("(3.3..)").send(@method, (2.5..8.5)).should be_false - eval("('a'..)").send(@method, ('d'..'f')).should be_true - eval("('p'..)").send(@method, ('d'..'z')).should be_false - end + eval("('a'..)").send(@method, ('d'..'f')).should be_true + eval("('p'..)").send(@method, ('d'..'z')).should be_false + end - it "accepts beginless range argument" do - eval("(..10)").send(@method, eval("(...10)")).should be_true - (0..10).send(@method, eval("(...10)")).should be_false + it "accepts beginless range argument" do + (..10).send(@method, (...10)).should be_true + (0..10).send(@method, (...10)).should be_false - (1.1..7.9).send(@method, eval("(...10.5)")).should be_false + (1.1..7.9).send(@method, (...10.5)).should be_false - ('c'..'i').send(@method, eval("(..'i')")).should be_false - end + ('c'..'i').send(@method, (..'i')).should be_false + end - it "accepts endless range argument" do - eval("(0..)").send(@method, eval("(0...)")).should be_true - (0..10).send(@method, eval("(0...)")).should be_false + it "accepts endless range argument" do + eval("(0..)").send(@method, eval("(0...)")).should be_true + (0..10).send(@method, eval("(0...)")).should be_false - (1.1..7.9).send(@method, eval("(0.8...)")).should be_false + (1.1..7.9).send(@method, eval("(0.8...)")).should be_false - ('c'..'i').send(@method, eval("('a'..)")).should be_false - end + ('c'..'i').send(@method, eval("('a'..)")).should be_false end end diff --git a/spec/ruby/core/range/shared/cover_and_include.rb b/spec/ruby/core/range/shared/cover_and_include.rb index e978e39af5..7028afaa89 100644 --- a/spec/ruby/core/range/shared/cover_and_include.rb +++ b/spec/ruby/core/range/shared/cover_and_include.rb @@ -24,11 +24,9 @@ describe :range_cover_and_include, shared: true do eval("(0.5...)").send(@method, 2.4).should == true end - ruby_version_is "2.7" do - it "returns true if other is an element of self for beginless ranges" do - eval("(..10)").send(@method, 2.4).should == true - eval("(...10.5)").send(@method, 2.4).should == true - end + it "returns true if other is an element of self for beginless ranges" do + (..10).send(@method, 2.4).should == true + (...10.5).send(@method, 2.4).should == true end it "compares values using <=>" do diff --git a/spec/ruby/core/range/size_spec.rb b/spec/ruby/core/range/size_spec.rb index 0019c5ff00..5462a1a5e1 100644 --- a/spec/ruby/core/range/size_spec.rb +++ b/spec/ruby/core/range/size_spec.rb @@ -34,13 +34,11 @@ describe "Range#size" do eval("([]...)").size.should == nil end - ruby_version_is "2.7" do - it 'returns Float::INFINITY for all beginless ranges' do - eval("(..1)").size.should == Float::INFINITY - eval("(...0.5)").size.should == Float::INFINITY - eval("(..nil)").size.should == Float::INFINITY - eval("(...'o')").size.should == Float::INFINITY - end + it 'returns Float::INFINITY for all beginless ranges' do + (..1).size.should == Float::INFINITY + (...0.5).size.should == Float::INFINITY + (..nil).size.should == Float::INFINITY + (...'o').size.should == Float::INFINITY end it "returns nil if first and last are not Numeric" do diff --git a/spec/ruby/core/range/step_spec.rb b/spec/ruby/core/range/step_spec.rb index 4c69073854..61ddc5205d 100644 --- a/spec/ruby/core/range/step_spec.rb +++ b/spec/ruby/core/range/step_spec.rb @@ -481,11 +481,9 @@ describe "Range#step" do end end - ruby_version_is "2.7" do - context "when begin is not defined and end is numeric" do - it "returns an instance of Enumerator::ArithmeticSequence" do - eval("(..10)").step.class.should == Enumerator::ArithmeticSequence - end + context "when begin is not defined and end is numeric" do + it "returns an instance of Enumerator::ArithmeticSequence" do + (..10).step.class.should == Enumerator::ArithmeticSequence end end @@ -499,11 +497,9 @@ describe "Range#step" do end end - ruby_version_is "2.7" do - context "when range is beginless and endless" do - it "returns an instance of Enumerator" do - Range.new(nil, nil).step.class.should == Enumerator - end + context "when range is beginless and endless" do + it "returns an instance of Enumerator" do + Range.new(nil, nil).step.class.should == Enumerator end end diff --git a/spec/ruby/core/range/to_a_spec.rb b/spec/ruby/core/range/to_a_spec.rb index 52ebc02941..b1d3de32db 100644 --- a/spec/ruby/core/range/to_a_spec.rb +++ b/spec/ruby/core/range/to_a_spec.rb @@ -33,9 +33,7 @@ describe "Range#to_a" do -> { eval("(1..)").to_a }.should raise_error(RangeError) end - ruby_version_is "2.7" do - it "throws an exception for beginless ranges" do - -> { eval("(..1)").to_a }.should raise_error(TypeError) - end + it "throws an exception for beginless ranges" do + -> { (..1).to_a }.should raise_error(TypeError) end end diff --git a/spec/ruby/core/range/to_s_spec.rb b/spec/ruby/core/range/to_s_spec.rb index 581c2e7d90..460c330912 100644 --- a/spec/ruby/core/range/to_s_spec.rb +++ b/spec/ruby/core/range/to_s_spec.rb @@ -16,24 +16,8 @@ describe "Range#to_s" do eval("(1.0...)").to_s.should == "1.0..." end - ruby_version_is "2.7" do - it "can show beginless ranges" do - eval("(..1)").to_s.should == "..1" - eval("(...1.0)").to_s.should == "...1.0" - end - end - - ruby_version_is ''...'2.7' do - it "returns a tainted string if either end is tainted" do - (("a".taint)..."c").to_s.tainted?.should be_true - ("a"...("c".taint)).to_s.tainted?.should be_true - ("a"..."c").taint.to_s.tainted?.should be_true - end - - it "returns a untrusted string if either end is untrusted" do - (("a".untrust)..."c").to_s.untrusted?.should be_true - ("a"...("c".untrust)).to_s.untrusted?.should be_true - ("a"..."c").untrust.to_s.untrusted?.should be_true - end + it "can show beginless ranges" do + (..1).to_s.should == "..1" + (...1.0).to_s.should == "...1.0" end end diff --git a/spec/ruby/core/rational/minus_spec.rb b/spec/ruby/core/rational/minus_spec.rb index 9e0f81556b..a61b62ebe6 100644 --- a/spec/ruby/core/rational/minus_spec.rb +++ b/spec/ruby/core/rational/minus_spec.rb @@ -1,7 +1,51 @@ -require_relative '../../shared/rational/minus' +require_relative '../../spec_helper' require_relative '../../shared/rational/arithmetic_exception_in_coerce' describe "Rational#-" do - it_behaves_like :rational_minus, :- it_behaves_like :rational_arithmetic_exception_in_coerce, :- + + it "calls #coerce on the passed argument with self" do + rational = Rational(3, 4) + obj = mock("Object") + obj.should_receive(:coerce).with(rational).and_return([1, 2]) + + rational - obj + end + + it "calls #- on the coerced Rational with the coerced Object" do + rational = Rational(3, 4) + + coerced_rational = mock("Coerced Rational") + coerced_rational.should_receive(:-).and_return(:result) + + coerced_obj = mock("Coerced Object") + + obj = mock("Object") + obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj]) + + (rational - obj).should == :result + end +end + +describe "Rational#- passed a Rational" do + it "returns the result of subtracting other from self as a Rational" do + (Rational(3, 4) - Rational(0, 1)).should eql(Rational(3, 4)) + (Rational(3, 4) - Rational(1, 4)).should eql(Rational(1, 2)) + + (Rational(3, 4) - Rational(2, 1)).should eql(Rational(-5, 4)) + end +end + +describe "Rational#- passed a Float" do + it "returns the result of subtracting other from self as a Float" do + (Rational(3, 4) - 0.2).should eql(0.55) + (Rational(3, 4) - 2.5).should eql(-1.75) + end +end + +describe "Rational#- passed an Integer" do + it "returns the result of subtracting other from self as a Rational" do + (Rational(3, 4) - 1).should eql(Rational(-1, 4)) + (Rational(3, 4) - 2).should eql(Rational(-5, 4)) + end end diff --git a/spec/ruby/core/refinement/append_features_spec.rb b/spec/ruby/core/refinement/append_features_spec.rb new file mode 100644 index 0000000000..fb84f245bd --- /dev/null +++ b/spec/ruby/core/refinement/append_features_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' + +describe "Refinement#append_features" do + ruby_version_is "3.2" do + it "is not defined" do + Refinement.should_not have_private_instance_method(:append_features) + end + + it "is not called by Module#include" do + c = Class.new + Module.new do + refine c do + called = false + define_method(:append_features){called = true} + proc{c.include(self)}.should raise_error(TypeError) + called.should == false + end + end + end + end +end diff --git a/spec/ruby/core/refinement/extend_object_spec.rb b/spec/ruby/core/refinement/extend_object_spec.rb new file mode 100644 index 0000000000..e44e9f46d8 --- /dev/null +++ b/spec/ruby/core/refinement/extend_object_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' + +describe "Refinement#extend_object" do + ruby_version_is "3.2" do + it "is not defined" do + Refinement.should_not have_private_instance_method(:extend_object) + end + + it "is not called by Object#extend" do + c = Class.new + Module.new do + refine c do + called = false + define_method(:extend_object){called = true} + proc{c.extend(self)}.should raise_error(TypeError) + called.should == false + end + end + end + end +end diff --git a/spec/ruby/core/refinement/prepend_features_spec.rb b/spec/ruby/core/refinement/prepend_features_spec.rb new file mode 100644 index 0000000000..9fdea199a2 --- /dev/null +++ b/spec/ruby/core/refinement/prepend_features_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../spec_helper' + +describe "Refinement#prepend_features" do + ruby_version_is "3.2" do + it "is not defined" do + Refinement.should_not have_private_instance_method(:prepend_features) + end + + it "is not called by Module#prepend" do + c = Class.new + Module.new do + refine c do + called = false + define_method(:prepend_features){called = true} + proc{c.prepend(self)}.should raise_error(TypeError) + called.should == false + end + end + end + end +end diff --git a/spec/ruby/core/string/allocate_spec.rb b/spec/ruby/core/string/allocate_spec.rb index 5b36b4fd05..30d5f60594 100644 --- a/spec/ruby/core/string/allocate_spec.rb +++ b/spec/ruby/core/string/allocate_spec.rb @@ -14,6 +14,6 @@ describe "String.allocate" do end it "returns a binary String" do - String.new.encoding.should == Encoding::BINARY + String.allocate.encoding.should == Encoding::BINARY end end diff --git a/spec/ruby/core/string/append_spec.rb b/spec/ruby/core/string/append_spec.rb index 1e1667f617..e001257621 100644 --- a/spec/ruby/core/string/append_spec.rb +++ b/spec/ruby/core/string/append_spec.rb @@ -5,4 +5,9 @@ require_relative 'shared/concat' describe "String#<<" do it_behaves_like :string_concat, :<< it_behaves_like :string_concat_encoding, :<< + + it "raises an ArgumentError when given the incorrect number of arguments" do + -> { "hello".send(:<<) }.should raise_error(ArgumentError) + -> { "hello".send(:<<, "one", "two") }.should raise_error(ArgumentError) + end end diff --git a/spec/ruby/core/string/b_spec.rb b/spec/ruby/core/string/b_spec.rb index b2e3d326ba..37c7994700 100644 --- a/spec/ruby/core/string/b_spec.rb +++ b/spec/ruby/core/string/b_spec.rb @@ -12,13 +12,4 @@ describe "String#b" do str.b.should_not equal(str) str.should == "こんちには" end - - ruby_version_is ''...'2.7' do - it "copies own tainted/untrusted status to the returning value" do - utf_8 = "こんちには".taint.untrust - ret = utf_8.b - ret.tainted?.should be_true - ret.untrusted?.should be_true - end - end end diff --git a/spec/ruby/core/string/bytesize_spec.rb b/spec/ruby/core/string/bytesize_spec.rb index b8b07cfbec..a31f3ae671 100644 --- a/spec/ruby/core/string/bytesize_spec.rb +++ b/spec/ruby/core/string/bytesize_spec.rb @@ -2,7 +2,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -describe "#String#bytesize" do +describe "String#bytesize" do it "returns the length of self in bytes" do "hello".bytesize.should == 5 " ".bytesize.should == 1 diff --git a/spec/ruby/core/string/capitalize_spec.rb b/spec/ruby/core/string/capitalize_spec.rb index 21df18a5ae..ca8df88fec 100644 --- a/spec/ruby/core/string/capitalize_spec.rb +++ b/spec/ruby/core/string/capitalize_spec.rb @@ -12,13 +12,6 @@ describe "String#capitalize" do "123ABC".capitalize.should == "123abc" end - ruby_version_is ''...'2.7' do - it "taints resulting string when self is tainted" do - "".taint.capitalize.should.tainted? - "hello".taint.capitalize.should.tainted? - end - end - describe "full Unicode case mapping" do it "works for all of Unicode with no option" do "äöÜ".capitalize.should == "Äöü" diff --git a/spec/ruby/core/string/center_spec.rb b/spec/ruby/core/string/center_spec.rb index b66015172c..76da6e1e09 100644 --- a/spec/ruby/core/string/center_spec.rb +++ b/spec/ruby/core/string/center_spec.rb @@ -47,16 +47,6 @@ describe "String#center with length, padding" do "radiology".center(8, '-').should == "radiology" end - ruby_version_is ''...'2.7' do - it "taints result when self or padstr is tainted" do - "x".taint.center(4).should.tainted? - "x".taint.center(0).should.tainted? - "".taint.center(0).should.tainted? - "x".taint.center(4, "*").should.tainted? - "x".center(4, "*".taint).should.tainted? - end - end - it "calls #to_int to convert length to an integer" do "_".center(3.8, "^").should == "^_^" @@ -113,14 +103,6 @@ describe "String#center with length, padding" do end end - ruby_version_is ''...'2.7' do - it "when padding is tainted and self is untainted returns a tainted string if and only if length is longer than self" do - "hello".center(4, 'X'.taint).tainted?.should be_false - "hello".center(5, 'X'.taint).tainted?.should be_false - "hello".center(6, 'X'.taint).tainted?.should be_true - end - end - describe "with width" do it "returns a String in the same encoding as the original" do str = "abc".force_encoding Encoding::IBM437 diff --git a/spec/ruby/core/string/chomp_spec.rb b/spec/ruby/core/string/chomp_spec.rb index 3d6207f876..c03bfc7951 100644 --- a/spec/ruby/core/string/chomp_spec.rb +++ b/spec/ruby/core/string/chomp_spec.rb @@ -40,12 +40,6 @@ describe "String#chomp" do "".chomp.should == "" end - ruby_version_is ''...'2.7' do - it "taints the result if self is tainted" do - "abc".taint.chomp.tainted?.should be_true - end - end - ruby_version_is ''...'3.0' do it "returns subclass instances when called on a subclass" do str = StringSpecs::MyString.new("hello\n").chomp @@ -80,12 +74,6 @@ describe "String#chomp" do str.chomp(nil).should_not equal(str) end - ruby_version_is ''...'2.7' do - it "taints the result if self is tainted" do - "abc".taint.chomp(nil).tainted?.should be_true - end - end - it "returns an empty String when self is empty" do "".chomp(nil).should == "" end @@ -112,12 +100,6 @@ describe "String#chomp" do "abc\r\n\r\n\r\n".chomp("").should == "abc" end - ruby_version_is ''...'2.7' do - it "taints the result if self is tainted" do - "abc".taint.chomp("").tainted?.should be_true - end - end - it "returns an empty String when self is empty" do "".chomp("").should == "" end @@ -140,12 +122,6 @@ describe "String#chomp" do "abc\r\n\r\n".chomp("\n").should == "abc\r\n" end - ruby_version_is ''...'2.7' do - it "taints the result if self is tainted" do - "abc".taint.chomp("\n").tainted?.should be_true - end - end - it "returns an empty String when self is empty" do "".chomp("\n").should == "" end @@ -178,16 +154,6 @@ describe "String#chomp" do "".chomp("abc").should == "" end - ruby_version_is ''...'2.7' do - it "taints the result if self is tainted" do - "abc".taint.chomp("abc").tainted?.should be_true - end - - it "does not taint the result when the argument is tainted" do - "abc".chomp("abc".taint).tainted?.should be_false - end - end - it "returns an empty String when the argument equals self" do "abc".chomp("abc").should == "" end @@ -232,12 +198,6 @@ describe "String#chomp!" do "".chomp!.should be_nil end - ruby_version_is ''...'2.7' do - it "taints the result if self is tainted" do - "abc\n".taint.chomp!.tainted?.should be_true - end - end - it "returns subclass instances when called on a subclass" do str = StringSpecs::MyString.new("hello\n").chomp! str.should be_an_instance_of(StringSpecs::MyString) @@ -280,12 +240,6 @@ describe "String#chomp!" do "abc\r\n\r\n\r\n".chomp!("").should == "abc" end - ruby_version_is ''...'2.7' do - it "taints the result if self is tainted" do - "abc\n".taint.chomp!("").tainted?.should be_true - end - end - it "returns nil when self is empty" do "".chomp!("").should be_nil end @@ -304,12 +258,6 @@ describe "String#chomp!" do "abc\r\n\r\n".chomp!("\n").should == "abc\r\n" end - ruby_version_is ''...'2.7' do - it "taints the result if self is tainted" do - "abc\n".taint.chomp!("\n").tainted?.should be_true - end - end - it "returns nil when self is empty" do "".chomp!("\n").should be_nil end @@ -341,16 +289,6 @@ describe "String#chomp!" do it "returns nil when self is empty" do "".chomp!("abc").should be_nil end - - ruby_version_is ''...'2.7' do - it "taints the result if self is tainted" do - "abc".taint.chomp!("abc").tainted?.should be_true - end - - it "does not taint the result when the argument is tainted" do - "abc".chomp!("abc".taint).tainted?.should be_false - end - end end it "raises a FrozenError on a frozen instance when it is modified" do diff --git a/spec/ruby/core/string/chop_spec.rb b/spec/ruby/core/string/chop_spec.rb index 9b4e7363c6..266d973f67 100644 --- a/spec/ruby/core/string/chop_spec.rb +++ b/spec/ruby/core/string/chop_spec.rb @@ -49,18 +49,6 @@ describe "String#chop" do s.chop.should_not equal(s) end - ruby_version_is ''...'2.7' do - it "taints result when self is tainted" do - "hello".taint.chop.should.tainted? - "".taint.chop.should.tainted? - end - - it "untrusts result when self is untrusted" do - "hello".untrust.chop.should.untrusted? - "".untrust.chop.should.untrusted? - end - end - ruby_version_is ''...'3.0' do it "returns subclass instances when called on a subclass" do StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(StringSpecs::MyString) diff --git a/spec/ruby/core/string/comparison_spec.rb b/spec/ruby/core/string/comparison_spec.rb index 01199274b6..91cfdca25a 100644 --- a/spec/ruby/core/string/comparison_spec.rb +++ b/spec/ruby/core/string/comparison_spec.rb @@ -75,6 +75,10 @@ describe "String#<=> with String" do (xff_1 <=> xff_2).should == -1 (xff_2 <=> xff_1).should == 1 end + + it "returns 0 when comparing 2 empty strings but one is not ASCII-compatible" do + ("" <=> "".force_encoding('iso-2022-jp')).should == 0 + end end # Note: This is inconsistent with Array#<=> which calls #to_ary instead of diff --git a/spec/ruby/core/string/crypt_spec.rb b/spec/ruby/core/string/crypt_spec.rb index b947702492..06f84c70a4 100644 --- a/spec/ruby/core/string/crypt_spec.rb +++ b/spec/ruby/core/string/crypt_spec.rb @@ -25,21 +25,6 @@ describe "String#crypt" do "mypassword".crypt(obj).should == "$2a$04$0WVaz0pV3jzfZ5G5tpmHWuBQGbkjzgtSc3gJbmdy0GAGMa45MFM2." end - ruby_version_is ''...'2.7' do - it "taints the result if either salt or self is tainted" do - tainted_salt = "$2a$04$0WVaz0pV3jzfZ5G5tpmHWu" - tainted_str = "mypassword" - - tainted_salt.taint - tainted_str.taint - - "mypassword".crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should_not.tainted? - tainted_str.crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should.tainted? - "mypassword".crypt(tainted_salt).should.tainted? - tainted_str.crypt(tainted_salt).should.tainted? - end - end - it "doesn't return subclass instances" do StringSpecs::MyString.new("mypassword").crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should be_an_instance_of(String) "mypassword".crypt(StringSpecs::MyString.new("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")).should be_an_instance_of(String) @@ -85,21 +70,6 @@ describe "String#crypt" do "".crypt(obj).should == "aaQSqAReePlq6" end - ruby_version_is ''...'2.7' do - it "taints the result if either salt or self is tainted" do - tainted_salt = "aa" - tainted_str = "hello" - - tainted_salt.taint - tainted_str.taint - - "hello".crypt("aa").should_not.tainted? - tainted_str.crypt("aa").should.tainted? - "hello".crypt(tainted_salt).should.tainted? - tainted_str.crypt(tainted_salt).should.tainted? - end - end - it "doesn't return subclass instances" do StringSpecs::MyString.new("hello").crypt("aa").should be_an_instance_of(String) "hello".crypt(StringSpecs::MyString.new("aa")).should be_an_instance_of(String) diff --git a/spec/ruby/core/string/dedup_spec.rb b/spec/ruby/core/string/dedup_spec.rb new file mode 100644 index 0000000000..919d440c51 --- /dev/null +++ b/spec/ruby/core/string/dedup_spec.rb @@ -0,0 +1,8 @@ +require_relative '../../spec_helper' +require_relative 'shared/dedup' + +describe 'String#dedup' do + ruby_version_is '3.2'do + it_behaves_like :string_dedup, :dedup + end +end diff --git a/spec/ruby/core/string/delete_prefix_spec.rb b/spec/ruby/core/string/delete_prefix_spec.rb index 8469791f74..a063e443d8 100644 --- a/spec/ruby/core/string/delete_prefix_spec.rb +++ b/spec/ruby/core/string/delete_prefix_spec.rb @@ -21,13 +21,6 @@ describe "String#delete_prefix" do r.should == s end - ruby_version_is ''...'2.7' do - it "taints resulting strings when other is tainted" do - 'hello'.taint.delete_prefix('hell').should.tainted? - 'hello'.taint.delete_prefix('').should.tainted? - end - end - it "doesn't set $~" do $~ = nil diff --git a/spec/ruby/core/string/delete_spec.rb b/spec/ruby/core/string/delete_spec.rb index ebca0b7dae..b91e88b76f 100644 --- a/spec/ruby/core/string/delete_spec.rb +++ b/spec/ruby/core/string/delete_spec.rb @@ -68,15 +68,6 @@ describe "String#delete" do -> { "hello".delete("^h-e") }.should raise_error(ArgumentError) end - ruby_version_is ''...'2.7' do - it "taints result when self is tainted" do - "hello".taint.delete("e").should.tainted? - "hello".taint.delete("a-z").should.tainted? - - "hello".delete("e".taint).should_not.tainted? - end - end - it "tries to convert each set arg to a string using to_str" do other_string = mock('lo') other_string.should_receive(:to_str).and_return("lo") diff --git a/spec/ruby/core/string/delete_suffix_spec.rb b/spec/ruby/core/string/delete_suffix_spec.rb index 12d0ee175e..3d3274bc5b 100644 --- a/spec/ruby/core/string/delete_suffix_spec.rb +++ b/spec/ruby/core/string/delete_suffix_spec.rb @@ -21,13 +21,6 @@ describe "String#delete_suffix" do r.should == s end - ruby_version_is ''...'2.7' do - it "taints resulting strings when other is tainted" do - 'hello'.taint.delete_suffix('ello').should.tainted? - 'hello'.taint.delete_suffix('').should.tainted? - end - end - it "doesn't set $~" do $~ = nil diff --git a/spec/ruby/core/string/downcase_spec.rb b/spec/ruby/core/string/downcase_spec.rb index 4427c9df10..86d8480889 100644 --- a/spec/ruby/core/string/downcase_spec.rb +++ b/spec/ruby/core/string/downcase_spec.rb @@ -68,14 +68,6 @@ describe "String#downcase" do -> { "ABC".downcase(:invalid_option) }.should raise_error(ArgumentError) end - ruby_version_is ''...'2.7' do - it "taints result when self is tainted" do - "".taint.downcase.should.tainted? - "x".taint.downcase.should.tainted? - "X".taint.downcase.should.tainted? - end - end - ruby_version_is ''...'3.0' do it "returns a subclass instance for subclasses" do StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(StringSpecs::MyString) diff --git a/spec/ruby/core/string/dump_spec.rb b/spec/ruby/core/string/dump_spec.rb index 817dec6c4d..79a8b55e6d 100644 --- a/spec/ruby/core/string/dump_spec.rb +++ b/spec/ruby/core/string/dump_spec.rb @@ -3,18 +3,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "String#dump" do - ruby_version_is ''...'2.7' do - it "taints the result if self is tainted" do - "foo".taint.dump.should.tainted? - "foo\n".taint.dump.should.tainted? - end - - it "untrusts the result if self is untrusted" do - "foo".untrust.dump.should.untrusted? - "foo\n".untrust.dump.should.untrusted? - end - end - it "does not take into account if a string is frozen" do "foo".freeze.dump.should_not.frozen? end diff --git a/spec/ruby/core/string/element_set_spec.rb b/spec/ruby/core/string/element_set_spec.rb index c9e02a7381..881b4343d4 100644 --- a/spec/ruby/core/string/element_set_spec.rb +++ b/spec/ruby/core/string/element_set_spec.rb @@ -14,18 +14,6 @@ describe "String#[]= with Integer index" do a.should == "bamelo" end - ruby_version_is ''...'2.7' do - it "taints self if other_str is tainted" do - a = "hello" - a[0] = "".taint - a.should.tainted? - - a = "hello" - a[0] = "x".taint - a.should.tainted? - end - end - it "raises an IndexError without changing self if idx is outside of self" do str = "hello" @@ -141,6 +129,12 @@ describe "String#[]= with Integer index" do str.encoding.should equal(Encoding::BINARY) end + it "updates the string to a compatible encoding" do + str = " " + str[1] = [0xB9].pack("C*") + str.encoding.should == Encoding::ASCII_8BIT + end + it "raises an Encoding::CompatibilityError if the replacement encoding is incompatible" do str = "あれ" rep = "が".encode Encoding::EUC_JP @@ -487,18 +481,6 @@ describe "String#[]= with Integer index, count" do a.should == "hellobob" end - ruby_version_is ''...'2.7' do - it "taints self if other_str is tainted" do - a = "hello" - a[0, 0] = "".taint - a.should.tainted? - - a = "hello" - a[1, 4] = "x".taint - a.should.tainted? - end - end - it "calls #to_int to convert the index and count objects" do index = mock("string element set index") index.should_receive(:to_int).and_return(-4) diff --git a/spec/ruby/core/string/gsub_spec.rb b/spec/ruby/core/string/gsub_spec.rb index ad41b7e0a2..3211ebbd0a 100644 --- a/spec/ruby/core/string/gsub_spec.rb +++ b/spec/ruby/core/string/gsub_spec.rb @@ -160,56 +160,12 @@ describe "String#gsub with pattern and replacement" do it_behaves_like :string_gsub_named_capture, :gsub - ruby_version_is ''...'2.7' do - it "taints the result if the original string or replacement is tainted" do - hello = "hello" - hello_t = "hello" - a = "a" - a_t = "a" - empty = "" - empty_t = "" - - hello_t.taint; a_t.taint; empty_t.taint - - hello_t.gsub(/./, a).should.tainted? - hello_t.gsub(/./, empty).should.tainted? - - hello.gsub(/./, a_t).should.tainted? - hello.gsub(/./, empty_t).should.tainted? - hello.gsub(//, empty_t).should.tainted? - - hello.gsub(//.taint, "foo").should_not.tainted? - end - end - it "handles pattern collapse" do str = "こにちわ" reg = %r!! str.gsub(reg, ".").should == ".こ.に.ち.わ." end - ruby_version_is ''...'2.7' do - it "untrusts the result if the original string or replacement is untrusted" do - hello = "hello" - hello_t = "hello" - a = "a" - a_t = "a" - empty = "" - empty_t = "" - - hello_t.untrust; a_t.untrust; empty_t.untrust - - hello_t.gsub(/./, a).should.untrusted? - hello_t.gsub(/./, empty).should.untrusted? - - hello.gsub(/./, a_t).should.untrusted? - hello.gsub(/./, empty_t).should.untrusted? - hello.gsub(//, empty_t).should.untrusted? - - hello.gsub(//.untrust, "foo").should_not.untrusted? - end - end - it "tries to convert pattern to a string using to_str" do pattern = mock('.') def pattern.to_str() "." end @@ -336,28 +292,6 @@ describe "String#gsub with pattern and Hash" do repl = '\& \0 \1 \` \\\' \+ \\\\ foo' "hello".gsub(/(.+)/, 'hello' => repl ).should == repl end - - ruby_version_is ''...'2.7' do - it "untrusts the result if the original string is untrusted" do - str = "Ghana".untrust - str.gsub(/[Aa]na/, 'ana' => '').untrusted?.should be_true - end - - it "untrusts the result if a hash value is untrusted" do - str = "Ghana" - str.gsub(/a$/, 'a' => 'di'.untrust).untrusted?.should be_true - end - - it "taints the result if the original string is tainted" do - str = "Ghana".taint - str.gsub(/[Aa]na/, 'ana' => '').tainted?.should be_true - end - - it "taints the result if a hash value is tainted" do - str = "Ghana" - str.gsub(/a$/, 'a' => 'di'.taint).tainted?.should be_true - end - end end describe "String#gsub! with pattern and Hash" do @@ -426,28 +360,6 @@ describe "String#gsub! with pattern and Hash" do repl = '\& \0 \1 \` \\\' \+ \\\\ foo' "hello".gsub!(/(.+)/, 'hello' => repl ).should == repl end - - ruby_version_is ''...'2.7' do - it "keeps untrusted state" do - str = "Ghana".untrust - str.gsub!(/[Aa]na/, 'ana' => '').untrusted?.should be_true - end - - it "untrusts self if a hash value is untrusted" do - str = "Ghana" - str.gsub!(/a$/, 'a' => 'di'.untrust).untrusted?.should be_true - end - - it "keeps tainted state" do - str = "Ghana".taint - str.gsub!(/[Aa]na/, 'ana' => '').tainted?.should be_true - end - - it "taints self if a hash value is tainted" do - str = "Ghana" - str.gsub!(/a$/, 'a' => 'di'.taint).tainted?.should be_true - end - end end describe "String#gsub with pattern and block" do @@ -526,28 +438,6 @@ describe "String#gsub with pattern and block" do "hello".gsub(/.+/) { obj }.should == "ok" end - ruby_version_is ''...'2.7' do - it "untrusts the result if the original string or replacement is untrusted" do - hello = "hello" - hello_t = "hello" - a = "a" - a_t = "a" - empty = "" - empty_t = "" - - hello_t.untrust; a_t.untrust; empty_t.untrust - - hello_t.gsub(/./) { a }.should.untrusted? - hello_t.gsub(/./) { empty }.should.untrusted? - - hello.gsub(/./) { a_t }.should.untrusted? - hello.gsub(/./) { empty_t }.should.untrusted? - hello.gsub(//) { empty_t }.should.untrusted? - - hello.gsub(//.untrust) { "foo" }.should_not.untrusted? - end - end - it "uses the compatible encoding if they are compatible" do s = "hello" s2 = "#{195.chr}#{192.chr}#{195.chr}" @@ -615,20 +505,6 @@ describe "String#gsub! with pattern and replacement" do a.should == "*¿** **é*?*" end - ruby_version_is ''...'2.7' do - it "taints self if replacement is tainted" do - a = "hello" - a.gsub!(/./.taint, "foo").should_not.tainted? - a.gsub!(/./, "foo".taint).should.tainted? - end - - it "untrusts self if replacement is untrusted" do - a = "hello" - a.gsub!(/./.untrust, "foo").should_not.untrusted? - a.gsub!(/./, "foo".untrust).should.untrusted? - end - end - it "returns nil if no modifications were made" do a = "hello" a.gsub!(/z/, '*').should == nil @@ -654,20 +530,6 @@ describe "String#gsub! with pattern and block" do a.should == "h*ll*" end - ruby_version_is ''...'2.7' do - it "taints self if block's result is tainted" do - a = "hello" - a.gsub!(/./.taint) { "foo" }.should_not.tainted? - a.gsub!(/./) { "foo".taint }.should.tainted? - end - - it "untrusts self if block's result is untrusted" do - a = "hello" - a.gsub!(/./.untrust) { "foo" }.should_not.untrusted? - a.gsub!(/./) { "foo".untrust }.should.untrusted? - end - end - it "returns nil if no modifications were made" do a = "hello" a.gsub!(/z/) { '*' }.should == nil diff --git a/spec/ruby/core/string/insert_spec.rb b/spec/ruby/core/string/insert_spec.rb index 752cbb2f37..db42a37941 100644 --- a/spec/ruby/core/string/insert_spec.rb +++ b/spec/ruby/core/string/insert_spec.rb @@ -41,18 +41,6 @@ describe "String#insert with index, other" do "abcd".insert(-3, other).should == "abXYZcd" end - ruby_version_is ''...'2.7' do - it "taints self if string to insert is tainted" do - str = "abcd" - str.insert(0, "T".taint).should.tainted? - - str = "abcd" - other = mock('T') - def other.to_str() "T".taint end - str.insert(0, other).should.tainted? - end - end - it "raises a TypeError if other can't be converted to string" do -> { "abcd".insert(-6, Object.new)}.should raise_error(TypeError) -> { "abcd".insert(-6, []) }.should raise_error(TypeError) diff --git a/spec/ruby/core/string/inspect_spec.rb b/spec/ruby/core/string/inspect_spec.rb index 98b5b32b61..8bfd465144 100644 --- a/spec/ruby/core/string/inspect_spec.rb +++ b/spec/ruby/core/string/inspect_spec.rb @@ -3,18 +3,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "String#inspect" do - ruby_version_is ''...'2.7' do - it "taints the result if self is tainted" do - "foo".taint.inspect.should.tainted? - "foo\n".taint.inspect.should.tainted? - end - - it "untrusts the result if self is untrusted" do - "foo".untrust.inspect.should.untrusted? - "foo\n".untrust.inspect.should.untrusted? - end - end - it "does not return a subclass instance" do StringSpecs::MyString.new.inspect.should be_an_instance_of(String) end diff --git a/spec/ruby/core/string/ljust_spec.rb b/spec/ruby/core/string/ljust_spec.rb index 0c3b2a2f44..9a25d3abd4 100644 --- a/spec/ruby/core/string/ljust_spec.rb +++ b/spec/ruby/core/string/ljust_spec.rb @@ -31,16 +31,6 @@ describe "String#ljust with length, padding" do "radiology".ljust(8, '-').should == "radiology" end - ruby_version_is ''...'2.7' do - it "taints result when self or padstr is tainted" do - "x".taint.ljust(4).should.tainted? - "x".taint.ljust(0).should.tainted? - "".taint.ljust(0).should.tainted? - "x".taint.ljust(4, "*").should.tainted? - "x".ljust(4, "*".taint).should.tainted? - end - end - it "tries to convert length to an integer using to_int" do "^".ljust(3.8, "_^").should == "^_^" @@ -96,14 +86,6 @@ describe "String#ljust with length, padding" do end end - ruby_version_is ''...'2.7' do - it "when padding is tainted and self is untainted returns a tainted string if and only if length is longer than self" do - "hello".ljust(4, 'X'.taint).tainted?.should be_false - "hello".ljust(5, 'X'.taint).tainted?.should be_false - "hello".ljust(6, 'X'.taint).tainted?.should be_true - end - end - describe "with width" do it "returns a String in the same encoding as the original" do str = "abc".force_encoding Encoding::IBM437 diff --git a/spec/ruby/core/string/lstrip_spec.rb b/spec/ruby/core/string/lstrip_spec.rb index 20e4cdeabd..6e868eac4f 100644 --- a/spec/ruby/core/string/lstrip_spec.rb +++ b/spec/ruby/core/string/lstrip_spec.rb @@ -12,20 +12,12 @@ describe "String#lstrip" do "hello".lstrip.should == "hello" end - ruby_version_is '3.1' do + ruby_version_is '3.0' do it "strips leading \\0" do "\x00hello".lstrip.should == "hello" "\000 \000hello\000 \000".lstrip.should == "hello\000 \000" end end - - ruby_version_is ''...'2.7' do - it "taints the result when self is tainted" do - "".taint.lstrip.should.tainted? - "ok".taint.lstrip.should.tainted? - " ok".taint.lstrip.should.tainted? - end - end end describe "String#lstrip!" do @@ -35,7 +27,7 @@ describe "String#lstrip!" do a.should == "hello " end - ruby_version_is '3.1' do + ruby_version_is '3.0' do it "strips leading \\0" do a = "\000 \000hello\000 \000" a.lstrip! diff --git a/spec/ruby/core/string/modulo_spec.rb b/spec/ruby/core/string/modulo_spec.rb index dc11ced4e2..99c1694417 100644 --- a/spec/ruby/core/string/modulo_spec.rb +++ b/spec/ruby/core/string/modulo_spec.rb @@ -302,29 +302,6 @@ describe "String#%" do end end - ruby_version_is ''...'2.7' do - it "always taints the result when the format string is tainted" do - universal = mock('0') - def universal.to_int() 0 end - def universal.to_str() "0" end - def universal.to_f() 0.0 end - - [ - "", "foo", - "%b", "%B", "%c", "%d", "%e", "%E", - "%f", "%g", "%G", "%i", "%o", "%p", - "%s", "%u", "%x", "%X" - ].each do |format| - subcls_format = StringSpecs::MyString.new(format) - subcls_format.taint - format.taint - - (format % universal).should.tainted? - (subcls_format % universal).should.tainted? - end - end - end - it "supports binary formats using %b for positive numbers" do ("%b" % 10).should == "1010" ("% b" % 10).should == " 1010" @@ -578,20 +555,6 @@ describe "String#%" do # ("%p" % obj).should == "obj" end - ruby_version_is ''...'2.7' do - it "taints result for %p when argument.inspect is tainted" do - obj = mock('x') - def obj.inspect() "x".taint end - - ("%p" % obj).should.tainted? - - obj = mock('x'); obj.taint - def obj.inspect() "x" end - - ("%p" % obj).should_not.tainted? - end - end - it "supports string formats using %s" do ("%s" % "hello").should == "hello" ("%s" % "").should == "" @@ -620,13 +583,6 @@ describe "String#%" do # ("%s" % obj).should == "obj" end - ruby_version_is ''...'2.7' do - it "taints result for %s when argument is tainted" do - ("%s" % "x".taint).should.tainted? - ("%s" % mock('x').taint).should.tainted? - end - end - # MRI crashes on this one. # See http://groups.google.com/group/ruby-core-google/t/c285c18cd94c216d it "raises an ArgumentError for huge precisions for %s" do @@ -786,12 +742,6 @@ describe "String#%" do it "behaves as if calling Kernel#Float for #{format} arguments, when the passed argument is hexadecimal string" do (format % "0xA").should == (format % 0xA) end - - ruby_version_is ''...'2.7' do - it "doesn't taint the result for #{format} when argument is tainted" do - (format % "5".taint).should_not.tainted? - end - end end describe "when format string contains %{} sections" do diff --git a/spec/ruby/core/string/plus_spec.rb b/spec/ruby/core/string/plus_spec.rb index 9f0db6427c..5ff198f07e 100644 --- a/spec/ruby/core/string/plus_spec.rb +++ b/spec/ruby/core/string/plus_spec.rb @@ -32,18 +32,5 @@ describe "String#+" do ("hello" + StringSpecs::MyString.new("")).should be_an_instance_of(String) end - ruby_version_is ''...'2.7' do - it "taints the result when self or other is tainted" do - strs = ["", "OK", StringSpecs::MyString.new(""), StringSpecs::MyString.new("OK")] - strs += strs.map { |s| s.dup.taint } - - strs.each do |str| - strs.each do |other| - (str + other).tainted?.should == (str.tainted? | other.tainted?) - end - end - end - end - it_behaves_like :string_concat_encoding, :+ end diff --git a/spec/ruby/core/string/prepend_spec.rb b/spec/ruby/core/string/prepend_spec.rb index a6074be3c6..a0393d4760 100644 --- a/spec/ruby/core/string/prepend_spec.rb +++ b/spec/ruby/core/string/prepend_spec.rb @@ -34,16 +34,6 @@ describe "String#prepend" do a.should == "hello world" end - ruby_version_is ''...'2.7' do - it "taints self if other is tainted" do - x = "x" - x.prepend("".taint).tainted?.should be_true - - x = "x" - x.prepend("y".taint).tainted?.should be_true - end - end - it "takes multiple arguments" do str = " world" str.prepend "he", "", "llo" diff --git a/spec/ruby/core/string/reverse_spec.rb b/spec/ruby/core/string/reverse_spec.rb index b45ff2cf6f..bade4685d9 100644 --- a/spec/ruby/core/string/reverse_spec.rb +++ b/spec/ruby/core/string/reverse_spec.rb @@ -26,13 +26,6 @@ describe "String#reverse" do end end - ruby_version_is ''...'2.7' do - it "taints the result if self is tainted" do - "".taint.reverse.should.tainted? - "m".taint.reverse.should.tainted? - end - end - it "reverses a string with multi byte characters" do "微軟正黑體".reverse.should == "體黑正軟微" end diff --git a/spec/ruby/core/string/rindex_spec.rb b/spec/ruby/core/string/rindex_spec.rb index 7a6af0c9d0..a3b437a1e4 100644 --- a/spec/ruby/core/string/rindex_spec.rb +++ b/spec/ruby/core/string/rindex_spec.rb @@ -4,13 +4,17 @@ require_relative 'fixtures/classes' require_relative 'fixtures/utf-8-encoding' describe "String#rindex with object" do - it "raises a TypeError if obj isn't a String, Integer or Regexp" do + it "raises a TypeError if obj isn't a String or Regexp" do not_supported_on :opal do -> { "hello".rindex(:sym) }.should raise_error(TypeError) end -> { "hello".rindex(mock('x')) }.should raise_error(TypeError) end + it "raises a TypeError if obj is an Integer" do + -> { "hello".rindex(42) }.should raise_error(TypeError) + end + it "doesn't try to convert obj to an integer via to_int" do obj = mock('x') obj.should_not_receive(:to_int) diff --git a/spec/ruby/core/string/rjust_spec.rb b/spec/ruby/core/string/rjust_spec.rb index f51aacff44..d067b7bdb3 100644 --- a/spec/ruby/core/string/rjust_spec.rb +++ b/spec/ruby/core/string/rjust_spec.rb @@ -31,16 +31,6 @@ describe "String#rjust with length, padding" do "radiology".rjust(8, '-').should == "radiology" end - ruby_version_is ''...'2.7' do - it "taints result when self or padstr is tainted" do - "x".taint.rjust(4).should.tainted? - "x".taint.rjust(0).should.tainted? - "".taint.rjust(0).should.tainted? - "x".taint.rjust(4, "*").should.tainted? - "x".rjust(4, "*".taint).should.tainted? - end - end - it "tries to convert length to an integer using to_int" do "^".rjust(3.8, "^_").should == "^_^" @@ -96,14 +86,6 @@ describe "String#rjust with length, padding" do end end - ruby_version_is ''...'2.7' do - it "when padding is tainted and self is untainted returns a tainted string if and only if length is longer than self" do - "hello".rjust(4, 'X'.taint).tainted?.should be_false - "hello".rjust(5, 'X'.taint).tainted?.should be_false - "hello".rjust(6, 'X'.taint).tainted?.should be_true - end - end - describe "with width" do it "returns a String in the same encoding as the original" do str = "abc".force_encoding Encoding::IBM437 diff --git a/spec/ruby/core/string/rstrip_spec.rb b/spec/ruby/core/string/rstrip_spec.rb index a1453f91fe..2dc55182ae 100644 --- a/spec/ruby/core/string/rstrip_spec.rb +++ b/spec/ruby/core/string/rstrip_spec.rb @@ -16,14 +16,6 @@ describe "String#rstrip" do it "returns a copy of self with all trailing whitespace and NULL bytes removed" do "\x00 \x00hello\x00 \x00".rstrip.should == "\x00 \x00hello" end - - ruby_version_is ''...'2.7' do - it "taints the result when self is tainted" do - "".taint.rstrip.should.tainted? - "ok".taint.rstrip.should.tainted? - "ok ".taint.rstrip.should.tainted? - end - end end describe "String#rstrip!" do diff --git a/spec/ruby/core/string/scan_spec.rb b/spec/ruby/core/string/scan_spec.rb index 5f86dbbecc..ab73f5747b 100644 --- a/spec/ruby/core/string/scan_spec.rb +++ b/spec/ruby/core/string/scan_spec.rb @@ -65,28 +65,6 @@ describe "String#scan" do -> { "cruel world".scan(mock('x')) }.should raise_error(TypeError) end - ruby_version_is ''...'2.7' do - it "taints the results if the String argument is tainted" do - a = "hello hello hello".scan("hello".taint) - a.each { |m| m.tainted?.should be_true } - end - - it "taints the results when passed a String argument if self is tainted" do - a = "hello hello hello".taint.scan("hello") - a.each { |m| m.tainted?.should be_true } - end - - it "taints the results if the Regexp argument is tainted" do - a = "hello".scan(/./.taint) - a.each { |m| m.tainted?.should be_true } - end - - it "taints the results when passed a Regexp argument if self is tainted" do - a = "hello".taint.scan(/./) - a.each { |m| m.tainted?.should be_true } - end - end - # jruby/jruby#5513 it "does not raise any errors when passed a multi-byte string" do "あああaaaあああ".scan("あああ").should == ["あああ", "あああ"] @@ -173,24 +151,6 @@ describe "String#scan with pattern and block" do $~.should == nil end - ruby_version_is ''...'2.7' do - it "taints the results if the String argument is tainted" do - "hello hello hello".scan("hello".taint).each { |m| m.tainted?.should be_true } - end - - it "taints the results when passed a String argument if self is tainted" do - "hello hello hello".taint.scan("hello").each { |m| m.tainted?.should be_true } - end - - it "taints the results if the Regexp argument is tainted" do - "hello".scan(/./.taint).each { |m| m.tainted?.should be_true } - end - - it "taints the results when passed a Regexp argument if self is tainted" do - "hello".taint.scan(/./).each { |m| m.tainted?.should be_true } - end - end - it "passes block arguments as individual arguments when blocks are provided" do "a b c\na b c\na b c".scan(/(\w*) (\w*) (\w*)/) do |first,second,third| first.should == 'a'; diff --git a/spec/ruby/core/string/shared/chars.rb b/spec/ruby/core/string/shared/chars.rb index 1f045e4530..e9fdf89fd6 100644 --- a/spec/ruby/core/string/shared/chars.rb +++ b/spec/ruby/core/string/shared/chars.rb @@ -63,18 +63,4 @@ describe :string_chars, shared: true do [0xA2].pack('C').force_encoding('SJIS') ] end - - ruby_version_is ''...'2.7' do - it "taints resulting strings when self is tainted" do - str = "hello" - - str.send(@method) do |x| - x.should_not.tainted? - end - - str.dup.taint.send(@method) do |x| - x.should.tainted? - end - end - end end diff --git a/spec/ruby/core/string/shared/concat.rb b/spec/ruby/core/string/shared/concat.rb index d6ffad7d4d..54ac1035d3 100644 --- a/spec/ruby/core/string/shared/concat.rb +++ b/spec/ruby/core/string/shared/concat.rb @@ -39,18 +39,6 @@ describe :string_concat, shared: true do str.should be_an_instance_of(StringSpecs::MyString) end - ruby_version_is ''...'2.7' do - it "taints self if other is tainted" do - "x".send(@method, "".taint).should.tainted? - "x".send(@method, "y".taint).should.tainted? - end - - it "untrusts self if other is untrusted" do - "x".send(@method, "".untrust).should.untrusted? - "x".send(@method, "y".untrust).should.untrusted? - end - end - describe "with Integer" do it "concatenates the argument interpreted as a codepoint" do b = "".send(@method, 33) diff --git a/spec/ruby/core/string/shared/dedup.rb b/spec/ruby/core/string/shared/dedup.rb new file mode 100644 index 0000000000..345e874583 --- /dev/null +++ b/spec/ruby/core/string/shared/dedup.rb @@ -0,0 +1,47 @@ +describe :string_dedup, shared: true do + it 'returns self if the String is frozen' do + input = 'foo'.freeze + output = input.send(@method) + + output.should equal(input) + output.should.frozen? + end + + it 'returns a frozen copy if the String is not frozen' do + input = 'foo' + output = input.send(@method) + + output.should.frozen? + output.should_not equal(input) + output.should == 'foo' + end + + it "returns the same object for equal unfrozen strings" do + origin = "this is a string" + dynamic = %w(this is a string).join(' ') + + origin.should_not equal(dynamic) + origin.send(@method).should equal(dynamic.send(@method)) + end + + it "returns the same object when it's called on the same String literal" do + "unfrozen string".send(@method).should equal("unfrozen string".send(@method)) + "unfrozen string".send(@method).should_not equal("another unfrozen string".send(@method)) + end + + it "deduplicates frozen strings" do + dynamic = %w(this string is frozen).join(' ').freeze + + dynamic.should_not equal("this string is frozen".freeze) + + dynamic.send(@method).should equal("this string is frozen".freeze) + dynamic.send(@method).should equal("this string is frozen".send(@method).freeze) + end + + ruby_version_is "3.0" do + it "interns the provided string if it is frozen" do + dynamic = "this string is unique and frozen #{rand}".freeze + dynamic.send(@method).should equal(dynamic) + end + end +end diff --git a/spec/ruby/core/string/shared/each_line.rb b/spec/ruby/core/string/shared/each_line.rb index f9c910596a..bfedf8f35a 100644 --- a/spec/ruby/core/string/shared/each_line.rb +++ b/spec/ruby/core/string/shared/each_line.rb @@ -40,14 +40,6 @@ describe :string_each_line, shared: true do b.should == ["foo\n", "🤡🤡🤡🤡🤡🤡🤡\n", "bar\n", "baz\n"] end - ruby_version_is ''...'2.7' do - it "taints substrings that are passed to the block if self is tainted" do - "one\ntwo\r\nthree".taint.send(@method) { |s| s.should.tainted? } - - "x.y.".send(@method, ".".taint) { |s| s.should_not.tainted? } - end - end - it "passes self as a whole to the block if the separator is nil" do a = [] "one\ntwo\r\nthree".send(@method, nil) { |s| a << s } diff --git a/spec/ruby/core/string/shared/eql.rb b/spec/ruby/core/string/shared/eql.rb index b57d6895ff..6f268c929c 100644 --- a/spec/ruby/core/string/shared/eql.rb +++ b/spec/ruby/core/string/shared/eql.rb @@ -31,4 +31,8 @@ describe :string_eql_value, shared: true do a.send(@method, b).should be_true b.send(@method, a).should be_true end + + it "returns true when comparing 2 empty strings but one is not ASCII-compatible" do + "".send(@method, "".force_encoding('iso-2022-jp')).should == true + end end diff --git a/spec/ruby/core/string/shared/length.rb b/spec/ruby/core/string/shared/length.rb index e931961455..94e5ec135b 100644 --- a/spec/ruby/core/string/shared/length.rb +++ b/spec/ruby/core/string/shared/length.rb @@ -12,9 +12,9 @@ describe :string_length, shared: true do it "returns the length of a string in different encodings" do utf8_str = 'こにちわ' * 100 - utf8_str.size.should == 400 - utf8_str.encode(Encoding::UTF_32BE).size.should == 400 - utf8_str.encode(Encoding::SHIFT_JIS).size.should == 400 + utf8_str.send(@method).should == 400 + utf8_str.encode(Encoding::UTF_32BE).send(@method).should == 400 + utf8_str.encode(Encoding::SHIFT_JIS).send(@method).should == 400 end it "returns the length of the new self after encoding is changed" do @@ -32,24 +32,24 @@ describe :string_length, shared: true do concat.encoding.should == Encoding::UTF_8 concat.bytesize.should == 4 - concat.size.should == 2 + concat.send(@method).should == 2 concat.force_encoding(Encoding::ASCII_8BIT) - concat.size.should == 4 + concat.send(@method).should == 4 end it "adds 1 for every invalid byte in UTF-8" do - "\xF4\x90\x80\x80".size.should == 4 - "a\xF4\x90\x80\x80b".size.should == 6 - "é\xF4\x90\x80\x80è".size.should == 6 + "\xF4\x90\x80\x80".send(@method).should == 4 + "a\xF4\x90\x80\x80b".send(@method).should == 6 + "é\xF4\x90\x80\x80è".send(@method).should == 6 end it "adds 1 (and not 2) for a incomplete surrogate in UTF-16" do - "\x00\xd8".force_encoding("UTF-16LE").size.should == 1 - "\xd8\x00".force_encoding("UTF-16BE").size.should == 1 + "\x00\xd8".force_encoding("UTF-16LE").send(@method).should == 1 + "\xd8\x00".force_encoding("UTF-16BE").send(@method).should == 1 end it "adds 1 for a broken sequence in UTF-32" do - "\x04\x03\x02\x01".force_encoding("UTF-32LE").size.should == 1 - "\x01\x02\x03\x04".force_encoding("UTF-32BE").size.should == 1 + "\x04\x03\x02\x01".force_encoding("UTF-32LE").send(@method).should == 1 + "\x01\x02\x03\x04".force_encoding("UTF-32BE").send(@method).should == 1 end end diff --git a/spec/ruby/core/string/shared/replace.rb b/spec/ruby/core/string/shared/replace.rb index 8dfac49f02..a5108d9e7c 100644 --- a/spec/ruby/core/string/shared/replace.rb +++ b/spec/ruby/core/string/shared/replace.rb @@ -10,36 +10,6 @@ describe :string_replace, shared: true do a.should == "another string" end - ruby_version_is ''...'2.7' do - it "taints self if other is tainted" do - a = "" - b = "".taint - a.send(@method, b) - a.should.tainted? - end - - it "does not untaint self if other is untainted" do - a = "".taint - b = "" - a.send(@method, b) - a.should.tainted? - end - - it "untrusts self if other is untrusted" do - a = "" - b = "".untrust - a.send(@method, b) - a.should.untrusted? - end - - it "does not trust self if other is trusted" do - a = "".untrust - b = "" - a.send(@method, b) - a.should.untrusted? - end - end - it "replaces the encoding of self with that of other" do a = "".encode("UTF-16LE") b = "".encode("UTF-8") diff --git a/spec/ruby/core/string/shared/slice.rb b/spec/ruby/core/string/shared/slice.rb index 1db8fd6730..228af5f824 100644 --- a/spec/ruby/core/string/shared/slice.rb +++ b/spec/ruby/core/string/shared/slice.rb @@ -80,17 +80,6 @@ describe :string_slice_index_length, shared: true do "hello there".send(@method, -3,2).should == "er" end - ruby_version_is ''...'2.7' do - it "always taints resulting strings when self is tainted" do - str = "hello world" - str.taint - - str.send(@method, 0,0).should.tainted? - str.send(@method, 0,1).should.tainted? - str.send(@method, 2,1).should.tainted? - end - end - it "returns a string with the same encoding" do s = "hello there" s.send(@method, 1, 9).encoding.should == s.encoding @@ -249,20 +238,6 @@ describe :string_slice_range, shared: true do "x".send(@method, 1...-1).should == "" end - ruby_version_is ''...'2.7' do - it "always taints resulting strings when self is tainted" do - str = "hello world" - str.taint - - str.send(@method, 0..0).should.tainted? - str.send(@method, 0...0).should.tainted? - str.send(@method, 0..1).should.tainted? - str.send(@method, 0...1).should.tainted? - str.send(@method, 2..3).should.tainted? - str.send(@method, 2..0).should.tainted? - end - end - ruby_version_is ''...'3.0' do it "returns subclass instances" do s = StringSpecs::MyString.new("hello") @@ -334,14 +309,12 @@ describe :string_slice_range, shared: true do "hello there".send(@method, eval("(-4...)")).should == "here" end - ruby_version_is "2.7" do - it "works with beginless ranges" do - "hello there".send(@method, eval("(..5)")).should == "hello " - "hello there".send(@method, eval("(...5)")).should == "hello" - "hello there".send(@method, eval("(..-4)")).should == "hello th" - "hello there".send(@method, eval("(...-4)")).should == "hello t" - "hello there".send(@method, eval("(...nil)")).should == "hello there" - end + it "works with beginless ranges" do + "hello there".send(@method, (..5)).should == "hello " + "hello there".send(@method, (...5)).should == "hello" + "hello there".send(@method, (..-4)).should == "hello th" + "hello there".send(@method, (...-4)).should == "hello t" + "hello there".send(@method, (...nil)).should == "hello there" end end @@ -356,26 +329,6 @@ describe :string_slice_regexp, shared: true do end not_supported_on :opal do - ruby_version_is ''...'2.7' do - it "always taints resulting strings when self or regexp is tainted" do - strs = ["hello world"] - strs += strs.map { |s| s.dup.taint } - - strs.each do |str| - str.send(@method, //).tainted?.should == str.tainted? - str.send(@method, /hello/).tainted?.should == str.tainted? - - tainted_re = /./ - tainted_re.taint - - str.send(@method, tainted_re).should.tainted? - end - end - - it "returns an untrusted string if the regexp is untrusted" do - "hello".send(@method, /./.untrust).untrusted?.should be_true - end - end end ruby_version_is ''...'3.0' do @@ -418,36 +371,6 @@ describe :string_slice_regexp_index, shared: true do "har".send(@method, /(.)(.)(.)/, -3).should == "h" end - ruby_version_is ''...'2.7' do - it "always taints resulting strings when self or regexp is tainted" do - strs = ["hello world"] - strs += strs.map { |s| s.dup.taint } - - strs.each do |str| - str.send(@method, //, 0).tainted?.should == str.tainted? - str.send(@method, /hello/, 0).tainted?.should == str.tainted? - - str.send(@method, /(.)(.)(.)/, 0).tainted?.should == str.tainted? - str.send(@method, /(.)(.)(.)/, 1).tainted?.should == str.tainted? - str.send(@method, /(.)(.)(.)/, -1).tainted?.should == str.tainted? - str.send(@method, /(.)(.)(.)/, -2).tainted?.should == str.tainted? - - tainted_re = /(.)(.)(.)/ - tainted_re.taint - - str.send(@method, tainted_re, 0).should.tainted? - str.send(@method, tainted_re, 1).should.tainted? - str.send(@method, tainted_re, -1).should.tainted? - end - end - - not_supported_on :opal do - it "returns an untrusted string if the regexp is untrusted" do - "hello".send(@method, /(.)/.untrust, 1).untrusted?.should be_true - end - end - end - it "returns nil if there is no match" do "hello there".send(@method, /(what?)/, 1).should == nil end @@ -510,21 +433,6 @@ describe :string_slice_string, shared: true do "hello there".send(@method, s).should == s end - ruby_version_is ''...'2.7' do - it "taints resulting strings when other is tainted" do - strs = ["", "hello world", "hello"] - strs += strs.map { |s| s.dup.taint } - - strs.each do |str| - strs.each do |other| - r = str.send(@method, other) - - r.tainted?.should == !r.nil? & other.tainted? - end - end - end - end - it "doesn't set $~" do $~ = nil @@ -584,30 +492,6 @@ describe :string_slice_regexp_group, shared: true do "hello there".send(@method, /(?<g>h(?<g>.))/, 'g').should == "e" end - ruby_version_is ''...'2.7' do - it "always taints resulting strings when self or regexp is tainted" do - strs = ["hello world"] - strs += strs.map { |s| s.dup.taint } - - strs.each do |str| - str.send(@method, /(?<hi>hello)/, 'hi').tainted?.should == str.tainted? - - str.send(@method, /(?<g>(.)(.)(.))/, 'g').tainted?.should == str.tainted? - str.send(@method, /(?<h>.)(.)(.)/, 'h').tainted?.should == str.tainted? - str.send(@method, /(.)(?<a>.)(.)/, 'a').tainted?.should == str.tainted? - str.send(@method, /(.)(.)(?<r>.)/, 'r').tainted?.should == str.tainted? - str.send(@method, /(?<h>.)(?<a>.)(?<r>.)/, 'r').tainted?.should == str.tainted? - - tainted_re = /(?<a>.)(?<b>.)(?<c>.)/ - tainted_re.taint - - str.send(@method, tainted_re, 'a').tainted?.should be_true - str.send(@method, tainted_re, 'b').tainted?.should be_true - str.send(@method, tainted_re, 'c').tainted?.should be_true - end - end - end - it "returns nil if there is no match" do "hello there".send(@method, /(?<whut>what?)/, 'whut').should be_nil end diff --git a/spec/ruby/core/string/shared/succ.rb b/spec/ruby/core/string/shared/succ.rb index 25602103b6..66edf6dc82 100644 --- a/spec/ruby/core/string/shared/succ.rb +++ b/spec/ruby/core/string/shared/succ.rb @@ -74,14 +74,6 @@ describe :string_succ, shared: true do StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(String) end end - - ruby_version_is ''...'2.7' do - it "taints the result if self is tainted" do - ["", "a", "z", "Z", "9", "\xFF", "\xFF\xFF"].each do |s| - s.taint.send(@method).should.tainted? - end - end - end end describe :string_succ_bang, shared: true do diff --git a/spec/ruby/core/string/shared/to_s.rb b/spec/ruby/core/string/shared/to_s.rb index b8c9b8ab44..4b87a6cbe1 100644 --- a/spec/ruby/core/string/shared/to_s.rb +++ b/spec/ruby/core/string/shared/to_s.rb @@ -10,11 +10,4 @@ describe :string_to_s, shared: true do s.should == "a string" s.should be_an_instance_of(String) end - - ruby_version_is ''...'2.7' do - it "taints the result when self is tainted" do - "x".taint.send(@method).should.tainted? - StringSpecs::MyString.new("x").taint.send(@method).should.tainted? - end - end end diff --git a/spec/ruby/core/string/shared/to_sym.rb b/spec/ruby/core/string/shared/to_sym.rb index 416f302aef..ef7c22bb6a 100644 --- a/spec/ruby/core/string/shared/to_sym.rb +++ b/spec/ruby/core/string/shared/to_sym.rb @@ -53,6 +53,15 @@ describe :string_to_sym, shared: true do sym.to_s.should == binary_string end + it "ignores existing symbols with different encoding" do + source = "fée" + + iso_symbol = source.force_encoding(Encoding::ISO_8859_1).send(@method) + iso_symbol.encoding.should == Encoding::ISO_8859_1 + binary_symbol = source.force_encoding(Encoding::BINARY).send(@method) + binary_symbol.encoding.should == Encoding::BINARY + end + it "raises an EncodingError for UTF-8 String containing invalid bytes" do invalid_utf8 = "\xC3" invalid_utf8.should_not.valid_encoding? diff --git a/spec/ruby/core/string/slice_spec.rb b/spec/ruby/core/string/slice_spec.rb index 83b475c8b5..c9e13ed1bc 100644 --- a/spec/ruby/core/string/slice_spec.rb +++ b/spec/ruby/core/string/slice_spec.rb @@ -94,16 +94,6 @@ describe "String#slice! with index, length" do a.should == "h" end - ruby_version_is ''...'2.7' do - it "always taints resulting strings when self is tainted" do - str = "hello world" - str.taint - - str.slice!(0, 0).should.tainted? - str.slice!(2, 1).should.tainted? - end - end - it "returns nil if the given position is out of self" do a = "hello" a.slice(10, 3).should == nil @@ -195,16 +185,6 @@ describe "String#slice! Range" do b.should == "hello" end - ruby_version_is ''...'2.7' do - it "always taints resulting strings when self is tainted" do - str = "hello world" - str.taint - - str.slice!(0..0).should.tainted? - str.slice!(2..3).should.tainted? - end - end - ruby_version_is ''...'3.0' do it "returns subclass instances" do s = StringSpecs::MyString.new("hello") @@ -294,30 +274,6 @@ describe "String#slice! with Regexp" do s.should == "this is a string" end - ruby_version_is ''...'2.7' do - it "always taints resulting strings when self or regexp is tainted" do - strs = ["hello world"] - strs += strs.map { |s| s.dup.taint } - - strs.each do |str| - str = str.dup - str.slice!(//).tainted?.should == str.tainted? - str.slice!(/hello/).tainted?.should == str.tainted? - - tainted_re = /./ - tainted_re.taint - - str.slice!(tainted_re).should.tainted? - end - end - - it "doesn't taint self when regexp is tainted" do - s = "hello" - s.slice!(/./.taint) - s.should_not.tainted? - end - end - ruby_version_is ''...'3.0' do it "returns subclass instances" do s = StringSpecs::MyString.new("hello") @@ -365,30 +321,6 @@ describe "String#slice! with Regexp, index" do str.should == "ho here" end - ruby_version_is ''...'2.7' do - it "always taints resulting strings when self or regexp is tainted" do - strs = ["hello world"] - strs += strs.map { |s| s.dup.taint } - - strs.each do |str| - str = str.dup - str.slice!(//, 0).tainted?.should == str.tainted? - str.slice!(/hello/, 0).tainted?.should == str.tainted? - - tainted_re = /(.)(.)(.)/ - tainted_re.taint - - str.slice!(tainted_re, 1).should.tainted? - end - end - - it "doesn't taint self when regexp is tainted" do - s = "hello" - s.slice!(/(.)(.)/.taint, 1) - s.should_not.tainted? - end - end - it "returns nil if there was no match" do s = "this is a string" s.slice!(/x(zzz)/, 1).should == nil @@ -463,23 +395,6 @@ describe "String#slice! with String" do c.should == "he hello" end - ruby_version_is ''...'2.7' do - it "taints resulting strings when other is tainted" do - strs = ["", "hello world", "hello"] - strs += strs.map { |s| s.dup.taint } - - strs.each do |str| - str = str.dup - strs.each do |other| - other = other.dup - r = str.slice!(other) - - r.tainted?.should == !r.nil? & other.tainted? - end - end - end - end - it "doesn't set $~" do $~ = nil diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb index a373be360d..82911ef50b 100644 --- a/spec/ruby/core/string/split_spec.rb +++ b/spec/ruby/core/string/split_spec.rb @@ -62,6 +62,10 @@ describe "String#split with String" do ",".split(",", -1).should == ["", ""] end + it "raises a RangeError when the limit is larger than int" do + -> { "a,b".split(" ", 2147483649) }.should raise_error(RangeError) + end + it "defaults to $; when string isn't given or nil" do suppress_warning do old_fs = $; @@ -85,21 +89,19 @@ describe "String#split with String" do end end - ruby_version_is "2.7" do - context "when $; is not nil" do - before do - suppress_warning do - @old_value, $; = $;, 'foobar' - end + context "when $; is not nil" do + before do + suppress_warning do + @old_value, $; = $;, 'foobar' end + end - after do - $; = @old_value - end + after do + $; = @old_value + end - it "warns" do - -> { "".split }.should complain(/warning: \$; is set to non-nil value/) - end + it "warns" do + -> { "".split }.should complain(/warning: \$; is set to non-nil value/) end end end @@ -203,22 +205,15 @@ describe "String#split with String" do end end - ruby_version_is ''...'2.7' do - it "taints the resulting strings if self is tainted" do - ["", "x.y.z.", " x y "].each do |str| - ["", ".", " "].each do |pat| - [-1, 0, 1, 2].each do |limit| - str.dup.taint.split(pat).each do |x| - x.should.tainted? - end + it "returns an empty array when whitespace is split on whitespace" do + " ".split(" ").should == [] + " \n ".split(" ").should == [] + " ".split(" ").should == [] + " \t ".split(" ").should == [] + end - str.split(pat.dup.taint).each do |x| - x.should_not.tainted? - end - end - end - end - end + it "doesn't split on non-ascii whitespace" do + "a\u{2008}b".split(" ").should == ["a\u{2008}b"] end end @@ -411,37 +406,6 @@ describe "String#split with Regexp" do end end - ruby_version_is ''...'2.7' do - it "taints the resulting strings if self is tainted" do - ["", "x:y:z:", " x y "].each do |str| - [//, /:/, /\s+/].each do |pat| - [-1, 0, 1, 2].each do |limit| - str.dup.taint.split(pat, limit).each do |x| - # See the spec below for why the conditional is here - x.tainted?.should be_true unless x.empty? - end - end - end - end - end - - it "taints an empty string if self is tainted" do - ":".taint.split(//, -1).last.tainted?.should be_true - end - - it "doesn't taints the resulting strings if the Regexp is tainted" do - ["", "x:y:z:", " x y "].each do |str| - [//, /:/, /\s+/].each do |pat| - [-1, 0, 1, 2].each do |limit| - str.split(pat.dup.taint, limit).each do |x| - x.tainted?.should be_false - end - end - end - end - end - end - it "retains the encoding of the source string" do ary = "а б в".split encodings = ary.map { |s| s.encoding } @@ -574,4 +538,11 @@ describe "String#split with Regexp" do end end end + + it "raises a TypeError when not called with nil, String, or Regexp" do + -> { "hello".split(42) }.should raise_error(TypeError) + -> { "hello".split(:ll) }.should raise_error(TypeError) + -> { "hello".split(false) }.should raise_error(TypeError) + -> { "hello".split(Object.new) }.should raise_error(TypeError) + end end diff --git a/spec/ruby/core/string/squeeze_spec.rb b/spec/ruby/core/string/squeeze_spec.rb index 6f75402c9c..5dc12a4247 100644 --- a/spec/ruby/core/string/squeeze_spec.rb +++ b/spec/ruby/core/string/squeeze_spec.rb @@ -54,16 +54,6 @@ describe "String#squeeze" do -> { s.squeeze("^e-b") }.should raise_error(ArgumentError) end - ruby_version_is ''...'2.7' do - it "taints the result when self is tainted" do - "hello".taint.squeeze("e").should.tainted? - "hello".taint.squeeze("a-z").should.tainted? - - "hello".squeeze("e".taint).should_not.tainted? - "hello".squeeze("l".taint).should_not.tainted? - end - end - it "tries to convert each set arg to a string using to_str" do other_string = mock('lo') other_string.should_receive(:to_str).and_return("lo") diff --git a/spec/ruby/core/string/strip_spec.rb b/spec/ruby/core/string/strip_spec.rb index 8517bf2d2a..e841db54ce 100644 --- a/spec/ruby/core/string/strip_spec.rb +++ b/spec/ruby/core/string/strip_spec.rb @@ -11,19 +11,11 @@ describe "String#strip" do "\tgoodbye\r\v\n".strip.should == "goodbye" end - ruby_version_is '3.1' do + ruby_version_is '3.0' do it "returns a copy of self without leading and trailing NULL bytes and whitespace" do " \x00 goodbye \x00 ".strip.should == "goodbye" end end - - ruby_version_is ''...'2.7' do - it "taints the result when self is tainted" do - "".taint.strip.should.tainted? - "ok".taint.strip.should.tainted? - " ok ".taint.strip.should.tainted? - end - end end describe "String#strip!" do @@ -43,7 +35,7 @@ describe "String#strip!" do a.should == "hello" end - ruby_version_is '3.1' do + ruby_version_is '3.0' do it "removes leading and trailing NULL bytes and whitespace" do a = "\000 goodbye \000" a.strip! diff --git a/spec/ruby/core/string/sub_spec.rb b/spec/ruby/core/string/sub_spec.rb index 5ae9a4bbf3..9effe88c27 100644 --- a/spec/ruby/core/string/sub_spec.rb +++ b/spec/ruby/core/string/sub_spec.rb @@ -137,28 +137,6 @@ describe "String#sub with pattern, replacement" do "hello".sub(/./, 'hah\\').should == 'hah\\ello' end - ruby_version_is ''...'2.7' do - it "taints the result if the original string or replacement is tainted" do - hello = "hello" - hello_t = "hello" - a = "a" - a_t = "a" - empty = "" - empty_t = "" - - hello_t.taint; a_t.taint; empty_t.taint - - hello_t.sub(/./, a).should.tainted? - hello_t.sub(/./, empty).should.tainted? - - hello.sub(/./, a_t).should.tainted? - hello.sub(/./, empty_t).should.tainted? - hello.sub(//, empty_t).should.tainted? - - hello.sub(//.taint, "foo").should_not.tainted? - end - end - it "tries to convert pattern to a string using to_str" do pattern = mock('.') pattern.should_receive(:to_str).and_return(".") @@ -297,28 +275,6 @@ describe "String#sub with pattern and block" do obj.should_receive(:to_s).and_return("ok") "hello".sub(/.+/) { obj }.should == "ok" end - - ruby_version_is ''...'2.7' do - it "taints the result if the original string or replacement is tainted" do - hello = "hello" - hello_t = "hello" - a = "a" - a_t = "a" - empty = "" - empty_t = "" - - hello_t.taint; a_t.taint; empty_t.taint - - hello_t.sub(/./) { a }.should.tainted? - hello_t.sub(/./) { empty }.should.tainted? - - hello.sub(/./) { a_t }.should.tainted? - hello.sub(/./) { empty_t }.should.tainted? - hello.sub(//) { empty_t }.should.tainted? - - hello.sub(//.taint) { "foo" }.should_not.tainted? - end - end end describe "String#sub! with pattern, replacement" do @@ -328,14 +284,6 @@ describe "String#sub! with pattern, replacement" do a.should == "h*llo" end - ruby_version_is ''...'2.7' do - it "taints self if replacement is tainted" do - a = "hello" - a.sub!(/./.taint, "foo").should_not.tainted? - a.sub!(/./, "foo".taint).should.tainted? - end - end - it "returns nil if no modifications were made" do a = "hello" a.sub!(/z/, '*').should == nil @@ -378,14 +326,6 @@ describe "String#sub! with pattern and block" do offsets.should == [[1, 2]] end - ruby_version_is ''...'2.7' do - it "taints self if block's result is tainted" do - a = "hello" - a.sub!(/./.taint) { "foo" }.should_not.tainted? - a.sub!(/./) { "foo".taint }.should.tainted? - end - end - it "returns nil if no modifications were made" do a = "hello" a.sub!(/z/) { '*' }.should == nil @@ -471,28 +411,6 @@ describe "String#sub with pattern and Hash" do "hello".sub(/(.+)/, 'hello' => repl ).should == repl end - ruby_version_is ''...'2.7' do - it "untrusts the result if the original string is untrusted" do - str = "Ghana".untrust - str.sub(/[Aa]na/, 'ana' => '').untrusted?.should be_true - end - - it "untrusts the result if a hash value is untrusted" do - str = "Ghana" - str.sub(/a$/, 'a' => 'di'.untrust).untrusted?.should be_true - end - - it "taints the result if the original string is tainted" do - str = "Ghana".taint - str.sub(/[Aa]na/, 'ana' => '').tainted?.should be_true - end - - it "taints the result if a hash value is tainted" do - str = "Ghana" - str.sub(/a$/, 'a' => 'di'.taint).tainted?.should be_true - end - end - end describe "String#sub! with pattern and Hash" do @@ -557,28 +475,6 @@ describe "String#sub! with pattern and Hash" do repl = '\& \0 \1 \` \\\' \+ \\\\ foo' "hello".sub!(/(.+)/, 'hello' => repl ).should == repl end - - ruby_version_is ''...'2.7' do - it "keeps untrusted state" do - str = "Ghana".untrust - str.sub!(/[Aa]na/, 'ana' => '').untrusted?.should be_true - end - - it "untrusts self if a hash value is untrusted" do - str = "Ghana" - str.sub!(/a$/, 'a' => 'di'.untrust).untrusted?.should be_true - end - - it "keeps tainted state" do - str = "Ghana".taint - str.sub!(/[Aa]na/, 'ana' => '').tainted?.should be_true - end - - it "taints self if a hash value is tainted" do - str = "Ghana" - str.sub!(/a$/, 'a' => 'di'.taint).tainted?.should be_true - end - end end describe "String#sub with pattern and without replacement and block" do diff --git a/spec/ruby/core/string/swapcase_spec.rb b/spec/ruby/core/string/swapcase_spec.rb index 32b358607e..417f6c6d8d 100644 --- a/spec/ruby/core/string/swapcase_spec.rb +++ b/spec/ruby/core/string/swapcase_spec.rb @@ -9,13 +9,6 @@ describe "String#swapcase" do "+++---111222???".swapcase.should == "+++---111222???" end - ruby_version_is ''...'2.7' do - it "taints resulting string when self is tainted" do - "".taint.swapcase.should.tainted? - "hello".taint.swapcase.should.tainted? - end - end - describe "full Unicode case mapping" do it "works for all of Unicode with no option" do "äÖü".swapcase.should == "ÄöÜ" diff --git a/spec/ruby/core/string/tr_s_spec.rb b/spec/ruby/core/string/tr_s_spec.rb index c6ad12139e..e1bb20ce35 100644 --- a/spec/ruby/core/string/tr_s_spec.rb +++ b/spec/ruby/core/string/tr_s_spec.rb @@ -57,19 +57,6 @@ describe "String#tr_s" do end end - ruby_version_is ''...'2.7' do - it "taints the result when self is tainted" do - ["h", "hello"].each do |str| - tainted_str = str.dup.taint - - tainted_str.tr_s("e", "a").should.tainted? - - str.tr_s("e".taint, "a").should_not.tainted? - str.tr_s("e", "a".taint).should_not.tainted? - end - end - end - # http://redmine.ruby-lang.org/issues/show/1839 it "can replace a 7-bit ASCII character with a multibyte one" do a = "uber" diff --git a/spec/ruby/core/string/tr_spec.rb b/spec/ruby/core/string/tr_spec.rb index 06be1e6641..72adb9f2eb 100644 --- a/spec/ruby/core/string/tr_spec.rb +++ b/spec/ruby/core/string/tr_spec.rb @@ -69,19 +69,6 @@ describe "String#tr" do end end - ruby_version_is ''...'2.7' do - it "taints the result when self is tainted" do - ["h", "hello"].each do |str| - tainted_str = str.dup.taint - - tainted_str.tr("e", "a").should.tainted? - - str.tr("e".taint, "a").should_not.tainted? - str.tr("e", "a".taint).should_not.tainted? - end - end - end - # http://redmine.ruby-lang.org/issues/show/1839 it "can replace a 7-bit ASCII character with a multibyte one" do a = "uber" diff --git a/spec/ruby/core/string/uminus_spec.rb b/spec/ruby/core/string/uminus_spec.rb index 800dca5044..46d88f6704 100644 --- a/spec/ruby/core/string/uminus_spec.rb +++ b/spec/ruby/core/string/uminus_spec.rb @@ -1,49 +1,6 @@ require_relative '../../spec_helper' +require_relative 'shared/dedup' describe 'String#-@' do - it 'returns self if the String is frozen' do - input = 'foo'.freeze - output = -input - - output.should equal(input) - output.should.frozen? - end - - it 'returns a frozen copy if the String is not frozen' do - input = 'foo' - output = -input - - output.should.frozen? - output.should_not equal(input) - output.should == 'foo' - end - - it "returns the same object for equal unfrozen strings" do - origin = "this is a string" - dynamic = %w(this is a string).join(' ') - - origin.should_not equal(dynamic) - (-origin).should equal(-dynamic) - end - - it "returns the same object when it's called on the same String literal" do - (-"unfrozen string").should equal(-"unfrozen string") - (-"unfrozen string").should_not equal(-"another unfrozen string") - end - - it "deduplicates frozen strings" do - dynamic = %w(this string is frozen).join(' ').freeze - - dynamic.should_not equal("this string is frozen".freeze) - - (-dynamic).should equal("this string is frozen".freeze) - (-dynamic).should equal(-"this string is frozen".freeze) - end - - ruby_version_is "3.0" do - it "interns the provided string if it is frozen" do - dynamic = "this string is unique and frozen #{rand}".freeze - (-dynamic).should equal(dynamic) - end - end + it_behaves_like :string_dedup, :-@ end diff --git a/spec/ruby/core/string/undump_spec.rb b/spec/ruby/core/string/undump_spec.rb index b990aa25ee..08058d9bd1 100644 --- a/spec/ruby/core/string/undump_spec.rb +++ b/spec/ruby/core/string/undump_spec.rb @@ -3,16 +3,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "String#undump" do - ruby_version_is ''...'2.7' do - it "taints the result if self is tainted" do - '"foo"'.taint.undump.should.tainted? - end - - it "untrusts the result if self is untrusted" do - '"foo"'.untrust.undump.should.untrusted? - end - end - it "does not take into account if a string is frozen" do '"foo"'.freeze.undump.should_not.frozen? end diff --git a/spec/ruby/core/string/unpack/p_spec.rb b/spec/ruby/core/string/unpack/p_spec.rb index 3e187d674f..cd48c0523d 100644 --- a/spec/ruby/core/string/unpack/p_spec.rb +++ b/spec/ruby/core/string/unpack/p_spec.rb @@ -18,12 +18,6 @@ describe "String#unpack with format 'P'" do -> { packed.to_sym.to_s.unpack("P5") }.should raise_error(ArgumentError, /no associated pointer/) end - ruby_version_is ''...'2.7' do - it "taints the unpacked string" do - ["hello"].pack("P").unpack("P5").first.tainted?.should be_true - end - end - it "reads as many characters as specified" do ["hello"].pack("P").unpack("P1").should == ["h"] end @@ -47,10 +41,4 @@ describe "String#unpack with format 'p'" do packed.dup.unpack("p").should == ["hello"] -> { packed.to_sym.to_s.unpack("p") }.should raise_error(ArgumentError, /no associated pointer/) end - - ruby_version_is ''...'2.7' do - it "taints the unpacked string" do - ["hello"].pack("p").unpack("p").first.tainted?.should be_true - end - end end diff --git a/spec/ruby/core/string/unpack/shared/taint.rb b/spec/ruby/core/string/unpack/shared/taint.rb index 061a3e26ad..79c7251f01 100644 --- a/spec/ruby/core/string/unpack/shared/taint.rb +++ b/spec/ruby/core/string/unpack/shared/taint.rb @@ -1,83 +1,2 @@ describe :string_unpack_taint, shared: true do - ruby_version_is ''...'2.7' do - it "does not taint returned arrays if given an untainted format string" do - "".unpack(unpack_format(2)).tainted?.should be_false - end - - it "does not taint returned arrays if given a tainted format string" do - format_string = unpack_format(2).dup - format_string.taint - "".unpack(format_string).tainted?.should be_false - end - - it "does not taint returned strings if given an untainted format string" do - "".unpack(unpack_format(2)).any?(&:tainted?).should be_false - end - - it "does not taint returned strings if given a tainted format string" do - format_string = unpack_format(2).dup - format_string.taint - "".unpack(format_string).any?(&:tainted?).should be_false - end - - it "does not taint returned arrays if given an untainted packed string" do - "".unpack(unpack_format(2)).tainted?.should be_false - end - - it "does not taint returned arrays if given a tainted packed string" do - packed_string = "" - packed_string.taint - packed_string.unpack(unpack_format(2)).tainted?.should be_false - end - - it "does not taint returned strings if given an untainted packed string" do - "".unpack(unpack_format(2)).any?(&:tainted?).should be_false - end - - it "taints returned strings if given a tainted packed string" do - packed_string = "" - packed_string.taint - packed_string.unpack(unpack_format(2)).all?(&:tainted?).should be_true - end - - it "does not untrust returned arrays if given an untrusted format string" do - "".unpack(unpack_format(2)).untrusted?.should be_false - end - - it "does not untrust returned arrays if given a untrusted format string" do - format_string = unpack_format(2).dup - format_string.untrust - "".unpack(format_string).untrusted?.should be_false - end - - it "does not untrust returned strings if given an untainted format string" do - "".unpack(unpack_format(2)).any?(&:untrusted?).should be_false - end - - it "does not untrust returned strings if given a untrusted format string" do - format_string = unpack_format(2).dup - format_string.untrust - "".unpack(format_string).any?(&:untrusted?).should be_false - end - - it "does not untrust returned arrays if given an trusted packed string" do - "".unpack(unpack_format(2)).untrusted?.should be_false - end - - it "does not untrust returned arrays if given a untrusted packed string" do - packed_string = "" - packed_string.untrust - packed_string.unpack(unpack_format(2)).untrusted?.should be_false - end - - it "does not untrust returned strings if given an trusted packed string" do - "".unpack(unpack_format(2)).any?(&:untrusted?).should be_false - end - - it "untrusts returned strings if given a untrusted packed string" do - packed_string = "" - packed_string.untrust - packed_string.unpack(unpack_format(2)).all?(&:untrusted?).should be_true - end - end end diff --git a/spec/ruby/core/string/upcase_spec.rb b/spec/ruby/core/string/upcase_spec.rb index 6cf44b4703..b2b34190fe 100644 --- a/spec/ruby/core/string/upcase_spec.rb +++ b/spec/ruby/core/string/upcase_spec.rb @@ -65,14 +65,6 @@ describe "String#upcase" do -> { "abc".upcase(:invalid_option) }.should raise_error(ArgumentError) end - ruby_version_is ''...'2.7' do - it "taints result when self is tainted" do - "".taint.upcase.should.tainted? - "X".taint.upcase.should.tainted? - "x".taint.upcase.should.tainted? - end - end - ruby_version_is ''...'3.0' do it "returns a subclass instance for subclasses" do StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(StringSpecs::MyString) diff --git a/spec/ruby/core/struct/deconstruct_keys_spec.rb b/spec/ruby/core/struct/deconstruct_keys_spec.rb index f0a1f50ad3..088803d028 100644 --- a/spec/ruby/core/struct/deconstruct_keys_spec.rb +++ b/spec/ruby/core/struct/deconstruct_keys_spec.rb @@ -1,78 +1,76 @@ require_relative '../../spec_helper' -ruby_version_is "2.7" do - describe "Struct#deconstruct_keys" do - it "returns a hash of attributes" do - struct = Struct.new(:x, :y) - s = struct.new(1, 2) - - s.deconstruct_keys([:x, :y]).should == {x: 1, y: 2} - end - - it "requires one argument" do - struct = Struct.new(:x) - obj = struct.new(1) - - -> { - obj.deconstruct_keys - }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/) - end - - it "returns only specified keys" do - struct = Struct.new(:x, :y, :z) - s = struct.new(1, 2, 3) - - s.deconstruct_keys([:x, :y]).should == {x: 1, y: 2} - s.deconstruct_keys([:x] ).should == {x: 1} - s.deconstruct_keys([] ).should == {} - end - - it "accepts string attribute names" do - struct = Struct.new(:x, :y) - s = struct.new(1, 2) - - s.deconstruct_keys(['x', 'y']).should == {'x' => 1, 'y' => 2} - end - - it "accepts argument position number as well but returns them as keys" do - struct = Struct.new(:x, :y, :z) - s = struct.new(10, 20, 30) - - s.deconstruct_keys([0, 1, 2]).should == {0 => 10, 1 => 20, 2 => 30} - s.deconstruct_keys([0, 1] ).should == {0 => 10, 1 => 20} - s.deconstruct_keys([0] ).should == {0 => 10} - end - - it "returns an empty hash when there are more keys than attributes" do - struct = Struct.new(:x, :y) - s = struct.new(1, 2) - - s.deconstruct_keys([:x, :y, :a]).should == {} - end - - it "returns at first not existing attribute name" do - struct = Struct.new(:x, :y) - s = struct.new(1, 2) - - s.deconstruct_keys([:a, :x]).should == {} - s.deconstruct_keys([:x, :a]).should == {x: 1} - end - - it "accepts nil argument and return all the attributes" do - struct = Struct.new(:x, :y) - obj = struct.new(1, 2) - - obj.deconstruct_keys(nil).should == {x: 1, y: 2} - end - - it "raise TypeError if passed anything accept nil or array" do - struct = Struct.new(:x, :y) - s = struct.new(1, 2) - - -> { s.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/) - -> { s.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/) - -> { s.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/) - -> { s.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/) - end +describe "Struct#deconstruct_keys" do + it "returns a hash of attributes" do + struct = Struct.new(:x, :y) + s = struct.new(1, 2) + + s.deconstruct_keys([:x, :y]).should == {x: 1, y: 2} + end + + it "requires one argument" do + struct = Struct.new(:x) + obj = struct.new(1) + + -> { + obj.deconstruct_keys + }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/) + end + + it "returns only specified keys" do + struct = Struct.new(:x, :y, :z) + s = struct.new(1, 2, 3) + + s.deconstruct_keys([:x, :y]).should == {x: 1, y: 2} + s.deconstruct_keys([:x] ).should == {x: 1} + s.deconstruct_keys([] ).should == {} + end + + it "accepts string attribute names" do + struct = Struct.new(:x, :y) + s = struct.new(1, 2) + + s.deconstruct_keys(['x', 'y']).should == {'x' => 1, 'y' => 2} + end + + it "accepts argument position number as well but returns them as keys" do + struct = Struct.new(:x, :y, :z) + s = struct.new(10, 20, 30) + + s.deconstruct_keys([0, 1, 2]).should == {0 => 10, 1 => 20, 2 => 30} + s.deconstruct_keys([0, 1] ).should == {0 => 10, 1 => 20} + s.deconstruct_keys([0] ).should == {0 => 10} + end + + it "returns an empty hash when there are more keys than attributes" do + struct = Struct.new(:x, :y) + s = struct.new(1, 2) + + s.deconstruct_keys([:x, :y, :a]).should == {} + end + + it "returns at first not existing attribute name" do + struct = Struct.new(:x, :y) + s = struct.new(1, 2) + + s.deconstruct_keys([:a, :x]).should == {} + s.deconstruct_keys([:x, :a]).should == {x: 1} + end + + it "accepts nil argument and return all the attributes" do + struct = Struct.new(:x, :y) + obj = struct.new(1, 2) + + obj.deconstruct_keys(nil).should == {x: 1, y: 2} + end + + it "raise TypeError if passed anything accept nil or array" do + struct = Struct.new(:x, :y) + s = struct.new(1, 2) + + -> { s.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/) + -> { s.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/) + -> { s.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/) + -> { s.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/) end end diff --git a/spec/ruby/core/struct/deconstruct_spec.rb b/spec/ruby/core/struct/deconstruct_spec.rb index 7518a40987..32d4f6bac4 100644 --- a/spec/ruby/core/struct/deconstruct_spec.rb +++ b/spec/ruby/core/struct/deconstruct_spec.rb @@ -1,12 +1,10 @@ require_relative '../../spec_helper' -ruby_version_is "2.7" do - describe "Struct#deconstruct" do - it "returns an array of attribute values" do - struct = Struct.new(:x, :y) - s = struct.new(1, 2) +describe "Struct#deconstruct" do + it "returns an array of attribute values" do + struct = Struct.new(:x, :y) + s = struct.new(1, 2) - s.deconstruct.should == [1, 2] - end + s.deconstruct.should == [1, 2] end end diff --git a/spec/ruby/core/struct/new_spec.rb b/spec/ruby/core/struct/new_spec.rb index cbbec829d7..7b4a4f7980 100644 --- a/spec/ruby/core/struct/new_spec.rb +++ b/spec/ruby/core/struct/new_spec.rb @@ -62,8 +62,20 @@ describe "Struct.new" do -> { Struct.new(:animal, ['chris', 'evan']) }.should raise_error(TypeError) end - it "raises a ArgumentError if passed a Hash with an unknown key" do - -> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(ArgumentError) + ruby_version_is ""..."3.2" do + it "raises a TypeError or ArgumentError if passed a Hash with an unknown key" do + # CRuby < 3.2 raises ArgumentError: unknown keyword: :name, but that seems a bug: + # https://bugs.ruby-lang.org/issues/18632 + -> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(StandardError) { |e| + [ArgumentError, TypeError].should.include?(e.class) + } + end + end + + ruby_version_is "3.2" do + it "raises a TypeError if passed a Hash with an unknown key" do + -> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(TypeError) + end end it "raises ArgumentError when there is a duplicate member" do diff --git a/spec/ruby/core/symbol/end_with_spec.rb b/spec/ruby/core/symbol/end_with_spec.rb index 77dc4caf71..4b9f5a4996 100644 --- a/spec/ruby/core/symbol/end_with_spec.rb +++ b/spec/ruby/core/symbol/end_with_spec.rb @@ -3,8 +3,6 @@ require_relative '../../spec_helper' require_relative '../../shared/string/end_with' -ruby_version_is "2.7" do - describe "Symbol#end_with?" do - it_behaves_like :end_with, :to_sym - end +describe "Symbol#end_with?" do + it_behaves_like :end_with, :to_sym end diff --git a/spec/ruby/core/symbol/shared/slice.rb b/spec/ruby/core/symbol/shared/slice.rb index 3f07f6aedb..0df87e183d 100644 --- a/spec/ruby/core/symbol/shared/slice.rb +++ b/spec/ruby/core/symbol/shared/slice.rb @@ -190,16 +190,6 @@ describe :symbol_slice, shared: true do :symbol.send(@method, /[0-9]+/) $~.should be_nil end - - ruby_version_is ''...'2.7' do - it "returns a tainted string if the regexp is tainted" do - :symbol.send(@method, /./.taint).tainted?.should be_true - end - - it "returns an untrusted string if the regexp is untrusted" do - :symbol.send(@method, /./.untrust).untrusted?.should be_true - end - end end describe "with a capture index" do @@ -221,16 +211,6 @@ describe :symbol_slice, shared: true do :symbol.send(@method, /(sy)(mb)(ol)/, 1.5).should == "sy" end - ruby_version_is ''...'2.7' do - it "returns a tainted string if the regexp is tainted" do - :symbol.send(@method, /(.)/.taint, 1).tainted?.should be_true - end - - it "returns an untrusted string if the regexp is untrusted" do - :symbol.send(@method, /(.)/.untrust, 1).untrusted?.should be_true - end - end - describe "and an index that cannot be converted to an Integer" do it "raises a TypeError when given an Hash" do -> { :symbol.send(@method, /(sy)(mb)(ol)/, Hash.new) }.should raise_error(TypeError) diff --git a/spec/ruby/core/symbol/start_with_spec.rb b/spec/ruby/core/symbol/start_with_spec.rb index f54b3e499e..cd43279003 100644 --- a/spec/ruby/core/symbol/start_with_spec.rb +++ b/spec/ruby/core/symbol/start_with_spec.rb @@ -3,8 +3,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative '../../shared/string/start_with' -ruby_version_is "2.7" do - describe "Symbol#start_with?" do - it_behaves_like :start_with, :to_sym - end +describe "Symbol#start_with?" do + it_behaves_like :start_with, :to_sym end diff --git a/spec/ruby/core/thread/backtrace_locations_spec.rb b/spec/ruby/core/thread/backtrace_locations_spec.rb index 237941c214..c970ae023b 100644 --- a/spec/ruby/core/thread/backtrace_locations_spec.rb +++ b/spec/ruby/core/thread/backtrace_locations_spec.rb @@ -49,12 +49,10 @@ describe "Thread#backtrace_locations" do locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s) end - ruby_version_is "2.7" do - it "can be called with an beginless range" do - locations1 = Thread.current.backtrace_locations(0) - locations2 = Thread.current.backtrace_locations(eval("(..5)")) - locations2.map(&:to_s)[eval("(2..)")].should == locations1[eval("(..5)")].map(&:to_s)[eval("(2..)")] - end + it "can be called with an beginless range" do + locations1 = Thread.current.backtrace_locations(0) + locations2 = Thread.current.backtrace_locations((..5)) + locations2.map(&:to_s)[eval("(2..)")].should == locations1[(..5)].map(&:to_s)[eval("(2..)")] end it "returns nil if omitting more locations than available" do diff --git a/spec/ruby/core/thread/report_on_exception_spec.rb b/spec/ruby/core/thread/report_on_exception_spec.rb index bf50a167df..9279fa1da5 100644 --- a/spec/ruby/core/thread/report_on_exception_spec.rb +++ b/spec/ruby/core/thread/report_on_exception_spec.rb @@ -60,6 +60,57 @@ describe "Thread#report_on_exception=" do t.join }.should raise_error(RuntimeError, "Thread#report_on_exception specs") end + + ruby_version_is "3.0" do + it "prints a backtrace on $stderr in the regular backtrace order" do + line_raise = __LINE__ + 2 + def foo + raise RuntimeError, "Thread#report_on_exception specs backtrace order" + end + + line_call_foo = __LINE__ + 5 + go = false + t = Thread.new { + Thread.current.report_on_exception = true + Thread.pass until go + foo + } + + -> { + go = true + Thread.pass while t.alive? + }.should output("", <<ERR) +#{t.inspect} terminated with exception (report_on_exception is true): +#{__FILE__}:#{line_raise}:in `foo': Thread#report_on_exception specs backtrace order (RuntimeError) +\tfrom #{__FILE__}:#{line_call_foo}:in `block (5 levels) in <top (required)>' +ERR + + -> { + t.join + }.should raise_error(RuntimeError, "Thread#report_on_exception specs backtrace order") + end + end + + it "prints the backtrace even if the thread was killed just after Thread#raise" do + t = nil + ready = false + -> { + t = Thread.new { + Thread.current.report_on_exception = true + ready = true + sleep + } + + Thread.pass until ready and t.stop? + t.raise RuntimeError, "Thread#report_on_exception before kill spec" + t.kill + Thread.pass while t.alive? + }.should output("", /Thread.+terminated with exception.+Thread#report_on_exception before kill spec/m) + + -> { + t.join + }.should raise_error(RuntimeError, "Thread#report_on_exception before kill spec") + end end describe "when set to false" do diff --git a/spec/ruby/core/thread/shared/exit.rb b/spec/ruby/core/thread/shared/exit.rb index 40dc478947..3663827579 100644 --- a/spec/ruby/core/thread/shared/exit.rb +++ b/spec/ruby/core/thread/shared/exit.rb @@ -66,6 +66,26 @@ describe :thread_exit, shared: true do ScratchPad.recorded.should == nil end + it "does not reset $!" do + ScratchPad.record [] + + exc = RuntimeError.new("foo") + thread = Thread.new do + begin + raise exc + ensure + ScratchPad << $! + begin + Thread.current.send(@method) + ensure + ScratchPad << $! + end + end + end + thread.join + ScratchPad.recorded.should == [exc, exc] + end + it "cannot be rescued" do thread = Thread.new do begin @@ -73,7 +93,7 @@ describe :thread_exit, shared: true do rescue Exception ScratchPad.record :in_rescue end - ScratchPad.record :end_of_thread_block + ScratchPad.record :end_of_thread_block end thread.join diff --git a/spec/ruby/core/thread/shared/to_s.rb b/spec/ruby/core/thread/shared/to_s.rb index 45c04af627..43640deb33 100644 --- a/spec/ruby/core/thread/shared/to_s.rb +++ b/spec/ruby/core/thread/shared/to_s.rb @@ -1,12 +1,10 @@ require_relative '../fixtures/classes' describe :thread_to_s, shared: true do - sep = ruby_version_is("2.7") ? " " : "@" - it "returns a description including file and line number" do thread, line = Thread.new { "hello" }, __LINE__ thread.join - thread.send(@method).should =~ /^#<Thread:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{line} \w+>$/ + thread.send(@method).should =~ /^#<Thread:([^ ]*?) #{Regexp.escape __FILE__}:#{line} \w+>$/ end it "has a binary encoding" do diff --git a/spec/ruby/core/time/ceil_spec.rb b/spec/ruby/core/time/ceil_spec.rb index 86029554db..9d624a1ed0 100644 --- a/spec/ruby/core/time/ceil_spec.rb +++ b/spec/ruby/core/time/ceil_spec.rb @@ -1,46 +1,44 @@ require_relative '../../spec_helper' -ruby_version_is "2.7" do - describe "Time#ceil" do - before do - @time = Time.utc(2010, 3, 30, 5, 43, "25.0123456789".to_r) - end - - it "defaults to ceiling to 0 places" do - @time.ceil.should == Time.utc(2010, 3, 30, 5, 43, 26.to_r) - end +describe "Time#ceil" do + before do + @time = Time.utc(2010, 3, 30, 5, 43, "25.0123456789".to_r) + end - it "ceils to 0 decimal places with an explicit argument" do - @time.ceil(0).should == Time.utc(2010, 3, 30, 5, 43, 26.to_r) - end + it "defaults to ceiling to 0 places" do + @time.ceil.should == Time.utc(2010, 3, 30, 5, 43, 26.to_r) + end - it "ceils to 2 decimal places with an explicit argument" do - @time.ceil(2).should == Time.utc(2010, 3, 30, 5, 43, "25.02".to_r) - end + it "ceils to 0 decimal places with an explicit argument" do + @time.ceil(0).should == Time.utc(2010, 3, 30, 5, 43, 26.to_r) + end - it "ceils to 4 decimal places with an explicit argument" do - @time.ceil(4).should == Time.utc(2010, 3, 30, 5, 43, "25.0124".to_r) - end + it "ceils to 2 decimal places with an explicit argument" do + @time.ceil(2).should == Time.utc(2010, 3, 30, 5, 43, "25.02".to_r) + end - it "ceils to 7 decimal places with an explicit argument" do - @time.ceil(7).should == Time.utc(2010, 3, 30, 5, 43, "25.0123457".to_r) - end + it "ceils to 4 decimal places with an explicit argument" do + @time.ceil(4).should == Time.utc(2010, 3, 30, 5, 43, "25.0124".to_r) + end - it "returns an instance of Time, even if #ceil is called on a subclass" do - subclass = Class.new(Time) - instance = subclass.at(0) - instance.class.should equal subclass - instance.ceil.should be_an_instance_of(Time) - end + it "ceils to 7 decimal places with an explicit argument" do + @time.ceil(7).should == Time.utc(2010, 3, 30, 5, 43, "25.0123457".to_r) + end - it "copies own timezone to the returning value" do - @time.zone.should == @time.ceil.zone + it "returns an instance of Time, even if #ceil is called on a subclass" do + subclass = Class.new(Time) + instance = subclass.at(0) + instance.class.should equal subclass + instance.ceil.should be_an_instance_of(Time) + end - time = with_timezone "JST-9" do - Time.at 0, 1 - end + it "copies own timezone to the returning value" do + @time.zone.should == @time.ceil.zone - time.zone.should == time.ceil.zone + time = with_timezone "JST-9" do + Time.at 0, 1 end + + time.zone.should == time.ceil.zone end end diff --git a/spec/ruby/core/time/floor_spec.rb b/spec/ruby/core/time/floor_spec.rb index a19585b787..b0003469c9 100644 --- a/spec/ruby/core/time/floor_spec.rb +++ b/spec/ruby/core/time/floor_spec.rb @@ -1,38 +1,36 @@ require_relative '../../spec_helper' -ruby_version_is "2.7" do - describe "Time#floor" do - before do - @time = Time.utc(2010, 3, 30, 5, 43, "25.123456789".to_r) - end - - it "defaults to flooring to 0 places" do - @time.floor.should == Time.utc(2010, 3, 30, 5, 43, 25.to_r) - end +describe "Time#floor" do + before do + @time = Time.utc(2010, 3, 30, 5, 43, "25.123456789".to_r) + end - it "floors to 0 decimal places with an explicit argument" do - @time.floor(0).should == Time.utc(2010, 3, 30, 5, 43, 25.to_r) - end + it "defaults to flooring to 0 places" do + @time.floor.should == Time.utc(2010, 3, 30, 5, 43, 25.to_r) + end - it "floors to 7 decimal places with an explicit argument" do - @time.floor(7).should == Time.utc(2010, 3, 30, 5, 43, "25.1234567".to_r) - end + it "floors to 0 decimal places with an explicit argument" do + @time.floor(0).should == Time.utc(2010, 3, 30, 5, 43, 25.to_r) + end - it "returns an instance of Time, even if #floor is called on a subclass" do - subclass = Class.new(Time) - instance = subclass.at(0) - instance.class.should equal subclass - instance.floor.should be_an_instance_of(Time) - end + it "floors to 7 decimal places with an explicit argument" do + @time.floor(7).should == Time.utc(2010, 3, 30, 5, 43, "25.1234567".to_r) + end - it "copies own timezone to the returning value" do - @time.zone.should == @time.floor.zone + it "returns an instance of Time, even if #floor is called on a subclass" do + subclass = Class.new(Time) + instance = subclass.at(0) + instance.class.should equal subclass + instance.floor.should be_an_instance_of(Time) + end - time = with_timezone "JST-9" do - Time.at 0, 1 - end + it "copies own timezone to the returning value" do + @time.zone.should == @time.floor.zone - time.zone.should == time.floor.zone + time = with_timezone "JST-9" do + Time.at 0, 1 end + + time.zone.should == time.floor.zone end end diff --git a/spec/ruby/core/time/inspect_spec.rb b/spec/ruby/core/time/inspect_spec.rb index 6f1b2e3ef1..c3a4519a24 100644 --- a/spec/ruby/core/time/inspect_spec.rb +++ b/spec/ruby/core/time/inspect_spec.rb @@ -4,32 +4,30 @@ require_relative 'shared/inspect' describe "Time#inspect" do it_behaves_like :inspect, :inspect - ruby_version_is "2.7" do - it "preserves microseconds" do - t = Time.utc(2007, 11, 1, 15, 25, 0, 123456) - t.inspect.should == "2007-11-01 15:25:00.123456 UTC" - end + it "preserves microseconds" do + t = Time.utc(2007, 11, 1, 15, 25, 0, 123456) + t.inspect.should == "2007-11-01 15:25:00.123456 UTC" + end - it "omits trailing zeros from microseconds" do - t = Time.utc(2007, 11, 1, 15, 25, 0, 100000) - t.inspect.should == "2007-11-01 15:25:00.1 UTC" - end + it "omits trailing zeros from microseconds" do + t = Time.utc(2007, 11, 1, 15, 25, 0, 100000) + t.inspect.should == "2007-11-01 15:25:00.1 UTC" + end - it "uses the correct time zone without microseconds" do - t = Time.utc(2000, 1, 1) - t = t.localtime(9*3600) - t.inspect.should == "2000-01-01 09:00:00 +0900" - end + it "uses the correct time zone without microseconds" do + t = Time.utc(2000, 1, 1) + t = t.localtime(9*3600) + t.inspect.should == "2000-01-01 09:00:00 +0900" + end - it "uses the correct time zone with microseconds" do - t = Time.utc(2000, 1, 1, 0, 0, 0, 123456) - t = t.localtime(9*3600) - t.inspect.should == "2000-01-01 09:00:00.123456 +0900" - end + it "uses the correct time zone with microseconds" do + t = Time.utc(2000, 1, 1, 0, 0, 0, 123456) + t = t.localtime(9*3600) + t.inspect.should == "2000-01-01 09:00:00.123456 +0900" + end - it "preserves nanoseconds" do - t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r) - t.inspect.should == "2007-11-01 15:25:00.123456789 UTC" - end + it "preserves nanoseconds" do + t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r) + t.inspect.should == "2007-11-01 15:25:00.123456789 UTC" end end diff --git a/spec/ruby/core/tracepoint/enable_spec.rb b/spec/ruby/core/tracepoint/enable_spec.rb index ab392c7583..24f6070b97 100644 --- a/spec/ruby/core/tracepoint/enable_spec.rb +++ b/spec/ruby/core/tracepoint/enable_spec.rb @@ -57,25 +57,50 @@ describe 'TracePoint#enable' do end.enable { event_name.should equal(:line) } end - it 'enables the trace object for any thread' do - threads = [] - trace = TracePoint.new(:line) do |tp| - # Runs on purpose on any Thread - threads << Thread.current - end + ruby_version_is '3.2' do + it 'enables the trace object only for the current thread' do + threads = [] + trace = TracePoint.new(:line) do |tp| + # Runs on purpose on any Thread + threads << Thread.current + end - thread = nil - trace.enable do - line_event = true - thread = Thread.new do - event_in_other_thread = true + thread = nil + trace.enable do + line_event = true + thread = Thread.new do + event_in_other_thread = true + end + thread.join end - thread.join + + threads = threads.uniq + threads.should.include?(Thread.current) + threads.should_not.include?(thread) end + end - threads = threads.uniq - threads.should.include?(Thread.current) - threads.should.include?(thread) + ruby_version_is ''...'3.2' do + it 'enables the trace object for any thread' do + threads = [] + trace = TracePoint.new(:line) do |tp| + # Runs on purpose on any Thread + threads << Thread.current + end + + thread = nil + trace.enable do + line_event = true + thread = Thread.new do + event_in_other_thread = true + end + thread.join + end + + threads = threads.uniq + threads.should.include?(Thread.current) + threads.should.include?(thread) + end end it 'can accept arguments within a block but it should not yield arguments' do diff --git a/spec/ruby/core/tracepoint/inspect_spec.rb b/spec/ruby/core/tracepoint/inspect_spec.rb index b9d7f35c32..a07b626212 100644 --- a/spec/ruby/core/tracepoint/inspect_spec.rb +++ b/spec/ruby/core/tracepoint/inspect_spec.rb @@ -98,7 +98,7 @@ describe 'TracePoint#inspect' do TracePoint.new(:thread_begin) { |tp| next unless Thread.current == thread inspect ||= tp.inspect - }.enable do + }.enable(target_thread: nil) do thread = Thread.new {} thread_inspection = thread.inspect thread.join @@ -114,7 +114,7 @@ describe 'TracePoint#inspect' do TracePoint.new(:thread_end) { |tp| next unless Thread.current == thread inspect ||= tp.inspect - }.enable do + }.enable(target_thread: nil) do thread = Thread.new {} thread_inspection = thread.inspect thread.join diff --git a/spec/ruby/core/true/to_s_spec.rb b/spec/ruby/core/true/to_s_spec.rb index f26cd138e2..fa1b53a580 100644 --- a/spec/ruby/core/true/to_s_spec.rb +++ b/spec/ruby/core/true/to_s_spec.rb @@ -5,13 +5,11 @@ describe "TrueClass#to_s" do true.to_s.should == "true" end - ruby_version_is "2.7" do - it "returns a frozen string" do - true.to_s.should.frozen? - end + it "returns a frozen string" do + true.to_s.should.frozen? + end - it "always returns the same string" do - true.to_s.should equal(true.to_s) - end + it "always returns the same string" do + true.to_s.should equal(true.to_s) end end diff --git a/spec/ruby/core/unboundmethod/bind_call_spec.rb b/spec/ruby/core/unboundmethod/bind_call_spec.rb index c5d392156c..8f25f8bd0d 100644 --- a/spec/ruby/core/unboundmethod/bind_call_spec.rb +++ b/spec/ruby/core/unboundmethod/bind_call_spec.rb @@ -1,52 +1,50 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -ruby_version_is '2.7' do - describe "UnboundMethod#bind_call" do - before :each do - @normal_um = UnboundMethodSpecs::Methods.new.method(:foo).unbind - @parent_um = UnboundMethodSpecs::Parent.new.method(:foo).unbind - @child1_um = UnboundMethodSpecs::Child1.new.method(:foo).unbind - @child2_um = UnboundMethodSpecs::Child2.new.method(:foo).unbind - end +describe "UnboundMethod#bind_call" do + before :each do + @normal_um = UnboundMethodSpecs::Methods.new.method(:foo).unbind + @parent_um = UnboundMethodSpecs::Parent.new.method(:foo).unbind + @child1_um = UnboundMethodSpecs::Child1.new.method(:foo).unbind + @child2_um = UnboundMethodSpecs::Child2.new.method(:foo).unbind + end - it "raises TypeError if object is not kind_of? the Module the method defined in" do - -> { @normal_um.bind_call(UnboundMethodSpecs::B.new) }.should raise_error(TypeError) - end + it "raises TypeError if object is not kind_of? the Module the method defined in" do + -> { @normal_um.bind_call(UnboundMethodSpecs::B.new) }.should raise_error(TypeError) + end - it "binds and calls the method if object is kind_of the Module the method defined in" do - @normal_um.bind_call(UnboundMethodSpecs::Methods.new).should == true - end + it "binds and calls the method if object is kind_of the Module the method defined in" do + @normal_um.bind_call(UnboundMethodSpecs::Methods.new).should == true + end - it "binds and calls the method on any object when UnboundMethod is unbound from a module" do - UnboundMethodSpecs::Mod.instance_method(:from_mod).bind_call(Object.new).should == nil - end + it "binds and calls the method on any object when UnboundMethod is unbound from a module" do + UnboundMethodSpecs::Mod.instance_method(:from_mod).bind_call(Object.new).should == nil + end - it "binds and calls the method for any object kind_of? the Module the method is defined in" do - @parent_um.bind_call(UnboundMethodSpecs::Child1.new).should == nil - @child1_um.bind_call(UnboundMethodSpecs::Parent.new).should == nil - @child2_um.bind_call(UnboundMethodSpecs::Child1.new).should == nil - end + it "binds and calls the method for any object kind_of? the Module the method is defined in" do + @parent_um.bind_call(UnboundMethodSpecs::Child1.new).should == nil + @child1_um.bind_call(UnboundMethodSpecs::Parent.new).should == nil + @child2_um.bind_call(UnboundMethodSpecs::Child1.new).should == nil + end - it "binds and calls a Kernel method retrieved from Object on BasicObject" do - Object.instance_method(:instance_of?).bind_call(BasicObject.new, BasicObject).should == true - end + it "binds and calls a Kernel method retrieved from Object on BasicObject" do + Object.instance_method(:instance_of?).bind_call(BasicObject.new, BasicObject).should == true + end - it "binds and calls a Parent's class method to any Child's class methods" do - um = UnboundMethodSpecs::Parent.method(:class_method).unbind - um.bind_call(UnboundMethodSpecs::Child1).should == "I am UnboundMethodSpecs::Child1" - end + it "binds and calls a Parent's class method to any Child's class methods" do + um = UnboundMethodSpecs::Parent.method(:class_method).unbind + um.bind_call(UnboundMethodSpecs::Child1).should == "I am UnboundMethodSpecs::Child1" + end - it "will raise when binding a an object singleton's method to another object" do - other = UnboundMethodSpecs::Parent.new - p = UnboundMethodSpecs::Parent.new - class << p - def singleton_method - :single - end + it "will raise when binding a an object singleton's method to another object" do + other = UnboundMethodSpecs::Parent.new + p = UnboundMethodSpecs::Parent.new + class << p + def singleton_method + :single end - um = p.method(:singleton_method).unbind - ->{ um.bind_call(other) }.should raise_error(TypeError) end + um = p.method(:singleton_method).unbind + ->{ um.bind_call(other) }.should raise_error(TypeError) end end diff --git a/spec/ruby/core/warning/element_reference_spec.rb b/spec/ruby/core/warning/element_reference_spec.rb index f51cc87de5..67728ca0f6 100644 --- a/spec/ruby/core/warning/element_reference_spec.rb +++ b/spec/ruby/core/warning/element_reference_spec.rb @@ -1,22 +1,20 @@ require_relative '../../spec_helper' -ruby_version_is '2.7' do - describe "Warning.[]" do - ruby_version_is '2.7.2' do - it "returns default values for categories :deprecated and :experimental" do - ruby_exe('p Warning[:deprecated]').chomp.should == "false" - ruby_exe('p Warning[:experimental]').chomp.should == "true" - end +describe "Warning.[]" do + ruby_version_is '2.7.2' do + it "returns default values for categories :deprecated and :experimental" do + ruby_exe('p Warning[:deprecated]').chomp.should == "false" + ruby_exe('p Warning[:experimental]').chomp.should == "true" end + end - it "raises for unknown category" do - -> { Warning[:noop] }.should raise_error(ArgumentError, /unknown category: noop/) - end + it "raises for unknown category" do + -> { Warning[:noop] }.should raise_error(ArgumentError, /unknown category: noop/) + end - it "raises for non-Symbol category" do - -> { Warning[42] }.should raise_error(TypeError) - -> { Warning[false] }.should raise_error(TypeError) - -> { Warning["noop"] }.should raise_error(TypeError) - end + it "raises for non-Symbol category" do + -> { Warning[42] }.should raise_error(TypeError) + -> { Warning[false] }.should raise_error(TypeError) + -> { Warning["noop"] }.should raise_error(TypeError) end end diff --git a/spec/ruby/core/warning/element_set_spec.rb b/spec/ruby/core/warning/element_set_spec.rb index 611060fb3a..d20ee215ad 100644 --- a/spec/ruby/core/warning/element_set_spec.rb +++ b/spec/ruby/core/warning/element_set_spec.rb @@ -1,37 +1,35 @@ require_relative '../../spec_helper' -ruby_version_is '2.7' do - describe "Warning.[]=" do - it "emits and suppresses warnings for :deprecated" do - ruby_exe('Warning[:deprecated] = true; $; = ""', args: "2>&1").should =~ /is deprecated/ - ruby_exe('Warning[:deprecated] = false; $; = ""', args: "2>&1").should == "" - end - - describe ":experimental" do - before do - ruby_version_is ""..."3.0" do - @src = 'case [0, 1]; in [a, b]; end' - end +describe "Warning.[]=" do + it "emits and suppresses warnings for :deprecated" do + ruby_exe('Warning[:deprecated] = true; $; = ""', args: "2>&1").should =~ /is deprecated/ + ruby_exe('Warning[:deprecated] = false; $; = ""', args: "2>&1").should == "" + end - ruby_version_is "3.0" do - @src = 'warn "This is experimental warning.", category: :experimental' - end + describe ":experimental" do + before do + ruby_version_is ""..."3.0" do + @src = 'case [0, 1]; in [a, b]; end' end - it "emits and suppresses warnings for :experimental" do - ruby_exe("Warning[:experimental] = true; eval('#{@src}')", args: "2>&1").should =~ /is experimental/ - ruby_exe("Warning[:experimental] = false; eval('#{@src}')", args: "2>&1").should == "" + ruby_version_is "3.0" do + @src = 'warn "This is experimental warning.", category: :experimental' end end - it "raises for unknown category" do - -> { Warning[:noop] = false }.should raise_error(ArgumentError, /unknown category: noop/) + it "emits and suppresses warnings for :experimental" do + ruby_exe("Warning[:experimental] = true; eval('#{@src}')", args: "2>&1").should =~ /is experimental/ + ruby_exe("Warning[:experimental] = false; eval('#{@src}')", args: "2>&1").should == "" end + end - it "raises for non-Symbol category" do - -> { Warning[42] = false }.should raise_error(TypeError) - -> { Warning[false] = false }.should raise_error(TypeError) - -> { Warning["noop"] = false }.should raise_error(TypeError) - end + it "raises for unknown category" do + -> { Warning[:noop] = false }.should raise_error(ArgumentError, /unknown category: noop/) + end + + it "raises for non-Symbol category" do + -> { Warning[42] = false }.should raise_error(TypeError) + -> { Warning[false] = false }.should raise_error(TypeError) + -> { Warning["noop"] = false }.should raise_error(TypeError) end end diff --git a/spec/ruby/fixtures/class.rb b/spec/ruby/fixtures/class.rb index 68fbca7ba7..98cb6c82a2 100644 --- a/spec/ruby/fixtures/class.rb +++ b/spec/ruby/fixtures/class.rb @@ -122,6 +122,10 @@ module ClassSpecs end end end + + DEFINE_CLASS = -> do + class ::A; end + end end class Class diff --git a/spec/ruby/fixtures/constants.rb b/spec/ruby/fixtures/constants.rb index 37271ddcc8..4c456dae89 100644 --- a/spec/ruby/fixtures/constants.rb +++ b/spec/ruby/fixtures/constants.rb @@ -299,4 +299,14 @@ module ConstantSpecs private_constant :CS_PRIVATE end +module ConstantSpecsThree + module ConstantSpecsTwo + Foo = :cs_three_foo + end +end + +module ConstantSpecsTwo + Foo = :cs_two_foo +end + include ConstantSpecs::ModuleA diff --git a/spec/ruby/language/alias_spec.rb b/spec/ruby/language/alias_spec.rb index d1d06e3fac..c353390679 100644 --- a/spec/ruby/language/alias_spec.rb +++ b/spec/ruby/language/alias_spec.rb @@ -243,6 +243,19 @@ describe "The alias keyword" do e.class.should == NameError } end + + it "defines the method on the aliased class when the original method is from a parent class" do + parent = Class.new do + def parent_method + end + end + child = Class.new(parent) do + alias parent_method_alias parent_method + end + + child.instance_method(:parent_method_alias).owner.should == child + child.instance_methods(false).should include(:parent_method_alias) + end end describe "The alias keyword" do diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb index b2a3cc84c4..42652152a1 100644 --- a/spec/ruby/language/block_spec.rb +++ b/spec/ruby/language/block_spec.rb @@ -40,8 +40,17 @@ describe "A block yielded a single" do m([1, 2]) { |a=5, b, c, d| [a, b, c, d] }.should == [5, 1, 2, nil] end - it "assigns elements to required arguments when a keyword rest argument is present" do - m([1, 2]) { |a, **k| [a, k] }.should == [1, {}] + ruby_version_is "3.2" do + it "does not autosplat single argument to required arguments when a keyword rest argument is present" do + m([1, 2]) { |a, **k| [a, k] }.should == [[1, 2], {}] + end + end + + ruby_version_is ''..."3.2" do + # https://bugs.ruby-lang.org/issues/18633 + it "autosplats single argument to required arguments when a keyword rest argument is present" do + m([1, 2]) { |a, **k| [a, k] }.should == [1, {}] + end end ruby_version_is ''..."3.0" do @@ -92,17 +101,7 @@ describe "A block yielded a single" do end end - ruby_version_is ""..."2.7" do - it "calls #to_hash on the argument and uses resulting hash as first argument when optional argument and keyword argument accepted" do - obj = mock("coerce block keyword arguments") - obj.should_receive(:to_hash).and_return({"a" => 1, "b" => 2}) - - result = m([obj]) { |a=nil, **b| [a, b] } - result.should == [{"a" => 1, "b" => 2}, {}] - end - end - - ruby_version_is "2.7"...'3.0' do + ruby_version_is ""...'3.0' do it "calls #to_hash on the argument but ignores result when optional argument and keyword argument accepted" do obj = mock("coerce block keyword arguments") obj.should_receive(:to_hash).and_return({"a" => 1, "b" => 2}) @@ -949,38 +948,18 @@ describe "Post-args" do end describe "with a circular argument reference" do - ruby_version_is ''...'2.7' do - it "warns and uses a nil value when there is an existing local variable with same name" do - a = 1 - -> { - @proc = eval "proc { |a=a| a }" - }.should complain(/circular argument reference/) - @proc.call.should == nil - end - - it "warns and uses a nil value when there is an existing method with same name" do - def a; 1; end - -> { - @proc = eval "proc { |a=a| a }" - }.should complain(/circular argument reference/) - @proc.call.should == nil - end + it "raises a SyntaxError if using an existing local with the same name as the argument" do + a = 1 + -> { + @proc = eval "proc { |a=a| a }" + }.should raise_error(SyntaxError) end - ruby_version_is '2.7' do - it "raises a SyntaxError if using an existing local with the same name as the argument" do - a = 1 - -> { - @proc = eval "proc { |a=a| a }" - }.should raise_error(SyntaxError) - end - - it "raises a SyntaxError if there is an existing method with the same name as the argument" do - def a; 1; end - -> { - @proc = eval "proc { |a=a| a }" - }.should raise_error(SyntaxError) - end + it "raises a SyntaxError if there is an existing method with the same name as the argument" do + def a; 1; end + -> { + @proc = eval "proc { |a=a| a }" + }.should raise_error(SyntaxError) end it "calls an existing method with the same name as the argument if explicitly using ()" do diff --git a/spec/ruby/language/case_spec.rb b/spec/ruby/language/case_spec.rb index 410cb9afb1..bf06803764 100644 --- a/spec/ruby/language/case_spec.rb +++ b/spec/ruby/language/case_spec.rb @@ -156,6 +156,15 @@ describe "The 'case'-construct" do end.should == "foo" end + it "tests an empty array" do + case [] + when [] + 'foo' + else + 'bar' + end.should == 'foo' + end + it "expands arrays to lists of values" do case 'z' when *['a', 'b', 'c', 'd'] diff --git a/spec/ruby/language/class_spec.rb b/spec/ruby/language/class_spec.rb index 83db164e1a..877895bf15 100644 --- a/spec/ruby/language/class_spec.rb +++ b/spec/ruby/language/class_spec.rb @@ -17,6 +17,19 @@ describe "The class keyword" do eval "class ClassSpecsKeywordWithoutSemicolon end" ClassSpecsKeywordWithoutSemicolon.should be_an_instance_of(Class) end + + it "can redefine a class when called from a block" do + ClassSpecs::DEFINE_CLASS.call + A.should be_an_instance_of(Class) + + Object.send(:remove_const, :A) + defined?(A).should be_nil + + ClassSpecs::DEFINE_CLASS.call + A.should be_an_instance_of(Class) + ensure + Object.send(:remove_const, :A) if defined?(::A) + end end describe "A class definition" do diff --git a/spec/ruby/language/comment_spec.rb b/spec/ruby/language/comment_spec.rb index 690e844dc0..dd788e681c 100644 --- a/spec/ruby/language/comment_spec.rb +++ b/spec/ruby/language/comment_spec.rb @@ -1,15 +1,13 @@ require_relative '../spec_helper' describe "The comment" do - ruby_version_is "2.7" do - it "can be placed between fluent dot now" do - code = <<~CODE - 10 - # some comment - .to_s - CODE + it "can be placed between fluent dot now" do + code = <<~CODE + 10 + # some comment + .to_s + CODE - eval(code).should == '10' - end + eval(code).should == '10' end end diff --git a/spec/ruby/language/constants_spec.rb b/spec/ruby/language/constants_spec.rb index 03f1272401..8586e46158 100644 --- a/spec/ruby/language/constants_spec.rb +++ b/spec/ruby/language/constants_spec.rb @@ -135,18 +135,34 @@ describe "Literal (A::X) constant resolution" do ConstantSpecs::ClassB::CS_CONST109.should == :const109_2 end - it "evaluates the right hand side before evaluating a constant path" do - mod = Module.new + ruby_version_is "3.2" do + it "evaluates left-to-right" do + mod = Module.new - mod.module_eval <<-EOC - ConstantSpecsRHS::B = begin - module ConstantSpecsRHS; end + mod.module_eval <<-EOC + order = [] + ConstantSpecsRHS = Module.new + (order << :lhs; ConstantSpecsRHS)::B = (order << :rhs) + EOC - "hello" - end - EOC + mod::ConstantSpecsRHS::B.should == [:lhs, :rhs] + end + end + + ruby_version_is ""..."3.2" do + it "evaluates the right hand side before evaluating a constant path" do + mod = Module.new + + mod.module_eval <<-EOC + ConstantSpecsRHS::B = begin + module ConstantSpecsRHS; end + + "hello" + end + EOC - mod::ConstantSpecsRHS::B.should == 'hello' + mod::ConstantSpecsRHS::B.should == 'hello' + end end end @@ -718,3 +734,17 @@ describe 'Allowed characters' do eval("mod::ἍBB").should == 1 end end + +describe 'Assignment' do + context 'dynamic assignment' do + it 'raises SyntaxError' do + -> do + eval <<-CODE + def test + B = 1 + end + CODE + end.should raise_error(SyntaxError, /dynamic constant assignment/) + end + end +end diff --git a/spec/ruby/language/def_spec.rb b/spec/ruby/language/def_spec.rb index 6b0be19d90..c8531343c0 100644 --- a/spec/ruby/language/def_spec.rb +++ b/spec/ruby/language/def_spec.rb @@ -197,32 +197,15 @@ describe "An instance method with a default argument" do foo(2,3,3).should == [2,3,[3]] end - ruby_version_is ''...'2.7' do - it "warns and uses a nil value when there is an existing local method with same name" do - def bar - 1 - end - -> { - eval "def foo(bar = bar) - bar - end" - }.should complain(/circular argument reference/) - foo.should == nil - foo(2).should == 2 - end - end - - ruby_version_is '2.7' do - it "raises a syntaxError an existing method with the same name as the local variable" do - def bar - 1 - end - -> { - eval "def foo(bar = bar) - bar - end" - }.should raise_error(SyntaxError) + it "raises a SyntaxError when there is an existing method with the same name as the local variable" do + def bar + 1 end + -> { + eval "def foo(bar = bar) + bar + end" + }.should raise_error(SyntaxError) end it "calls a method with the same name as the local when explicitly using ()" do diff --git a/spec/ruby/language/defined_spec.rb b/spec/ruby/language/defined_spec.rb index 38345c3727..ae2bf45bda 100644 --- a/spec/ruby/language/defined_spec.rb +++ b/spec/ruby/language/defined_spec.rb @@ -48,6 +48,20 @@ describe "The defined? keyword for literals" do end describe "The defined? keyword when called with a method name" do + before :each do + ScratchPad.clear + end + + it "does not call the method" do + defined?(DefinedSpecs.side_effects).should == "method" + ScratchPad.recorded.should != :defined_specs_side_effects + end + + it "does not execute the arguments" do + defined?(DefinedSpecs.any_args(DefinedSpecs.side_effects)).should == "method" + ScratchPad.recorded.should != :defined_specs_side_effects + end + describe "without a receiver" do it "returns 'method' if the method is defined" do ret = defined?(puts) diff --git a/spec/ruby/language/delegation_spec.rb b/spec/ruby/language/delegation_spec.rb index 8e4183cbcc..3f24a79d5c 100644 --- a/spec/ruby/language/delegation_spec.rb +++ b/spec/ruby/language/delegation_spec.rb @@ -1,42 +1,40 @@ require_relative '../spec_helper' require_relative 'fixtures/delegation' -ruby_version_is "2.7" do - describe "delegation with def(...)" do - it "delegates rest and kwargs" do - a = Class.new(DelegationSpecs::Target) - a.class_eval(<<-RUBY) - def delegate(...) - target(...) - end - RUBY +describe "delegation with def(...)" do + it "delegates rest and kwargs" do + a = Class.new(DelegationSpecs::Target) + a.class_eval(<<-RUBY) + def delegate(...) + target(...) + end + RUBY - a.new.delegate(1, b: 2).should == [[1], {b: 2}] - end + a.new.delegate(1, b: 2).should == [[1], {b: 2}] + end - it "delegates block" do - a = Class.new(DelegationSpecs::Target) - a.class_eval(<<-RUBY) - def delegate_block(...) - target_block(...) - end - RUBY + it "delegates block" do + a = Class.new(DelegationSpecs::Target) + a.class_eval(<<-RUBY) + def delegate_block(...) + target_block(...) + end + RUBY - a.new.delegate_block(1, b: 2) { |x| x }.should == [{b: 2}, [1]] - end + a.new.delegate_block(1, b: 2) { |x| x }.should == [{b: 2}, [1]] + end - it "parses as open endless Range when brackets are omitted" do - a = Class.new(DelegationSpecs::Target) - suppress_warning do - a.class_eval(<<-RUBY) - def delegate(...) - target ... - end - RUBY - end + it "parses as open endless Range when brackets are omitted" do + a = Class.new(DelegationSpecs::Target) + suppress_warning do + a.class_eval(<<-RUBY) + def delegate(...) + target ... + end + RUBY + end - a.new.delegate(1, b: 2).should == Range.new([[], {}], nil, true) - end + a.new.delegate(1, b: 2).should == Range.new([[], {}], nil, true) end end @@ -63,6 +61,5 @@ ruby_version_is "2.7.3" do a.new.delegate_block(0, 1, b: 2) { |x| x }.should == [{b: 2}, [1]] end - end end diff --git a/spec/ruby/language/file_spec.rb b/spec/ruby/language/file_spec.rb index 729dee1008..136b262d07 100644 --- a/spec/ruby/language/file_spec.rb +++ b/spec/ruby/language/file_spec.rb @@ -12,18 +12,10 @@ describe "The __FILE__ pseudo-variable" do end end -describe "The __FILE__ pseudo-variable" do - it_behaves_like :language___FILE__, :require, CodeLoadingSpecs::Method.new -end - -describe "The __FILE__ pseudo-variable" do +describe "The __FILE__ pseudo-variable with require" do it_behaves_like :language___FILE__, :require, Kernel end -describe "The __FILE__ pseudo-variable" do - it_behaves_like :language___FILE__, :load, CodeLoadingSpecs::Method.new -end - -describe "The __FILE__ pseudo-variable" do +describe "The __FILE__ pseudo-variable with load" do it_behaves_like :language___FILE__, :load, Kernel end diff --git a/spec/ruby/language/fixtures/defined.rb b/spec/ruby/language/fixtures/defined.rb index 8b6004c19f..a9552619bf 100644 --- a/spec/ruby/language/fixtures/defined.rb +++ b/spec/ruby/language/fixtures/defined.rb @@ -19,6 +19,9 @@ module DefinedSpecs DefinedSpecs end + def self.any_args(*) + end + class Basic A = 42 diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_two_literals.rb b/spec/ruby/language/fixtures/freeze_magic_comment_two_literals.rb index a4d655ad02..cccc5969bd 100644 --- a/spec/ruby/language/fixtures/freeze_magic_comment_two_literals.rb +++ b/spec/ruby/language/fixtures/freeze_magic_comment_two_literals.rb @@ -1,3 +1,3 @@ # frozen_string_literal: true -p "abc".object_id == "abc".object_id +p "abc".equal?("abc") diff --git a/spec/ruby/language/hash_spec.rb b/spec/ruby/language/hash_spec.rb index 2f8b97199a..c84564d3ea 100644 --- a/spec/ruby/language/hash_spec.rb +++ b/spec/ruby/language/hash_spec.rb @@ -148,18 +148,9 @@ describe "Hash literal" do {a: 1, **obj, c: 3}.should == {a:1, b: 2, c: 3, d: 4} end - ruby_version_is ""..."2.7" do - it "raises a TypeError if any splatted elements keys are not symbols" do - h = {1 => 2, b: 3} - -> { {a: 1, **h} }.should raise_error(TypeError) - end - end - - ruby_version_is "2.7" do - it "allows splatted elements keys that are not symbols" do - h = {1 => 2, b: 3} - {a: 1, **h}.should == {a: 1, 1 => 2, b: 3} - end + it "allows splatted elements keys that are not symbols" do + h = {1 => 2, b: 3} + {a: 1, **h}.should == {a: 1, 1 => 2, b: 3} end it "raises a TypeError if #to_hash does not return a Hash" do diff --git a/spec/ruby/language/heredoc_spec.rb b/spec/ruby/language/heredoc_spec.rb index 61a27ad8e0..b3b160fd11 100644 --- a/spec/ruby/language/heredoc_spec.rb +++ b/spec/ruby/language/heredoc_spec.rb @@ -59,20 +59,10 @@ HERE s.encoding.should == Encoding::US_ASCII end - ruby_version_is "2.7" do - it 'raises SyntaxError if quoted HEREDOC identifier is ending not on same line' do - -> { - eval %{<<"HERE\n"\nraises syntax error\nHERE} - }.should raise_error(SyntaxError) - end - end - - ruby_version_is ""..."2.7" do - it 'prints a warning if quoted HEREDOC identifier is ending not on same line' do - -> { - eval %{<<"HERE\n"\nit warns\nHERE} - }.should complain(/here document identifier ends with a newline/) - end + it 'raises SyntaxError if quoted HEREDOC identifier is ending not on same line' do + -> { + eval %{<<"HERE\n"\nraises syntax error\nHERE} + }.should raise_error(SyntaxError) end it "allows HEREDOC with <<~'identifier', allowing to indent identifier and content" do diff --git a/spec/ruby/language/keyword_arguments_spec.rb b/spec/ruby/language/keyword_arguments_spec.rb new file mode 100644 index 0000000000..0c72f59d38 --- /dev/null +++ b/spec/ruby/language/keyword_arguments_spec.rb @@ -0,0 +1,364 @@ +require_relative '../spec_helper' + +ruby_version_is "3.0" do + describe "Keyword arguments" do + def target(*args, **kwargs) + [args, kwargs] + end + + it "are separated from positional arguments" do + def m(*args, **kwargs) + [args, kwargs] + end + + empty = {} + m(**empty).should == [[], {}] + m(empty).should == [[{}], {}] + + m(a: 1).should == [[], {a: 1}] + m({a: 1}).should == [[{a: 1}], {}] + end + + it "when the receiving method has not keyword parameters it treats kwargs as positional" do + def m(*a) + a + end + + m(a: 1).should == [{a: 1}] + m({a: 1}).should == [{a: 1}] + end + + context "empty kwargs are treated as if they were not passed" do + it "when calling a method" do + def m(*a) + a + end + + empty = {} + m(**empty).should == [] + m(empty).should == [{}] + end + + it "when yielding to a block" do + def y(*args, **kwargs) + yield(*args, **kwargs) + end + + empty = {} + y(**empty) { |*a| a }.should == [] + y(empty) { |*a| a }.should == [{}] + end + end + + it "extra keywords are not allowed without **kwrest" do + def m(*a, kw:) + a + end + + m(kw: 1).should == [] + -> { m(kw: 1, kw2: 2) }.should raise_error(ArgumentError, 'unknown keyword: :kw2') + -> { m(kw: 1, true => false) }.should raise_error(ArgumentError, 'unknown keyword: true') + end + + it "handle * and ** at the same call site" do + def m(*a) + a + end + + m(*[], **{}).should == [] + m(*[], 42, **{}).should == [42] + end + + context "**" do + it "does not copy a non-empty Hash for a method taking (*args)" do + def m(*args) + args[0] + end + + h = {a: 1} + m(**h).should.equal?(h) + end + + it "copies the given Hash for a method taking (**kwargs)" do + def m(**kw) + kw + end + + empty = {} + m(**empty).should == empty + m(**empty).should_not.equal?(empty) + + h = {a: 1} + m(**h).should == h + m(**h).should_not.equal?(h) + end + end + + context "delegation" do + it "works with (*args, **kwargs)" do + def m(*args, **kwargs) + target(*args, **kwargs) + end + + empty = {} + m(**empty).should == [[], {}] + m(empty).should == [[{}], {}] + + m(a: 1).should == [[], {a: 1}] + m({a: 1}).should == [[{a: 1}], {}] + end + + it "works with proc { |*args, **kwargs| }" do + m = proc do |*args, **kwargs| + target(*args, **kwargs) + end + + empty = {} + m.(**empty).should == [[], {}] + m.(empty).should == [[{}], {}] + + m.(a: 1).should == [[], {a: 1}] + m.({a: 1}).should == [[{a: 1}], {}] + + # no autosplatting for |*args, **kwargs| + m.([1, 2]).should == [[[1, 2]], {}] + end + + it "works with -> (*args, **kwargs) {}" do + m = -> *args, **kwargs do + target(*args, **kwargs) + end + + empty = {} + m.(**empty).should == [[], {}] + m.(empty).should == [[{}], {}] + + m.(a: 1).should == [[], {a: 1}] + m.({a: 1}).should == [[{a: 1}], {}] + end + + it "works with (...)" do + instance_eval <<~DEF + def m(...) + target(...) + end + DEF + + empty = {} + m(**empty).should == [[], {}] + m(empty).should == [[{}], {}] + + m(a: 1).should == [[], {a: 1}] + m({a: 1}).should == [[{a: 1}], {}] + end + + it "works with call(*ruby2_keyword_args)" do + class << self + ruby2_keywords def m(*args) + target(*args) + end + end + + empty = {} + m(**empty).should == [[], {}] + Hash.ruby2_keywords_hash?(empty).should == false + m(empty).should == [[{}], {}] + Hash.ruby2_keywords_hash?(empty).should == false + + m(a: 1).should == [[], {a: 1}] + m({a: 1}).should == [[{a: 1}], {}] + + kw = {a: 1} + + m(**kw).should == [[], {a: 1}] + m(**kw)[1].should == kw + m(**kw)[1].should_not.equal?(kw) + Hash.ruby2_keywords_hash?(kw).should == false + Hash.ruby2_keywords_hash?(m(**kw)[1]).should == false + + m(kw).should == [[{a: 1}], {}] + m(kw)[0][0].should.equal?(kw) + Hash.ruby2_keywords_hash?(kw).should == false + end + + it "works with super(*ruby2_keyword_args)" do + parent = Class.new do + def m(*args, **kwargs) + [args, kwargs] + end + end + + child = Class.new(parent) do + ruby2_keywords def m(*args) + super(*args) + end + end + + obj = child.new + + empty = {} + obj.m(**empty).should == [[], {}] + Hash.ruby2_keywords_hash?(empty).should == false + obj.m(empty).should == [[{}], {}] + Hash.ruby2_keywords_hash?(empty).should == false + + obj.m(a: 1).should == [[], {a: 1}] + obj.m({a: 1}).should == [[{a: 1}], {}] + + kw = {a: 1} + + obj.m(**kw).should == [[], {a: 1}] + obj.m(**kw)[1].should == kw + obj.m(**kw)[1].should_not.equal?(kw) + Hash.ruby2_keywords_hash?(kw).should == false + Hash.ruby2_keywords_hash?(obj.m(**kw)[1]).should == false + + obj.m(kw).should == [[{a: 1}], {}] + obj.m(kw)[0][0].should.equal?(kw) + Hash.ruby2_keywords_hash?(kw).should == false + end + + it "works with zsuper" do + parent = Class.new do + def m(*args, **kwargs) + [args, kwargs] + end + end + + child = Class.new(parent) do + ruby2_keywords def m(*args) + super + end + end + + obj = child.new + + empty = {} + obj.m(**empty).should == [[], {}] + Hash.ruby2_keywords_hash?(empty).should == false + obj.m(empty).should == [[{}], {}] + Hash.ruby2_keywords_hash?(empty).should == false + + obj.m(a: 1).should == [[], {a: 1}] + obj.m({a: 1}).should == [[{a: 1}], {}] + + kw = {a: 1} + + obj.m(**kw).should == [[], {a: 1}] + obj.m(**kw)[1].should == kw + obj.m(**kw)[1].should_not.equal?(kw) + Hash.ruby2_keywords_hash?(kw).should == false + Hash.ruby2_keywords_hash?(obj.m(**kw)[1]).should == false + + obj.m(kw).should == [[{a: 1}], {}] + obj.m(kw)[0][0].should.equal?(kw) + Hash.ruby2_keywords_hash?(kw).should == false + end + + it "works with yield(*ruby2_keyword_args)" do + class << self + def y(args) + yield(*args) + end + + ruby2_keywords def m(*outer_args) + y(outer_args, &-> *args, **kwargs { target(*args, **kwargs) }) + end + end + + empty = {} + m(**empty).should == [[], {}] + Hash.ruby2_keywords_hash?(empty).should == false + m(empty).should == [[{}], {}] + Hash.ruby2_keywords_hash?(empty).should == false + + m(a: 1).should == [[], {a: 1}] + m({a: 1}).should == [[{a: 1}], {}] + + kw = {a: 1} + + m(**kw).should == [[], {a: 1}] + m(**kw)[1].should == kw + m(**kw)[1].should_not.equal?(kw) + Hash.ruby2_keywords_hash?(kw).should == false + Hash.ruby2_keywords_hash?(m(**kw)[1]).should == false + + m(kw).should == [[{a: 1}], {}] + m(kw)[0][0].should.equal?(kw) + Hash.ruby2_keywords_hash?(kw).should == false + end + + it "does not work with (*args)" do + class << self + def m(*args) + target(*args) + end + end + + empty = {} + m(**empty).should == [[], {}] + m(empty).should == [[{}], {}] + + m(a: 1).should == [[{a: 1}], {}] + m({a: 1}).should == [[{a: 1}], {}] + end + + ruby_version_is "3.2" do + it "does not work with call(*ruby2_keyword_args) with missing ruby2_keywords in between" do + class << self + def n(*args) # Note the missing ruby2_keywords here + target(*args) + end + + ruby2_keywords def m(*args) + n(*args) + end + end + + empty = {} + m(**empty).should == [[], {}] + m(empty).should == [[{}], {}] + + m(a: 1).should == [[{a: 1}], {}] + m({a: 1}).should == [[{a: 1}], {}] + end + end + + ruby_version_is ""..."3.2" do + # https://bugs.ruby-lang.org/issues/18625 + it "works with call(*ruby2_keyword_args) with missing ruby2_keywords in between due to CRuby bug #18625" do + class << self + def n(*args) # Note the missing ruby2_keywords here + target(*args) + end + + ruby2_keywords def m(*args) + n(*args) + end + end + + empty = {} + m(**empty).should == [[], {}] + Hash.ruby2_keywords_hash?(empty).should == false + m(empty).should == [[{}], {}] + Hash.ruby2_keywords_hash?(empty).should == false + + m(a: 1).should == [[], {a: 1}] + m({a: 1}).should == [[{a: 1}], {}] + + kw = {a: 1} + + m(**kw).should == [[], {a: 1}] + m(**kw)[1].should == kw + m(**kw)[1].should_not.equal?(kw) + Hash.ruby2_keywords_hash?(kw).should == false + Hash.ruby2_keywords_hash?(m(**kw)[1]).should == false + + m(kw).should == [[{a: 1}], {}] + m(kw)[0][0].should.equal?(kw) + Hash.ruby2_keywords_hash?(kw).should == false + end + end + end + end +end diff --git a/spec/ruby/language/lambda_spec.rb b/spec/ruby/language/lambda_spec.rb index 6393fb5c47..a3f01ec04b 100644 --- a/spec/ruby/language/lambda_spec.rb +++ b/spec/ruby/language/lambda_spec.rb @@ -281,38 +281,18 @@ describe "A lambda literal -> () { }" do end describe "with circular optional argument reference" do - ruby_version_is ''...'2.7' do - it "warns and uses a nil value when there is an existing local variable with same name" do - a = 1 - -> { - @proc = eval "-> (a=a) { a }" - }.should complain(/circular argument reference/) - @proc.call.should == nil - end - - it "warns and uses a nil value when there is an existing method with same name" do - def a; 1; end - -> { - @proc = eval "-> (a=a) { a }" - }.should complain(/circular argument reference/) - @proc.call.should == nil - end + it "raises a SyntaxError if using an existing local with the same name as the argument" do + a = 1 + -> { + @proc = eval "-> (a=a) { a }" + }.should raise_error(SyntaxError) end - ruby_version_is '2.7' do - it "raises a SyntaxError if using an existing local with the same name as the argument" do - a = 1 - -> { - @proc = eval "-> (a=a) { a }" - }.should raise_error(SyntaxError) - end - - it "raises a SyntaxError if there is an existing method with the same name as the argument" do - def a; 1; end - -> { - @proc = eval "-> (a=a) { a }" - }.should raise_error(SyntaxError) - end + it "raises a SyntaxError if there is an existing method with the same name as the argument" do + def a; 1; end + -> { + @proc = eval "-> (a=a) { a }" + }.should raise_error(SyntaxError) end it "calls an existing method with the same name as the argument if explicitly using ()" do @@ -360,26 +340,12 @@ describe "A lambda expression 'lambda { ... }'" do def meth; lambda; end end - ruby_version_is ""..."2.7" do - it "can be created" do - implicit_lambda = nil + it "raises ArgumentError" do + implicit_lambda = nil + suppress_warning do -> { - implicit_lambda = meth { 1 } - }.should complain(/tried to create Proc object without a block/) - - implicit_lambda.lambda?.should be_true - implicit_lambda.call.should == 1 - end - end - - ruby_version_is "2.7" do - it "raises ArgumentError" do - implicit_lambda = nil - suppress_warning do - -> { - meth { 1 } - }.should raise_error(ArgumentError, /tried to create Proc object without a block/) - end + meth { 1 } + }.should raise_error(ArgumentError, /tried to create Proc object without a block/) end end end diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb index 0a5bb99d0b..d464e79403 100644 --- a/spec/ruby/language/method_spec.rb +++ b/spec/ruby/language/method_spec.rb @@ -602,13 +602,11 @@ describe "A method" do -> { m(2) }.should raise_error(ArgumentError) end - ruby_version_is "2.7" do - evaluate <<-ruby do - def m(**k); k end; - ruby + evaluate <<-ruby do + def m(**k); k end; + ruby - m("a" => 1).should == { "a" => 1 } - end + m("a" => 1).should == { "a" => 1 } end evaluate <<-ruby do @@ -962,26 +960,13 @@ describe "A method" do end end - ruby_version_is ""..."2.7" do - evaluate <<-ruby do - def m(a=1, **) a end - ruby - - m().should == 1 - m(2, a: 1, b: 0).should == 2 - m("a" => 1, a: 2).should == {"a" => 1} - end - end - - ruby_version_is "2.7" do - evaluate <<-ruby do - def m(a=1, **) a end - ruby + evaluate <<-ruby do + def m(a=1, **) a end + ruby - m().should == 1 - m(2, a: 1, b: 0).should == 2 - m("a" => 1, a: 2).should == 1 - end + m().should == 1 + m(2, a: 1, b: 0).should == 2 + m("a" => 1, a: 2).should == 1 end evaluate <<-ruby do @@ -1021,164 +1006,7 @@ describe "A method" do m(1, 2, 3).should == [[1, 2], 3] end - ruby_version_is ""..."2.7" do - evaluate <<-ruby do - def m(*, a:) a end - ruby - - m(a: 1).should == 1 - m(1, 2, a: 3).should == 3 - suppress_keyword_warning do - m("a" => 1, a: 2).should == 2 - end - end - - evaluate <<-ruby do - def m(*a, b:) [a, b] end - ruby - - m(b: 1).should == [[], 1] - m(1, 2, b: 3).should == [[1, 2], 3] - suppress_keyword_warning do - m("a" => 1, b: 2).should == [[{"a" => 1}], 2] - end - end - - evaluate <<-ruby do - def m(*, a: 1) a end - ruby - - m().should == 1 - m(1, 2).should == 1 - m(a: 2).should == 2 - m(1, a: 2).should == 2 - suppress_keyword_warning do - m("a" => 1, a: 2).should == 2 - end - end - - evaluate <<-ruby do - def m(*a, b: 1) [a, b] end - ruby - - m().should == [[], 1] - m(1, 2, 3, b: 4).should == [[1, 2, 3], 4] - suppress_keyword_warning do - m("a" => 1, b: 2).should == [[{"a" => 1}], 2] - end - - a = mock("splat") - a.should_not_receive(:to_ary) - m(*a).should == [[a], 1] - end - - evaluate <<-ruby do - def m(*, **) end - ruby - - m().should be_nil - m(a: 1, b: 2).should be_nil - m(1, 2, 3, a: 4, b: 5).should be_nil - - h = mock("keyword splat") - h.should_receive(:to_hash).and_return({a: 1}) - suppress_keyword_warning do - m(h).should be_nil - end - - h = mock("keyword splat") - error = RuntimeError.new("error while converting to a hash") - h.should_receive(:to_hash).and_raise(error) - -> { m(h) }.should raise_error(error) - end - - evaluate <<-ruby do - def m(*a, **) a end - ruby - - m().should == [] - m(1, 2, 3, a: 4, b: 5).should == [1, 2, 3] - m("a" => 1, a: 1).should == [{"a" => 1}] - m(1, **{a: 2}).should == [1] - - h = mock("keyword splat") - h.should_receive(:to_hash) - -> { m(**h) }.should raise_error(TypeError) - end - - evaluate <<-ruby do - def m(*, **k) k end - ruby - - m().should == {} - m(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5} - m("a" => 1, a: 1).should == {a: 1} - - h = mock("keyword splat") - h.should_receive(:to_hash).and_return({a: 1}) - m(h).should == {a: 1} - end - - evaluate <<-ruby do - def m(a = nil, **k) [a, k] end - ruby - - m().should == [nil, {}] - m("a" => 1).should == [{"a" => 1}, {}] - m(a: 1).should == [nil, {a: 1}] - m("a" => 1, a: 1).should == [{"a" => 1}, {a: 1}] - m({ "a" => 1 }, a: 1).should == [{"a" => 1}, {a: 1}] - m({a: 1}, {}).should == [{a: 1}, {}] - - h = {"a" => 1, b: 2} - m(h).should == [{"a" => 1}, {b: 2}] - h.should == {"a" => 1, b: 2} - - h = {"a" => 1} - m(h).first.should == h - - h = {} - r = m(h) - r.first.should be_nil - r.last.should == {} - - hh = {} - h = mock("keyword splat empty hash") - h.should_receive(:to_hash).and_return(hh) - r = m(h) - r.first.should be_nil - r.last.should == {} - - h = mock("keyword splat") - h.should_receive(:to_hash).and_return({"a" => 1, a: 2}) - m(h).should == [{"a" => 1}, {a: 2}] - end - - evaluate <<-ruby do - def m(*a, **k) [a, k] end - ruby - - m().should == [[], {}] - m(1).should == [[1], {}] - m(a: 1, b: 2).should == [[], {a: 1, b: 2}] - m(1, 2, 3, a: 2).should == [[1, 2, 3], {a: 2}] - - m("a" => 1).should == [[{"a" => 1}], {}] - m(a: 1).should == [[], {a: 1}] - m("a" => 1, a: 1).should == [[{"a" => 1}], {a: 1}] - m({ "a" => 1 }, a: 1).should == [[{"a" => 1}], {a: 1}] - m({a: 1}, {}).should == [[{a: 1}], {}] - m({a: 1}, {"a" => 1}).should == [[{a: 1}, {"a" => 1}], {}] - - bo = BasicObject.new - def bo.to_a; [1, 2, 3]; end - def bo.to_hash; {:b => 2, :c => 3}; end - - m(*bo, **bo).should == [[1, 2, 3], {:b => 2, :c => 3}] - end - end - - ruby_version_is "2.7"...'3.0' do + ruby_version_is ""...'3.0' do evaluate <<-ruby do def m(*, a:) a end ruby @@ -1503,44 +1331,22 @@ describe "A method" do end end - ruby_version_is ''...'2.7' do - evaluate <<-ruby do - def m(a:, **) a end - ruby - - m(a: 1).should == 1 - m(a: 1, b: 2).should == 1 - -> { m("a" => 1, a: 1, b: 2) }.should raise_error(ArgumentError) - end - - evaluate <<-ruby do - def m(a:, **k) [a, k] end - ruby + evaluate <<-ruby do + def m(a:, **) a end + ruby - m(a: 1).should == [1, {}] - m(a: 1, b: 2, c: 3).should == [1, {b: 2, c: 3}] - -> { m("a" => 1, a: 1, b: 2) }.should raise_error(ArgumentError) - end + m(a: 1).should == 1 + m(a: 1, b: 2).should == 1 + m("a" => 1, a: 1, b: 2).should == 1 end - ruby_version_is '2.7' do - evaluate <<-ruby do - def m(a:, **) a end - ruby - - m(a: 1).should == 1 - m(a: 1, b: 2).should == 1 - m("a" => 1, a: 1, b: 2).should == 1 - end - - evaluate <<-ruby do - def m(a:, **k) [a, k] end - ruby + evaluate <<-ruby do + def m(a:, **k) [a, k] end + ruby - m(a: 1).should == [1, {}] - m(a: 1, b: 2, c: 3).should == [1, {b: 2, c: 3}] - m("a" => 1, a: 1, b: 2).should == [1, {"a" => 1, b: 2}] - end + m(a: 1).should == [1, {}] + m(a: 1, b: 2, c: 3).should == [1, {b: 2, c: 3}] + m("a" => 1, a: 1, b: 2).should == [1, {"a" => 1, b: 2}] end evaluate <<-ruby do @@ -1637,18 +1443,16 @@ describe "A method" do result.should == [1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l] end - ruby_version_is "2.7" do - evaluate <<-ruby do - def m(a, **nil); a end; - ruby + evaluate <<-ruby do + def m(a, **nil); a end; + ruby - m({a: 1}).should == {a: 1} - m({"a" => 1}).should == {"a" => 1} + m({a: 1}).should == {a: 1} + m({"a" => 1}).should == {"a" => 1} - -> { m(a: 1) }.should raise_error(ArgumentError) - -> { m(**{a: 1}) }.should raise_error(ArgumentError) - -> { m("a" => 1) }.should raise_error(ArgumentError) - end + -> { m(a: 1) }.should raise_error(ArgumentError) + -> { m(**{a: 1}) }.should raise_error(ArgumentError) + -> { m("a" => 1) }.should raise_error(ArgumentError) end ruby_version_is ''...'3.0' do @@ -1690,19 +1494,17 @@ describe "A method" do end end - ruby_version_is '2.7' do - context 'when passing an empty keyword splat to a method that does not accept keywords' do - evaluate <<-ruby do - def m(*a); a; end - ruby + context 'when passing an empty keyword splat to a method that does not accept keywords' do + evaluate <<-ruby do + def m(*a); a; end + ruby - h = {} - m(**h).should == [] - end + h = {} + m(**h).should == [] end end - ruby_version_is '2.7'...'3.0' do + ruby_version_is ''...'3.0' do context 'when passing an empty keyword splat to a method that does not accept keywords' do evaluate <<-ruby do def m(a); a; end diff --git a/spec/ruby/language/numbered_parameters_spec.rb b/spec/ruby/language/numbered_parameters_spec.rb index 838822b2d6..424d7a06e3 100644 --- a/spec/ruby/language/numbered_parameters_spec.rb +++ b/spec/ruby/language/numbered_parameters_spec.rb @@ -1,120 +1,118 @@ require_relative '../spec_helper' -ruby_version_is "2.7" do - describe "Numbered parameters" do - it "provides default parameters _1, _2, ... in a block" do - -> { _1 }.call("a").should == "a" - proc { _1 }.call("a").should == "a" - lambda { _1 }.call("a").should == "a" - ["a"].map { _1 }.should == ["a"] - end +describe "Numbered parameters" do + it "provides default parameters _1, _2, ... in a block" do + -> { _1 }.call("a").should == "a" + proc { _1 }.call("a").should == "a" + lambda { _1 }.call("a").should == "a" + ["a"].map { _1 }.should == ["a"] + end - it "assigns nil to not passed parameters" do - proc { [_1, _2] }.call("a").should == ["a", nil] - proc { [_1, _2] }.call("a", "b").should == ["a", "b"] - end + it "assigns nil to not passed parameters" do + proc { [_1, _2] }.call("a").should == ["a", nil] + proc { [_1, _2] }.call("a", "b").should == ["a", "b"] + end - it "supports variables _1-_9 only for the first 9 passed parameters" do - block = proc { [_1, _2, _3, _4, _5, _6, _7, _8, _9] } - result = block.call(1, 2, 3, 4, 5, 6, 7, 8, 9) - result.should == [1, 2, 3, 4, 5, 6, 7, 8, 9] - end + it "supports variables _1-_9 only for the first 9 passed parameters" do + block = proc { [_1, _2, _3, _4, _5, _6, _7, _8, _9] } + result = block.call(1, 2, 3, 4, 5, 6, 7, 8, 9) + result.should == [1, 2, 3, 4, 5, 6, 7, 8, 9] + end - it "does not support more than 9 parameters" do - -> { - proc { [_10] }.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) - }.should raise_error(NameError, /undefined local variable or method `_10'/) - end + it "does not support more than 9 parameters" do + -> { + proc { [_10] }.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + }.should raise_error(NameError, /undefined local variable or method `_10'/) + end - it "can not be used in both outer and nested blocks at the same time" do - -> { - eval("-> { _1; -> { _2 } }") - }.should raise_error(SyntaxError, /numbered parameter is already used in/m) - end + it "can not be used in both outer and nested blocks at the same time" do + -> { + eval("-> { _1; -> { _2 } }") + }.should raise_error(SyntaxError, /numbered parameter is already used in/m) + end - ruby_version_is '2.7'...'3.0' do - it "can be overwritten with local variable" do - suppress_warning do - eval <<~CODE - _1 = 0 - proc { _1 }.call("a").should == 0 - CODE - end + ruby_version_is ''...'3.0' do + it "can be overwritten with local varia |