diff options
Diffstat (limited to 'spec/ruby')
1421 files changed, 18703 insertions, 25850 deletions
diff --git a/spec/ruby/.mspec.constants b/spec/ruby/.mspec.constants index 6e09a44362..6b70274c52 100644 --- a/spec/ruby/.mspec.constants +++ b/spec/ruby/.mspec.constants @@ -39,8 +39,6 @@ CodingUS_ASCII CodingUTF_8 ComparisonTest ConstantSpecsIncludedModule -ConstantSpecsTwo -ConstantSpecsThree ConstantVisibility Coverage CoverageSpecs @@ -75,7 +73,6 @@ EvalBindingProcA Exception2MessageMapper ExceptionForMatrix Fcntl -Fiddle FileStat FileUtils Find @@ -204,7 +201,6 @@ UserArray UserCustomConstructorString UserDefined UserDefinedImmediate -UserDefinedString UserDefinedWithIvar UserHash UserHashInitParams diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml index 9ad57dd51c..eab4c3c4a6 100644 --- a/spec/ruby/.rubocop.yml +++ b/spec/ruby/.rubocop.yml @@ -1,12 +1,11 @@ inherit_from: .rubocop_todo.yml AllCops: - TargetRubyVersion: 3.0 + TargetRubyVersion: 2.6 DisplayCopNames: true Exclude: - command_line/fixtures/bad_syntax.rb DisabledByDefault: true - NewCops: disable Layout/TrailingWhitespace: Enabled: true @@ -33,10 +32,6 @@ Lint/AssignmentInCondition: Lint/BooleanSymbol: Enabled: false -Lint/DeprecatedOpenSSLConstant: - Exclude: - - library/openssl/digest/**/*.rb - Lint/InterpolationCheck: Enabled: false @@ -61,55 +56,12 @@ Lint/UnusedMethodArgument: Lint/UselessAssignment: Enabled: false -Lint/BinaryOperatorWithIdenticalOperands: +Lint/UselessComparison: 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/InheritException: - Enabled: false - -Lint/ElseLayout: - Exclude: - - 'language/if_spec.rb' - Lint/EmptyExpression: Exclude: - 'language/**/*.rb' @@ -119,10 +71,6 @@ Lint/EmptyWhen: - language/case_spec.rb - optional/capi/spec_helper.rb -Lint/ErbNewArguments: - Exclude: - - 'library/erb/new_spec.rb' - Lint/FormatParameterMismatch: Exclude: - 'core/kernel/shared/sprintf.rb' @@ -169,9 +117,6 @@ Lint/Debugger: Lint/Loop: Enabled: false -Style/BlockComments: - Enabled: true - Style/Lambda: Enabled: true EnforcedStyle: literal diff --git a/spec/ruby/.rubocop_todo.yml b/spec/ruby/.rubocop_todo.yml index a59e64bd58..a469213841 100644 --- a/spec/ruby/.rubocop_todo.yml +++ b/spec/ruby/.rubocop_todo.yml @@ -50,6 +50,17 @@ Lint/IneffectiveAccessModifier: - 'core/module/fixtures/classes.rb' - 'language/fixtures/private.rb' +# Offense count: 6 +# Cop supports --auto-correct. +# Configuration parameters: EnforcedStyle. +# SupportedStyles: runtime_error, standard_error +Lint/InheritException: + Exclude: + - 'core/enumerator/lazy/fixtures/classes.rb' + - 'core/exception/fixtures/common.rb' + - 'core/module/fixtures/autoload_ex1.rb' + - 'shared/kernel/raise.rb' + # Offense count: 72 # Cop supports --auto-correct. Lint/LiteralInInterpolation: @@ -98,7 +109,6 @@ Lint/RescueException: - 'core/dir/fileno_spec.rb' - 'core/exception/cause_spec.rb' - 'core/exception/no_method_error_spec.rb' - - 'core/fiber/kill_spec.rb' - 'core/kernel/fixtures/autoload_frozen.rb' - 'core/kernel/raise_spec.rb' - 'core/module/autoload_spec.rb' diff --git a/spec/ruby/CONTRIBUTING.md b/spec/ruby/CONTRIBUTING.md index c82eb5ea4f..30941677e0 100644 --- a/spec/ruby/CONTRIBUTING.md +++ b/spec/ruby/CONTRIBUTING.md @@ -13,14 +13,12 @@ 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 @@ -138,12 +136,12 @@ Here is a list of the most commonly-used guards: #### Version guards ```ruby -ruby_version_is ""..."3.2" do - # Specs for RUBY_VERSION < 3.2 +ruby_version_is ""..."2.6" do + # Specs for RUBY_VERSION < 2.6 end -ruby_version_is "3.2" do - # Specs for RUBY_VERSION >= 3.2 +ruby_version_is "2.6" do + # Specs for RUBY_VERSION >= 2.6 end ``` @@ -175,14 +173,12 @@ end #### Guard for bug -In case there is a bug in MRI and the fix will be backported to previous versions. -If it is not backported or not likely, use `ruby_version_is` instead. +In case there is a bug in MRI but the expected behavior is obvious. First, file a bug at https://bugs.ruby-lang.org/. -The problem is `ruby_bug` would make non-MRI implementations fail this spec while MRI itself does not pass it, so it should only be used if the bug is/will be fixed and backported. -Otherwise, non-MRI implementations would have to choose between being incompatible with the latest release of MRI to pass the spec or fail the spec, both which make no sense. +It is better to use a `ruby_version_is` guard if there was a release with the fix. ```ruby -ruby_bug '#13669', ''...'3.2' do +ruby_bug '#13669', ''...'2.7' do it "works like this" do # Specify the expected behavior here, not the bug end @@ -192,11 +188,11 @@ end #### Combining guards ```ruby -guard -> { platform_is :windows and ruby_version_is ""..."3.2" } do - # Windows and RUBY_VERSION < 3.2 +guard -> { platform_is :windows and ruby_version_is ""..."2.6" } do + # Windows and RUBY_VERSION < 2.6 end -guard_not -> { platform_is :windows and ruby_version_is ""..."3.2" } do +guard_not -> { platform_is :windows and ruby_version_is ""..."2.6" } do # The opposite end ``` @@ -224,7 +220,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 @@ -236,7 +232,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: @@ -261,12 +257,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 115392835f..e62ddc7dce 100644 --- a/spec/ruby/README.md +++ b/spec/ruby/README.md @@ -1,6 +1,7 @@ # The Ruby Spec Suite [](https://github.com/ruby/spec/actions) +[](https://gitter.im/ruby/spec) The Ruby Spec Suite, abbreviated `ruby/spec`, is a test suite for the behavior of the Ruby programming language. @@ -17,21 +18,20 @@ 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](https://github.com/ruby/mspec) project. +For more information, see the [MSpec](http://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](https://rubyci.org/) on 30 platforms and 4 versions +* [MRI](http://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 3.0 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 (3.0.x, 3.1.x, 3.2.x, etc), and those are tested in CI. +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. ### Synchronization with Ruby Implementations @@ -53,15 +53,12 @@ $ ../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) -* Ruby 2.7.8 - [Suite](https://github.com/ruby/spec/commit/93787e6035c925b593a9c0c6fb0e7e07a6f1df1f) using [MSpec](https://github.com/ruby/mspec/commit/1d8cf64722d8a7529f7cd205be5f16a89b7a67fd) ### Running the specs @@ -73,7 +70,7 @@ Then move to it: $ cd spec -Clone [MSpec](https://github.com/ruby/mspec): +Clone [MSpec](http://github.com/ruby/mspec): $ git clone https://github.com/ruby/mspec.git ../mspec @@ -128,12 +125,6 @@ MSpec can automatically add new top-level constants in this file with: $ CHECK_LEAKS=save mspec ../mspec/bin/mspec file -### Running Specs on S390x CPU Architecture - -Run the specs with `DFLTCC=0` if you see failing specs related to the zlib library on s390x CPU architecture. The failures can happen with the zlib library applying the patch madler/zlib#410 to enable the deflate algorithm producing a different compressed byte stream. - - $ DFLTCC=0 ../mspec/bin/mspec - ### Contributing and Writing Specs See [CONTRIBUTING.md](https://github.com/ruby/spec/blob/master/CONTRIBUTING.md) for documentation about contributing and writing specs (guards, matchers, etc). @@ -150,9 +141,10 @@ The file `/etc/services` is required for socket specs (package `netbase` on Debi ### Socket specs from rubysl-socket -Most specs under `library/socket` were imported from the rubysl-socket project (which is no longer on GitHub). +Most specs under `library/socket` were imported from [the rubysl-socket project](https://github.com/rubysl/rubysl-socket). The 3 copyright holders of rubysl-socket, Yorick Peterse, Chuck Remes and -Brian Shirai, agreed to relicense those specs under the MIT license in ruby/spec. +Brian Shirai, [agreed to relicense those specs](https://github.com/rubysl/rubysl-socket/issues/15) +under the MIT license in ruby/spec. ### History and RubySpec @@ -160,5 +152,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](https://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](http://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/backtrace_limit_spec.rb b/spec/ruby/command_line/backtrace_limit_spec.rb index bc40a542a0..56afa8efef 100644 --- a/spec/ruby/command_line/backtrace_limit_spec.rb +++ b/spec/ruby/command_line/backtrace_limit_spec.rb @@ -1,46 +1,48 @@ require_relative '../spec_helper' -describe "The --backtrace-limit command line option" do - it "limits top-level backtraces to a given number of entries" do - file = fixture(__FILE__ , "backtrace.rb") - out = ruby_exe(file, options: "--backtrace-limit=2", args: "top 2>&1", exit_status: 1) - out = out.gsub(__dir__, '') +ruby_version_is "3.0" do + describe "The --backtrace-limit command line option" do + it "limits top-level backtraces to a given number of entries" do + file = fixture(__FILE__ , "backtrace.rb") + out = ruby_exe(file, options: "--backtrace-limit=2", args: "top 2>&1", exit_status: 1) + out = out.gsub(__dir__, '') - out.should == <<-MSG + out.should == <<-MSG top /fixtures/backtrace.rb:2:in `a': oops (RuntimeError) \tfrom /fixtures/backtrace.rb:6:in `b' \tfrom /fixtures/backtrace.rb:10:in `c' \t ... 2 levels... - MSG - end + MSG + end - it "affects Exception#full_message" do - file = fixture(__FILE__ , "backtrace.rb") - out = ruby_exe(file, options: "--backtrace-limit=2", args: "full_message 2>&1") - out = out.gsub(__dir__, '') + it "affects Exception#full_message" do + file = fixture(__FILE__ , "backtrace.rb") + out = ruby_exe(file, options: "--backtrace-limit=2", args: "full_message 2>&1") + out = out.gsub(__dir__, '') - out.should == <<-MSG + out.should == <<-MSG full_message /fixtures/backtrace.rb:2:in `a': oops (RuntimeError) \tfrom /fixtures/backtrace.rb:6:in `b' \tfrom /fixtures/backtrace.rb:10:in `c' \t ... 2 levels... - MSG - end + MSG + end - it "does not affect Exception#backtrace" do - file = fixture(__FILE__ , "backtrace.rb") - out = ruby_exe(file, options: "--backtrace-limit=2", args: "backtrace 2>&1") - out = out.gsub(__dir__, '') + it "does not affect Exception#backtrace" do + file = fixture(__FILE__ , "backtrace.rb") + out = ruby_exe(file, options: "--backtrace-limit=2", args: "backtrace 2>&1") + out = out.gsub(__dir__, '') - out.should == <<-MSG + out.should == <<-MSG backtrace /fixtures/backtrace.rb:2:in `a' /fixtures/backtrace.rb:6:in `b' /fixtures/backtrace.rb:10:in `c' /fixtures/backtrace.rb:14:in `d' /fixtures/backtrace.rb:29:in `<main>' - MSG + MSG + end end end diff --git a/spec/ruby/command_line/dash_a_spec.rb b/spec/ruby/command_line/dash_a_spec.rb index 43d923ce16..9ea135dc76 100644 --- a/spec/ruby/command_line/dash_a_spec.rb +++ b/spec/ruby/command_line/dash_a_spec.rb @@ -6,13 +6,13 @@ describe "The -a command line option" do end it "runs the code in loop conditional on Kernel.gets()" do - ruby_exe("puts $F.last", options: "-n -a", + ruby_exe("puts $F.last", options: "-n -a", escape: true, args: " < #{@names}").should == "jones\nfield\ngrey\n" end it "sets $-a" do - ruby_exe("puts $-a", options: "-n -a", + ruby_exe("puts $-a", options: "-n -a", escape: true, args: " < #{@names}").should == "true\ntrue\ntrue\n" end diff --git a/spec/ruby/command_line/dash_l_spec.rb b/spec/ruby/command_line/dash_l_spec.rb index 44a98445f3..5c1d3cf4cd 100644 --- a/spec/ruby/command_line/dash_l_spec.rb +++ b/spec/ruby/command_line/dash_l_spec.rb @@ -6,25 +6,25 @@ describe "The -l command line option" do end it "chomps lines with default separator" do - ruby_exe('puts $_.end_with?("\n")', options: "-n -l", + ruby_exe('puts $_.end_with?("\n")', options: "-n -l", escape: true, args: " < #{@names}").should == "false\nfalse\nfalse\n" end it "chomps last line based on $/" do - ruby_exe('BEGIN { $/ = "ones\n" }; puts $_', options: "-W0 -n -l", + ruby_exe('BEGIN { $/ = "ones\n" }; puts $_', options: "-W0 -n -l", escape: true, args: " < #{@names}").should == "alice j\nbob field\njames grey\n" end it "sets $\\ to the value of $/" do - ruby_exe("puts $\\ == $/", options: "-W0 -n -l", + ruby_exe("puts $\\ == $/", options: "-W0 -n -l", escape: true, args: " < #{@names}").should == "true\ntrue\ntrue\n" end it "sets $-l" do - ruby_exe("puts $-l", options: "-n -l", + ruby_exe("puts $-l", options: "-n -l", escape: true, args: " < #{@names}").should == "true\ntrue\ntrue\n" end diff --git a/spec/ruby/command_line/dash_n_spec.rb b/spec/ruby/command_line/dash_n_spec.rb index 1dd9379259..9d331d6065 100644 --- a/spec/ruby/command_line/dash_n_spec.rb +++ b/spec/ruby/command_line/dash_n_spec.rb @@ -6,19 +6,19 @@ describe "The -n command line option" do end it "runs the code in loop conditional on Kernel.gets()" do - ruby_exe("puts $_", options: "-n", + ruby_exe("puts $_", options: "-n", escape: true, args: " < #{@names}").should == "alice\nbob\njames\n" end it "only evaluates BEGIN blocks once" do - ruby_exe("BEGIN { puts \"hi\" }; puts $_", options: "-n", + ruby_exe("BEGIN { puts \"hi\" }; puts $_", options: "-n", escape: true, args: " < #{@names}").should == "hi\nalice\nbob\njames\n" end it "only evaluates END blocks once" do - ruby_exe("puts $_; END {puts \"bye\"}", options: "-n", + ruby_exe("puts $_; END {puts \"bye\"}", options: "-n", escape: true, args: " < #{@names}").should == "alice\nbob\njames\nbye\n" end @@ -29,7 +29,7 @@ describe "The -n command line option" do $total += 1 END { puts $total } script - ruby_exe(script, options: "-n", + ruby_exe(script, options: "-n", escape: true, args: " < #{@names}").should == "3\n" end diff --git a/spec/ruby/command_line/dash_p_spec.rb b/spec/ruby/command_line/dash_p_spec.rb index 967e3796de..39827c3868 100644 --- a/spec/ruby/command_line/dash_p_spec.rb +++ b/spec/ruby/command_line/dash_p_spec.rb @@ -6,13 +6,13 @@ describe "The -p command line option" do end it "runs the code in loop conditional on Kernel.gets() and prints $_" do - ruby_exe("$_ = $_.upcase", options: "-p", + ruby_exe("$_ = $_.upcase", options: "-p", escape: true, args: " < #{@names}").should == "ALICE\nBOB\nJAMES\n" end it "sets $-p" do - ruby_exe("$_ = $-p", options: "-p", + ruby_exe("$_ = $-p", options: "-p", escape: true, args: " < #{@names}").should == "truetruetrue" end diff --git a/spec/ruby/command_line/dash_upper_f_spec.rb b/spec/ruby/command_line/dash_upper_f_spec.rb index 5c10a7140d..967acc2ece 100644 --- a/spec/ruby/command_line/dash_upper_f_spec.rb +++ b/spec/ruby/command_line/dash_upper_f_spec.rb @@ -6,7 +6,7 @@ describe "the -F command line option" do end it "specifies the field separator pattern for -a" do - ruby_exe("puts $F[0]", options: "-naF:", + ruby_exe("puts $F[0]", options: "-naF:", escape: true, args: " < #{@passwd}").should == "nobody\nroot\ndaemon\n" end diff --git a/spec/ruby/command_line/dash_upper_u_spec.rb b/spec/ruby/command_line/dash_upper_u_spec.rb index 15854e7b73..d62718b095 100644 --- a/spec/ruby/command_line/dash_upper_u_spec.rb +++ b/spec/ruby/command_line/dash_upper_u_spec.rb @@ -6,13 +6,6 @@ describe "ruby -U" do options: '-U').should == 'UTF-8' end - it "sets Encoding.default_internal to UTF-8 when RUBYOPT is empty or only spaces" do - ruby_exe('p Encoding.default_internal', - options: '-U', env: { 'RUBYOPT' => '' }).should == "#<Encoding:UTF-8>\n" - ruby_exe('p Encoding.default_internal', - options: '-U', env: { 'RUBYOPT' => ' ' }).should == "#<Encoding:UTF-8>\n" - end - it "does nothing different if specified multiple times" do ruby_exe('print Encoding.default_internal.name', options: '-U -U').should == 'UTF-8' diff --git a/spec/ruby/command_line/dash_upper_w_spec.rb b/spec/ruby/command_line/dash_upper_w_spec.rb index 4019510d42..cbb040a8dd 100644 --- a/spec/ruby/command_line/dash_upper_w_spec.rb +++ b/spec/ruby/command_line/dash_upper_w_spec.rb @@ -19,26 +19,29 @@ describe "The -W command line option with 2" do it_behaves_like :command_line_verbose, "-W2" 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" +# 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 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" + 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 -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" + 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 -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" + 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 end diff --git a/spec/ruby/command_line/dash_v_spec.rb b/spec/ruby/command_line/dash_v_spec.rb index 7c7ca1bca6..a4f4dcd051 100644 --- a/spec/ruby/command_line/dash_v_spec.rb +++ b/spec/ruby/command_line/dash_v_spec.rb @@ -8,7 +8,6 @@ describe "The -v command line option" do it "prints version and ends" do ruby_exe(nil, args: '-v').should include(RUBY_DESCRIPTION) end unless (defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?) || - (defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled?) || - (ENV['RUBY_MN_THREADS'] == '1') + (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 f310dca3ed..c262df12cc 100644 --- a/spec/ruby/command_line/dash_w_spec.rb +++ b/spec/ruby/command_line/dash_w_spec.rb @@ -4,7 +4,9 @@ require_relative 'shared/verbose' describe "The -w command line option" do it_behaves_like :command_line_verbose, "-w" - it "enables both deprecated and experimental warnings" do - ruby_exe('p Warning[:deprecated]; p Warning[:experimental]', options: '-w').should == "true\ntrue\n" + 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 end end diff --git a/spec/ruby/command_line/feature_spec.rb b/spec/ruby/command_line/feature_spec.rb index 4a24cc6795..1a9ea925c9 100644 --- a/spec/ruby/command_line/feature_spec.rb +++ b/spec/ruby/command_line/feature_spec.rb @@ -43,9 +43,7 @@ describe "The --enable and --disable flags" do ruby_exe("p 'foo'.frozen?", options: "--disable-frozen-string-literal").chomp.should == "false" end - # frequently hangs for >60s on GitHub Actions macos-latest - # MinGW's YJIT support seems broken - platform_is_not :darwin, :mingw do + platform_is_not :darwin do # frequently hangs for >60s on GitHub Actions macos-latest 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/bin/embedded_ruby.txt b/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt index 1da779b1b9..c556bf0b71 100644 --- a/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt +++ b/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt @@ -1,3 +1,3 @@ @@@This line is not value Ruby #!ruby -puts 'success' +puts 'success'
\ No newline at end of file diff --git a/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb b/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb Binary files differindex df4b952c46..fa348d59e7 100644 --- a/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb +++ b/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb 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 f5547a5bae..074092c9d9 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".equal?("abc") +p "abc".object_id == "abc".object_id diff --git a/spec/ruby/command_line/rubyopt_spec.rb b/spec/ruby/command_line/rubyopt_spec.rb index 734db8d519..a2b817bad8 100644 --- a/spec/ruby/command_line/rubyopt_spec.rb +++ b/spec/ruby/command_line/rubyopt_spec.rb @@ -11,14 +11,14 @@ describe "Processing RUBYOPT" do it "adds the -I path to $LOAD_PATH" do ENV["RUBYOPT"] = "-Ioptrubyspecincl" - result = ruby_exe("puts $LOAD_PATH.grep(/byspecin/)") + result = ruby_exe("puts $LOAD_PATH.grep(/byspecin/)", escape: true) result.chomp[-15..-1].should == "optrubyspecincl" end it "sets $DEBUG to true for '-d'" do ENV["RUBYOPT"] = '-d' command = %[puts "value of $DEBUG is \#{$DEBUG}"] - result = ruby_exe(command, args: "2>&1") + result = ruby_exe(command, escape: true, args: "2>&1") result.should =~ /value of \$DEBUG is true/ end @@ -36,45 +36,47 @@ describe "Processing RUBYOPT" do it "sets $VERBOSE to true for '-w'" do ENV["RUBYOPT"] = '-w' - ruby_exe("p $VERBOSE").chomp.should == "true" + ruby_exe("p $VERBOSE", escape: true).chomp.should == "true" end it "sets $VERBOSE to true for '-W'" do ENV["RUBYOPT"] = '-W' - ruby_exe("p $VERBOSE").chomp.should == "true" + ruby_exe("p $VERBOSE", escape: true).chomp.should == "true" end it "sets $VERBOSE to nil for '-W0'" do ENV["RUBYOPT"] = '-W0' - ruby_exe("p $VERBOSE").chomp.should == "nil" + ruby_exe("p $VERBOSE", escape: true).chomp.should == "nil" end it "sets $VERBOSE to false for '-W1'" do ENV["RUBYOPT"] = '-W1' - ruby_exe("p $VERBOSE").chomp.should == "false" + ruby_exe("p $VERBOSE", escape: true).chomp.should == "false" end it "sets $VERBOSE to true for '-W2'" do ENV["RUBYOPT"] = '-W2' - ruby_exe("p $VERBOSE").chomp.should == "true" + ruby_exe("p $VERBOSE", escape: true).chomp.should == "true" end - it "suppresses deprecation warnings for '-W:no-deprecated'" do - ENV["RUBYOPT"] = '-W:no-deprecated' - result = ruby_exe('$; = ""', args: '2>&1') - result.should == "" - 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 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 == "" + 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 end it "requires the file for '-r'" do diff --git a/spec/ruby/core/argf/bytes_spec.rb b/spec/ruby/core/argf/bytes_spec.rb new file mode 100644 index 0000000000..bf35ded1db --- /dev/null +++ b/spec/ruby/core/argf/bytes_spec.rb @@ -0,0 +1,16 @@ +require_relative '../../spec_helper' +require_relative 'shared/each_byte' + +ruby_version_is ''...'3.0' do + describe "ARGF.bytes" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :argf_each_byte, :bytes + end +end diff --git a/spec/ruby/core/argf/chars_spec.rb b/spec/ruby/core/argf/chars_spec.rb new file mode 100644 index 0000000000..6af73cdabb --- /dev/null +++ b/spec/ruby/core/argf/chars_spec.rb @@ -0,0 +1,16 @@ +require_relative '../../spec_helper' +require_relative 'shared/each_char' + +ruby_version_is ''...'3.0' do + describe "ARGF.chars" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :argf_each_char, :chars + end +end diff --git a/spec/ruby/core/argf/codepoints_spec.rb b/spec/ruby/core/argf/codepoints_spec.rb new file mode 100644 index 0000000000..bb28c17fbb --- /dev/null +++ b/spec/ruby/core/argf/codepoints_spec.rb @@ -0,0 +1,16 @@ +require_relative '../../spec_helper' +require_relative 'shared/each_codepoint' + +ruby_version_is ''...'3.0' do + describe "ARGF.codepoints" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :argf_each_codepoint, :codepoints + end +end diff --git a/spec/ruby/core/argf/lines_spec.rb b/spec/ruby/core/argf/lines_spec.rb new file mode 100644 index 0000000000..e964dbd0d3 --- /dev/null +++ b/spec/ruby/core/argf/lines_spec.rb @@ -0,0 +1,16 @@ +require_relative '../../spec_helper' +require_relative 'shared/each_line' + +ruby_version_is ''...'3.0' do + describe "ARGF.lines" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :argf_each_line, :lines + end +end diff --git a/spec/ruby/core/argf/readpartial_spec.rb b/spec/ruby/core/argf/readpartial_spec.rb index bbc8831131..5e284b3423 100644 --- a/spec/ruby/core/argf/readpartial_spec.rb +++ b/spec/ruby/core/argf/readpartial_spec.rb @@ -69,7 +69,7 @@ describe "ARGF.readpartial" do print ARGF.readpartial(#{@stdin.size}) ARGF.readpartial(1) rescue print $!.class STR - stdin = ruby_exe(ruby_str, args: "< #{@stdin_name}") + stdin = ruby_exe(ruby_str, args: "< #{@stdin_name}", escape: true) stdin.should == @stdin + "EOFError" end end diff --git a/spec/ruby/core/array/all_spec.rb b/spec/ruby/core/array/all_spec.rb deleted file mode 100644 index 680e8c26fa..0000000000 --- a/spec/ruby/core/array/all_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'shared/iterable_and_tolerating_size_increasing' - -describe "Array#all?" do - @value_to_return = -> _ { true } - it_behaves_like :array_iterable_and_tolerating_size_increasing, :all? - - it "ignores the block if there is an argument" do - -> { - ['bar', 'foobar'].all?(/bar/) { false }.should == true - }.should complain(/given block not used/) - end -end diff --git a/spec/ruby/core/array/any_spec.rb b/spec/ruby/core/array/any_spec.rb index b51ce62f0f..09d949fe6e 100644 --- a/spec/ruby/core/array/any_spec.rb +++ b/spec/ruby/core/array/any_spec.rb @@ -1,5 +1,4 @@ require_relative '../../spec_helper' -require_relative 'shared/iterable_and_tolerating_size_increasing' describe "Array#any?" do describe 'with no block given (a default block of { |x| x } is implicit)' do @@ -20,9 +19,6 @@ describe "Array#any?" do end describe 'with a block given' do - @value_to_return = -> _ { false } - it_behaves_like :array_iterable_and_tolerating_size_increasing, :any? - it 'is false if the array is empty' do empty_array = [] empty_array.any? {|v| 1 == 1 }.should == false @@ -38,12 +34,4 @@ describe "Array#any?" do array_with_members.any? {|v| v == 42 }.should == false end end - - describe 'when given a pattern argument' do - it "ignores the block if there is an argument" do - -> { - ['bar', 'foobar'].any?(/bar/) { false }.should == true - }.should complain(/given block not used/) - end - end end diff --git a/spec/ruby/core/array/assoc_spec.rb b/spec/ruby/core/array/assoc_spec.rb index f0be3de795..f8479d763c 100644 --- a/spec/ruby/core/array/assoc_spec.rb +++ b/spec/ruby/core/array/assoc_spec.rb @@ -6,7 +6,7 @@ describe "Array#assoc" do s1 = ["colors", "red", "blue", "green"] s2 = [:letters, "a", "b", "c"] s3 = [4] - s4 = ["colors", "cyan", "yellow", "magenta"] + s4 = ["colors", "cyan", "yellow", "magenda"] s5 = [:letters, "a", "i", "u"] s_nil = [nil, nil] a = [s1, s2, s3, s4, s5, s_nil] @@ -37,16 +37,4 @@ describe "Array#assoc" do a.assoc(s1.first).should equal(s1) a.assoc(s2.first).should equal(s2) end - - it "calls to_ary on non-array elements" do - s1 = [1, 2] - s2 = ArraySpecs::ArrayConvertible.new(2, 3) - a = [s1, s2] - - s1.should_not_receive(:to_ary) - a.assoc(s1.first).should equal(s1) - - a.assoc(2).should == [2, 3] - s2.called.should equal(:to_ary) - end end diff --git a/spec/ruby/core/array/bsearch_index_spec.rb b/spec/ruby/core/array/bsearch_index_spec.rb index 94d85b37f3..df2c7c098e 100644 --- a/spec/ruby/core/array/bsearch_index_spec.rb +++ b/spec/ruby/core/array/bsearch_index_spec.rb @@ -63,6 +63,10 @@ describe "Array#bsearch_index" do @array.bsearch_index { |x| -1 }.should be_nil end + it "returns the middle element when block always returns zero" do + @array.bsearch_index { |x| 0 }.should == 2 + end + context "magnitude does not effect the result" do it "returns the index of any matched elements where element is between 4n <= xn < 8n" do [1, 2].should include(@array.bsearch_index { |x| (1 - x / 4) * (2**100) }) diff --git a/spec/ruby/core/array/clear_spec.rb b/spec/ruby/core/array/clear_spec.rb index 81ba56e01e..bddc672d3b 100644 --- a/spec/ruby/core/array/clear_spec.rb +++ b/spec/ruby/core/array/clear_spec.rb @@ -20,10 +20,30 @@ 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 83b3fa2a89..aa3c1c0446 100644 --- a/spec/ruby/core/array/compact_spec.rb +++ b/spec/ruby/core/array/compact_spec.rb @@ -21,6 +21,20 @@ 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 @@ -45,6 +59,22 @@ 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 f3cab9c17c..da6763bfd6 100644 --- a/spec/ruby/core/array/concat_spec.rb +++ b/spec/ruby/core/array/concat_spec.rb @@ -41,6 +41,64 @@ 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/count_spec.rb b/spec/ruby/core/array/count_spec.rb index e778233c16..eaf275aeb7 100644 --- a/spec/ruby/core/array/count_spec.rb +++ b/spec/ruby/core/array/count_spec.rb @@ -1,5 +1,4 @@ require_relative '../../spec_helper' -require_relative 'shared/iterable_and_tolerating_size_increasing' describe "Array#count" do it "returns the number of elements" do @@ -13,14 +12,4 @@ describe "Array#count" do it "returns the number of element for which the block evaluates to true" do [:a, :b, :c].count { |s| s != :b }.should == 2 end - - it "ignores the block if there is an argument" do - -> { - [:a, :b, :b, :c].count(:b) { |e| e.size > 10 }.should == 2 - }.should complain(/given block not used/) - end - - context "when a block argument given" do - it_behaves_like :array_iterable_and_tolerating_size_increasing, :count - end end diff --git a/spec/ruby/core/array/deconstruct_spec.rb b/spec/ruby/core/array/deconstruct_spec.rb index ad67abe47b..2b07152dfc 100644 --- a/spec/ruby/core/array/deconstruct_spec.rb +++ b/spec/ruby/core/array/deconstruct_spec.rb @@ -1,9 +1,11 @@ require_relative '../../spec_helper' -describe "Array#deconstruct" do - it "returns self" do - array = [1] +ruby_version_is "2.7" do + describe "Array#deconstruct" do + it "returns self" do + array = [1] - array.deconstruct.should equal array + array.deconstruct.should equal array + end end end diff --git a/spec/ruby/core/array/delete_at_spec.rb b/spec/ruby/core/array/delete_at_spec.rb index 80ec643702..fc225a03f1 100644 --- a/spec/ruby/core/array/delete_at_spec.rb +++ b/spec/ruby/core/array/delete_at_spec.rb @@ -38,4 +38,26 @@ 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 10972eee0e..e1931220f5 100644 --- a/spec/ruby/core/array/delete_if_spec.rb +++ b/spec/ruby/core/array/delete_if_spec.rb @@ -2,7 +2,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative 'shared/enumeratorize' require_relative 'shared/delete_if' -require_relative 'shared/iterable_and_tolerating_size_increasing' require_relative '../enumerable/shared/enumeratorized' describe "Array#delete_if" do @@ -48,35 +47,22 @@ describe "Array#delete_if" do -> { ArraySpecs.empty_frozen_array.delete_if {} }.should raise_error(FrozenError) end - it "does not truncate the array is the block raises an exception" do - a = [1, 2, 3] - begin - a.delete_if { raise StandardError, 'Oops' } - rescue + 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 - a.should == [1, 2, 3] - end - - it "only removes elements for which the block returns true, keeping the element which raised an error." do - a = [1, 2, 3, 4] - begin - a.delete_if do |e| - case e - when 2 then true - when 3 then raise StandardError, 'Oops' - else false - end - end - rescue StandardError + it "keeps untrusted status" do + @a.untrust + @a.untrusted?.should be_true + @a.delete_if{ true } + @a.untrusted?.should be_true end - - a.should == [1, 3, 4] end it_behaves_like :enumeratorized_with_origin_size, :delete_if, [1,2,3] it_behaves_like :delete_if, :delete_if - - @value_to_return = -> _ { false } - it_behaves_like :array_iterable_and_tolerating_size_increasing, :delete_if end diff --git a/spec/ruby/core/array/delete_spec.rb b/spec/ruby/core/array/delete_spec.rb index dddbbe6bd3..5d53c74e47 100644 --- a/spec/ruby/core/array/delete_spec.rb +++ b/spec/ruby/core/array/delete_spec.rb @@ -43,4 +43,26 @@ 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/drop_spec.rb b/spec/ruby/core/array/drop_spec.rb index 0ea748e47d..f911fd9018 100644 --- a/spec/ruby/core/array/drop_spec.rb +++ b/spec/ruby/core/array/drop_spec.rb @@ -50,7 +50,15 @@ describe "Array#drop" do -> { [1, 2].drop(obj) }.should raise_error(TypeError) end - it 'returns a Array instance for Array subclasses' do - ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should be_an_instance_of(Array) + ruby_version_is ''...'3.0' do + it 'returns a subclass instance for Array subclasses' do + ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should be_an_instance_of(ArraySpecs::MyArray) + end + end + + ruby_version_is '3.0' do + it 'returns a Array instance for Array subclasses' do + ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should be_an_instance_of(Array) + end end end diff --git a/spec/ruby/core/array/drop_while_spec.rb b/spec/ruby/core/array/drop_while_spec.rb index bd46e8b882..bb783d22a5 100644 --- a/spec/ruby/core/array/drop_while_spec.rb +++ b/spec/ruby/core/array/drop_while_spec.rb @@ -1,11 +1,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -require_relative 'shared/iterable_and_tolerating_size_increasing' describe "Array#drop_while" do - @value_to_return = -> _ { true } - it_behaves_like :array_iterable_and_tolerating_size_increasing, :drop_while - it "removes elements from the start of the array while the block evaluates to true" do [1, 2, 3, 4].drop_while { |n| n < 4 }.should == [4] end @@ -18,7 +14,15 @@ describe "Array#drop_while" do [1, 2, 3, false, 5].drop_while { |n| n }.should == [false, 5] end - it 'returns a Array instance for Array subclasses' do - ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should be_an_instance_of(Array) + ruby_version_is ''...'3.0' do + it 'returns a subclass instance for Array subclasses' do + ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should be_an_instance_of(ArraySpecs::MyArray) + end + end + + ruby_version_is '3.0' do + it 'returns a Array instance for Array subclasses' do + ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should be_an_instance_of(Array) + end end end diff --git a/spec/ruby/core/array/each_index_spec.rb b/spec/ruby/core/array/each_index_spec.rb index 3a4bca9251..51af5842c4 100644 --- a/spec/ruby/core/array/each_index_spec.rb +++ b/spec/ruby/core/array/each_index_spec.rb @@ -5,7 +5,7 @@ require_relative '../enumerable/shared/enumeratorized' # Modifying a collection while the contents are being iterated # gives undefined behavior. See -# https://blade.ruby-lang.org/ruby-core/23633 +# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633 describe "Array#each_index" do before :each do @@ -40,19 +40,3 @@ describe "Array#each_index" do it_behaves_like :enumeratorize, :each_index it_behaves_like :enumeratorized_with_origin_size, :each_index, [1,2,3] end - -describe "Array#each_index" do - it "tolerates increasing an array size during iteration" do - array = [:a, :b, :c] - ScratchPad.record [] - i = 0 - - array.each_index do |index| - ScratchPad << index - array << i if i < 100 - i += 1 - end - - ScratchPad.recorded.should == (0..102).to_a # element indices - end -end diff --git a/spec/ruby/core/array/each_spec.rb b/spec/ruby/core/array/each_spec.rb index 57d6082f01..256647d61e 100644 --- a/spec/ruby/core/array/each_spec.rb +++ b/spec/ruby/core/array/each_spec.rb @@ -1,13 +1,11 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative 'shared/enumeratorize' -require_relative 'shared/iterable_and_tolerating_size_increasing' require_relative '../enumerable/shared/enumeratorized' -# 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` +# 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 describe "Array#each" do it "yields each element to the block" do @@ -17,34 +15,6 @@ 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 = [] @@ -76,7 +46,3 @@ describe "Array#each" do it_behaves_like :enumeratorize, :each it_behaves_like :enumeratorized_with_origin_size, :each, [1,2,3] end - -describe "Array#each" do - it_behaves_like :array_iterable_and_tolerating_size_increasing, :each -end diff --git a/spec/ruby/core/array/element_set_spec.rb b/spec/ruby/core/array/element_set_spec.rb index df5ca9582e..1e192c100f 100644 --- a/spec/ruby/core/array/element_set_spec.rb +++ b/spec/ruby/core/array/element_set_spec.rb @@ -481,48 +481,50 @@ describe "Array#[]= with [m..]" do end 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 +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 - 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 "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 "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 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 if n < 0" do - a = [1, 2, 3, 4, 5] - a[(..-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[eval("(..-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[(...7)] = [4] - a.should == [4] - end + it "replaces everything if n > the array size" do + a = [1, 2, 3] + a[eval("(...7)")] = [4] + a.should == [4] + 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] + 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 end end diff --git a/spec/ruby/core/array/fill_spec.rb b/spec/ruby/core/array/fill_spec.rb index 02360e550d..bfa8db551b 100644 --- a/spec/ruby/core/array/fill_spec.rb +++ b/spec/ruby/core/array/fill_spec.rb @@ -52,9 +52,11 @@ describe "Array#fill" do end it "raises an ArgumentError if 4 or more arguments are passed when no block given" do - [].fill('a').should == [] - [].fill('a', 1).should == [] - [].fill('a', 1, 2).should == [nil, 'a', 'a'] + -> { [].fill('a') }.should_not raise_error(ArgumentError) + + -> { [].fill('a', 1) }.should_not raise_error(ArgumentError) + + -> { [].fill('a', 1, 2) }.should_not raise_error(ArgumentError) -> { [].fill('a', 1, 2, true) }.should raise_error(ArgumentError) end @@ -63,52 +65,12 @@ describe "Array#fill" do end it "raises an ArgumentError if 3 or more arguments are passed when a block given" do - [].fill() {|i|}.should == [] - [].fill(1) {|i|}.should == [] - [].fill(1, 2) {|i|}.should == [nil, nil, nil] - -> { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError) - end + -> { [].fill() {|i|} }.should_not raise_error(ArgumentError) - it "does not truncate the array is the block raises an exception" do - a = [1, 2, 3] - begin - a.fill { raise StandardError, 'Oops' } - rescue - end - - a.should == [1, 2, 3] - end - - it "only changes elements before error is raised, keeping the element which raised an error." do - a = [1, 2, 3, 4] - begin - a.fill do |i| - case i - when 0 then -1 - when 1 then -2 - when 2 then raise StandardError, 'Oops' - else 0 - end - end - rescue StandardError - end + -> { [].fill(1) {|i|} }.should_not raise_error(ArgumentError) - a.should == [-1, -2, 3, 4] - end - - it "tolerates increasing an array size during iteration" do - array = [:a, :b, :c] - ScratchPad.record [] - i = 0 - - array.fill do |index| - ScratchPad << index - array << i if i < 100 - i++ - index - end - - ScratchPad.recorded.should == [0, 1, 2] + -> { [].fill(1, 2) {|i|} }.should_not raise_error(ArgumentError) + -> { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError) end end @@ -207,25 +169,25 @@ describe "Array#fill with (filler, index, length)" do [1, 2, 3, 4, 5].fill(-2, -2, &@never_passed).should == [1, 2, 3, 4, 5] end - # See: https://blade.ruby-lang.org/ruby-core/17481 + # See: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/17481 it "does not raise an exception if the given length is negative and its absolute value does not exceed the index" do - [1, 2, 3, 4].fill('a', 3, -1).should == [1, 2, 3, 4] - [1, 2, 3, 4].fill('a', 3, -2).should == [1, 2, 3, 4] - [1, 2, 3, 4].fill('a', 3, -3).should == [1, 2, 3, 4] + -> { [1, 2, 3, 4].fill('a', 3, -1)}.should_not raise_error(ArgumentError) + -> { [1, 2, 3, 4].fill('a', 3, -2)}.should_not raise_error(ArgumentError) + -> { [1, 2, 3, 4].fill('a', 3, -3)}.should_not raise_error(ArgumentError) - [1, 2, 3, 4].fill(3, -1, &@never_passed).should == [1, 2, 3, 4] - [1, 2, 3, 4].fill(3, -2, &@never_passed).should == [1, 2, 3, 4] - [1, 2, 3, 4].fill(3, -3, &@never_passed).should == [1, 2, 3, 4] + -> { [1, 2, 3, 4].fill(3, -1, &@never_passed)}.should_not raise_error(ArgumentError) + -> { [1, 2, 3, 4].fill(3, -2, &@never_passed)}.should_not raise_error(ArgumentError) + -> { [1, 2, 3, 4].fill(3, -3, &@never_passed)}.should_not raise_error(ArgumentError) end it "does not raise an exception even if the given length is negative and its absolute value exceeds the index" do - [1, 2, 3, 4].fill('a', 3, -4).should == [1, 2, 3, 4] - [1, 2, 3, 4].fill('a', 3, -5).should == [1, 2, 3, 4] - [1, 2, 3, 4].fill('a', 3, -10000).should == [1, 2, 3, 4] + -> { [1, 2, 3, 4].fill('a', 3, -4)}.should_not raise_error(ArgumentError) + -> { [1, 2, 3, 4].fill('a', 3, -5)}.should_not raise_error(ArgumentError) + -> { [1, 2, 3, 4].fill('a', 3, -10000)}.should_not raise_error(ArgumentError) - [1, 2, 3, 4].fill(3, -4, &@never_passed).should == [1, 2, 3, 4] - [1, 2, 3, 4].fill(3, -5, &@never_passed).should == [1, 2, 3, 4] - [1, 2, 3, 4].fill(3, -10000, &@never_passed).should == [1, 2, 3, 4] + -> { [1, 2, 3, 4].fill(3, -4, &@never_passed)}.should_not raise_error(ArgumentError) + -> { [1, 2, 3, 4].fill(3, -5, &@never_passed)}.should_not raise_error(ArgumentError) + -> { [1, 2, 3, 4].fill(3, -10000, &@never_passed)}.should_not raise_error(ArgumentError) end it "tries to convert the second and third arguments to Integers using #to_int" do @@ -243,12 +205,6 @@ describe "Array#fill with (filler, index, length)" do -> { [].fill('a', obj) }.should raise_error(TypeError) end - it "raises a TypeError when the length is not numeric" do - -> { [1, 2, 3].fill("x", 1, "foo") }.should raise_error(TypeError, /no implicit conversion of String into Integer/) - -> { [1, 2, 3].fill("x", 1, :"foo") }.should raise_error(TypeError, /no implicit conversion of Symbol into Integer/) - -> { [1, 2, 3].fill("x", 1, Object.new) }.should raise_error(TypeError, /no implicit conversion of Object into Integer/) - end - not_supported_on :opal do it "raises an ArgumentError or RangeError for too-large sizes" do error_types = [RangeError, ArgumentError] @@ -367,8 +323,10 @@ describe "Array#fill with (filler, range)" do [1, 2, 3, 4].fill(eval("(3...)")) { |x| x + 2 }.should == [1, 2, 3, 5] 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] + 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 end end diff --git a/spec/ruby/core/array/fixtures/classes.rb b/spec/ruby/core/array/fixtures/classes.rb index 8596245fb8..affb3b49e6 100644 --- a/spec/ruby/core/array/fixtures/classes.rb +++ b/spec/ruby/core/array/fixtures/classes.rb @@ -40,68 +40,6 @@ module ArraySpecs a end - # Chi squared critical values for tests with n degrees of freedom at 99% confidence. - # Values obtained from NIST Engineering Statistic Handbook at - # https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm - - CHI_SQUARED_CRITICAL_VALUES = [ - 0, - 6.635, 9.210, 11.345, 13.277, 15.086, 16.812, 18.475, 20.090, 21.666, 23.209, - 24.725, 26.217, 27.688, 29.141, 30.578, 32.000, 33.409, 34.805, 36.191, 37.566, - 38.932, 40.289, 41.638, 42.980, 44.314, 45.642, 46.963, 48.278, 49.588, 50.892, - 52.191, 53.486, 54.776, 56.061, 57.342, 58.619, 59.893, 61.162, 62.428, 63.691, - 64.950, 66.206, 67.459, 68.710, 69.957, 71.201, 72.443, 73.683, 74.919, 76.154, - 77.386, 78.616, 79.843, 81.069, 82.292, 83.513, 84.733, 85.950, 87.166, 88.379, - 89.591, 90.802, 92.010, 93.217, 94.422, 95.626, 96.828, 98.028, 99.228, 100.425, - 101.621, 102.816, 104.010, 105.202, 106.393, 107.583, 108.771, 109.958, 111.144, 112.329, - 113.512, 114.695, 115.876, 117.057, 118.236, 119.414, 120.591, 121.767, 122.942, 124.116, - 125.289, 126.462, 127.633, 128.803, 129.973, 131.141, 132.309, 133.476, 134.642, 135.807, - ] - - def self.measure_sample_fairness(size, samples, iters) - ary = Array.new(size) { |x| x } - (samples).times do |i| - chi_results = [] - 3.times do - counts = Array.new(size) { 0 } - expected = iters / size - iters.times do - x = ary.sample(samples)[i] - counts[x] += 1 - end - chi_squared = 0.0 - counts.each do |count| - chi_squared += (((count - expected) ** 2) * 1.0 / expected) - end - chi_results << chi_squared - break if chi_squared <= CHI_SQUARED_CRITICAL_VALUES[size] - end - - chi_results.min.should <= CHI_SQUARED_CRITICAL_VALUES[size] - end - end - - def self.measure_sample_fairness_large_sample_size(size, samples, iters) - ary = Array.new(size) { |x| x } - counts = Array.new(size) { 0 } - expected = iters * samples / size - iters.times do - ary.sample(samples).each do |sample| - counts[sample] += 1 - end - end - chi_squared = 0.0 - counts.each do |count| - chi_squared += (((count - expected) ** 2) * 1.0 / expected) - end - - # Chi squared critical values for tests with 4 degrees of freedom - # Values obtained from NIST Engineering Statistic Handbook at - # https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm - - chi_squared.should <= CHI_SQUARED_CRITICAL_VALUES[size] - end - class MyArray < Array # The #initialize method has a different signature than Array to help # catch places in the specs that do not assert the #initialize is not @@ -160,16 +98,6 @@ module ArraySpecs end end - class ArrayMethodMissing - def initialize(*values, &block) - @values = values; - end - - def method_missing(name, *args) - @values - end - end - class SortSame def <=>(other); 0; end def ==(other); true; end diff --git a/spec/ruby/core/array/flatten_spec.rb b/spec/ruby/core/array/flatten_spec.rb index 8c97000c79..2f9fb8a3ec 100644 --- a/spec/ruby/core/array/flatten_spec.rb +++ b/spec/ruby/core/array/flatten_spec.rb @@ -75,12 +75,24 @@ describe "Array#flatten" do [[obj]].flatten(1) end - it "returns Array instance for Array subclasses" do - ArraySpecs::MyArray[].flatten.should be_an_instance_of(Array) - ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(Array) - ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(Array) - ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == [1, 2, 3, 4] - [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array) + ruby_version_is ''...'3.0' do + it "returns subclass instance for Array subclasses" do + ArraySpecs::MyArray[].flatten.should be_an_instance_of(ArraySpecs::MyArray) + ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(ArraySpecs::MyArray) + ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(ArraySpecs::MyArray) + ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == ArraySpecs::MyArray[1, 2, 3, 4] + [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array) + end + end + + ruby_version_is '3.0' do + it "returns Array instance for Array subclasses" do + ArraySpecs::MyArray[].flatten.should be_an_instance_of(Array) + ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(Array) + ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(Array) + ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == [1, 2, 3, 4] + [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array) + end end it "is not destructive" do @@ -135,6 +147,16 @@ 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/initialize_spec.rb b/spec/ruby/core/array/initialize_spec.rb index b9fa77b16e..a8deed2b84 100644 --- a/spec/ruby/core/array/initialize_spec.rb +++ b/spec/ruby/core/array/initialize_spec.rb @@ -53,9 +53,7 @@ describe "Array#initialize with no arguments" do end it "does not use the given block" do - -> { - -> { [1, 2, 3].send(:initialize) { raise } }.should_not raise_error - }.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true) + ->{ [1, 2, 3].send(:initialize) { raise } }.should_not raise_error end end diff --git a/spec/ruby/core/array/intersect_spec.rb b/spec/ruby/core/array/intersect_spec.rb index 62ac157278..b8c5b1e69a 100644 --- a/spec/ruby/core/array/intersect_spec.rb +++ b/spec/ruby/core/array/intersect_spec.rb @@ -1,66 +1,17 @@ require_relative '../../spec_helper' -require_relative 'fixtures/classes' describe 'Array#intersect?' do ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/15198 describe 'when at least one element in two Arrays is the same' do it 'returns true' do - [1, 2].intersect?([2, 3, 4]).should == true - [2, 3, 4].intersect?([1, 2]).should == true + [1, 2].intersect?([2, 3]).should == true end end describe 'when there are no elements in common between two Arrays' do it 'returns false' do - [0, 1, 2].intersect?([3, 4]).should == false - [3, 4].intersect?([0, 1, 2]).should == false - [3, 4].intersect?([]).should == false - [].intersect?([0, 1, 2]).should == false + [1, 2].intersect?([3, 4]).should == false end end - - it "tries to convert the passed argument to an Array using #to_ary" do - obj = mock('[1,2,3]') - obj.should_receive(:to_ary).and_return([1, 2, 3]) - - [1, 2].intersect?(obj).should == true - end - - it "determines equivalence between elements in the sense of eql?" do - obj1 = mock('1') - obj2 = mock('2') - obj1.stub!(:hash).and_return(0) - obj2.stub!(:hash).and_return(0) - obj1.stub!(:eql?).and_return(true) - obj2.stub!(:eql?).and_return(true) - - [obj1].intersect?([obj2]).should == true - - obj1 = mock('3') - obj2 = mock('4') - obj1.stub!(:hash).and_return(0) - obj2.stub!(:hash).and_return(0) - obj1.stub!(:eql?).and_return(false) - obj2.stub!(:eql?).and_return(false) - - [obj1].intersect?([obj2]).should == false - end - - it "does not call to_ary on array subclasses" do - [5, 6].intersect?(ArraySpecs::ToAryArray[1, 2, 5, 6]).should == true - end - - it "properly handles an identical item even when its #eql? isn't reflexive" do - x = mock('x') - x.stub!(:hash).and_return(42) - x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI. - - [x].intersect?([x]).should == true - end - - it "has semantic of !(a & b).empty?" do - [].intersect?([]).should == false - [nil].intersect?([nil]).should == true - end end end diff --git a/spec/ruby/core/array/intersection_spec.rb b/spec/ruby/core/array/intersection_spec.rb index e01a68d389..27d90f1e44 100644 --- a/spec/ruby/core/array/intersection_spec.rb +++ b/spec/ruby/core/array/intersection_spec.rb @@ -6,14 +6,16 @@ describe "Array#&" do it_behaves_like :array_intersection, :& end -describe "Array#intersection" do - it_behaves_like :array_intersection, :intersection +ruby_version_is "2.7" do + 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] + it "preserves elements order from original array" do + [1, 2, 3, 4].intersection([3, 2, 1]).should == [1, 2, 3] + end end end diff --git a/spec/ruby/core/array/keep_if_spec.rb b/spec/ruby/core/array/keep_if_spec.rb index 40f7329b7c..bf2bdeaf91 100644 --- a/spec/ruby/core/array/keep_if_spec.rb +++ b/spec/ruby/core/array/keep_if_spec.rb @@ -1,4 +1,3 @@ -require_relative '../../spec_helper' require_relative 'shared/keep_if' describe "Array#keep_if" do diff --git a/spec/ruby/core/array/multiply_spec.rb b/spec/ruby/core/array/multiply_spec.rb index eca51142fb..16e407348b 100644 --- a/spec/ruby/core/array/multiply_spec.rb +++ b/spec/ruby/core/array/multiply_spec.rb @@ -76,10 +76,20 @@ describe "Array#* with an integer" do @array = ArraySpecs::MyArray[1, 2, 3, 4, 5] end - it "returns an Array instance" do - (@array * 0).should be_an_instance_of(Array) - (@array * 1).should be_an_instance_of(Array) - (@array * 2).should be_an_instance_of(Array) + ruby_version_is ''...'3.0' do + it "returns a subclass instance" do + (@array * 0).should be_an_instance_of(ArraySpecs::MyArray) + (@array * 1).should be_an_instance_of(ArraySpecs::MyArray) + (@array * 2).should be_an_instance_of(ArraySpecs::MyArray) + end + end + + ruby_version_is '3.0' do + it "returns an Array instance" do + (@array * 0).should be_an_instance_of(Array) + (@array * 1).should be_an_instance_of(Array) + (@array * 2).should be_an_instance_of(Array) + end end it "does not call #initialize on the subclass instance" do @@ -87,6 +97,46 @@ 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/new_spec.rb b/spec/ruby/core/array/new_spec.rb index b50a4857b0..96ec6b8198 100644 --- a/spec/ruby/core/array/new_spec.rb +++ b/spec/ruby/core/array/new_spec.rb @@ -26,9 +26,7 @@ describe "Array.new with no arguments" do end it "does not use the given block" do - -> { - -> { Array.new { raise } }.should_not raise_error - }.should complain(/warning: given block not used/, verbose: true) + ->{ Array.new { raise } }.should_not raise_error end end diff --git a/spec/ruby/core/array/none_spec.rb b/spec/ruby/core/array/none_spec.rb deleted file mode 100644 index 31cd8c46d6..0000000000 --- a/spec/ruby/core/array/none_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'shared/iterable_and_tolerating_size_increasing' - -describe "Array#none?" do - @value_to_return = -> _ { false } - it_behaves_like :array_iterable_and_tolerating_size_increasing, :none? - - it "ignores the block if there is an argument" do - -> { - ['bar', 'foobar'].none?(/baz/) { true }.should == true - }.should complain(/given block not used/) - end -end diff --git a/spec/ruby/core/array/one_spec.rb b/spec/ruby/core/array/one_spec.rb deleted file mode 100644 index 0c61907881..0000000000 --- a/spec/ruby/core/array/one_spec.rb +++ /dev/null @@ -1,13 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'shared/iterable_and_tolerating_size_increasing' - -describe "Array#one?" do - @value_to_return = -> _ { false } - it_behaves_like :array_iterable_and_tolerating_size_increasing, :one? - - it "ignores the block if there is an argument" do - -> { - ['bar', 'foobar'].one?(/foo/) { false }.should == true - }.should complain(/given block not used/) - end -end diff --git a/spec/ruby/core/array/pack/a_spec.rb b/spec/ruby/core/array/pack/a_spec.rb index f4a40502c2..7af7a16c68 100644 --- a/spec/ruby/core/array/pack/a_spec.rb +++ b/spec/ruby/core/array/pack/a_spec.rb @@ -12,17 +12,6 @@ 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 ec82b7d1ab..872c1b88d5 100644 --- a/spec/ruby/core/array/pack/b_spec.rb +++ b/spec/ruby/core/array/pack/b_spec.rb @@ -13,16 +13,11 @@ 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 B string") + obj = mock("pack H 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/c_spec.rb b/spec/ruby/core/array/pack/c_spec.rb index ac133ff9b6..7200830331 100644 --- a/spec/ruby/core/array/pack/c_spec.rb +++ b/spec/ruby/core/array/pack/c_spec.rb @@ -45,20 +45,8 @@ describe :array_pack_8bit, shared: true do [1, 2, 3, 4, 5].pack(pack_format('*')).should == "\x01\x02\x03\x04\x05" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - [1, 2, 3].pack(pack_format("\000", 2)).should == "\x01\x02" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [1, 2, 3].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "ignores NULL bytes between directives" do + [1, 2, 3].pack(pack_format("\000", 2)).should == "\x01\x02" end it "ignores spaces between directives" do diff --git a/spec/ruby/core/array/pack/h_spec.rb b/spec/ruby/core/array/pack/h_spec.rb index 2c1dac8d4a..85a875fc8b 100644 --- a/spec/ruby/core/array/pack/h_spec.rb +++ b/spec/ruby/core/array/pack/h_spec.rb @@ -18,11 +18,6 @@ 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/m_spec.rb b/spec/ruby/core/array/pack/m_spec.rb index c6364af12d..2b1a84abca 100644 --- a/spec/ruby/core/array/pack/m_spec.rb +++ b/spec/ruby/core/array/pack/m_spec.rb @@ -80,16 +80,8 @@ describe "Array#pack with format 'M'" do ].should be_computed_by(:pack, "M") end - it "encodes a tab at the end of a line with an encoded newline" do - ["\t"].pack("M").should == "\t=\n" + it "encodes a tab followed by a newline with an encoded newline" do ["\t\n"].pack("M").should == "\t=\n\n" - ["abc\t\nxyz"].pack("M").should == "abc\t=\n\nxyz=\n" - end - - it "encodes a space at the end of a line with an encoded newline" do - [" "].pack("M").should == " =\n" - [" \n"].pack("M").should == " =\n\n" - ["abc \nxyz"].pack("M").should == "abc =\n\nxyz=\n" end it "encodes 127..255 in hex format" do diff --git a/spec/ruby/core/array/pack/p_spec.rb b/spec/ruby/core/array/pack/p_spec.rb index b023bf9110..d7dff8a4da 100644 --- a/spec/ruby/core/array/pack/p_spec.rb +++ b/spec/ruby/core/array/pack/p_spec.rb @@ -15,6 +15,18 @@ 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 @@ -32,6 +44,18 @@ 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 5e3eea55f9..9061273ad6 100644 --- a/spec/ruby/core/array/pack/shared/basic.rb +++ b/spec/ruby/core/array/pack/shared/basic.rb @@ -27,47 +27,17 @@ describe :array_pack_basic_non_float, shared: true do [@obj, @obj].pack("a \t\n\v\f\r"+pack_format).should be_an_instance_of(String) end - it "ignores comments in the format string" do - # 2 additional directives ('a') are required for the X directive - [@obj, @obj, @obj, @obj].pack("aa #{pack_format} # some comment \n#{pack_format}").should be_an_instance_of(String) - end - - ruby_version_is ""..."3.2" do - it "warns in verbose mode that a directive is unknown" do - # additional directive ('a') is required for the X directive - -> { [@obj, @obj].pack("a R" + pack_format) }.should complain(/unknown pack directive 'R'/, verbose: true) - -> { [@obj, @obj].pack("a 0" + pack_format) }.should complain(/unknown pack directive '0'/, verbose: true) - -> { [@obj, @obj].pack("a :" + pack_format) }.should complain(/unknown pack directive ':'/, verbose: true) - end - end - - ruby_version_is "3.2"..."3.3" do - # https://bugs.ruby-lang.org/issues/19150 - # NOTE: it's just a plan of the Ruby core team - it "warns that a directive is unknown" do - # additional directive ('a') is required for the X directive - -> { [@obj, @obj].pack("a R" + pack_format) }.should complain(/unknown pack directive 'R'/) - -> { [@obj, @obj].pack("a 0" + pack_format) }.should complain(/unknown pack directive '0'/) - -> { [@obj, @obj].pack("a :" + pack_format) }.should complain(/unknown pack directive ':'/) - end - end - - ruby_version_is "3.3" do - # https://bugs.ruby-lang.org/issues/19150 - # NOTE: Added this case just to not forget about the decision in the ticket - it "raise ArgumentError when a directive is unknown" do - # additional directive ('a') is required for the X directive - -> { [@obj, @obj].pack("a R" + pack_format) }.should raise_error(ArgumentError) - -> { [@obj, @obj].pack("a 0" + pack_format) }.should raise_error(ArgumentError) - -> { [@obj, @obj].pack("a :" + pack_format) }.should raise_error(ArgumentError) - end - end - it "calls #to_str to coerce the directives string" do d = mock("pack directive") 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 @@ -75,15 +45,17 @@ describe :array_pack_basic_float, shared: true do [9.3, 4.7].pack(" \t\n\v\f\r"+pack_format).should be_an_instance_of(String) end - it "ignores comments in the format string" do - [9.3, 4.7].pack(pack_format + "# some comment \n" + pack_format).should be_an_instance_of(String) - end - it "calls #to_str to coerce the directives string" do d = mock("pack directive") 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 1780d7635e..c6b194007f 100644 --- a/spec/ruby/core/array/pack/shared/float.rb +++ b/spec/ruby/core/array/pack/shared/float.rb @@ -25,20 +25,8 @@ describe :array_pack_float_le, shared: true do [2.9, 1.4, 8.2].pack(pack_format("*")).should == "\x9a\x999@33\xb3?33\x03A" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [5.3, 9.2].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "ignores NULL bytes between directives" do + [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A" end it "ignores spaces between directives" do @@ -65,14 +53,6 @@ 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 @@ -86,11 +66,6 @@ describe :array_pack_float_be, shared: true do it "converts an Integer to a Float" do [8].pack(pack_format).should == "A\x00\x00\x00" - [bignum_value].pack(pack_format).should == "_\x80\x00\x00" - end - - it "converts a Rational to a Float" do - [Rational(8)].pack(pack_format).should == "A\x00\x00\x00" end it "raises a TypeError if passed a String representation of a floating point number" do @@ -105,20 +80,8 @@ describe :array_pack_float_be, shared: true do [2.9, 1.4, 8.2].pack(pack_format("*")).should == "@9\x99\x9a?\xb333A\x0333" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [5.3, 9.2].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "ignores NULL bytes between directives" do + [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333" end it "ignores spaces between directives" do @@ -158,11 +121,6 @@ describe :array_pack_double_le, shared: true do it "converts an Integer to a Float" do [8].pack(pack_format).should == "\x00\x00\x00\x00\x00\x00\x20@" - [bignum_value].pack(pack_format).should == "\x00\x00\x00\x00\x00\x00\xF0C" - end - - it "converts a Rational to a Float" do - [Rational(8)].pack(pack_format).should == "\x00\x00\x00\x00\x00\x00 @" end it "raises a TypeError if passed a String representation of a floating point number" do @@ -177,20 +135,8 @@ describe :array_pack_double_le, shared: true do [2.9, 1.4, 8.2].pack(pack_format("*")).should == "333333\x07@ffffff\xf6?ffffff\x20@" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [5.3, 9.2].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "ignores NULL bytes between directives" do + [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@" end it "ignores spaces between directives" do @@ -248,20 +194,8 @@ describe :array_pack_double_be, shared: true do [2.9, 1.4, 8.2].pack(pack_format("*")).should == "@\x07333333?\xf6ffffff@\x20ffffff" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [5.3, 9.2].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "ignores NULL bytes between directives" do + [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff" end it "ignores spaces between directives" do diff --git a/spec/ruby/core/array/pack/shared/integer.rb b/spec/ruby/core/array/pack/shared/integer.rb index fd21b25b19..6592f85022 100644 --- a/spec/ruby/core/array/pack/shared/integer.rb +++ b/spec/ruby/core/array/pack/shared/integer.rb @@ -41,21 +41,9 @@ describe :array_pack_16bit_le, shared: true do str.should == "\x78\x65\xcd\xab\x21\x43" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - str.should == "\x78\x65\xcd\xab" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "ignores NULL bytes between directives" do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + str.should == "\x78\x65\xcd\xab" end it "ignores spaces between directives" do @@ -105,21 +93,9 @@ describe :array_pack_16bit_be, shared: true do str.should == "\x65\x78\xab\xcd\x43\x21" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - str.should == "\x65\x78\xab\xcd" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "ignores NULL bytes between directives" do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + str.should == "\x65\x78\xab\xcd" end it "ignores spaces between directives" do @@ -169,21 +145,9 @@ describe :array_pack_32bit_le, shared: true do str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde\x21\x43\x65\x78" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "ignores NULL bytes between directives" do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde" end it "ignores spaces between directives" do @@ -233,21 +197,9 @@ describe :array_pack_32bit_be, shared: true do str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd\x78\x65\x43\x21" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "ignores NULL bytes between directives" do + str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2)) + str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd" end it "ignores spaces between directives" do @@ -357,21 +309,9 @@ describe :array_pack_64bit_le, shared: true do str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) - str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "ignores NULL bytes between directives" do + str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) + str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78" end it "ignores spaces between directives" do @@ -429,21 +369,9 @@ describe :array_pack_64bit_be, shared: true do str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) - str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "ignores NULL bytes between directives" do + str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2)) + str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0" end it "ignores spaces between directives" do diff --git a/spec/ruby/core/array/pack/shared/numeric_basic.rb b/spec/ruby/core/array/pack/shared/numeric_basic.rb index 545e215e64..7c36ba4a32 100644 --- a/spec/ruby/core/array/pack/shared/numeric_basic.rb +++ b/spec/ruby/core/array/pack/shared/numeric_basic.rb @@ -37,14 +37,8 @@ describe :array_pack_float, shared: true do -> { ["a"].pack(pack_format) }.should raise_error(TypeError) end - it "raises a TypeError when the object is not Numeric" do - obj = Object.new - -> { [obj].pack(pack_format) }.should raise_error(TypeError, /can't convert Object into Float/) - end - - it "raises a TypeError when the Numeric object does not respond to #to_f" do - klass = Class.new(Numeric) - obj = klass.new + it "raises a TypeError when the object does not respond to #to_f" do + obj = mock('not an float') -> { [obj].pack(pack_format) }.should raise_error(TypeError) end end diff --git a/spec/ruby/core/array/pack/shared/taint.rb b/spec/ruby/core/array/pack/shared/taint.rb index 2c2b011c34..565f04b8b9 100644 --- a/spec/ruby/core/array/pack/shared/taint.rb +++ b/spec/ruby/core/array/pack/shared/taint.rb @@ -1,2 +1,35 @@ 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/shared/unicode.rb b/spec/ruby/core/array/pack/shared/unicode.rb index 4d8eaef323..dd0f8b38aa 100644 --- a/spec/ruby/core/array/pack/shared/unicode.rb +++ b/spec/ruby/core/array/pack/shared/unicode.rb @@ -67,20 +67,8 @@ describe :array_pack_unicode, shared: true do -> { [obj].pack("U") }.should raise_error(TypeError) end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - [1, 2, 3].pack("U\x00U").should == "\x01\x02" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [1, 2, 3].pack("U\x00U") - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "ignores NULL bytes between directives" do + [1, 2, 3].pack("U\x00U").should == "\x01\x02" end it "ignores spaces between directives" do diff --git a/spec/ruby/core/array/pack/u_spec.rb b/spec/ruby/core/array/pack/u_spec.rb index b20093a647..fe969cbb2d 100644 --- a/spec/ruby/core/array/pack/u_spec.rb +++ b/spec/ruby/core/array/pack/u_spec.rb @@ -18,16 +18,6 @@ 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/w_spec.rb b/spec/ruby/core/array/pack/w_spec.rb index 48ed4496a5..439fa02198 100644 --- a/spec/ruby/core/array/pack/w_spec.rb +++ b/spec/ruby/core/array/pack/w_spec.rb @@ -24,20 +24,8 @@ describe "Array#pack with format 'w'" do [obj].pack("w").should == "\x05" end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - [1, 2, 3].pack("w\x00w").should == "\x01\x02" - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - [1, 2, 3].pack("w\x00w") - }.should raise_error(ArgumentError, /unknown pack directive/) - end + it "ignores NULL bytes between directives" do + [1, 2, 3].pack("w\x00w").should == "\x01\x02" end it "ignores spaces between directives" do diff --git a/spec/ruby/core/array/pack/x_spec.rb b/spec/ruby/core/array/pack/x_spec.rb index 86c3ad1aa4..a28dd0bf21 100644 --- a/spec/ruby/core/array/pack/x_spec.rb +++ b/spec/ruby/core/array/pack/x_spec.rb @@ -30,7 +30,6 @@ 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 5ad3afd69e..82ce7b4a1c 100644 --- a/spec/ruby/core/array/pack/z_spec.rb +++ b/spec/ruby/core/array/pack/z_spec.rb @@ -12,16 +12,6 @@ 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 635bd131c9..45f8438208 100644 --- a/spec/ruby/core/array/plus_spec.rb +++ b/spec/ruby/core/array/plus_spec.rb @@ -14,23 +14,10 @@ describe "Array#+" do (ary + ary).should == [1, 2, 3, 1, 2, 3] end - describe "converts the passed argument to an Array using #to_ary" do - it "successfully concatenates the resulting array from the #to_ary call" do - obj = mock('["x", "y"]') - obj.should_receive(:to_ary).and_return(["x", "y"]) - ([1, 2, 3] + obj).should == [1, 2, 3, "x", "y"] - end - - it "raises a Typeerror if the given argument can't be converted to an array" do - -> { [1, 2, 3] + nil }.should raise_error(TypeError) - -> { [1, 2, 3] + "abc" }.should raise_error(TypeError) - end - - it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do - obj = mock("hello") - obj.should_receive(:to_ary).and_raise(NoMethodError) - -> { [1, 2, 3] + obj }.should raise_error(NoMethodError) - end + it "tries to convert the passed argument to an Array using #to_ary" do + obj = mock('["x", "y"]') + obj.should_receive(:to_ary).and_return(["x", "y"]) + ([1, 2, 3] + obj).should == [1, 2, 3, "x", "y"] end it "properly handles recursive arrays" do @@ -53,4 +40,20 @@ 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 2a19408660..96ef78da32 100644 --- a/spec/ruby/core/array/pop_spec.rb +++ b/spec/ruby/core/array/pop_spec.rb @@ -30,6 +30,16 @@ 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 @@ -38,6 +48,16 @@ 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] @@ -116,9 +136,41 @@ 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/product_spec.rb b/spec/ruby/core/array/product_spec.rb index 6fb3818508..07d2880a96 100644 --- a/spec/ruby/core/array/product_spec.rb +++ b/spec/ruby/core/array/product_spec.rb @@ -9,11 +9,6 @@ describe "Array#product" do ar.called.should == :to_ary end - it "returns converted arguments using :method_missing" do - ar = ArraySpecs::ArrayMethodMissing.new(2,3) - [1].product(ar).should == [[1,2],[1,3]] - end - it "returns the expected result" do [1,2].product([3,4,5],[6,8]).should == [[1, 3, 6], [1, 3, 8], [1, 4, 6], [1, 4, 8], [1, 5, 6], [1, 5, 8], [2, 3, 6], [2, 3, 8], [2, 4, 6], [2, 4, 8], [2, 5, 6], [2, 5, 8]] diff --git a/spec/ruby/core/array/rassoc_spec.rb b/spec/ruby/core/array/rassoc_spec.rb index 632a05e8b3..62fbd40611 100644 --- a/spec/ruby/core/array/rassoc_spec.rb +++ b/spec/ruby/core/array/rassoc_spec.rb @@ -35,18 +35,4 @@ describe "Array#rassoc" do [[1, :foobar, o], [2, o, 1], [3, mock('foo')]].rassoc(key).should == [2, o, 1] end - - ruby_version_is "3.3" do - it "calls to_ary on non-array elements" do - s1 = [1, 2] - s2 = ArraySpecs::ArrayConvertible.new(2, 3) - a = [s1, s2] - - s1.should_not_receive(:to_ary) - a.rassoc(2).should equal(s1) - - a.rassoc(3).should == [2, 3] - s2.called.should equal(:to_ary) - end - end end diff --git a/spec/ruby/core/array/reject_spec.rb b/spec/ruby/core/array/reject_spec.rb index 81a467e364..fcf43fabde 100644 --- a/spec/ruby/core/array/reject_spec.rb +++ b/spec/ruby/core/array/reject_spec.rb @@ -2,7 +2,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative 'shared/enumeratorize' require_relative 'shared/delete_if' -require_relative 'shared/iterable_and_tolerating_size_increasing' require_relative '../enumerable/shared/enumeratorized' describe "Array#reject" do @@ -48,10 +47,6 @@ describe "Array#reject" do it_behaves_like :enumeratorized_with_origin_size, :reject, [1,2,3] end -describe "Array#reject" do - it_behaves_like :array_iterable_and_tolerating_size_increasing, :reject -end - describe "Array#reject!" do it "removes elements for which block is true" do a = [3, 4, 5, 6, 7, 8, 9, 10, 11] @@ -116,11 +111,6 @@ describe "Array#reject!" do -> { ArraySpecs.empty_frozen_array.reject! {} }.should raise_error(FrozenError) end - it "raises a FrozenError on a frozen array only during iteration if called without a block" do - enum = ArraySpecs.frozen_array.reject! - -> { enum.each {} }.should raise_error(FrozenError) - end - it "does not truncate the array is the block raises an exception" do a = [1, 2, 3] begin @@ -151,8 +141,3 @@ describe "Array#reject!" do it_behaves_like :enumeratorized_with_origin_size, :reject!, [1,2,3] it_behaves_like :delete_if, :reject! end - -describe "Array#reject!" do - @value_to_return = -> _ { false } - it_behaves_like :array_iterable_and_tolerating_size_increasing, :reject! -end diff --git a/spec/ruby/core/array/reverse_each_spec.rb b/spec/ruby/core/array/reverse_each_spec.rb index 59dabcd33d..28b8bfcb34 100644 --- a/spec/ruby/core/array/reverse_each_spec.rb +++ b/spec/ruby/core/array/reverse_each_spec.rb @@ -5,7 +5,7 @@ require_relative '../enumerable/shared/enumeratorized' # Modifying a collection while the contents are being iterated # gives undefined behavior. See -# https://blade.ruby-lang.org/ruby-core/23633 +# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633 describe "Array#reverse_each" do before :each do @@ -38,20 +38,6 @@ describe "Array#reverse_each" do [1, 2, 3].reverse_each.size.should == 3 end - it "tolerates increasing an array size during iteration" do - array = [:a, :b, :c] - ScratchPad.record [] - i = 0 - - array.reverse_each do |e| - ScratchPad << e - array.prepend i if i < 100 - i += 1 - end - - ScratchPad.recorded.should == [:c, :a, 1] - end - it_behaves_like :enumeratorize, :reverse_each it_behaves_like :enumeratorized_with_origin_size, :reverse_each, [1,2,3] end diff --git a/spec/ruby/core/array/rindex_spec.rb b/spec/ruby/core/array/rindex_spec.rb index 13de88818c..175c7bcfe2 100644 --- a/spec/ruby/core/array/rindex_spec.rb +++ b/spec/ruby/core/array/rindex_spec.rb @@ -4,7 +4,7 @@ require_relative '../enumerable/shared/enumeratorized' # Modifying a collection while the contents are being iterated # gives undefined behavior. See -# https://blade.ruby-lang.org/ruby-core/23633 +# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633 describe "Array#rindex" do it "returns the first index backwards from the end where element == to object" do @@ -68,21 +68,6 @@ describe "Array#rindex" do seen.should == [3] end - it "tolerates increasing an array size during iteration" do - array = [:a, :b, :c] - ScratchPad.record [] - i = 0 - - array.rindex do |e| - ScratchPad << e - array.prepend i if i < 100 - i += 1 - false - end - - ScratchPad.recorded.should == [:c, :a, 1] - end - describe "given no argument and no block" do it "produces an Enumerator" do enum = [4, 2, 1, 5, 1, 3].rindex diff --git a/spec/ruby/core/array/sample_spec.rb b/spec/ruby/core/array/sample_spec.rb index 6ef78594f0..565d7ff7f9 100644 --- a/spec/ruby/core/array/sample_spec.rb +++ b/spec/ruby/core/array/sample_spec.rb @@ -3,36 +3,26 @@ require_relative 'fixtures/classes' describe "Array#sample" do it "samples evenly" do - ArraySpecs.measure_sample_fairness(4, 1, 400) - ArraySpecs.measure_sample_fairness(4, 2, 400) - ArraySpecs.measure_sample_fairness(4, 3, 400) - ArraySpecs.measure_sample_fairness(40, 3, 400) - ArraySpecs.measure_sample_fairness(40, 4, 400) - ArraySpecs.measure_sample_fairness(40, 8, 400) - ArraySpecs.measure_sample_fairness(40, 16, 400) - ArraySpecs.measure_sample_fairness_large_sample_size(100, 80, 4000) + ary = [0, 1, 2, 3] + 3.times do |i| + counts = [0, 0, 0, 0] + 4000.times do + counts[ary.sample(3)[i]] += 1 + end + counts.each do |count| + (800..1200).should include(count) + end + end end it "returns nil for an empty Array" 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 a single value when not passed a count and a Random class is given" do - [4].sample(random: Random).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 035b45ec99..3c17b1f10f 100644 --- a/spec/ruby/core/array/shared/clone.rb +++ b/spec/ruby/core/array/shared/clone.rb @@ -17,4 +17,28 @@ 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 030302ced6..d84432734a 100644 --- a/spec/ruby/core/array/shared/collect.rb +++ b/spec/ruby/core/array/shared/collect.rb @@ -1,5 +1,4 @@ require_relative '../../enumerable/shared/enumeratorized' -require_relative '../shared/iterable_and_tolerating_size_increasing' describe :array_collect, shared: true do it "returns a copy of array with each element replaced by the value returned by block" do @@ -43,12 +42,24 @@ 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 it_should_behave_like :enumeratorized_with_origin_size - - it_should_behave_like :array_iterable_and_tolerating_size_increasing end describe :array_collect_b, shared: true do @@ -85,6 +96,23 @@ 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) @@ -105,37 +133,8 @@ describe :array_collect_b, shared: true do end end - it "does not truncate the array is the block raises an exception" do - a = [1, 2, 3] - begin - a.send(@method) { raise StandardError, 'Oops' } - rescue - end - - a.should == [1, 2, 3] - end - - it "only changes elements before error is raised, keeping the element which raised an error." do - a = [1, 2, 3, 4] - begin - a.send(@method) do |e| - case e - when 1 then -1 - when 2 then -2 - when 3 then raise StandardError, 'Oops' - else 0 - end - end - rescue StandardError - end - - a.should == [-1, -2, 3, 4] - end - before :all do @object = [1, 2, 3, 4] end it_should_behave_like :enumeratorized_with_origin_size - - it_should_behave_like :array_iterable_and_tolerating_size_increasing end diff --git a/spec/ruby/core/array/shared/index.rb b/spec/ruby/core/array/shared/index.rb index a4a0adbab6..a9896554f2 100644 --- a/spec/ruby/core/array/shared/index.rb +++ b/spec/ruby/core/array/shared/index.rb @@ -1,5 +1,3 @@ -require_relative '../shared/iterable_and_tolerating_size_increasing' - describe :array_index, shared: true do it "returns the index of the first element == to object" do x = mock('3') @@ -36,6 +34,4 @@ describe :array_index, shared: true do [].send(@method).should be_an_instance_of(Enumerator) end end - - it_should_behave_like :array_iterable_and_tolerating_size_increasing end diff --git a/spec/ruby/core/array/shared/inspect.rb b/spec/ruby/core/array/shared/inspect.rb index a2b43d4959..736f8d946b 100644 --- a/spec/ruby/core/array/shared/inspect.rb +++ b/spec/ruby/core/array/shared/inspect.rb @@ -64,6 +64,32 @@ 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/intersection.rb b/spec/ruby/core/array/shared/intersection.rb index 0b4166ab63..49849b08c2 100644 --- a/spec/ruby/core/array/shared/intersection.rb +++ b/spec/ruby/core/array/shared/intersection.rb @@ -11,8 +11,7 @@ describe :array_intersection, shared: true do end it "creates an array with elements in order they are first encountered" do - [ 1, 2, 3, 2, 5, 6, 7, 8 ].send(@method, [ 5, 2, 3, 4 ]).should == [2, 3, 5] # array > other - [ 5, 2, 3, 4 ].send(@method, [ 1, 2, 3, 2, 5, 6, 7, 8 ]).should == [5, 2, 3] # array < other + [ 1, 2, 3, 2, 5 ].send(@method, [ 5, 2, 3, 4 ]).should == [2, 3, 5] end it "does not modify the original Array" do diff --git a/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb b/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb deleted file mode 100644 index 3e73bad44b..0000000000 --- a/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb +++ /dev/null @@ -1,25 +0,0 @@ -describe :array_iterable_and_tolerating_size_increasing, shared: true do - before do - @value_to_return ||= -> _ { nil } - end - - it "tolerates increasing an array size during iteration" do - # The goal is to trigger potential reallocation of internal array storage, so we: - # - use elements of different types, starting with the less generic (Integer) - # - add reasonably big number of new elements (~ 100) - array = [1, 2, 3] # to test some methods we need several uniq elements - array_to_join = [:a, :b, :c] + (4..100).to_a - - ScratchPad.record [] - i = 0 - - array.send(@method) do |e| - ScratchPad << e - array << array_to_join[i] if i < array_to_join.size - i += 1 - @value_to_return.call(e) - end - - ScratchPad.recorded.should == [1, 2, 3] + array_to_join - end -end diff --git a/spec/ruby/core/array/shared/join.rb b/spec/ruby/core/array/shared/join.rb index 507b13e3c8..dfdb4ae1e4 100644 --- a/spec/ruby/core/array/shared/join.rb +++ b/spec/ruby/core/array/shared/join.rb @@ -58,6 +58,36 @@ 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 @@ -84,16 +114,18 @@ describe :array_join_with_default_separator, shared: true do -> { ary_utf8_bad_binary.send(@method) }.should raise_error(EncodingError) end - context "when $, is not nil" do - before do - suppress_warning do - $, = '*' + ruby_version_is "2.7" do + context "when $, is not nil" do + before do + suppress_warning do + $, = '*' + end 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/) + 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 end @@ -109,4 +141,42 @@ 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/keep_if.rb b/spec/ruby/core/array/shared/keep_if.rb index 43a047c0a7..f26aff028c 100644 --- a/spec/ruby/core/array/shared/keep_if.rb +++ b/spec/ruby/core/array/shared/keep_if.rb @@ -1,5 +1,4 @@ require_relative '../../enumerable/shared/enumeratorized' -require_relative '../shared/iterable_and_tolerating_size_increasing' describe :keep_if, shared: true do it "deletes elements for which the block returns a false value" do @@ -57,39 +56,5 @@ describe :keep_if, shared: true do -> { @frozen.send(@method) { false } }.should raise_error(FrozenError) end end - - it "raises a FrozenError on a frozen array only during iteration if called without a block" do - enum = @frozen.send(@method) - -> { enum.each {} }.should raise_error(FrozenError) - end - end - - it "does not truncate the array is the block raises an exception" do - a = [1, 2, 3] - begin - a.send(@method) { raise StandardError, 'Oops' } - rescue - end - - a.should == [1, 2, 3] end - - it "only changes elements before error is raised, keeping the element which raised an error." do - a = [1, 2, 3, 4] - begin - a.send(@method) do |e| - case e - when 2 then false - when 3 then raise StandardError, 'Oops' - else true - end - end - rescue StandardError - end - - a.should == [1, 3, 4] - end - - @value_to_return = -> _ { true } - it_should_behave_like :array_iterable_and_tolerating_size_increasing end diff --git a/spec/ruby/core/array/shared/select.rb b/spec/ruby/core/array/shared/select.rb index 9c2cbf76c4..09101e8ab5 100644 --- a/spec/ruby/core/array/shared/select.rb +++ b/spec/ruby/core/array/shared/select.rb @@ -2,14 +2,11 @@ require_relative '../../../spec_helper' require_relative '../fixtures/classes' require_relative '../shared/enumeratorize' require_relative '../shared/keep_if' -require_relative '../shared/iterable_and_tolerating_size_increasing' require_relative '../../enumerable/shared/enumeratorized' describe :array_select, shared: true do it_should_behave_like :enumeratorize - it_should_behave_like :array_iterable_and_tolerating_size_increasing - before :each do @object = [1,2,3] end diff --git a/spec/ruby/core/array/shared/slice.rb b/spec/ruby/core/array/shared/slice.rb index d2866970a5..540a050130 100644 --- a/spec/ruby/core/array/shared/slice.rb +++ b/spec/ruby/core/array/shared/slice.rb @@ -397,28 +397,56 @@ describe :array_slice, shared: true do @array = ArraySpecs::MyArray[1, 2, 3, 4, 5] end - it "returns a Array instance with [n, m]" do - @array.send(@method, 0, 2).should be_an_instance_of(Array) - end + ruby_version_is ''...'3.0' do + it "returns a subclass instance with [n, m]" do + @array.send(@method, 0, 2).should be_an_instance_of(ArraySpecs::MyArray) + end - it "returns a Array instance with [-n, m]" do - @array.send(@method, -3, 2).should be_an_instance_of(Array) - end + it "returns a subclass instance with [-n, m]" do + @array.send(@method, -3, 2).should be_an_instance_of(ArraySpecs::MyArray) + end - it "returns a Array instance with [n..m]" do - @array.send(@method, 1..3).should be_an_instance_of(Array) - end + it "returns a subclass instance with [n..m]" do + @array.send(@method, 1..3).should be_an_instance_of(ArraySpecs::MyArray) + end - it "returns a Array instance with [n...m]" do - @array.send(@method, 1...3).should be_an_instance_of(Array) - end + it "returns a subclass instance with [n...m]" do + @array.send(@method, 1...3).should be_an_instance_of(ArraySpecs::MyArray) + end + + it "returns a subclass instance with [-n..-m]" do + @array.send(@method, -3..-1).should be_an_instance_of(ArraySpecs::MyArray) + end - it "returns a Array instance with [-n..-m]" do - @array.send(@method, -3..-1).should be_an_instance_of(Array) + it "returns a subclass instance with [-n...-m]" do + @array.send(@method, -3...-1).should be_an_instance_of(ArraySpecs::MyArray) + end end - it "returns a Array instance with [-n...-m]" do - @array.send(@method, -3...-1).should be_an_instance_of(Array) + ruby_version_is '3.0' do + it "returns a Array instance with [n, m]" do + @array.send(@method, 0, 2).should be_an_instance_of(Array) + end + + it "returns a Array instance with [-n, m]" do + @array.send(@method, -3, 2).should be_an_instance_of(Array) + end + + it "returns a Array instance with [n..m]" do + @array.send(@method, 1..3).should be_an_instance_of(Array) + end + + it "returns a Array instance with [n...m]" do + @array.send(@method, 1...3).should be_an_instance_of(Array) + end + + it "returns a Array instance with [-n..-m]" do + @array.send(@method, -3..-1).should be_an_instance_of(Array) + end + + it "returns a Array instance with [-n...-m]" do + @array.send(@method, -3...-1).should be_an_instance_of(Array) + end end it "returns an empty array when m == n with [m...n]" do @@ -506,354 +534,262 @@ describe :array_slice, shared: true do a.send(@method, eval("(-9...)")).should == nil end - describe "can be sliced with Enumerator::ArithmeticSequence" do - before :each do - @array = [0, 1, 2, 3, 4, 5] - end + ruby_version_is "3.0" do + describe "can be sliced with Enumerator::ArithmeticSequence" do + before :each do + @array = [0, 1, 2, 3, 4, 5] + end - it "has endless range and positive steps" do - @array.send(@method, eval("(0..).step(1)")).should == [0, 1, 2, 3, 4, 5] - @array.send(@method, eval("(0..).step(2)")).should == [0, 2, 4] - @array.send(@method, eval("(0..).step(10)")).should == [0] + it "has endless range and positive steps" do + @array.send(@method, eval("(0..).step(1)")).should == [0, 1, 2, 3, 4, 5] + @array.send(@method, eval("(0..).step(2)")).should == [0, 2, 4] + @array.send(@method, eval("(0..).step(10)")).should == [0] - @array.send(@method, eval("(2..).step(1)")).should == [2, 3, 4, 5] - @array.send(@method, eval("(2..).step(2)")).should == [2, 4] - @array.send(@method, eval("(2..).step(10)")).should == [2] + @array.send(@method, eval("(2..).step(1)")).should == [2, 3, 4, 5] + @array.send(@method, eval("(2..).step(2)")).should == [2, 4] + @array.send(@method, eval("(2..).step(10)")).should == [2] - @array.send(@method, eval("(-3..).step(1)")).should == [3, 4, 5] - @array.send(@method, eval("(-3..).step(2)")).should == [3, 5] - @array.send(@method, eval("(-3..).step(10)")).should == [3] - end + @array.send(@method, eval("(-3..).step(1)")).should == [3, 4, 5] + @array.send(@method, eval("(-3..).step(2)")).should == [3, 5] + @array.send(@method, eval("(-3..).step(10)")).should == [3] + end - it "has beginless range and positive steps" do - # end with zero index - @array.send(@method, (..0).step(1)).should == [0] - @array.send(@method, (...0).step(1)).should == [] + 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(2)).should == [0] - @array.send(@method, (...0).step(2)).should == [] + @array.send(@method, eval("(..0).step(2)")).should == [0] + @array.send(@method, eval("(...0).step(2)")).should == [] - @array.send(@method, (..0).step(10)).should == [0] - @array.send(@method, (...0).step(10)).should == [] + @array.send(@method, eval("(..0).step(10)")).should == [0] + @array.send(@method, eval("(...0).step(10)")).should == [] - # end with positive index - @array.send(@method, (..3).step(1)).should == [0, 1, 2, 3] - @array.send(@method, (...3).step(1)).should == [0, 1, 2] + # 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(2)).should == [0, 2] - @array.send(@method, (...3).step(2)).should == [0, 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(10)).should == [0] - @array.send(@method, (...3).step(10)).should == [0] + @array.send(@method, eval("(..3).step(10)")).should == [0] + @array.send(@method, eval("(...3).step(10)")).should == [0] - # end with negative index - @array.send(@method, (..-2).step(1)).should == [0, 1, 2, 3, 4,] - @array.send(@method, (...-2).step(1)).should == [0, 1, 2, 3] + # 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(2)).should == [0, 2, 4] - @array.send(@method, (...-2).step(2)).should == [0, 2] + @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(10)).should == [0] - @array.send(@method, (...-2).step(10)).should == [0] - end + @array.send(@method, eval("(..-2).step(10)")).should == [0] + @array.send(@method, eval("(...-2).step(10)")).should == [0] + end - it "has endless range and negative steps" do - @array.send(@method, eval("(0..).step(-1)")).should == [0] - @array.send(@method, eval("(0..).step(-2)")).should == [0] - @array.send(@method, eval("(0..).step(-10)")).should == [0] + it "has endless range and negative steps" do + @array.send(@method, eval("(0..).step(-1)")).should == [0] + @array.send(@method, eval("(0..).step(-2)")).should == [0] + @array.send(@method, eval("(0..).step(-10)")).should == [0] - @array.send(@method, eval("(2..).step(-1)")).should == [2, 1, 0] - @array.send(@method, eval("(2..).step(-2)")).should == [2, 0] + @array.send(@method, eval("(2..).step(-1)")).should == [2, 1, 0] + @array.send(@method, eval("(2..).step(-2)")).should == [2, 0] - @array.send(@method, eval("(-3..).step(-1)")).should == [3, 2, 1, 0] - @array.send(@method, eval("(-3..).step(-2)")).should == [3, 1] - end + @array.send(@method, eval("(-3..).step(-1)")).should == [3, 2, 1, 0] + @array.send(@method, eval("(-3..).step(-2)")).should == [3, 1] + end - it "has closed range and positive steps" do - # start and end with 0 - @array.send(@method, eval("(0..0).step(1)")).should == [0] - @array.send(@method, eval("(0...0).step(1)")).should == [] + it "has closed range and positive steps" do + # start and end with 0 + @array.send(@method, eval("(0..0).step(1)")).should == [0] + @array.send(@method, eval("(0...0).step(1)")).should == [] - @array.send(@method, eval("(0..0).step(2)")).should == [0] - @array.send(@method, eval("(0...0).step(2)")).should == [] + @array.send(@method, eval("(0..0).step(2)")).should == [0] + @array.send(@method, eval("(0...0).step(2)")).should == [] - @array.send(@method, eval("(0..0).step(10)")).should == [0] - @array.send(@method, eval("(0...0).step(10)")).should == [] + @array.send(@method, eval("(0..0).step(10)")).should == [0] + @array.send(@method, eval("(0...0).step(10)")).should == [] - # start and end with positive index - @array.send(@method, eval("(1..3).step(1)")).should == [1, 2, 3] - @array.send(@method, eval("(1...3).step(1)")).should == [1, 2] + # start and end with positive index + @array.send(@method, eval("(1..3).step(1)")).should == [1, 2, 3] + @array.send(@method, eval("(1...3).step(1)")).should == [1, 2] - @array.send(@method, eval("(1..3).step(2)")).should == [1, 3] - @array.send(@method, eval("(1...3).step(2)")).should == [1] + @array.send(@method, eval("(1..3).step(2)")).should == [1, 3] + @array.send(@method, eval("(1...3).step(2)")).should == [1] - @array.send(@method, eval("(1..3).step(10)")).should == [1] - @array.send(@method, eval("(1...3).step(10)")).should == [1] + @array.send(@method, eval("(1..3).step(10)")).should == [1] + @array.send(@method, eval("(1...3).step(10)")).should == [1] - # start with positive index, end with negative index - @array.send(@method, eval("(1..-2).step(1)")).should == [1, 2, 3, 4] - @array.send(@method, eval("(1...-2).step(1)")).should == [1, 2, 3] + # start with positive index, end with negative index + @array.send(@method, eval("(1..-2).step(1)")).should == [1, 2, 3, 4] + @array.send(@method, eval("(1...-2).step(1)")).should == [1, 2, 3] - @array.send(@method, eval("(1..-2).step(2)")).should == [1, 3] - @array.send(@method, eval("(1...-2).step(2)")).should == [1, 3] + @array.send(@method, eval("(1..-2).step(2)")).should == [1, 3] + @array.send(@method, eval("(1...-2).step(2)")).should == [1, 3] - @array.send(@method, eval("(1..-2).step(10)")).should == [1] - @array.send(@method, eval("(1...-2).step(10)")).should == [1] + @array.send(@method, eval("(1..-2).step(10)")).should == [1] + @array.send(@method, eval("(1...-2).step(10)")).should == [1] - # start with negative index, end with positive index - @array.send(@method, eval("(-4..4).step(1)")).should == [2, 3, 4] - @array.send(@method, eval("(-4...4).step(1)")).should == [2, 3] + # start with negative index, end with positive index + @array.send(@method, eval("(-4..4).step(1)")).should == [2, 3, 4] + @array.send(@method, eval("(-4...4).step(1)")).should == [2, 3] - @array.send(@method, eval("(-4..4).step(2)")).should == [2, 4] - @array.send(@method, eval("(-4...4).step(2)")).should == [2] + @array.send(@method, eval("(-4..4).step(2)")).should == [2, 4] + @array.send(@method, eval("(-4...4).step(2)")).should == [2] - @array.send(@method, eval("(-4..4).step(10)")).should == [2] - @array.send(@method, eval("(-4...4).step(10)")).should == [2] + @array.send(@method, eval("(-4..4).step(10)")).should == [2] + @array.send(@method, eval("(-4...4).step(10)")).should == [2] - # start with negative index, end with negative index - @array.send(@method, eval("(-4..-2).step(1)")).should == [2, 3, 4] - @array.send(@method, eval("(-4...-2).step(1)")).should == [2, 3] + # start with negative index, end with negative index + @array.send(@method, eval("(-4..-2).step(1)")).should == [2, 3, 4] + @array.send(@method, eval("(-4...-2).step(1)")).should == [2, 3] - @array.send(@method, eval("(-4..-2).step(2)")).should == [2, 4] - @array.send(@method, eval("(-4...-2).step(2)")).should == [2] + @array.send(@method, eval("(-4..-2).step(2)")).should == [2, 4] + @array.send(@method, eval("(-4...-2).step(2)")).should == [2] - @array.send(@method, eval("(-4..-2).step(10)")).should == [2] - @array.send(@method, eval("(-4...-2).step(10)")).should == [2] - end + @array.send(@method, eval("(-4..-2).step(10)")).should == [2] + @array.send(@method, eval("(-4...-2).step(10)")).should == [2] + end - it "has closed range and negative steps" do - # start and end with 0 - @array.send(@method, eval("(0..0).step(-1)")).should == [0] - @array.send(@method, eval("(0...0).step(-1)")).should == [] + it "has closed range and negative steps" do + # start and end with 0 + @array.send(@method, eval("(0..0).step(-1)")).should == [0] + @array.send(@method, eval("(0...0).step(-1)")).should == [] - @array.send(@method, eval("(0..0).step(-2)")).should == [0] - @array.send(@method, eval("(0...0).step(-2)")).should == [] + @array.send(@method, eval("(0..0).step(-2)")).should == [0] + @array.send(@method, eval("(0...0).step(-2)")).should == [] - @array.send(@method, eval("(0..0).step(-10)")).should == [0] - @array.send(@method, eval("(0...0).step(-10)")).should == [] + @array.send(@method, eval("(0..0).step(-10)")).should == [0] + @array.send(@method, eval("(0...0).step(-10)")).should == [] - # start and end with positive index - @array.send(@method, eval("(1..3).step(-1)")).should == [] - @array.send(@method, eval("(1...3).step(-1)")).should == [] + # start and end with positive index + @array.send(@method, eval("(1..3).step(-1)")).should == [] + @array.send(@method, eval("(1...3).step(-1)")).should == [] - @array.send(@method, eval("(1..3).step(-2)")).should == [] - @array.send(@method, eval("(1...3).step(-2)")).should == [] + @array.send(@method, eval("(1..3).step(-2)")).should == [] + @array.send(@method, eval("(1...3).step(-2)")).should == [] - @array.send(@method, eval("(1..3).step(-10)")).should == [] - @array.send(@method, eval("(1...3).step(-10)")).should == [] + @array.send(@method, eval("(1..3).step(-10)")).should == [] + @array.send(@method, eval("(1...3).step(-10)")).should == [] - # start with positive index, end with negative index - @array.send(@method, eval("(1..-2).step(-1)")).should == [] - @array.send(@method, eval("(1...-2).step(-1)")).should == [] + # start with positive index, end with negative index + @array.send(@method, eval("(1..-2).step(-1)")).should == [] + @array.send(@method, eval("(1...-2).step(-1)")).should == [] - @array.send(@method, eval("(1..-2).step(-2)")).should == [] - @array.send(@method, eval("(1...-2).step(-2)")).should == [] + @array.send(@method, eval("(1..-2).step(-2)")).should == [] + @array.send(@method, eval("(1...-2).step(-2)")).should == [] - @array.send(@method, eval("(1..-2).step(-10)")).should == [] - @array.send(@method, eval("(1...-2).step(-10)")).should == [] + @array.send(@method, eval("(1..-2).step(-10)")).should == [] + @array.send(@method, eval("(1...-2).step(-10)")).should == [] - # start with negative index, end with positive index - @array.send(@method, eval("(-4..4).step(-1)")).should == [] - @array.send(@method, eval("(-4...4).step(-1)")).should == [] + # start with negative index, end with positive index + @array.send(@method, eval("(-4..4).step(-1)")).should == [] + @array.send(@method, eval("(-4...4).step(-1)")).should == [] - @array.send(@method, eval("(-4..4).step(-2)")).should == [] - @array.send(@method, eval("(-4...4).step(-2)")).should == [] + @array.send(@method, eval("(-4..4).step(-2)")).should == [] + @array.send(@method, eval("(-4...4).step(-2)")).should == [] - @array.send(@method, eval("(-4..4).step(-10)")).should == [] - @array.send(@method, eval("(-4...4).step(-10)")).should == [] + @array.send(@method, eval("(-4..4).step(-10)")).should == [] + @array.send(@method, eval("(-4...4).step(-10)")).should == [] - # start with negative index, end with negative index - @array.send(@method, eval("(-4..-2).step(-1)")).should == [] - @array.send(@method, eval("(-4...-2).step(-1)")).should == [] + # start with negative index, end with negative index + @array.send(@method, eval("(-4..-2).step(-1)")).should == [] + @array.send(@method, eval("(-4...-2).step(-1)")).should == [] - @array.send(@method, eval("(-4..-2).step(-2)")).should == [] - @array.send(@method, eval("(-4...-2).step(-2)")).should == [] + @array.send(@method, eval("(-4..-2).step(-2)")).should == [] + @array.send(@method, eval("(-4...-2).step(-2)")).should == [] - @array.send(@method, eval("(-4..-2).step(-10)")).should == [] - @array.send(@method, eval("(-4...-2).step(-10)")).should == [] - end + @array.send(@method, eval("(-4..-2).step(-10)")).should == [] + @array.send(@method, eval("(-4...-2).step(-10)")).should == [] + end - it "has inverted closed range and positive steps" do - # start and end with positive index - @array.send(@method, eval("(3..1).step(1)")).should == [] - @array.send(@method, eval("(3...1).step(1)")).should == [] + it "has inverted closed range and positive steps" do + # start and end with positive index + @array.send(@method, eval("(3..1).step(1)")).should == [] + @array.send(@method, eval("(3...1).step(1)")).should == [] - @array.send(@method, eval("(3..1).step(2)")).should == [] - @array.send(@method, eval("(3...1).step(2)")).should == [] + @array.send(@method, eval("(3..1).step(2)")).should == [] + @array.send(@method, eval("(3...1).step(2)")).should == [] - @array.send(@method, eval("(3..1).step(10)")).should == [] - @array.send(@method, eval("(3...1).step(10)")).should == [] + @array.send(@method, eval("(3..1).step(10)")).should == [] + @array.send(@method, eval("(3...1).step(10)")).should == [] - # start with negative index, end with positive index - @array.send(@method, eval("(-2..1).step(1)")).should == [] - @array.send(@method, eval("(-2...1).step(1)")).should == [] + # start with negative index, end with positive index + @array.send(@method, eval("(-2..1).step(1)")).should == [] + @array.send(@method, eval("(-2...1).step(1)")).should == [] - @array.send(@method, eval("(-2..1).step(2)")).should == [] - @array.send(@method, eval("(-2...1).step(2)")).should == [] + @array.send(@method, eval("(-2..1).step(2)")).should == [] + @array.send(@method, eval("(-2...1).step(2)")).should == [] - @array.send(@method, eval("(-2..1).step(10)")).should == [] - @array.send(@method, eval("(-2...1).step(10)")).should == [] + @array.send(@method, eval("(-2..1).step(10)")).should == [] + @array.send(@method, eval("(-2...1).step(10)")).should == [] - # start with positive index, end with negative index - @array.send(@method, eval("(4..-4).step(1)")).should == [] - @array.send(@method, eval("(4...-4).step(1)")).should == [] + # start with positive index, end with negative index + @array.send(@method, eval("(4..-4).step(1)")).should == [] + @array.send(@method, eval("(4...-4).step(1)")).should == [] - @array.send(@method, eval("(4..-4).step(2)")).should == [] - @array.send(@method, eval("(4...-4).step(2)")).should == [] + @array.send(@method, eval("(4..-4).step(2)")).should == [] + @array.send(@method, eval("(4...-4).step(2)")).should == [] - @array.send(@method, eval("(4..-4).step(10)")).should == [] - @array.send(@method, eval("(4...-4).step(10)")).should == [] + @array.send(@method, eval("(4..-4).step(10)")).should == [] + @array.send(@method, eval("(4...-4).step(10)")).should == [] - # start with negative index, end with negative index - @array.send(@method, eval("(-2..-4).step(1)")).should == [] - @array.send(@method, eval("(-2...-4).step(1)")).should == [] + # start with negative index, end with negative index + @array.send(@method, eval("(-2..-4).step(1)")).should == [] + @array.send(@method, eval("(-2...-4).step(1)")).should == [] - @array.send(@method, eval("(-2..-4).step(2)")).should == [] - @array.send(@method, eval("(-2...-4).step(2)")).should == [] + @array.send(@method, eval("(-2..-4).step(2)")).should == [] + @array.send(@method, eval("(-2...-4).step(2)")).should == [] - @array.send(@method, eval("(-2..-4).step(10)")).should == [] - @array.send(@method, eval("(-2...-4).step(10)")).should == [] - end + @array.send(@method, eval("(-2..-4).step(10)")).should == [] + @array.send(@method, eval("(-2...-4).step(10)")).should == [] + end - it "has range with bounds outside of array" do - # end is equal to array's length - @array.send(@method, (0..6).step(1)).should == [0, 1, 2, 3, 4, 5] - -> { @array.send(@method, (0..6).step(2)) }.should raise_error(RangeError) + it "has range with bounds outside of array" do + # end is equal to array's length + @array.send(@method, (0..6).step(1)).should == [0, 1, 2, 3, 4, 5] + -> { @array.send(@method, (0..6).step(2)) }.should raise_error(RangeError) - # end is greater than length with positive steps - @array.send(@method, (1..6).step(2)).should == [1, 3, 5] - @array.send(@method, (2..7).step(2)).should == [2, 4] - -> { @array.send(@method, (2..8).step(2)) }.should raise_error(RangeError) + # end is greater than length with positive steps + @array.send(@method, (1..6).step(2)).should == [1, 3, 5] + @array.send(@method, (2..7).step(2)).should == [2, 4] + -> { @array.send(@method, (2..8).step(2)) }.should raise_error(RangeError) - # begin is greater than length with negative steps - @array.send(@method, (6..1).step(-2)).should == [5, 3, 1] - @array.send(@method, (7..2).step(-2)).should == [5, 3] - -> { @array.send(@method, (8..2).step(-2)) }.should raise_error(RangeError) - end + # begin is greater than length with negative steps + @array.send(@method, (6..1).step(-2)).should == [5, 3, 1] + @array.send(@method, (7..2).step(-2)).should == [5, 3] + -> { @array.send(@method, (8..2).step(-2)) }.should raise_error(RangeError) + end - it "has endless range with start outside of array's bounds" do - @array.send(@method, eval("(6..).step(1)")).should == [] - @array.send(@method, eval("(7..).step(1)")).should == nil + it "has endless range with start outside of array's bounds" do + @array.send(@method, eval("(6..).step(1)")).should == [] + @array.send(@method, eval("(7..).step(1)")).should == nil - @array.send(@method, eval("(6..).step(2)")).should == [] - -> { @array.send(@method, eval("(7..).step(2)")) }.should raise_error(RangeError) + @array.send(@method, eval("(6..).step(2)")).should == [] + -> { @array.send(@method, eval("(7..).step(2)")) }.should raise_error(RangeError) + end end 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 - - ruby_version_is "3.2" do - describe "can be sliced with Enumerator::ArithmeticSequence" do - it "with infinite/inverted ranges and negative steps" do - @array = [0, 1, 2, 3, 4, 5] - @array.send(@method, (2..).step(-1)).should == [2, 1, 0] - @array.send(@method, (2..).step(-2)).should == [2, 0] - @array.send(@method, (2..).step(-3)).should == [2] - @array.send(@method, (2..).step(-4)).should == [2] - - @array.send(@method, (-3..).step(-1)).should == [3, 2, 1, 0] - @array.send(@method, (-3..).step(-2)).should == [3, 1] - @array.send(@method, (-3..).step(-3)).should == [3, 0] - @array.send(@method, (-3..).step(-4)).should == [3] - @array.send(@method, (-3..).step(-5)).should == [3] - - @array.send(@method, (..0).step(-1)).should == [5, 4, 3, 2, 1, 0] - @array.send(@method, (..0).step(-2)).should == [5, 3, 1] - @array.send(@method, (..0).step(-3)).should == [5, 2] - @array.send(@method, (..0).step(-4)).should == [5, 1] - @array.send(@method, (..0).step(-5)).should == [5, 0] - @array.send(@method, (..0).step(-6)).should == [5] - @array.send(@method, (..0).step(-7)).should == [5] - - @array.send(@method, (...0).step(-1)).should == [5, 4, 3, 2, 1] - @array.send(@method, (...0).step(-2)).should == [5, 3, 1] - @array.send(@method, (...0).step(-3)).should == [5, 2] - @array.send(@method, (...0).step(-4)).should == [5, 1] - @array.send(@method, (...0).step(-5)).should == [5] - @array.send(@method, (...0).step(-6)).should == [5] - - @array.send(@method, (...1).step(-1)).should == [5, 4, 3, 2] - @array.send(@method, (...1).step(-2)).should == [5, 3] - @array.send(@method, (...1).step(-3)).should == [5, 2] - @array.send(@method, (...1).step(-4)).should == [5] - @array.send(@method, (...1).step(-5)).should == [5] - - @array.send(@method, (..-5).step(-1)).should == [5, 4, 3, 2, 1] - @array.send(@method, (..-5).step(-2)).should == [5, 3, 1] - @array.send(@method, (..-5).step(-3)).should == [5, 2] - @array.send(@method, (..-5).step(-4)).should == [5, 1] - @array.send(@method, (..-5).step(-5)).should == [5] - @array.send(@method, (..-5).step(-6)).should == [5] - - @array.send(@method, (...-5).step(-1)).should == [5, 4, 3, 2] - @array.send(@method, (...-5).step(-2)).should == [5, 3] - @array.send(@method, (...-5).step(-3)).should == [5, 2] - @array.send(@method, (...-5).step(-4)).should == [5] - @array.send(@method, (...-5).step(-5)).should == [5] - - @array.send(@method, (4..1).step(-1)).should == [4, 3, 2, 1] - @array.send(@method, (4..1).step(-2)).should == [4, 2] - @array.send(@method, (4..1).step(-3)).should == [4, 1] - @array.send(@method, (4..1).step(-4)).should == [4] - @array.send(@method, (4..1).step(-5)).should == [4] - - @array.send(@method, (4...1).step(-1)).should == [4, 3, 2] - @array.send(@method, (4...1).step(-2)).should == [4, 2] - @array.send(@method, (4...1).step(-3)).should == [4] - @array.send(@method, (4...1).step(-4)).should == [4] - - @array.send(@method, (-2..1).step(-1)).should == [4, 3, 2, 1] - @array.send(@method, (-2..1).step(-2)).should == [4, 2] - @array.send(@method, (-2..1).step(-3)).should == [4, 1] - @array.send(@method, (-2..1).step(-4)).should == [4] - @array.send(@method, (-2..1).step(-5)).should == [4] - - @array.send(@method, (-2...1).step(-1)).should == [4, 3, 2] - @array.send(@method, (-2...1).step(-2)).should == [4, 2] - @array.send(@method, (-2...1).step(-3)).should == [4] - @array.send(@method, (-2...1).step(-4)).should == [4] - - @array.send(@method, (4..-5).step(-1)).should == [4, 3, 2, 1] - @array.send(@method, (4..-5).step(-2)).should == [4, 2] - @array.send(@method, (4..-5).step(-3)).should == [4, 1] - @array.send(@method, (4..-5).step(-4)).should == [4] - @array.send(@method, (4..-5).step(-5)).should == [4] - - @array.send(@method, (4...-5).step(-1)).should == [4, 3, 2] - @array.send(@method, (4...-5).step(-2)).should == [4, 2] - @array.send(@method, (4...-5).step(-3)).should == [4] - @array.send(@method, (4...-5).step(-4)).should == [4] - - @array.send(@method, (-2..-5).step(-1)).should == [4, 3, 2, 1] - @array.send(@method, (-2..-5).step(-2)).should == [4, 2] - @array.send(@method, (-2..-5).step(-3)).should == [4, 1] - @array.send(@method, (-2..-5).step(-4)).should == [4] - @array.send(@method, (-2..-5).step(-5)).should == [4] - - @array.send(@method, (-2...-5).step(-1)).should == [4, 3, 2] - @array.send(@method, (-2...-5).step(-2)).should == [4, 2] - @array.send(@method, (-2...-5).step(-3)).should == [4] - @array.send(@method, (-2...-5).step(-4)).should == [4] - 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 - 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 + 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 end end diff --git a/spec/ruby/core/array/shared/unshift.rb b/spec/ruby/core/array/shared/unshift.rb index 4941e098f6..fc82e19e2a 100644 --- a/spec/ruby/core/array/shared/unshift.rb +++ b/spec/ruby/core/array/shared/unshift.rb @@ -22,11 +22,6 @@ describe :array_unshift, shared: true do a.should == [3, 4] end - it "returns self" do - a = [1, 2, 3] - a.send(@method, "a").should.equal?(a) - end - it "quietly ignores unshifting nothing" do [].send(@method).should == [] end @@ -48,17 +43,4 @@ describe :array_unshift, shared: true do it "raises a FrozenError on a frozen array when the array would not be modified" do -> { ArraySpecs.frozen_array.send(@method) }.should raise_error(FrozenError) end - - # https://github.com/oracle/truffleruby/issues/2772 - it "doesn't rely on Array#[]= so it can be overridden" do - subclass = Class.new(Array) do - def []=(*) - raise "[]= is called" - end - end - - array = subclass.new - array.send(@method, 1) - array.should == [1] - end end diff --git a/spec/ruby/core/array/shift_spec.rb b/spec/ruby/core/array/shift_spec.rb index 6b4ef39f77..b998e45d28 100644 --- a/spec/ruby/core/array/shift_spec.rb +++ b/spec/ruby/core/array/shift_spec.rb @@ -116,5 +116,21 @@ 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/shuffle_spec.rb b/spec/ruby/core/array/shuffle_spec.rb index 1d528c124f..b255147c75 100644 --- a/spec/ruby/core/array/shuffle_spec.rb +++ b/spec/ruby/core/array/shuffle_spec.rb @@ -47,10 +47,6 @@ describe "Array#shuffle" do [1, 2].shuffle(random: random).should be_an_instance_of(Array) end - it "accepts a Random class for the value for random: argument" do - [1, 2].shuffle(random: Random).should be_an_instance_of(Array) - end - it "calls #to_int on the Object returned by #rand" do value = mock("array_shuffle_random_value") value.should_receive(:to_int).at_least(1).times.and_return(0) @@ -97,14 +93,4 @@ describe "Array#shuffle!" do -> { ArraySpecs.frozen_array.shuffle! }.should raise_error(FrozenError) -> { ArraySpecs.empty_frozen_array.shuffle! }.should raise_error(FrozenError) end - - it "matches CRuby with random:" do - %w[a b c].shuffle(random: Random.new(1)).should == %w[a c b] - (0..10).to_a.shuffle(random: Random.new(10)).should == [2, 6, 8, 5, 7, 10, 3, 1, 0, 4, 9] - end - - it "matches CRuby with srand" do - srand(123) - %w[a b c d e f g h i j k].shuffle.should == %w[a e f h i j d b g k c] - end end diff --git a/spec/ruby/core/array/slice_spec.rb b/spec/ruby/core/array/slice_spec.rb index 731c129251..8c276f9084 100644 --- a/spec/ruby/core/array/slice_spec.rb +++ b/spec/ruby/core/array/slice_spec.rb @@ -172,14 +172,16 @@ describe "Array#slice!" do a.should == [1, 2] 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] + 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 end describe "with a subclass of Array" do @@ -187,28 +189,56 @@ describe "Array#slice!" do @array = ArraySpecs::MyArray[1, 2, 3, 4, 5] end - it "returns a Array instance with [n, m]" do - @array.slice!(0, 2).should be_an_instance_of(Array) - end + ruby_version_is ''...'3.0' do + it "returns a subclass instance with [n, m]" do + @array.slice!(0, 2).should be_an_instance_of(ArraySpecs::MyArray) + end - it "returns a Array instance with [-n, m]" do - @array.slice!(-3, 2).should be_an_instance_of(Array) - end + it "returns a subclass instance with [-n, m]" do + @array.slice!(-3, 2).should be_an_instance_of(ArraySpecs::MyArray) + end - it "returns a Array instance with [n..m]" do - @array.slice!(1..3).should be_an_instance_of(Array) - end + it "returns a subclass instance with [n..m]" do + @array.slice!(1..3).should be_an_instance_of(ArraySpecs::MyArray) + end - it "returns a Array instance with [n...m]" do - @array.slice!(1...3).should be_an_instance_of(Array) - end + it "returns a subclass instance with [n...m]" do + @array.slice!(1...3).should be_an_instance_of(ArraySpecs::MyArray) + end + + it "returns a subclass instance with [-n..-m]" do + @array.slice!(-3..-1).should be_an_instance_of(ArraySpecs::MyArray) + end - it "returns a Array instance with [-n..-m]" do - @array.slice!(-3..-1).should be_an_instance_of(Array) + it "returns a subclass instance with [-n...-m]" do + @array.slice!(-3...-1).should be_an_instance_of(ArraySpecs::MyArray) + end end - it "returns a Array instance with [-n...-m]" do - @array.slice!(-3...-1).should be_an_instance_of(Array) + ruby_version_is '3.0' do + it "returns a Array instance with [n, m]" do + @array.slice!(0, 2).should be_an_instance_of(Array) + end + + it "returns a Array instance with [-n, m]" do + @array.slice!(-3, 2).should be_an_instance_of(Array) + end + + it "returns a Array instance with [n..m]" do + @array.slice!(1..3).should be_an_instance_of(Array) + end + + it "returns a Array instance with [n...m]" do + @array.slice!(1...3).should be_an_instance_of(Array) + end + + it "returns a Array instance with [-n..-m]" do + @array.slice!(-3..-1).should be_an_instance_of(Array) + end + + it "returns a Array instance with [-n...-m]" do + @array.slice!(-3...-1).should be_an_instance_of(Array) + end end end end diff --git a/spec/ruby/core/array/sort_by_spec.rb b/spec/ruby/core/array/sort_by_spec.rb index 0334f953f6..7cea6ec6d3 100644 --- a/spec/ruby/core/array/sort_by_spec.rb +++ b/spec/ruby/core/array/sort_by_spec.rb @@ -1,6 +1,5 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -require_relative 'shared/iterable_and_tolerating_size_increasing' require_relative '../enumerable/shared/enumeratorized' describe "Array#sort_by!" do @@ -32,11 +31,6 @@ describe "Array#sort_by!" do -> { ArraySpecs.empty_frozen_array.sort_by! {}}.should raise_error(FrozenError) end - it "raises a FrozenError on a frozen array only during iteration if called without a block" do - enum = ArraySpecs.frozen_array.sort_by! - -> { enum.each {} }.should raise_error(FrozenError) - end - it "returns the specified value when it would break in the given block" do [1, 2, 3].sort_by!{ break :a }.should == :a end @@ -54,32 +48,5 @@ describe "Array#sort_by!" do [1].sort_by!(&:to_s).should == [1] end - it "does not truncate the array is the block raises an exception" do - a = [1, 2, 3] - begin - a.sort_by! { raise StandardError, 'Oops' } - rescue - end - - a.should == [1, 2, 3] - end - - it "doesn't change array if error is raised" do - a = [4, 3, 2, 1] - begin - a.sort_by! do |e| - raise StandardError, 'Oops' if e == 1 - e - end - rescue StandardError - end - - a.should == [4, 3, 2, 1] - end - it_behaves_like :enumeratorized_with_origin_size, :sort_by!, [1,2,3] end - -describe "Array#sort_by!" do - it_behaves_like :array_iterable_and_tolerating_size_increasing, :sort_by! -end diff --git a/spec/ruby/core/array/sum_spec.rb b/spec/ruby/core/array/sum_spec.rb index 06abe06135..8ca8353a67 100644 --- a/spec/ruby/core/array/sum_spec.rb +++ b/spec/ruby/core/array/sum_spec.rb @@ -1,5 +1,4 @@ require_relative '../../spec_helper' -require_relative 'shared/iterable_and_tolerating_size_increasing' describe "Array#sum" do it "returns the sum of elements" do @@ -10,12 +9,8 @@ describe "Array#sum" do [1, 2, 3].sum { |i| i * 10 }.should == 60 end - it "doesn't apply the block init" do - [1, 2, 3].sum(1) { |i| i * 10 }.should == 61 - end - # https://bugs.ruby-lang.org/issues/12217 - # https://github.com/ruby/ruby/blob/master/doc/ChangeLog/ChangeLog-2.4.0#L6208-L6214 + # https://github.com/ruby/ruby/blob/master/doc/ChangeLog-2.4.0#L6208-L6214 it "uses Kahan's compensated summation algorithm for precise sum of float numbers" do floats = [2.7800000000000002, 5.0, 2.5, 4.44, 3.89, 3.89, 4.44, 7.78, 5.0, 2.7800000000000002, 5.0, 2.5] naive_sum = floats.reduce { |sum, e| sum + e } @@ -73,18 +68,4 @@ describe "Array#sum" do a.should_receive(:+).with(b).and_return(42) [b].sum(a).should == 42 end - - ruby_bug '#19530', ''...'3.3' do - it "calls + on the init value" do - a = mock("a") - b = mock("b") - a.should_receive(:+).with(42).and_return(b) - [42].sum(a).should == b - end - end -end - -describe "Array#sum" do - @value_to_return = -> _ { 1 } - it_behaves_like :array_iterable_and_tolerating_size_increasing, :sum end diff --git a/spec/ruby/core/array/take_spec.rb b/spec/ruby/core/array/take_spec.rb index c4f0ac9aa4..4fb6f0ce75 100644 --- a/spec/ruby/core/array/take_spec.rb +++ b/spec/ruby/core/array/take_spec.rb @@ -26,7 +26,15 @@ describe "Array#take" do ->{ [1].take(-3) }.should raise_error(ArgumentError) end - it 'returns a Array instance for Array subclasses' do - ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should be_an_instance_of(Array) + ruby_version_is ''...'3.0' do + it 'returns a subclass instance for Array subclasses' do + ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should be_an_instance_of(ArraySpecs::MyArray) + end + end + + ruby_version_is '3.0' do + it 'returns a Array instance for Array subclasses' do + ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should be_an_instance_of(Array) + end end end diff --git a/spec/ruby/core/array/take_while_spec.rb b/spec/ruby/core/array/take_while_spec.rb index 8f50260b42..363419b265 100644 --- a/spec/ruby/core/array/take_while_spec.rb +++ b/spec/ruby/core/array/take_while_spec.rb @@ -1,6 +1,5 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -require_relative 'shared/iterable_and_tolerating_size_increasing' describe "Array#take_while" do it "returns all elements until the block returns false" do @@ -15,12 +14,15 @@ describe "Array#take_while" do [1, 2, false, 4].take_while{ |element| element }.should == [1, 2] end - it 'returns a Array instance for Array subclasses' do - ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should be_an_instance_of(Array) + ruby_version_is ''...'3.0' do + it 'returns a subclass instance for Array subclasses' do + ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should be_an_instance_of(ArraySpecs::MyArray) + end end -end -describe "Array#take_while" do - @value_to_return = -> _ { true } - it_behaves_like :array_iterable_and_tolerating_size_increasing, :take_while + ruby_version_is '3.0' do + it 'returns a Array instance for Array subclasses' do + ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should be_an_instance_of(Array) + end + end end diff --git a/spec/ruby/core/array/to_h_spec.rb b/spec/ruby/core/array/to_h_spec.rb index f4578211a1..f5a7e546e6 100644 --- a/spec/ruby/core/array/to_h_spec.rb +++ b/spec/ruby/core/array/to_h_spec.rb @@ -1,6 +1,5 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -require_relative 'shared/iterable_and_tolerating_size_increasing' describe "Array#to_h" do it "converts empty array to empty hash" do @@ -78,8 +77,3 @@ describe "Array#to_h" do end end end - -describe "Array#to_h" do - @value_to_return = -> e { [e, e.to_s] } - it_behaves_like :array_iterable_and_tolerating_size_increasing, :to_h -end diff --git a/spec/ruby/core/array/try_convert_spec.rb b/spec/ruby/core/array/try_convert_spec.rb index bea8815006..47b4722d80 100644 --- a/spec/ruby/core/array/try_convert_spec.rb +++ b/spec/ruby/core/array/try_convert_spec.rb @@ -39,7 +39,7 @@ describe "Array.try_convert" do it "sends #to_ary to the argument and raises TypeError if it's not a kind of Array" do obj = mock("to_ary") obj.should_receive(:to_ary).and_return(Object.new) - -> { Array.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_ary gives Object)") + -> { Array.try_convert obj }.should raise_error(TypeError) end it "does not rescue exceptions raised by #to_ary" do diff --git a/spec/ruby/core/array/uniq_spec.rb b/spec/ruby/core/array/uniq_spec.rb index d5d826db15..5911c23e6a 100644 --- a/spec/ruby/core/array/uniq_spec.rb +++ b/spec/ruby/core/array/uniq_spec.rb @@ -1,6 +1,5 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -require_relative 'shared/iterable_and_tolerating_size_increasing' describe "Array#uniq" do it "returns an array with no duplicates" do @@ -40,32 +39,76 @@ describe "Array#uniq" do [x, y].uniq.should == [x, y] end - 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) + 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 + def obj.eql?(o) + false + end + + obj end - obj - end + a.uniq.should == a - 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) + true + end - def obj.eql?(o) - true + obj end - obj + a.uniq.size.should == 1 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.size.should == 1 + a.uniq.should == a + a[0].should.tainted? + a[1].should.tainted? + + 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 + end + + a.uniq.size.should == 1 + a[0].should.tainted? + a[1].should.tainted? + end end it "compares elements based on the value returned from the block" do @@ -85,8 +128,16 @@ describe "Array#uniq" do [false, nil, 42].uniq { :bar }.should == [false] end - it "returns Array instance on Array subclasses" do - ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(Array) + ruby_version_is ''...'3.0' do + it "returns subclass instance on Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(ArraySpecs::MyArray) + end + end + + ruby_version_is '3.0' do + it "returns Array instance on Array subclasses" do + ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(Array) + end end it "properly handles an identical item even when its #eql? isn't reflexive" do @@ -124,11 +175,6 @@ describe "Array#uniq" do end end -describe "Array#uniq" do - @value_to_return = -> e { e } - it_behaves_like :array_iterable_and_tolerating_size_increasing, :uniq -end - describe "Array#uniq!" do it "modifies the array in place" do a = [ "a", "a", "b", "b", "c" ] @@ -212,32 +258,4 @@ describe "Array#uniq!" do a.uniq! a.should == [x] end - - it "does not truncate the array is the block raises an exception" do - a = [1, 2, 3] - begin - a.send(@method) { raise StandardError, 'Oops' } - rescue - end - - a.should == [1, 2, 3] - end - - it "doesn't change array if error is raised" do - a = [1, 1, 2, 2, 3, 3, 4, 4] - begin - a.send(@method) do |e| - raise StandardError, 'Oops' if e == 3 - e - end - rescue StandardError - end - - a.should == [1, 1, 2, 2, 3, 3, 4, 4] - end -end - -describe "Array#uniq!" do - @value_to_return = -> e { e } - it_behaves_like :array_iterable_and_tolerating_size_increasing, :uniq! end diff --git a/spec/ruby/core/array/values_at_spec.rb b/spec/ruby/core/array/values_at_spec.rb index e85bbee400..f1522e0bfe 100644 --- a/spec/ruby/core/array/values_at_spec.rb +++ b/spec/ruby/core/array/values_at_spec.rb @@ -1,7 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -# Should be synchronized with core/struct/values_at_spec.rb describe "Array#values_at" do it "returns an array of elements at the indexes when passed indexes" do [1, 2, 3, 4, 5].values_at().should == [] @@ -67,8 +66,10 @@ describe "Array#values_at" do [1, 2, 3, 4].values_at(eval("(3...)")).should == [4] 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] + 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 end end diff --git a/spec/ruby/core/array/zip_spec.rb b/spec/ruby/core/array/zip_spec.rb index 2a0f64cb49..af4013debe 100644 --- a/spec/ruby/core/array/zip_spec.rb +++ b/spec/ruby/core/array/zip_spec.rb @@ -62,10 +62,4 @@ describe "Array#zip" do it "does not return subclass instance on Array subclasses" do ArraySpecs::MyArray[1, 2, 3].zip(["a", "b"]).should be_an_instance_of(Array) end - - it "raises TypeError when some argument isn't Array and doesn't respond to #to_ary and #to_enum" do - -> { [1, 2, 3].zip(Object.new) }.should raise_error(TypeError, "wrong argument type Object (must respond to :each)") - -> { [1, 2, 3].zip(1) }.should raise_error(TypeError, "wrong argument type Integer (must respond to :each)") - -> { [1, 2, 3].zip(true) }.should raise_error(TypeError, "wrong argument type TrueClass (must respond to :each)") - end end diff --git a/spec/ruby/core/basicobject/fixtures/classes.rb b/spec/ruby/core/basicobject/fixtures/classes.rb index ed5a2dda17..d1785afe31 100644 --- a/spec/ruby/core/basicobject/fixtures/classes.rb +++ b/spec/ruby/core/basicobject/fixtures/classes.rb @@ -15,231 +15,8 @@ module BasicObjectSpecs include InstExec end - module InstEval - module CVar - module Get - class ReceiverScope - @@cvar = :value_defined_in_receiver_scope - end - - class BlockDefinitionScope - @@cvar = :value_defined_in_block_definition_scope - - def block - -> * { @@cvar } - end - end - - class CallerScope - @@cvar = :value_defined_in_caller_scope - - def get_class_variable_with_string(obj) - obj.instance_eval("@@cvar") - end - - def get_class_variable_with_block(obj, block) - obj.instance_eval(&block) - end - end - - class CallerWithoutCVarScope - def get_class_variable_with_string(obj) - obj.instance_eval("@@cvar") - end - end - - ReceiverWithCVarDefinedInSingletonClass = Class.new.new.tap do |obj| - obj.singleton_class.class_variable_set(:@@cvar, :value_defined_in_receiver_singleton_class) - end - end - - module Set - class ReceiverScope - end - - class BlockDefinitionScope - def self.get_class_variable - @@cvar - end - - def block_to_assign(value) - -> * { @@cvar = value } - end - end - - class CallerScope - def self.get_class_variable - @@cvar - end - - def set_class_variable_with_string(obj, value) - obj.instance_eval("@@cvar=#{value.inspect}") - end - - def set_class_variable_with_block(obj, block) - obj.instance_eval(&block) - end - end - end - end - end - - module InstEval - module Constants - module ConstantInReceiverSingletonClass - module ReceiverScope - FOO = :ReceiverScope - - class ReceiverParent - FOO = :ReceiverParent - end - - class Receiver < ReceiverParent - FOO = :Receiver - - def initialize - self.singleton_class.const_set(:FOO, :singleton_class) - end - end - end - - module CallerScope - FOO = :CallerScope - - class CallerParent - FOO = :CallerParent - end - - class Caller < CallerParent - FOO = :Caller - - def get_constant_with_string(receiver) - receiver.instance_eval("FOO") - end - end - end - end - - module ConstantInReceiverClass - module ReceiverScope - FOO = :ReceiverScope - - class ReceiverParent - FOO = :ReceiverParent - end - - class Receiver < ReceiverParent - FOO = :Receiver - end - end - - module CallerScope - FOO = :CallerScope - - class CallerParent - FOO = :CallerParent - end - - class Caller < CallerParent - FOO = :Caller - - def get_constant_with_string(receiver) - receiver.instance_eval("FOO") - end - end - end - end - - module ConstantInCallerClass - module ReceiverScope - FOO = :ReceiverScope - - class ReceiverParent - FOO = :ReceiverParent - end - - class Receiver < ReceiverParent - # FOO is not declared in a receiver class - end - end - - module CallerScope - FOO = :CallerScope - - class CallerParent - FOO = :CallerParent - end - - class Caller < CallerParent - FOO = :Caller - - def get_constant_with_string(receiver) - receiver.instance_eval("FOO") - end - end - end - end - - module ConstantInCallerOuterScopes - module ReceiverScope - FOO = :ReceiverScope - - class ReceiverParent - FOO = :ReceiverParent - end - - class Receiver < ReceiverParent - # FOO is not declared in a receiver class - end - end - - module CallerScope - FOO = :CallerScope - - class CallerParent - FOO = :CallerParent - end - - class Caller < CallerParent - # FOO is not declared in a caller class - - def get_constant_with_string(receiver) - receiver.instance_eval("FOO") - end - end - end - end - - module ConstantInReceiverParentClass - module ReceiverScope - FOO = :ReceiverScope - - class ReceiverParent - FOO = :ReceiverParent - end - - class Receiver < ReceiverParent - # FOO is not declared in a receiver class - end - end - - module CallerScope - # FOO is not declared in a caller outer scopes - - class CallerParent - FOO = :CallerParent - end - - class Caller < CallerParent - # FOO is not declared in a caller class - - def get_constant_with_string(receiver) - receiver.instance_eval("FOO") - end - end - end - end - end + module InstEvalCVar + instance_eval { @@count = 2 } end class InstEvalConst @@ -249,6 +26,7 @@ module BasicObjectSpecs module InstEvalOuter module Inner obj = InstEvalConst.new + X_BY_STR = obj.instance_eval("INST_EVAL_CONST_X") rescue nil X_BY_BLOCK = obj.instance_eval { INST_EVAL_CONST_X } rescue nil end end diff --git a/spec/ruby/core/basicobject/instance_eval_spec.rb b/spec/ruby/core/basicobject/instance_eval_spec.rb index 1f3a43f341..b6a146095d 100644 --- a/spec/ruby/core/basicobject/instance_eval_spec.rb +++ b/spec/ruby/core/basicobject/instance_eval_spec.rb @@ -20,18 +20,12 @@ describe "BasicObject#instance_eval" do a.instance_eval('self').equal?(a).should be_true end - it "raises an ArgumentError when no arguments and no block are given" do - -> { "hola".instance_eval }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1..3)") + it "expects a block with no arguments" do + -> { "hola".instance_eval }.should raise_error(ArgumentError) end - it "raises an ArgumentError when a block and normal arguments are given" do - -> { "hola".instance_eval(4, 5) {|a,b| a + b } }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)") - end - - it "raises an ArgumentError when more than 3 arguments are given" do - -> { - "hola".instance_eval("1 + 1", "some file", 0, "bogus") - }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)") + it "takes no arguments with a block" do + -> { "hola".instance_eval(4, 5) {|a,b| a + b } }.should raise_error(ArgumentError) end it "yields the object to the block" do @@ -84,30 +78,11 @@ describe "BasicObject#instance_eval" do end - ruby_version_is "3.3" do - it "uses the caller location as default location" do - f = Object.new - f.instance_eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1] - end - end - it "has access to receiver's instance variables" do BasicObjectSpecs::IVars.new.instance_eval { @secret }.should == 99 BasicObjectSpecs::IVars.new.instance_eval("@secret").should == 99 end - it "raises TypeError for frozen objects when tries to set receiver's instance variables" do - -> { nil.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen NilClass: nil") - -> { true.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen TrueClass: true") - -> { false.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen FalseClass: false") - -> { 1.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen Integer: 1") - -> { :symbol.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen Symbol: :symbol") - - obj = Object.new - obj.freeze - -> { obj.instance_eval { @foo = 42 } }.should raise_error(FrozenError) - end - it "treats block-local variables as local to the block" do prc = instance_eval <<-CODE proc do |x, prc| @@ -124,6 +99,11 @@ describe "BasicObject#instance_eval" do prc.call(false, prc).should == 1 end + it "sets class variables in the receiver" do + BasicObjectSpecs::InstEvalCVar.class_variables.should include(:@@count) + BasicObjectSpecs::InstEvalCVar.send(:class_variable_get, :@@count).should == 2 + end + it "makes the receiver metaclass the scoped class when used with a string" do obj = Object.new obj.instance_eval %{ @@ -133,52 +113,8 @@ describe "BasicObject#instance_eval" do obj.singleton_class.const_get(:B).should be_an_instance_of(Class) end - describe "constants lookup when a String given" do - it "looks in the receiver singleton class first" do - receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverSingletonClass::ReceiverScope::Receiver.new - caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverSingletonClass::CallerScope::Caller.new - - caller.get_constant_with_string(receiver).should == :singleton_class - end - - ruby_version_is ""..."3.1" do - it "looks in the caller scope next" do - receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new - caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new - - caller.get_constant_with_string(receiver).should == :Caller - end - end - - ruby_version_is "3.1" do - it "looks in the receiver class next" do - receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new - caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new - - caller.get_constant_with_string(receiver).should == :Receiver - end - end - - it "looks in the caller class next" do - receiver = BasicObjectSpecs::InstEval::Constants::ConstantInCallerClass::ReceiverScope::Receiver.new - caller = BasicObjectSpecs::InstEval::Constants::ConstantInCallerClass::CallerScope::Caller.new - - caller.get_constant_with_string(receiver).should == :Caller - end - - it "looks in the caller outer scopes next" do - receiver = BasicObjectSpecs::InstEval::Constants::ConstantInCallerOuterScopes::ReceiverScope::Receiver.new - caller = BasicObjectSpecs::InstEval::Constants::ConstantInCallerOuterScopes::CallerScope::Caller.new - - caller.get_constant_with_string(receiver).should == :CallerScope - end - - it "looks in the receiver class hierarchy next" do - receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverParentClass::ReceiverScope::Receiver.new - caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverParentClass::CallerScope::Caller.new - - caller.get_constant_with_string(receiver).should == :ReceiverParent - end + it "gets constants in the receiver if a string given" do + BasicObjectSpecs::InstEvalOuter::Inner::X_BY_STR.should == 2 end it "doesn't get constants in the receiver if a block given" do @@ -194,51 +130,17 @@ describe "BasicObject#instance_eval" do end.should raise_error(TypeError) end - describe "class variables lookup" do - it "gets class variables in the caller class when called with a String" do - receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverScope.new - caller = BasicObjectSpecs::InstEval::CVar::Get::CallerScope.new +quarantine! do # Not clean, leaves cvars lying around to break other specs + it "scopes class var accesses in the caller when called on an Integer" do + # Integer can take instance vars + Integer.class_eval "@@__tmp_instance_eval_spec = 1" + (defined? @@__tmp_instance_eval_spec).should be_nil - caller.get_class_variable_with_string(receiver).should == :value_defined_in_caller_scope - end - - it "gets class variables in the block definition scope when called with a block" do - receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverScope.new - caller = BasicObjectSpecs::InstEval::CVar::Get::CallerScope.new - block = BasicObjectSpecs::InstEval::CVar::Get::BlockDefinitionScope.new.block - - caller.get_class_variable_with_block(receiver, block).should == :value_defined_in_block_definition_scope - end - - it "sets class variables in the caller class when called with a String" do - receiver = BasicObjectSpecs::InstEval::CVar::Set::ReceiverScope.new - caller = BasicObjectSpecs::InstEval::CVar::Set::CallerScope.new - - caller.set_class_variable_with_string(receiver, 1) - BasicObjectSpecs::InstEval::CVar::Set::CallerScope.get_class_variable.should == 1 - end - - it "sets class variables in the block definition scope when called with a block" do - receiver = BasicObjectSpecs::InstEval::CVar::Set::ReceiverScope.new - caller = BasicObjectSpecs::InstEval::CVar::Set::CallerScope.new - block = BasicObjectSpecs::InstEval::CVar::Set::BlockDefinitionScope.new.block_to_assign(1) - - caller.set_class_variable_with_block(receiver, block) - BasicObjectSpecs::InstEval::CVar::Set::BlockDefinitionScope.get_class_variable.should == 1 - end - - it "does not have access to class variables in the receiver class when called with a String" do - receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverScope.new - caller = BasicObjectSpecs::InstEval::CVar::Get::CallerWithoutCVarScope.new - -> { caller.get_class_variable_with_string(receiver) }.should raise_error(NameError, /uninitialized class variable @@cvar/) - end - - it "does not have access to class variables in the receiver's singleton class when called with a String" do - receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverWithCVarDefinedInSingletonClass - caller = BasicObjectSpecs::InstEval::CVar::Get::CallerWithoutCVarScope.new - -> { caller.get_class_variable_with_string(receiver) }.should raise_error(NameError, /uninitialized class variable @@cvar/) - end + @@__tmp_instance_eval_spec = 2 + 1.instance_eval { @@__tmp_instance_eval_spec }.should == 2 + Integer.__send__(:remove_class_variable, :@@__tmp_instance_eval_spec) end +end it "raises a TypeError when defining methods on numerics" do -> do @@ -283,58 +185,4 @@ describe "BasicObject#instance_eval" do x.should == :value end - - it "converts string argument with #to_str method" do - source_code = Object.new - def source_code.to_str() "1" end - - a = BasicObject.new - a.instance_eval(source_code).should == 1 - end - - it "raises ArgumentError if returned value is not String" do - source_code = Object.new - def source_code.to_str() :symbol end - - a = BasicObject.new - -> { a.instance_eval(source_code) }.should raise_error(TypeError, /can't convert Object to String/) - end - - it "converts filename argument with #to_str method" do - filename = Object.new - def filename.to_str() "file.rb" end - - err = begin - Object.new.instance_eval("raise", filename) - rescue => e - e - end - err.backtrace.first.split(":")[0].should == "file.rb" - end - - it "raises ArgumentError if returned value is not String" do - filename = Object.new - def filename.to_str() :symbol end - - -> { Object.new.instance_eval("raise", filename) }.should raise_error(TypeError, /can't convert Object to String/) - end - - it "converts lineno argument with #to_int method" do - lineno = Object.new - def lineno.to_int() 15 end - - err = begin - Object.new.instance_eval("raise", "file.rb", lineno) - rescue => e - e - end - err.backtrace.first.split(":")[1].should == "15" - end - - it "raises ArgumentError if returned value is not Integer" do - lineno = Object.new - def lineno.to_int() :symbol end - - -> { Object.new.instance_eval("raise", "file.rb", lineno) }.should raise_error(TypeError, /can't convert Object to Integer/) - end end diff --git a/spec/ruby/core/basicobject/method_missing_spec.rb b/spec/ruby/core/basicobject/method_missing_spec.rb index a29d4375bc..b048780ee8 100644 --- a/spec/ruby/core/basicobject/method_missing_spec.rb +++ b/spec/ruby/core/basicobject/method_missing_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/basicobject/method_missing' describe "BasicObject#method_missing" do diff --git a/spec/ruby/core/binding/clone_spec.rb b/spec/ruby/core/binding/clone_spec.rb index f1769ac6de..ebd40f5377 100644 --- a/spec/ruby/core/binding/clone_spec.rb +++ b/spec/ruby/core/binding/clone_spec.rb @@ -4,10 +4,4 @@ require_relative 'shared/clone' describe "Binding#clone" do it_behaves_like :binding_clone, :clone - - it "preserves frozen status" do - bind = binding.freeze - bind.frozen?.should == true - bind.clone.frozen?.should == true - end end diff --git a/spec/ruby/core/binding/dup_spec.rb b/spec/ruby/core/binding/dup_spec.rb index 55fac6e333..43968213c8 100644 --- a/spec/ruby/core/binding/dup_spec.rb +++ b/spec/ruby/core/binding/dup_spec.rb @@ -4,10 +4,4 @@ require_relative 'shared/clone' describe "Binding#dup" do it_behaves_like :binding_clone, :dup - - it "resets frozen status" do - bind = binding.freeze - bind.frozen?.should == true - bind.dup.frozen?.should == false - end end diff --git a/spec/ruby/core/binding/eval_spec.rb b/spec/ruby/core/binding/eval_spec.rb index bb2036f739..4bb3da7a6c 100644 --- a/spec/ruby/core/binding/eval_spec.rb +++ b/spec/ruby/core/binding/eval_spec.rb @@ -23,29 +23,58 @@ describe "Binding#eval" do bind2.local_variables.should == [] end - it "starts with line 1 if single argument is given" do - obj = BindingSpecs::Demo.new(1) - bind = obj.get_binding - bind.eval("__LINE__").should == 1 - end + ruby_version_is ""..."3.0" do + it "inherits __LINE__ from the enclosing scope" do + obj = BindingSpecs::Demo.new(1) + bind = obj.get_binding + suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding + end - it "preserves __LINE__ across multiple calls to eval" do - obj = BindingSpecs::Demo.new(1) - bind = obj.get_binding - bind.eval("__LINE__").should == 1 - bind.eval("__LINE__").should == 1 - end + it "preserves __LINE__ across multiple calls to eval" do + obj = BindingSpecs::Demo.new(1) + bind = obj.get_binding + suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding + suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding + end - it "increments __LINE__ on each line of a multiline eval" do - obj = BindingSpecs::Demo.new(1) - bind = obj.get_binding - bind.eval("#foo\n__LINE__").should == 2 + it "increments __LINE__ on each line of a multiline eval" do + obj = BindingSpecs::Demo.new(1) + bind = obj.get_binding + suppress_warning {bind.eval("#foo\n__LINE__")}.should == obj.get_line_of_binding + 1 + end + + it "inherits __LINE__ from the enclosing scope even if the Binding is created with #send" do + obj = BindingSpecs::Demo.new(1) + bind, line = obj.get_binding_with_send_and_line + suppress_warning {bind.eval("__LINE__")}.should == line + end end - it "starts with line 1 if the Binding is created with #send" do - obj = BindingSpecs::Demo.new(1) - bind, line = obj.get_binding_with_send_and_line - bind.eval("__LINE__").should == 1 + ruby_version_is "3.0" do + it "starts with line 1 if single argument is given" do + obj = BindingSpecs::Demo.new(1) + bind = obj.get_binding + bind.eval("__LINE__").should == 1 + end + + it "preserves __LINE__ across multiple calls to eval" do + obj = BindingSpecs::Demo.new(1) + bind = obj.get_binding + bind.eval("__LINE__").should == 1 + bind.eval("__LINE__").should == 1 + end + + it "increments __LINE__ on each line of a multiline eval" do + obj = BindingSpecs::Demo.new(1) + bind = obj.get_binding + bind.eval("#foo\n__LINE__").should == 2 + end + + it "starts with line 1 if the Binding is created with #send" do + obj = BindingSpecs::Demo.new(1) + bind, line = obj.get_binding_with_send_and_line + bind.eval("__LINE__").should == 1 + end end it "starts with a __LINE__ of 1 if a filename is passed" do @@ -60,18 +89,32 @@ describe "Binding#eval" do bind.eval("#foo\n__LINE__", "(test)", 88).should == 89 end - ruby_version_is ""..."3.3" do + ruby_version_is ""..."3.0" do + it "inherits __FILE__ from the enclosing scope" do + obj = BindingSpecs::Demo.new(1) + bind = obj.get_binding + suppress_warning { bind.eval("__FILE__") }.should == obj.get_file_of_binding + end + + it "inherits __LINE__ from the enclosing scope" do + obj = BindingSpecs::Demo.new(1) + bind, line = obj.get_binding_and_line + suppress_warning { bind.eval("__LINE__") }.should == line + end + end + + ruby_version_is "3.0" do it "uses (eval) as __FILE__ if single argument given" do obj = BindingSpecs::Demo.new(1) bind = obj.get_binding bind.eval("__FILE__").should == '(eval)' end - end - it "uses 1 as __LINE__" do - obj = BindingSpecs::Demo.new(1) - bind = obj.get_binding - suppress_warning { bind.eval("__LINE__") }.should == 1 + it "uses 1 as __LINE__" do + obj = BindingSpecs::Demo.new(1) + bind = obj.get_binding + suppress_warning { bind.eval("__LINE__") }.should == 1 + end end it "uses the __FILE__ that is passed in" do @@ -106,10 +149,4 @@ describe "Binding#eval" do bind.eval("'bar'.foo").should == "foo" end - - ruby_version_is "3.3" do - it "uses the caller location as default filename" do - binding.eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1] - end - end end diff --git a/spec/ruby/core/binding/shared/clone.rb b/spec/ruby/core/binding/shared/clone.rb index 1224b8ec7d..0e934ac1b5 100644 --- a/spec/ruby/core/binding/shared/clone.rb +++ b/spec/ruby/core/binding/shared/clone.rb @@ -31,26 +31,4 @@ describe :binding_clone, shared: true do b2.local_variable_defined?(:x).should == false end end - - ruby_version_is "3.4" do - it "copies instance variables" do - @b1.instance_variable_set(:@ivar, 1) - cl = @b1.send(@method) - cl.instance_variables.should == [:@ivar] - end - - it "copies the finalizer" do - code = <<-RUBY - obj = binding - - ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" }) - - obj.clone - - exit 0 - RUBY - - ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"] - end - end end diff --git a/spec/ruby/core/binding/source_location_spec.rb b/spec/ruby/core/binding/source_location_spec.rb index d1c8191ea8..d439c3e399 100644 --- a/spec/ruby/core/binding/source_location_spec.rb +++ b/spec/ruby/core/binding/source_location_spec.rb @@ -6,9 +6,4 @@ describe "Binding#source_location" do b = BindingSpecs::LocationMethod::TEST_BINDING b.source_location.should == [BindingSpecs::LocationMethod::FILE_PATH, 4] end - - it "works for eval with a given line" do - b = eval('binding', nil, "foo", 100) - b.source_location.should == ["foo", 100] - 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 1960f5721f..7c87a970d7 100644 --- a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb +++ b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb @@ -34,6 +34,12 @@ describe "RUBY_PLATFORM" do it "is a String" do RUBY_PLATFORM.should be_kind_of(String) end + + platform_is :darwin do + it 'ends with the build time kernel major version on darwin' do + RUBY_PLATFORM.should =~ /-darwin\d+$/ + end + end end describe "RUBY_RELEASE_DATE" do @@ -43,7 +49,15 @@ describe "RUBY_RELEASE_DATE" do end describe "RUBY_REVISION" do - it "is a String" do - RUBY_REVISION.should be_kind_of(String) + 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 end end diff --git a/spec/ruby/core/class/attached_object_spec.rb b/spec/ruby/core/class/attached_object_spec.rb deleted file mode 100644 index 115d5fa563..0000000000 --- a/spec/ruby/core/class/attached_object_spec.rb +++ /dev/null @@ -1,31 +0,0 @@ -require_relative '../../spec_helper' - -ruby_version_is '3.2' do - describe "Class#attached_object" do - it "returns the object that is attached to a singleton class" do - a = Class.new - - a_obj = a.new - a_obj.singleton_class.attached_object.should == a_obj - end - - it "returns the class object that is attached to a class's singleton class" do - a = Class.new - singleton_class = (class << a; self; end) - - singleton_class.attached_object.should == a - end - - it "raises TypeError if the class is not a singleton class" do - a = Class.new - - -> { a.attached_object }.should raise_error(TypeError) - end - - it "raises TypeError for special singleton classes" do - -> { nil.singleton_class.attached_object }.should raise_error(TypeError) - -> { true.singleton_class.attached_object }.should raise_error(TypeError) - -> { false.singleton_class.attached_object }.should raise_error(TypeError) - end - end -end diff --git a/spec/ruby/core/class/dup_spec.rb b/spec/ruby/core/class/dup_spec.rb index c09ed71b31..701fd72e19 100644 --- a/spec/ruby/core/class/dup_spec.rb +++ b/spec/ruby/core/class/dup_spec.rb @@ -61,7 +61,4 @@ describe "Class#dup" do CoreClassSpecs::RecordCopy.name.should == "CoreClassSpecs::RecordCopy" end - it "raises TypeError if called on BasicObject" do - -> { BasicObject.dup }.should raise_error(TypeError, "can't copy the root class") - end end diff --git a/spec/ruby/core/class/subclasses_spec.rb b/spec/ruby/core/class/subclasses_spec.rb index a16b934d4f..ddbcfb02c0 100644 --- a/spec/ruby/core/class/subclasses_spec.rb +++ b/spec/ruby/core/class/subclasses_spec.rb @@ -31,28 +31,6 @@ ruby_version_is '3.1' do ModuleSpecs::Parent.subclasses.should == ModuleSpecs::Parent.subclasses.uniq end - it "works when creating subclasses concurrently" do - t = 16 - n = 1000 - go = false - superclass = Class.new - - threads = t.times.map do - Thread.new do - Thread.pass until go - n.times.map do - Class.new(superclass) - end - end - end - - go = true - classes = threads.map(&:value) - - superclass.subclasses.size.should == t * n - superclass.subclasses.each { |c| c.should be_kind_of(Class) } - end - def assert_subclasses(mod,subclasses) mod.subclasses.sort_by(&:inspect).should == subclasses.sort_by(&:inspect) end diff --git a/spec/ruby/core/comparable/clamp_spec.rb b/spec/ruby/core/comparable/clamp_spec.rb index 796d4a18c1..393496fc76 100644 --- a/spec/ruby/core/comparable/clamp_spec.rb +++ b/spec/ruby/core/comparable/clamp_spec.rb @@ -2,6 +2,14 @@ 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) @@ -40,39 +48,41 @@ describe 'Comparable#clamp' do c.clamp(one, two).should equal(two) 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) + 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 end end diff --git a/spec/ruby/core/complex/comparison_spec.rb b/spec/ruby/core/complex/comparison_spec.rb index 3a3142f234..2a437afb71 100644 --- a/spec/ruby/core/complex/comparison_spec.rb +++ b/spec/ruby/core/complex/comparison_spec.rb @@ -1,25 +1,27 @@ require_relative '../../spec_helper' describe "Complex#<=>" 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 + 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 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 + (Complex(5) <=> 2).should == 1 + (Complex(2) <=> 3).should == -1 + (Complex(2) <=> 2).should == 0 + end end end diff --git a/spec/ruby/core/complex/inspect_spec.rb b/spec/ruby/core/complex/inspect_spec.rb index 7a89ec6854..71aabde5be 100644 --- a/spec/ruby/core/complex/inspect_spec.rb +++ b/spec/ruby/core/complex/inspect_spec.rb @@ -1,5 +1,4 @@ require_relative '../../spec_helper' -require_relative '../numeric/fixtures/classes' describe "Complex#inspect" do it "returns (${real}+${image}i) for positive imaginary parts" do @@ -14,22 +13,4 @@ describe "Complex#inspect" do Complex(-1, -4).inspect.should == "(-1-4i)" Complex(-7, -6.7).inspect.should == "(-7-6.7i)" end - - it "calls #inspect on real and imaginary" do - real = NumericSpecs::Subclass.new - real.should_receive(:inspect).and_return("1") - imaginary = NumericSpecs::Subclass.new - imaginary.should_receive(:inspect).and_return("2") - imaginary.should_receive(:<).any_number_of_times.and_return(false) - Complex(real, imaginary).inspect.should == "(1+2i)" - end - - it "adds an `*' before the `i' if the last character of the imaginary part is not numeric" do - real = NumericSpecs::Subclass.new - real.should_receive(:inspect).and_return("(1)") - imaginary = NumericSpecs::Subclass.new - imaginary.should_receive(:inspect).and_return("(2)") - imaginary.should_receive(:<).any_number_of_times.and_return(false) - Complex(real, imaginary).inspect.should == "((1)+(2)*i)" - end end diff --git a/spec/ruby/core/complex/to_s_spec.rb b/spec/ruby/core/complex/to_s_spec.rb index 7677dcd0b5..989a7ae0b7 100644 --- a/spec/ruby/core/complex/to_s_spec.rb +++ b/spec/ruby/core/complex/to_s_spec.rb @@ -1,5 +1,4 @@ require_relative '../../spec_helper' -require_relative '../numeric/fixtures/classes' describe "Complex#to_s" do describe "when self's real component is 0" do @@ -42,13 +41,4 @@ describe "Complex#to_s" do it "returns 1+NaN*i for Complex(1, NaN)" do Complex(1, nan_value).to_s.should == "1+NaN*i" end - - it "treats real and imaginary parts as strings" do - real = NumericSpecs::Subclass.new - real.should_receive(:to_s).and_return("1") - imaginary = NumericSpecs::Subclass.new - imaginary.should_receive(:to_s).and_return("2") - imaginary.should_receive(:<).any_number_of_times.and_return(false) - Complex(real, imaginary).to_s.should == "1+2i" - end end diff --git a/spec/ruby/core/data/constants_spec.rb b/spec/ruby/core/data/constants_spec.rb index 2eb43d501e..1d469f9237 100644 --- a/spec/ruby/core/data/constants_spec.rb +++ b/spec/ruby/core/data/constants_spec.rb @@ -1,21 +1,23 @@ require_relative '../../spec_helper' -ruby_version_is ''...'3.2' do +ruby_version_is ''...'3.0' do describe "Data" do - it "does not exist anymore" do - Object.should_not have_constant(:Data) + it "is a subclass of Object" do + suppress_warning do + Data.superclass.should == Object + end + end + + it "is deprecated" do + -> { Data }.should complain(/constant ::Data is deprecated/) end end end -ruby_version_is '3.2' do +ruby_version_is '3.0' do describe "Data" do - it "is a new constant" do - Data.superclass.should == Object - end - - it "is not deprecated" do - -> { Data }.should_not complain + it "does not exist anymore" do + Object.should_not have_constant(:Data) end end end diff --git a/spec/ruby/core/data/define_spec.rb b/spec/ruby/core/data/define_spec.rb deleted file mode 100644 index 2aa2c50d4c..0000000000 --- a/spec/ruby/core/data/define_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/classes' - -ruby_version_is "3.2" do - describe "Data.define" do - it "accepts no arguments" do - empty_data = Data.define - empty_data.members.should == [] - end - - it "accepts symbols" do - movie = Data.define(:title, :year) - movie.members.should == [:title, :year] - end - - it "accepts strings" do - movie = Data.define("title", "year") - movie.members.should == [:title, :year] - end - - it "accepts a mix of strings and symbols" do - movie = Data.define("title", :year, "genre") - movie.members.should == [:title, :year, :genre] - end - - it "accepts a block" do - movie = Data.define(:title, :year) do - def title_with_year - "#{title} (#{year})" - end - end - movie.members.should == [:title, :year] - movie.new("Matrix", 1999).title_with_year.should == "Matrix (1999)" - end - end -end diff --git a/spec/ruby/core/data/fixtures/classes.rb b/spec/ruby/core/data/fixtures/classes.rb deleted file mode 100644 index 46a6b48bb2..0000000000 --- a/spec/ruby/core/data/fixtures/classes.rb +++ /dev/null @@ -1,5 +0,0 @@ -module DataSpecs - guard -> { ruby_version_is "3.2" and Data.respond_to?(:define) } do - Measure = Data.define(:amount, :unit) - end -end diff --git a/spec/ruby/core/data/initialize_spec.rb b/spec/ruby/core/data/initialize_spec.rb deleted file mode 100644 index 94470cd108..0000000000 --- a/spec/ruby/core/data/initialize_spec.rb +++ /dev/null @@ -1,58 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/classes' - -ruby_version_is "3.2" do - describe "Data#initialize" do - it "accepts positional arguments" do - data = DataSpecs::Measure.new(42, "km") - - data.amount.should == 42 - data.unit.should == "km" - end - - it "accepts alternative positional arguments" do - data = DataSpecs::Measure[42, "km"] - - data.amount.should == 42 - data.unit.should == "km" - end - - it "accepts keyword arguments" do - data = DataSpecs::Measure.new(amount: 42, unit: "km") - - data.amount.should == 42 - data.unit.should == "km" - end - - it "accepts alternative keyword arguments" do - data = DataSpecs::Measure[amount: 42, unit: "km"] - - data.amount.should == 42 - data.unit.should == "km" - end - - it "raises ArgumentError if no arguments are given" do - -> { - DataSpecs::Measure.new - }.should raise_error(ArgumentError) { |e| - e.message.should.include?("missing keywords: :amount, :unit") - } - end - - it "raises ArgumentError if at least one argument is missing" do - -> { - DataSpecs::Measure.new(unit: "km") - }.should raise_error(ArgumentError) { |e| - e.message.should.include?("missing keyword: :amount") - } - end - - it "raises ArgumentError if unknown keyword is given" do - -> { - DataSpecs::Measure.new(amount: 42, unit: "km", system: "metric") - }.should raise_error(ArgumentError) { |e| - e.message.should.include?("unknown keyword: :system") - } - end - end -end diff --git a/spec/ruby/core/dir/children_spec.rb b/spec/ruby/core/dir/children_spec.rb index 03698cc246..986c8f38c0 100644 --- a/spec/ruby/core/dir/children_spec.rb +++ b/spec/ruby/core/dir/children_spec.rb @@ -105,6 +105,14 @@ 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 520186e79e..f7980991e5 100644 --- a/spec/ruby/core/dir/each_child_spec.rb +++ b/spec/ruby/core/dir/each_child_spec.rb @@ -15,6 +15,13 @@ 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 91c30fccae..9aa58657db 100644 --- a/spec/ruby/core/dir/entries_spec.rb +++ b/spec/ruby/core/dir/entries_spec.rb @@ -40,6 +40,13 @@ 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/exist_spec.rb b/spec/ruby/core/dir/exist_spec.rb index 9023de533f..43987b0f32 100644 --- a/spec/ruby/core/dir/exist_spec.rb +++ b/spec/ruby/core/dir/exist_spec.rb @@ -13,11 +13,3 @@ describe "Dir.exist?" do it_behaves_like :dir_exist, :exist? end - -ruby_version_is "3.2" do - describe "Dir.exists?" do - it "has been removed" do - Dir.should_not.respond_to?(:exists?) - end - end -end diff --git a/spec/ruby/core/dir/fchdir_spec.rb b/spec/ruby/core/dir/fchdir_spec.rb deleted file mode 100644 index 429e569691..0000000000 --- a/spec/ruby/core/dir/fchdir_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' - -ruby_version_is '3.3' do - guard -> { Dir.respond_to? :fchdir } do - describe "Dir.fchdir" do - before :all do - DirSpecs.create_mock_dirs - end - - after :all do - DirSpecs.delete_mock_dirs - end - - before :each do - @dirs = [Dir.new('.')] - @original = @dirs.first.fileno - end - - after :each do - Dir.fchdir(@original) - @dirs.each(&:close) - end - - it "changes to the specified directory" do - dir = Dir.new(DirSpecs.mock_dir) - @dirs << dir - Dir.fchdir dir.fileno - Dir.pwd.should == DirSpecs.mock_dir - end - - it "returns 0 when successfully changing directory" do - Dir.fchdir(@original).should == 0 - end - - it "returns the value of the block when a block is given" do - Dir.fchdir(@original) { :block_value }.should == :block_value - end - - it "changes to the specified directory for the duration of the block" do - pwd = Dir.pwd - dir = Dir.new(DirSpecs.mock_dir) - @dirs << dir - Dir.fchdir(dir.fileno) { Dir.pwd }.should == DirSpecs.mock_dir - Dir.pwd.should == pwd - end - - it "raises a SystemCallError if the file descriptor given is not valid" do - -> { Dir.fchdir(-1) }.should raise_error(SystemCallError) - -> { Dir.fchdir(-1) { } }.should raise_error(SystemCallError) - end - - it "raises a SystemCallError if the file descriptor given is not for a directory" do - -> { Dir.fchdir $stdout.fileno }.should raise_error(SystemCallError) - -> { Dir.fchdir($stdout.fileno) { } }.should raise_error(SystemCallError) - end - end - end - - guard_not -> { Dir.respond_to? :fchdir } do - describe "Dir.fchdir" do - it "raises NotImplementedError" do - -> { Dir.fchdir 1 }.should raise_error(NotImplementedError) - -> { Dir.fchdir(1) { } }.should raise_error(NotImplementedError) - end - end - end -end diff --git a/spec/ruby/core/dir/fixtures/common.rb b/spec/ruby/core/dir/fixtures/common.rb index 087f46b331..c32b056819 100644 --- a/spec/ruby/core/dir/fixtures/common.rb +++ b/spec/ruby/core/dir/fixtures/common.rb @@ -82,7 +82,6 @@ module DirSpecs special/test{1}/file[1] special/{}/special - special/test\ +()[]{}/hello_world.erb ] platform_is_not :windows do @@ -95,37 +94,18 @@ 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 9cf34b1d71..c3ddb27a84 100644 --- a/spec/ruby/core/dir/foreach_spec.rb +++ b/spec/ruby/core/dir/foreach_spec.rb @@ -41,13 +41,13 @@ 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 } - - dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::ISO_8859_1).to_a.sort - dirs.each { |dir| dir.encoding.should == Encoding::ISO_8859_1 } + dirs.each {|dir| dir.encoding.should == Encoding::UTF_8} + end - Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::ISO_8859_1) do |f| - f.encoding.should == Encoding::ISO_8859_1 + 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")} end end diff --git a/spec/ruby/core/dir/glob_spec.rb b/spec/ruby/core/dir/glob_spec.rb index 32f515c81d..295a7ab920 100644 --- a/spec/ruby/core/dir/glob_spec.rb +++ b/spec/ruby/core/dir/glob_spec.rb @@ -79,7 +79,6 @@ describe "Dir.glob" do nested/ nested/.dotsubir/ special/ - special/test\ +()[]{}/ special/test{1}/ special/{}/ subdir_one/ @@ -106,11 +105,11 @@ describe "Dir.glob" do ruby_version_is '3.1' do it "recursively matches files and directories in nested dot subdirectory except . with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH" do expected = %w[ - nested/. - nested/.dotsubir - nested/.dotsubir/.dotfile - nested/.dotsubir/nondotfile - ] + nested/. + nested/.dotsubir + nested/.dotsubir/.dotfile + nested/.dotsubir/nondotfile + ] Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort end @@ -131,7 +130,6 @@ describe "Dir.glob" do ./nested/ ./nested/.dotsubir/ ./special/ - ./special/test\ +()[]{}/ ./special/test{1}/ ./special/{}/ ./subdir_one/ @@ -182,134 +180,6 @@ describe "Dir.glob" do Dir.glob('**/**/**').should_not.empty? end - it "handles **/** with base keyword argument" do - Dir.glob('**/**', base: "dir").should == ["filename_ordering"] - - expected = %w[ - nested - nested/directory - nested/directory/structure - nested/directory/structure/bar - nested/directory/structure/baz - nested/directory/structure/file_one - nested/directory/structure/file_one.ext - nested/directory/structure/foo - nondotfile - ].sort - - Dir.glob('**/**', base: "deeply").sort.should == expected - end - - it "handles **/ with base keyword argument" do - expected = %w[ - / - directory/ - directory/structure/ - ] - Dir.glob('**/', base: "deeply/nested").sort.should == expected - end - - it "handles **/nondotfile with base keyword argument" do - expected = %w[ - deeply/nondotfile - nondotfile - subdir_one/nondotfile - subdir_two/nondotfile - ] - Dir.glob('**/nondotfile', base: ".").sort.should == expected - end - - it "handles **/nondotfile with base keyword argument and FNM_DOTMATCH" do - expected = %w[ - .dotsubdir/nondotfile - deeply/nondotfile - nested/.dotsubir/nondotfile - nondotfile - subdir_one/nondotfile - subdir_two/nondotfile - ] - Dir.glob('**/nondotfile', File::FNM_DOTMATCH, base: ".").sort.should == expected - end - - it "handles **/.dotfile with base keyword argument" do - expected = %w[ - .dotfile - deeply/.dotfile - subdir_one/.dotfile - ] - Dir.glob('**/.dotfile', base: ".").sort.should == expected - end - - it "handles **/.dotfile with base keyword argument and FNM_DOTMATCH" do - expected = %w[ - .dotfile - .dotsubdir/.dotfile - deeply/.dotfile - nested/.dotsubir/.dotfile - subdir_one/.dotfile - ] - Dir.glob('**/.dotfile', File::FNM_DOTMATCH, base: ".").sort.should == expected - end - - it "handles **/.* with base keyword argument" do - expected = %w[ - .dotfile.ext - directory/structure/.ext - ].sort - - Dir.glob('**/.*', base: "deeply/nested").sort.should == expected - end - - # < 3.1 include a "." entry for every dir: ["directory/.", "directory/structure/.", ...] - ruby_version_is '3.1' do - it "handles **/.* with base keyword argument and FNM_DOTMATCH" do - expected = %w[ - . - .dotfile.ext - directory/structure/.ext - ].sort - - Dir.glob('**/.*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected - end - - it "handles **/** with base keyword argument and FNM_DOTMATCH" do - expected = %w[ - . - .dotfile.ext - directory - directory/structure - directory/structure/.ext - directory/structure/bar - directory/structure/baz - directory/structure/file_one - directory/structure/file_one.ext - directory/structure/foo - ].sort - - Dir.glob('**/**', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected - end - end - - it "handles **/*pattern* with base keyword argument and FNM_DOTMATCH" do - expected = %w[ - .dotfile.ext - directory/structure/file_one - directory/structure/file_one.ext - ] - - Dir.glob('**/*file*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected - end - - it "handles **/glob with base keyword argument and FNM_EXTGLOB" do - expected = %w[ - directory/structure/bar - directory/structure/file_one - directory/structure/file_one.ext - ] - - Dir.glob('**/*{file,bar}*', File::FNM_EXTGLOB, base: "deeply/nested").sort.should == expected - end - it "handles simple filename patterns" do Dir.glob('.dotfile').should == ['.dotfile'] end @@ -352,30 +222,5 @@ 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 3cf745ab46..e8c7f5970b 100644 --- a/spec/ruby/core/dir/home_spec.rb +++ b/spec/ruby/core/dir/home_spec.rb @@ -20,41 +20,14 @@ describe "Dir.home" do Dir.home.should_not.frozen? end - it "returns a string with the filesystem encoding" do - Dir.home.encoding.should == Encoding.find("filesystem") - end - - platform_is_not :windows do - it "works even if HOME is unset" do - ENV.delete('HOME') - Dir.home.should.start_with?('/') - Dir.home.encoding.should == Encoding.find("filesystem") - end - end - platform_is :windows do - ruby_version_is "3.2" do + ruby_version_is "3.0" do it "returns the home directory with forward slashs and as UTF-8" do ENV['HOME'] = "C:\\rubyspäc\\home" home = Dir.home home.should == "C:/rubyspäc/home" home.encoding.should == Encoding::UTF_8 end - - it "retrieves the directory from HOME, USERPROFILE, HOMEDRIVE/HOMEPATH and the WinAPI in that order" do - old_dirs = [ENV.delete('HOME'), ENV.delete('USERPROFILE'), ENV.delete('HOMEDRIVE'), ENV.delete('HOMEPATH')] - - Dir.home.should == old_dirs[1].gsub("\\", "/") - ENV['HOMEDRIVE'] = "C:" - ENV['HOMEPATH'] = "\\rubyspec\\home1" - Dir.home.should == "C:/rubyspec/home1" - ENV['USERPROFILE'] = "C:\\rubyspec\\home2" - Dir.home.should == "C:/rubyspec/home2" - ENV['HOME'] = "C:\\rubyspec\\home3" - Dir.home.should == "C:/rubyspec/home3" - ensure - ENV['HOME'], ENV['USERPROFILE'], ENV['HOMEDRIVE'], ENV['HOMEPATH'] = *old_dirs - end end end end @@ -66,7 +39,7 @@ describe "Dir.home" do end end - platform_is_not :windows, :solaris, :android, :wasi do + platform_is_not :windows, :solaris, :android do it "returns the named user's home directory, from the user database" do Dir.home(ENV['USER']).should == `echo ~#{ENV['USER']}`.chomp end @@ -75,19 +48,9 @@ describe "Dir.home" do it "returns a non-frozen string" do Dir.home(ENV['USER']).should_not.frozen? end - - it "returns a string with the filesystem encoding" do - Dir.home(ENV['USER']).encoding.should == Encoding.find("filesystem") - end end it "raises an ArgumentError if the named user doesn't exist" do -> { Dir.home('geuw2n288dh2k') }.should raise_error(ArgumentError) end - - describe "when called with a nil user name" do - it "returns the current user's home directory, reading $HOME first" do - Dir.home(nil).should == "/rubyspec_home" - end - end end diff --git a/spec/ruby/core/dir/mkdir_spec.rb b/spec/ruby/core/dir/mkdir_spec.rb index 076ec19dd9..0ed28f5a99 100644 --- a/spec/ruby/core/dir/mkdir_spec.rb +++ b/spec/ruby/core/dir/mkdir_spec.rb @@ -46,7 +46,7 @@ describe "Dir.mkdir" do end end - it "calls #to_path on non-String path arguments" do + it "calls #to_path on non-String arguments" do DirSpecs.clear_dirs p = mock('path') p.should_receive(:to_path).and_return(DirSpecs.mock_dir('nonexisting')) @@ -54,22 +54,6 @@ describe "Dir.mkdir" do DirSpecs.clear_dirs end - it "calls #to_int on non-Integer permissions argument" do - DirSpecs.clear_dirs - path = DirSpecs.mock_dir('nonexisting') - permissions = mock('permissions') - permissions.should_receive(:to_int).and_return(0666) - Dir.mkdir(path, permissions) - DirSpecs.clear_dirs - end - - it "raises TypeError if non-Integer permissions argument does not have #to_int method" do - path = DirSpecs.mock_dir('nonexisting') - permissions = Object.new - - -> { Dir.mkdir(path, permissions) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer') - end - it "raises a SystemCallError if any of the directories in the path before the last does not exist" do -> { Dir.mkdir "#{DirSpecs.nonexistent}/subdir" }.should raise_error(SystemCallError) end diff --git a/spec/ruby/core/dir/read_spec.rb b/spec/ruby/core/dir/read_spec.rb index 276930c6b7..59de2e81cf 100644 --- a/spec/ruby/core/dir/read_spec.rb +++ b/spec/ruby/core/dir/read_spec.rb @@ -39,38 +39,5 @@ 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/chroot.rb b/spec/ruby/core/dir/shared/chroot.rb index a8f7c10a19..b14a433670 100644 --- a/spec/ruby/core/dir/shared/chroot.rb +++ b/spec/ruby/core/dir/shared/chroot.rb @@ -2,8 +2,8 @@ describe :dir_chroot_as_root, shared: true do before :all do DirSpecs.create_mock_dirs - @real_root = "../" * (__dir__.count('/') - 1) - @ref_dir = File.join("/", File.basename(Dir["/*"].first)) + @real_root = "../" * (File.dirname(__FILE__).count('/') - 1) + @ref_dir = File.join("/", Dir.new('/').entries.first) end after :all do @@ -14,13 +14,10 @@ describe :dir_chroot_as_root, shared: true do DirSpecs.delete_mock_dirs end - # Pending until https://github.com/ruby/ruby/runs/8075149420 is fixed - compilations_ci = ENV["GITHUB_WORKFLOW"] == "Compilations" - it "can be used to change the process' root directory" do - -> { Dir.send(@method, __dir__) }.should_not raise_error + -> { Dir.send(@method, File.dirname(__FILE__)) }.should_not raise_error File.should.exist?("/#{File.basename(__FILE__)}") - end unless compilations_ci + end it "returns 0 if successful" do Dir.send(@method, '/').should == 0 @@ -34,7 +31,7 @@ describe :dir_chroot_as_root, shared: true do Dir.send(@method, @real_root) File.should.exist?(@ref_dir) File.should_not.exist?("/#{File.basename(__FILE__)}") - end unless compilations_ci + end it "calls #to_path on non-String argument" do p = mock('path') diff --git a/spec/ruby/core/dir/shared/exist.rb b/spec/ruby/core/dir/shared/exist.rb index 2ea4f88a80..765d1b656c 100644 --- a/spec/ruby/core/dir/shared/exist.rb +++ b/spec/ruby/core/dir/shared/exist.rb @@ -1,6 +1,6 @@ describe :dir_exist, shared: true do it "returns true if the given directory exists" do - Dir.send(@method, __dir__).should be_true + Dir.send(@method, File.dirname(__FILE__)).should be_true end it "returns true for '.'" do @@ -20,7 +20,7 @@ describe :dir_exist, shared: true do end it "understands relative paths" do - Dir.send(@method, __dir__ + '/../').should be_true + Dir.send(@method, File.dirname(__FILE__) + '/../').should be_true end it "returns false if the given directory doesn't exist" do @@ -28,7 +28,7 @@ describe :dir_exist, shared: true do end it "doesn't require the name to have a trailing slash" do - dir = __dir__ + dir = File.dirname(__FILE__) dir.sub!(/\/$/,'') Dir.send(@method, dir).should be_true end @@ -50,7 +50,7 @@ describe :dir_exist, shared: true do it "calls #to_path on non String arguments" do p = mock('path') - p.should_receive(:to_path).and_return(__dir__) + p.should_receive(:to_path).and_return(File.dirname(__FILE__)) Dir.send(@method, p) end end diff --git a/spec/ruby/core/dir/shared/glob.rb b/spec/ruby/core/dir/shared/glob.rb index 27ae0e3000..a38ff8aa68 100644 --- a/spec/ruby/core/dir/shared/glob.rb +++ b/spec/ruby/core/dir/shared/glob.rb @@ -23,26 +23,39 @@ describe :dir_glob, shared: true do Dir.send(@method, obj).should == %w[file_one.ext] end - it "raises an ArgumentError if the string contains \\0" do - -> {Dir.send(@method, "file_o*\0file_t*")}.should raise_error ArgumentError, /nul-separated/ + 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 - it "result is sorted by default" do - result = Dir.send(@method, '*') - result.should == result.sort + 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 end - it "result is sorted with sort: true" do - result = Dir.send(@method, '*', sort: true) - result.should == result.sort - end + ruby_version_is "3.0" do + it "result is sorted by default" do + result = Dir.send(@method, '*') + result.should == result.sort + end - it "sort: false returns same files" do - result = Dir.send(@method,'*', sort: false) - result.sort.should == Dir.send(@method, '*').sort + it "result is sorted with sort: true" do + result = Dir.send(@method, '*', sort: true) + result.should == result.sort + end + + it "sort: false returns same files" do + result = Dir.send(@method,'*', sort: false) + result.sort.should == Dir.send(@method, '*').sort + end end - ruby_version_is ""..."3.1" do + ruby_version_is "3.0"..."3.1" do it "result is sorted with any non false value of sort:" do result = Dir.send(@method, '*', sort: 0) result.should == result.sort @@ -109,10 +122,6 @@ describe :dir_glob, shared: true do it "matches files with backslashes in their name" do Dir.glob('special/\\\\{a,b}').should == ['special/\a'] end - - it "matches directory with special characters in their name in complex patterns" do - Dir.glob("special/test +()\\[\\]\\{\\}/hello_world{.{en},}{.{html},}{+{phone},}{.{erb},}").should == ['special/test +()[]{}/hello_world.erb'] - end end it "matches regexp special ^" do @@ -227,7 +236,6 @@ describe :dir_glob, shared: true do dir/ nested/ special/ - special/test\ +()[]{}/ special/test{1}/ special/{}/ subdir_one/ diff --git a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb index ab34ebf33f..802d8e7cb1 100644 --- a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb +++ b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb @@ -14,10 +14,6 @@ describe "Encoding::Converter#primitive_convert" do -> { @ec.primitive_convert("","") }.should_not raise_error end - it "raises FrozenError when the destination buffer is a frozen String" do - -> { @ec.primitive_convert("", "".freeze) }.should raise_error(FrozenError) - end - it "accepts nil for the destination byte offset" do -> { @ec.primitive_convert("","", nil) }.should_not raise_error end diff --git a/spec/ruby/core/encoding/default_external_spec.rb b/spec/ruby/core/encoding/default_external_spec.rb index 9aae4976e0..682d49d37c 100644 --- a/spec/ruby/core/encoding/default_external_spec.rb +++ b/spec/ruby/core/encoding/default_external_spec.rb @@ -18,9 +18,11 @@ describe "Encoding.default_external" do Encoding.default_external.should == Encoding::SHIFT_JIS end - platform_is :windows do - it 'is UTF-8 by default on Windows' do - Encoding.default_external.should == Encoding::UTF_8 + ruby_version_is "3.0" do + platform_is :windows do + it 'is UTF-8 by default on Windows' do + Encoding.default_external.should == Encoding::UTF_8 + end end end end diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb index 2b15fc1a0f..f5fa6f55e3 100644 --- a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb +++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative '../fixtures/classes' describe "Encoding::InvalidByteSequenceError#destination_encoding_name" do diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb index c2ed6de1d8..43be3ddd71 100644 --- a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb +++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative '../fixtures/classes' describe "Encoding::InvalidByteSequenceError#destination_encoding" do diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb index d2fc360dce..a8f7354b16 100644 --- a/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb +++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb @@ -1,5 +1,4 @@ # -*- encoding: binary -*- -require_relative "../../../spec_helper" require_relative '../fixtures/classes' describe "Encoding::InvalidByteSequenceError#error_bytes" do diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb index 9866310c25..93823b5db4 100644 --- a/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb +++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb @@ -1,5 +1,4 @@ # -*- encoding: binary -*- -require_relative "../../../spec_helper" require_relative '../fixtures/classes' describe "Encoding::InvalidByteSequenceError#readagain_bytes" do diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb index a9464114a8..bd3a51cbc5 100644 --- a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb +++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative '../fixtures/classes' describe "Encoding::UndefinedConversionError#source_encoding_name" do diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb index 7fdc0a122b..f43d6d5830 100644 --- a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb +++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative '../fixtures/classes' describe "Encoding::InvalidByteSequenceError#source_encoding" do diff --git a/spec/ruby/core/encoding/list_spec.rb b/spec/ruby/core/encoding/list_spec.rb index bd3d5b7bc0..8efd94ab9c 100644 --- a/spec/ruby/core/encoding/list_spec.rb +++ b/spec/ruby/core/encoding/list_spec.rb @@ -40,8 +40,10 @@ describe "Encoding.list" do Encoding.list.should.include?(Encoding::UTF_8) end - it 'includes CESU-8 encoding' do - Encoding.list.should.include?(Encoding::CESU_8) + ruby_version_is "2.7" do + it 'includes CESU-8 encoding' do + Encoding.list.should.include?(Encoding::CESU_8) + end end # TODO: Find example that illustrates this diff --git a/spec/ruby/core/encoding/name_spec.rb b/spec/ruby/core/encoding/name_spec.rb index dce9347978..5eadb1d2f5 100644 --- a/spec/ruby/core/encoding/name_spec.rb +++ b/spec/ruby/core/encoding/name_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative 'shared/name' describe "Encoding#name" do diff --git a/spec/ruby/core/encoding/replicate_spec.rb b/spec/ruby/core/encoding/replicate_spec.rb index 498d03581a..45727a5c0d 100644 --- a/spec/ruby/core/encoding/replicate_spec.rb +++ b/spec/ruby/core/encoding/replicate_spec.rb @@ -2,82 +2,66 @@ require_relative '../../spec_helper' describe "Encoding#replicate" do - ruby_version_is ""..."3.3" do - before :all do - @i = 0 - end - - before :each do - @i += 1 - @prefix = "RS#{@i}" - end - - it "returns a replica of ASCII" do - name = @prefix + '-ASCII' - e = suppress_warning { Encoding::ASCII.replicate(name) } - e.name.should == name - Encoding.find(name).should == e + before :all do + @i = 0 + end - "a".force_encoding(e).valid_encoding?.should be_true - "\x80".force_encoding(e).valid_encoding?.should be_false - end + before :each do + @i += 1 + @prefix = "RS#{@i}" + end - it "returns a replica of UTF-8" do - name = @prefix + 'UTF-8' - e = suppress_warning { Encoding::UTF_8.replicate(name) } - e.name.should == name - Encoding.find(name).should == e + it "returns a replica of ASCII" do + name = @prefix + '-ASCII' + e = Encoding::ASCII.replicate(name) + e.name.should == name + Encoding.find(name).should == e - "a".force_encoding(e).valid_encoding?.should be_true - "\u3042".force_encoding(e).valid_encoding?.should be_true - "\x80".force_encoding(e).valid_encoding?.should be_false - end + "a".force_encoding(e).valid_encoding?.should be_true + "\x80".force_encoding(e).valid_encoding?.should be_false + end - it "returns a replica of UTF-16BE" do - name = @prefix + 'UTF-16-BE' - e = suppress_warning { Encoding::UTF_16BE.replicate(name) } - e.name.should == name - Encoding.find(name).should == e + it "returns a replica of UTF-8" do + name = @prefix + 'UTF-8' + e = Encoding::UTF_8.replicate(name) + e.name.should == name + Encoding.find(name).should == e - "a".force_encoding(e).valid_encoding?.should be_false - "\x30\x42".force_encoding(e).valid_encoding?.should be_true - "\x80".force_encoding(e).valid_encoding?.should be_false - end + "a".force_encoding(e).valid_encoding?.should be_true + "\u3042".force_encoding(e).valid_encoding?.should be_true + "\x80".force_encoding(e).valid_encoding?.should be_false + end - it "returns a replica of ISO-2022-JP" do - name = @prefix + 'ISO-2022-JP' - e = suppress_warning { Encoding::ISO_2022_JP.replicate(name) } - Encoding.find(name).should == e + it "returns a replica of UTF-16BE" do + name = @prefix + 'UTF-16-BE' + e = Encoding::UTF_16BE.replicate(name) + e.name.should == name + Encoding.find(name).should == e - e.name.should == name - e.dummy?.should be_true - end + "a".force_encoding(e).valid_encoding?.should be_false + "\x30\x42".force_encoding(e).valid_encoding?.should be_true + "\x80".force_encoding(e).valid_encoding?.should be_false + end - # NOTE: it's unclear of the value of this (for the complexity cost of it), - # but it is the current CRuby behavior. - it "can be associated with a String" do - name = @prefix + '-US-ASCII' - e = suppress_warning { Encoding::US_ASCII.replicate(name) } - e.name.should == name - Encoding.find(name).should == e + it "returns a replica of ISO-2022-JP" do + name = @prefix + 'ISO-2022-JP' + e = Encoding::ISO_2022_JP.replicate(name) + Encoding.find(name).should == e - s = "abc".force_encoding(e) - s.encoding.should == e - s.encoding.name.should == name - end + e.name.should == name + e.dummy?.should be_true end - ruby_version_is "3.2"..."3.3" do - it "warns about deprecation" do - -> { - Encoding::US_ASCII.replicate('MY-US-ASCII') - }.should complain(/warning: Encoding#replicate is deprecated and will be removed in Ruby 3.3; use the original encoding instead/) - end - end + # NOTE: it's unclear of the value of this (for the complexity cost of it), + # but it is the current CRuby behavior. + it "can be associated with a String" do + name = @prefix + '-US-ASCII' + e = Encoding::US_ASCII.replicate(name) + e.name.should == name + Encoding.find(name).should == e - ruby_version_is "3.3" do - it "has been removed" do - Encoding::US_ASCII.should_not.respond_to?(:replicate, true) - end + s = "abc".force_encoding(e) + s.encoding.should == e + s.encoding.name.should == name end end diff --git a/spec/ruby/core/encoding/to_s_spec.rb b/spec/ruby/core/encoding/to_s_spec.rb index bab394a888..82d282386b 100644 --- a/spec/ruby/core/encoding/to_s_spec.rb +++ b/spec/ruby/core/encoding/to_s_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative 'shared/name' describe "Encoding#to_s" do diff --git a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb index a51a9f46a0..106fc7ecac 100644 --- a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb +++ b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative '../fixtures/classes' describe "Encoding::UndefinedConversionError#destination_encoding_name" do diff --git a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb index 905556407c..c6e24732fd 100644 --- a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb +++ b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative '../fixtures/classes' describe "Encoding::UndefinedConversionError#destination_encoding" do diff --git a/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb index 9cb55e6d95..780d81c1ee 100644 --- a/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb +++ b/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative '../fixtures/classes' describe "Encoding::UndefinedConversionError#error_char" do diff --git a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb index d5e60e78db..3b697cb82f 100644 --- a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb +++ b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative '../fixtures/classes' describe "Encoding::UndefinedConversionError#source_encoding_name" do diff --git a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb index de456a4b5a..9101d51e11 100644 --- a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb +++ b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative '../fixtures/classes' describe "Encoding::UndefinedConversionError#source_encoding" do diff --git a/spec/ruby/core/enumerable/all_spec.rb b/spec/ruby/core/enumerable/all_spec.rb index 160cd52628..b782f94a3e 100644 --- a/spec/ruby/core/enumerable/all_spec.rb +++ b/spec/ruby/core/enumerable/all_spec.rb @@ -131,6 +131,7 @@ 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 @@ -177,11 +178,5 @@ describe "Enumerable#all?" do multi.all?(pattern).should == true pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]] end - - it "ignores the block if there is an argument" do - -> { - EnumerableSpecs::Numerous.new(1, 2, 3, 4, 5).all?(String) { true }.should == false - }.should complain(/given block not used/) - end end end diff --git a/spec/ruby/core/enumerable/any_spec.rb b/spec/ruby/core/enumerable/any_spec.rb index 243f8735d5..636b1fa450 100644 --- a/spec/ruby/core/enumerable/any_spec.rb +++ b/spec/ruby/core/enumerable/any_spec.rb @@ -145,6 +145,7 @@ 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 @@ -190,11 +191,5 @@ describe "Enumerable#any?" do multi.any?(pattern).should == false pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]] end - - it "ignores the block if there is an argument" do - -> { - EnumerableSpecs::Numerous.new(1, 2, 3, 4, 5).any?(String) { true }.should == false - }.should complain(/given block not used/) - end end end diff --git a/spec/ruby/core/enumerable/chunk_spec.rb b/spec/ruby/core/enumerable/chunk_spec.rb index ed6304307f..c5579d67fa 100644 --- a/spec/ruby/core/enumerable/chunk_spec.rb +++ b/spec/ruby/core/enumerable/chunk_spec.rb @@ -29,11 +29,6 @@ describe "Enumerable#chunk" do result.should == [[1, [1, 2]], [0, [3]], [1, [2]], [0, [3]], [1, [2, 1]]] end - it "returns a partitioned Array of values" do - e = EnumerableSpecs::Numerous.new(1,2,3) - e.chunk { |x| x > 2 }.map(&:last).should == [[1, 2], [3]] - end - it "returns elements for which the block returns :_alone in separate Arrays" do e = EnumerableSpecs::Numerous.new(1, 2, 3, 2, 1) result = e.chunk { |x| x < 2 && :_alone }.to_a diff --git a/spec/ruby/core/enumerable/compact_spec.rb b/spec/ruby/core/enumerable/compact_spec.rb deleted file mode 100644 index 86e95dce08..0000000000 --- a/spec/ruby/core/enumerable/compact_spec.rb +++ /dev/null @@ -1,11 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/classes' - -ruby_version_is '3.1' do - describe "Enumerable#compact" do - it 'returns array without nil elements' do - arr = EnumerableSpecs::Numerous.new(nil, 1, 2, nil, true) - arr.compact.should == [1, 2, true] - end - end -end diff --git a/spec/ruby/core/enumerable/each_cons_spec.rb b/spec/ruby/core/enumerable/each_cons_spec.rb index 8fb31fb925..ba658203a2 100644 --- a/spec/ruby/core/enumerable/each_cons_spec.rb +++ b/spec/ruby/core/enumerable/each_cons_spec.rb @@ -56,12 +56,6 @@ describe "Enumerable#each_cons" do multi.each_cons(2).to_a.should == [[[1, 2], [3, 4, 5]], [[3, 4, 5], [6, 7, 8, 9]]] end - ruby_version_is "3.1" do - it "returns self when a block is given" do - @enum.each_cons(3){}.should == @enum - end - end - describe "when no block is given" do it "returns an enumerator" do e = @enum.each_cons(3) diff --git a/spec/ruby/core/enumerable/each_slice_spec.rb b/spec/ruby/core/enumerable/each_slice_spec.rb index a57a1dba81..2ea89f5e72 100644 --- a/spec/ruby/core/enumerable/each_slice_spec.rb +++ b/spec/ruby/core/enumerable/each_slice_spec.rb @@ -57,12 +57,6 @@ describe "Enumerable#each_slice" do e.to_a.should == @sliced end - ruby_version_is "3.1" do - it "returns self when a block is given" do - @enum.each_slice(3){}.should == @enum - end - end - it "gathers whole arrays as elements when each yields multiple" do multi = EnumerableSpecs::YieldsMulti.new multi.each_slice(2).to_a.should == [[[1, 2], [3, 4, 5]], [[6, 7, 8, 9]]] diff --git a/spec/ruby/core/enumerable/filter_map_spec.rb b/spec/ruby/core/enumerable/filter_map_spec.rb index aa4894230b..31acc277b4 100644 --- a/spec/ruby/core/enumerable/filter_map_spec.rb +++ b/spec/ruby/core/enumerable/filter_map_spec.rb @@ -1,24 +1,26 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -describe 'Enumerable#filter_map' do - before :each do - @numerous = EnumerableSpecs::Numerous.new(*(1..8).to_a) - end +ruby_version_is '2.7' do + 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) + it 'returns an enumerator when no block given' do + @numerous.filter_map.should be_an_instance_of(Enumerator) + end end end diff --git a/spec/ruby/core/enumerable/grep_spec.rb b/spec/ruby/core/enumerable/grep_spec.rb index 989358f01b..b81075291f 100644 --- a/spec/ruby/core/enumerable/grep_spec.rb +++ b/spec/ruby/core/enumerable/grep_spec.rb @@ -40,28 +40,43 @@ describe "Enumerable#grep" do $~.should == nil end - it "does not set $~ when given no block" do - "z" =~ /z/ # Reset $~ - ["abc", "def"].grep(/b/).should == ["abc"] - $&.should == "z" - end + ruby_version_is ""..."3.0.0" do + it "sets $~ to the last match when given no block" do + "z" =~ /z/ # Reset $~ + ["abc", "def"].grep(/b/).should == ["abc"] + + # Set by the failed match of "def" + $~.should == nil - it "does not modify Regexp.last_match without block" do - "z" =~ /z/ # Reset last match - ["abc", "def"].grep(/b/).should == ["abc"] - Regexp.last_match[0].should == "z" + ["abc", "def"].grep(/e/) + $&.should == "e" + end end - it "correctly handles non-string elements" do - 'set last match' =~ /set last (.*)/ - [:a, 'b', 'z', :c, 42, nil].grep(/[a-d]/).should == [:a, 'b', :c] - $1.should == 'match' + ruby_version_is "3.0.0" do + it "does not set $~ when given no block" do + "z" =~ /z/ # Reset $~ + ["abc", "def"].grep(/b/).should == ["abc"] + $&.should == "z" + end - o = Object.new - def o.to_str - 'hello' + it "does not modify Regexp.last_match without block" do + "z" =~ /z/ # Reset last match + ["abc", "def"].grep(/b/).should == ["abc"] + Regexp.last_match[0].should == "z" + end + + it "correctly handles non-string elements" do + 'set last match' =~ /set last (.*)/ + [:a, 'b', 'z', :c, 42, nil].grep(/[a-d]/).should == [:a, 'b', :c] + $1.should == 'match' + + o = Object.new + def o.to_str + 'hello' + end + [o].grep(/ll/).first.should.equal?(o) end - [o].grep(/ll/).first.should.equal?(o) end describe "with a block" do diff --git a/spec/ruby/core/enumerable/grep_v_spec.rb b/spec/ruby/core/enumerable/grep_v_spec.rb index ba19216968..35fde27eb6 100644 --- a/spec/ruby/core/enumerable/grep_v_spec.rb +++ b/spec/ruby/core/enumerable/grep_v_spec.rb @@ -20,28 +20,43 @@ describe "Enumerable#grep_v" do $&.should == "e" end - it "does not set $~ when given no block" do - "z" =~ /z/ # Reset $~ - ["abc", "def"].grep_v(/e/).should == ["abc"] - $&.should == "z" - end + ruby_version_is ""..."3.0.0" do + it "sets $~ to the last match when given no block" do + "z" =~ /z/ # Reset $~ + ["abc", "def"].grep_v(/e/).should == ["abc"] - it "does not modify Regexp.last_match without block" do - "z" =~ /z/ # Reset last match - ["abc", "def"].grep_v(/e/).should == ["abc"] - Regexp.last_match[0].should == "z" + # Set by the match of "def" + $&.should == "e" + + ["abc", "def"].grep_v(/b/) + $&.should == nil + end end - it "correctly handles non-string elements" do - 'set last match' =~ /set last (.*)/ - [:a, 'b', 'z', :c, 42, nil].grep_v(/[a-d]/).should == ['z', 42, nil] - $1.should == 'match' + ruby_version_is "3.0.0" do + it "does not set $~ when given no block" do + "z" =~ /z/ # Reset $~ + ["abc", "def"].grep_v(/e/).should == ["abc"] + $&.should == "z" + end + + it "does not modify Regexp.last_match without block" do + "z" =~ /z/ # Reset last match + ["abc", "def"].grep_v(/e/).should == ["abc"] + Regexp.last_match[0].should == "z" + end + + it "correctly handles non-string elements" do + 'set last match' =~ /set last (.*)/ + [:a, 'b', 'z', :c, 42, nil].grep_v(/[a-d]/).should == ['z', 42, nil] + $1.should == 'match' - o = Object.new - def o.to_str - 'hello' + o = Object.new + def o.to_str + 'hello' + end + [o].grep_v(/mm/).first.should.equal?(o) end - [o].grep_v(/mm/).first.should.equal?(o) end describe "without block" do diff --git a/spec/ruby/core/enumerable/group_by_spec.rb b/spec/ruby/core/enumerable/group_by_spec.rb index 4fd1603819..52b5a68d64 100644 --- a/spec/ruby/core/enumerable/group_by_spec.rb +++ b/spec/ruby/core/enumerable/group_by_spec.rb @@ -33,5 +33,15 @@ 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 fb42f13386..b898d00063 100644 --- a/spec/ruby/core/enumerable/none_spec.rb +++ b/spec/ruby/core/enumerable/none_spec.rb @@ -100,6 +100,7 @@ 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 @@ -143,11 +144,5 @@ describe "Enumerable#none?" do multi.none?(pattern).should == true pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]] end - - it "ignores the block if there is an argument" do - -> { - EnumerableSpecs::Numerous.new(1, 2, 3, 4, 5).none?(String) { true }.should == true - }.should complain(/given block not used/) - end end end diff --git a/spec/ruby/core/enumerable/one_spec.rb b/spec/ruby/core/enumerable/one_spec.rb index 4bf8623d2e..d54dd4a527 100644 --- a/spec/ruby/core/enumerable/one_spec.rb +++ b/spec/ruby/core/enumerable/one_spec.rb @@ -83,6 +83,7 @@ describe "Enumerable#one?" do end end + describe 'when given a pattern argument' do it "calls `===` on the pattern the return value " do pattern = EnumerableSpecs::Pattern.new { |x| x == 1 } @@ -90,6 +91,7 @@ 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 @@ -144,11 +146,5 @@ describe "Enumerable#one?" do multi.one?(pattern).should == false pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]] end - - it "ignores the block if there is an argument" do - -> { - EnumerableSpecs::Numerous.new(1, 2, 3, 4, "5").one?(String) { false }.should == true - }.should complain(/given block not used/) - end end end diff --git a/spec/ruby/core/enumerable/shared/entries.rb b/spec/ruby/core/enumerable/shared/entries.rb index e32eb23d2a..590ce73bcf 100644 --- a/spec/ruby/core/enumerable/shared/entries.rb +++ b/spec/ruby/core/enumerable/shared/entries.rb @@ -13,4 +13,14 @@ 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 693d34d675..12e0665dda 100644 --- a/spec/ruby/core/enumerable/shared/inject.rb +++ b/spec/ruby/core/enumerable/shared/inject.rb @@ -1,5 +1,3 @@ -require_relative '../../array/shared/iterable_and_tolerating_size_increasing' - describe :enumerable_inject, shared: true do it "with argument takes a block with an accumulator (with argument as initial value) and the current element. Value of block becomes new accumulator" do a = [] @@ -19,22 +17,7 @@ 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 - }.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true) - - -> { - [1, 2, 3].send(@method, 10, :-) { raise "we never get here"}.should == 4 - }.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true) - end - - it "does not warn when given a Symbol with $VERBOSE true" do - -> { - [1, 2].send(@method, 0, :+) - [1, 2].send(@method, :+) - EnumerableSpecs::Numerous.new(1, 2).send(@method, 0, :+) - EnumerableSpecs::Numerous.new(1, 2).send(@method, :+) - }.should_not complain(verbose: true) + EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, :-){ raise "we never get here"}.should == 4 end it "can take a symbol argument" do @@ -47,10 +30,10 @@ describe :enumerable_inject, shared: true do a.should == [[2, 5], [5, 3], [3, 6], [6, 1], [1, 4]] end - it "gathers whole arrays as elements when each yields multiple" do - multi = EnumerableSpecs::YieldsMulti.new - multi.send(@method, []) {|acc, e| acc << e }.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]] - end + it "gathers whole arrays as elements when each yields multiple" do + multi = EnumerableSpecs::YieldsMulti.new + multi.send(@method, []) {|acc, e| acc << e }.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]] + end it "with inject arguments(legacy rubycon)" do # with inject argument @@ -83,27 +66,4 @@ 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 - - it "tolerates increasing a collection size during iterating Array" do - array = [:a, :b, :c] - ScratchPad.record [] - i = 0 - - array.send(@method, nil) do |_, e| - ScratchPad << e - array << i if i < 100 - i += 1 - end - - actual = ScratchPad.recorded - expected = [:a, :b, :c] + (0..99).to_a - actual.sort_by(&:to_s).should == expected.sort_by(&:to_s) - 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/sum_spec.rb b/spec/ruby/core/enumerable/sum_spec.rb index 2eb74db6ac..4a978794e5 100644 --- a/spec/ruby/core/enumerable/sum_spec.rb +++ b/spec/ruby/core/enumerable/sum_spec.rb @@ -22,25 +22,12 @@ describe 'Enumerable#sum' do @enum.sum.should == 5/3r end - context 'with a block' do - it 'transforms the elements' do - @enum.sum { |element| element * 2 }.should == 10/3r - end - - it 'does not destructure array elements' do - class << @enum - def each - yield [1,2] - yield [3] - end - end - - @enum.sum(&:last).should == 5 - end + it 'takes a block to transform the elements' do + @enum.sum { |element| element * 2 }.should == 10/3r end # https://bugs.ruby-lang.org/issues/12217 - # https://github.com/ruby/ruby/blob/master/doc/ChangeLog/ChangeLog-2.4.0#L6208-L6214 + # https://github.com/ruby/ruby/blob/master/doc/ChangeLog-2.4.0#L6208-L6214 it "uses Kahan's compensated summation algorithm for precise sum of float numbers" do floats = [2.7800000000000002, 5.0, 2.5, 4.44, 3.89, 3.89, 4.44, 7.78, 5.0, 2.7800000000000002, 5.0, 2.5].to_enum naive_sum = floats.reduce { |sum, e| sum + e } diff --git a/spec/ruby/core/enumerable/tally_spec.rb b/spec/ruby/core/enumerable/tally_spec.rb index e0edc8dc75..92aac507ff 100644 --- a/spec/ruby/core/enumerable/tally_spec.rb +++ b/spec/ruby/core/enumerable/tally_spec.rb @@ -1,34 +1,36 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -describe "Enumerable#tally" do - before :each do - ScratchPad.record [] - end +ruby_version_is "2.7" do + 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 == [] + 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 end @@ -49,13 +51,6 @@ ruby_version_is "3.1" do enum.tally(hash).should equal(hash) end - it "calls #to_hash to convert argument to Hash implicitly if passed not a Hash" do - enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz') - object = Object.new - def object.to_hash; { 'foo' => 1 }; end - enum.tally(object).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1} - end - it "raises a FrozenError and does not update the given hash when the hash is frozen" do enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz') hash = { 'foo' => 1 }.freeze @@ -63,12 +58,6 @@ ruby_version_is "3.1" do hash.should == { 'foo' => 1 } end - it "raises a FrozenError even if enumerable is empty" do - enum = EnumerableSpecs::Numerous.new() - hash = { 'foo' => 1 }.freeze - -> { enum.tally(hash) }.should raise_error(FrozenError) - end - it "does not call given block" do enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz') enum.tally({ 'foo' => 1 }) { |v| ScratchPad << v } diff --git a/spec/ruby/core/enumerable/uniq_spec.rb b/spec/ruby/core/enumerable/uniq_spec.rb index a1ed44796f..e58dd36366 100644 --- a/spec/ruby/core/enumerable/uniq_spec.rb +++ b/spec/ruby/core/enumerable/uniq_spec.rb @@ -31,32 +31,76 @@ describe 'Enumerable#uniq' do [x, y].to_enum.uniq.should == [x, y] end - 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) + 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 - def obj.eql?(o) - false + obj end - obj - end + a.uniq.should == a - 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) + true + end - def obj.eql?(o) - true + obj end - obj + a.to_enum.uniq.size.should == 1 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.to_enum.uniq.size.should == 1 + a.uniq.should == a + a[0].should.tainted? + a[1].should.tainted? + + 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 + end + + a.to_enum.uniq.size.should == 1 + a[0].should.tainted? + a[1].should.tainted? + end end context 'when yielded with multiple arguments' do diff --git a/spec/ruby/core/enumerable/zip_spec.rb b/spec/ruby/core/enumerable/zip_spec.rb index ab148f2a6e..9ec15aa030 100644 --- a/spec/ruby/core/enumerable/zip_spec.rb +++ b/spec/ruby/core/enumerable/zip_spec.rb @@ -38,9 +38,4 @@ describe "Enumerable#zip" do multi.zip(multi).should == [[[1, 2], [1, 2]], [[3, 4, 5], [3, 4, 5]], [[6, 7, 8, 9], [6, 7, 8, 9]]] end - it "raises TypeError when some argument isn't Array and doesn't respond to #to_ary and #to_enum" do - -> { EnumerableSpecs::Numerous.new(1,2,3).zip(Object.new) }.should raise_error(TypeError, "wrong argument type Object (must respond to :each)") - -> { EnumerableSpecs::Numerous.new(1,2,3).zip(1) }.should raise_error(TypeError, "wrong argument type Integer (must respond to :each)") - -> { EnumerableSpecs::Numerous.new(1,2,3).zip(true) }.should raise_error(TypeError, "wrong argument type TrueClass (must respond to :each)") - end end diff --git a/spec/ruby/core/enumerator/arithmetic_sequence/begin_spec.rb b/spec/ruby/core/enumerator/arithmetic_sequence/begin_spec.rb index bd243fa0b5..1837a4f246 100644 --- a/spec/ruby/core/enumerator/arithmetic_sequence/begin_spec.rb +++ b/spec/ruby/core/enumerator/arithmetic_sequence/begin_spec.rb @@ -7,10 +7,12 @@ describe "Enumerator::ArithmeticSequence#begin" do (1...10).step.begin.should == 1 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 + 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 end end end diff --git a/spec/ruby/core/enumerator/chain/initialize_spec.rb b/spec/ruby/core/enumerator/chain/initialize_spec.rb index daa30351d7..69484dfcb4 100644 --- a/spec/ruby/core/enumerator/chain/initialize_spec.rb +++ b/spec/ruby/core/enumerator/chain/initialize_spec.rb @@ -22,10 +22,10 @@ describe "Enumerator::Chain#initialize" do end describe "on frozen instance" do - it "raises a FrozenError" do + it "raises a RuntimeError" do -> { @uninitialized.freeze.send(:initialize) - }.should raise_error(FrozenError) + }.should raise_error(RuntimeError) end end end diff --git a/spec/ruby/core/enumerator/chain/inspect_spec.rb b/spec/ruby/core/enumerator/chain/inspect_spec.rb index 9b5a442b75..a0450c808a 100644 --- a/spec/ruby/core/enumerator/chain/inspect_spec.rb +++ b/spec/ruby/core/enumerator/chain/inspect_spec.rb @@ -11,8 +11,4 @@ describe "Enumerator::Chain#inspect" do obj.should_receive(:inspect).and_return('some desc') Enumerator::Chain.new(obj).inspect.should == "#<Enumerator::Chain: [some desc]>" end - - it "returns a not initialized representation if #initialized is not called yet" do - Enumerator::Chain.allocate.inspect.should == "#<Enumerator::Chain: uninitialized>" - end end diff --git a/spec/ruby/core/enumerator/each_spec.rb b/spec/ruby/core/enumerator/each_spec.rb index 3af16e5587..99ac3120af 100644 --- a/spec/ruby/core/enumerator/each_spec.rb +++ b/spec/ruby/core/enumerator/each_spec.rb @@ -10,41 +10,41 @@ describe "Enumerator#each" do @enum_with_arguments = object_each_with_arguments.to_enum(:each_with_arguments, :arg0, :arg1, :arg2) - @enum_with_yielder = Enumerator.new { |y| y.yield :ok } + @enum_with_yielder = Enumerator.new {|y| y.yield :ok} end it "yields each element of self to the given block" do acc = [] - [1, 2, 3].to_enum.each { |e| acc << e } - acc.should == [1, 2, 3] + [1,2,3].to_enum.each {|e| acc << e } + acc.should == [1,2,3] end it "calls #each on the object given in the constructor by default" do each = mock('each') each.should_receive(:each) - each.to_enum.each { |e| e } + each.to_enum.each {|e| e } end it "calls #each on the underlying object until it's exhausted" do each = mock('each') each.should_receive(:each).and_yield(1).and_yield(2).and_yield(3) acc = [] - each.to_enum.each { |e| acc << e } - acc.should == [1, 2, 3] + each.to_enum.each {|e| acc << e } + acc.should == [1,2,3] end it "calls the method given in the constructor instead of #each" do each = mock('peach') each.should_receive(:peach) - each.to_enum(:peach).each { |e| e } + each.to_enum(:peach).each {|e| e } end it "calls the method given in the constructor until it's exhausted" do each = mock('peach') each.should_receive(:peach).and_yield(1).and_yield(2).and_yield(3) acc = [] - each.to_enum(:peach).each { |e| acc << e } - acc.should == [1, 2, 3] + each.to_enum(:peach).each {|e| acc << e } + acc.should == [1,2,3] end it "raises a NoMethodError if the object doesn't respond to #each" do diff --git a/spec/ruby/core/enumerator/generator/initialize_spec.rb b/spec/ruby/core/enumerator/generator/initialize_spec.rb index acc1174253..f75c7d6f26 100644 --- a/spec/ruby/core/enumerator/generator/initialize_spec.rb +++ b/spec/ruby/core/enumerator/generator/initialize_spec.rb @@ -17,10 +17,10 @@ describe "Enumerator::Generator#initialize" do end describe "on frozen instance" do - it "raises a FrozenError" do + it "raises a RuntimeError" do -> { @uninitialized.freeze.send(:initialize) {} - }.should raise_error(FrozenError) + }.should raise_error(RuntimeError) end end end diff --git a/spec/ruby/core/enumerator/initialize_spec.rb b/spec/ruby/core/enumerator/initialize_spec.rb index 5e0256ca46..217af1d3bc 100644 --- a/spec/ruby/core/enumerator/initialize_spec.rb +++ b/spec/ruby/core/enumerator/initialize_spec.rb @@ -11,6 +11,14 @@ describe "Enumerator#initialize" do Enumerator.should have_private_instance_method(:initialize, false) end + ruby_version_is ''...'3.0' do + it "returns self when given an object" do + suppress_warning do + @uninitialized.send(:initialize, Object.new).should equal(@uninitialized) + end + end + end + it "returns self when given a block" do @uninitialized.send(:initialize) {}.should equal(@uninitialized) end @@ -48,10 +56,10 @@ describe "Enumerator#initialize" do end describe "on frozen instance" do - it "raises a FrozenError" do + it "raises a RuntimeError" do -> { @uninitialized.freeze.send(:initialize) {} - }.should raise_error(FrozenError) + }.should raise_error(RuntimeError) end end end diff --git a/spec/ruby/core/enumerator/inspect_spec.rb b/spec/ruby/core/enumerator/inspect_spec.rb index 7e97864246..3bcf07e754 100644 --- a/spec/ruby/core/enumerator/inspect_spec.rb +++ b/spec/ruby/core/enumerator/inspect_spec.rb @@ -14,9 +14,4 @@ describe "Enumerator#inspect" do (1..3).each.each_slice(2).inspect.should == "#<Enumerator: #<Enumerator: 1..3:each>:each_slice(2)>" end end - - it "returns a not initialized representation if #initialized is not called yet" do - Enumerator.allocate.inspect.should == "#<Enumerator: uninitialized>" - Enumerator::Lazy.allocate.inspect.should == "#<Enumerator::Lazy: uninitialized>" - end end diff --git a/spec/ruby/core/enumerator/lazy/compact_spec.rb b/spec/ruby/core/enumerator/lazy/compact_spec.rb deleted file mode 100644 index e678bc71eb..0000000000 --- a/spec/ruby/core/enumerator/lazy/compact_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -require_relative '../../../spec_helper' -require_relative 'fixtures/classes' - -ruby_version_is '3.1' do - describe "Enumerator::Lazy#compact" do - it 'returns array without nil elements' do - arr = [1, nil, 3, false, 5].to_enum.lazy.compact - arr.should be_an_instance_of(Enumerator::Lazy) - arr.force.should == [1, 3, false, 5] - end - - it "sets #size to nil" do - Enumerator::Lazy.new(Object.new, 100) {}.compact.size.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 592da4fd8c..30ba2dfe0e 100644 --- a/spec/ruby/core/enumerator/lazy/eager_spec.rb +++ b/spec/ruby/core/enumerator/lazy/eager_spec.rb @@ -1,27 +1,29 @@ require_relative '../../../spec_helper' -describe "Enumerator::Lazy#eager" do - it "returns a non-lazy Enumerator converted from the lazy enumerator" do - enum = [1, 2, 3].lazy +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 - 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] + enum.map { |i| i }.should == [1, 2, 3] + ScratchPad.recorded.should == [1, 2, 3] + end 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 99dd59cebe..3480af0865 100644 --- a/spec/ruby/core/enumerator/lazy/filter_map_spec.rb +++ b/spec/ruby/core/enumerator/lazy/filter_map_spec.rb @@ -3,12 +3,14 @@ require_relative '../../../spec_helper' require_relative 'fixtures/classes' -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 +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 - 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] + 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 end diff --git a/spec/ruby/core/enumerator/lazy/initialize_spec.rb b/spec/ruby/core/enumerator/lazy/initialize_spec.rb index e1e0b1d608..f23018d010 100644 --- a/spec/ruby/core/enumerator/lazy/initialize_spec.rb +++ b/spec/ruby/core/enumerator/lazy/initialize_spec.rb @@ -56,8 +56,8 @@ describe "Enumerator::Lazy#initialize" do end describe "on frozen instance" do - it "raises a FrozenError" do - -> { @uninitialized.freeze.send(:initialize, @receiver) {} }.should raise_error(FrozenError) + it "raises a RuntimeError" do + -> { @uninitialized.freeze.send(:initialize, @receiver) {} }.should raise_error(RuntimeError) end end end diff --git a/spec/ruby/core/enumerator/lazy/lazy_spec.rb b/spec/ruby/core/enumerator/lazy/lazy_spec.rb index 0fb104e25a..cde9b31066 100644 --- a/spec/ruby/core/enumerator/lazy/lazy_spec.rb +++ b/spec/ruby/core/enumerator/lazy/lazy_spec.rb @@ -16,10 +16,6 @@ describe "Enumerator::Lazy" do ] lazy_methods += [:chunk_while, :uniq] - ruby_version_is '3.1' do - lazy_methods += [:compact] - end - Enumerator::Lazy.instance_methods(false).should include(*lazy_methods) 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 a6b5c38777..3a59ba4116 100644 --- a/spec/ruby/core/enumerator/lazy/with_index_spec.rb +++ b/spec/ruby/core/enumerator/lazy/with_index_spec.rb @@ -3,34 +3,28 @@ require_relative '../../../spec_helper' require_relative 'fixtures/classes' -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 +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 - 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 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 "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 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 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 "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 "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]] + 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 end end diff --git a/spec/ruby/core/enumerator/new_spec.rb b/spec/ruby/core/enumerator/new_spec.rb index 671912224f..5cc0b3ff2e 100644 --- a/spec/ruby/core/enumerator/new_spec.rb +++ b/spec/ruby/core/enumerator/new_spec.rb @@ -2,8 +2,51 @@ require_relative '../../spec_helper' describe "Enumerator.new" do context "no block given" do - it "raises" do - -> { Enumerator.new(1, :upto, 3) }.should raise_error(ArgumentError) + ruby_version_is '3.0' do + it "raises" do + -> { Enumerator.new(1, :upto, 3) }.should raise_error(ArgumentError) + end + end + + ruby_version_is ''...'3.0' do + it "creates a new custom enumerator with the given object, iterator and arguments" do + enum = suppress_warning { Enumerator.new(1, :upto, 3) } + enum.should be_an_instance_of(Enumerator) + end + + it "creates a new custom enumerator that responds to #each" do + enum = suppress_warning { Enumerator.new(1, :upto, 3) } + enum.respond_to?(:each).should == true + end + + it "creates a new custom enumerator that runs correctly" do + suppress_warning { Enumerator.new(1, :upto, 3) }.map{ |x| x }.should == [1,2,3] + end + + it "aliases the second argument to :each" do + suppress_warning { Enumerator.new(1..2) }.to_a.should == + suppress_warning { Enumerator.new(1..2, :each) }.to_a + end + + it "doesn't check for the presence of the iterator method" do + suppress_warning { Enumerator.new(nil) }.should be_an_instance_of(Enumerator) + end + + it "uses the latest define iterator method" do + class StrangeEach + def each + yield :foo + end + end + enum = suppress_warning { Enumerator.new(StrangeEach.new) } + enum.to_a.should == [:foo] + class StrangeEach + def each + yield :bar + end + end + enum.to_a.should == [:bar] + end end end @@ -34,12 +77,14 @@ describe "Enumerator.new" do enum.take(3).should == [1, 2, 3] end - 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 + 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"] + enum.to_a.should == ["a\n", "b\n", "c"] + end end describe 'yielded values' do diff --git a/spec/ruby/core/enumerator/produce_spec.rb b/spec/ruby/core/enumerator/produce_spec.rb index c69fb49303..f6f1dcd429 100644 --- a/spec/ruby/core/enumerator/produce_spec.rb +++ b/spec/ruby/core/enumerator/produce_spec.rb @@ -1,34 +1,36 @@ require_relative '../../spec_helper' -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 +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 - 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 } + it "terminates iteration when block raises StopIteration exception" do + enum = Enumerator.produce(0) do | prev| + raise StopIteration if prev >= 2 + prev + 1 + end - enum.take(3).should == [1, 2, 3] - ScratchPad.recorded.should == [nil, 1, 2] + enum.to_a.should == [0, 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 } + 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 + + 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"] + lines.should == ["a\n", "b\n", "c\n", "d"] + end end end end diff --git a/spec/ruby/core/enumerator/product/each_spec.rb b/spec/ruby/core/enumerator/product/each_spec.rb deleted file mode 100644 index 868a1ea6bf..0000000000 --- a/spec/ruby/core/enumerator/product/each_spec.rb +++ /dev/null @@ -1,73 +0,0 @@ -require_relative '../../../spec_helper' -require_relative '../../enumerable/shared/enumeratorized' - -ruby_version_is "3.2" do - describe "Enumerator::Product#each" do - it_behaves_like :enumeratorized_with_origin_size, :each, Enumerator::Product.new([1, 2], [:a, :b]) - - it "yields each element of Cartesian product of enumerators" do - enum = Enumerator::Product.new([1, 2], [:a, :b]) - acc = [] - enum.each { |e| acc << e } - acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]] - end - - it "calls #each_entry method on enumerators" do - object1 = Object.new - def object1.each_entry - yield 1 - yield 2 - end - - object2 = Object.new - def object2.each_entry - yield :a - yield :b - end - - enum = Enumerator::Product.new(object1, object2) - acc = [] - enum.each { |e| acc << e } - acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]] - end - - it "raises a NoMethodError if the object doesn't respond to #each_entry" do - -> { - Enumerator::Product.new(Object.new).each {} - }.should raise_error(NoMethodError, /undefined method `each_entry' for/) - end - - it "returns enumerator if not given a block" do - enum = Enumerator::Product.new([1, 2], [:a, :b]) - enum.each.should.kind_of?(Enumerator) - - enum = Enumerator::Product.new([1, 2], [:a, :b]) - enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]] - end - - it "returns self if given a block" do - enum = Enumerator::Product.new([1, 2], [:a, :b]) - enum.each {}.should.equal?(enum) - end - - it "doesn't accept arguments" do - Enumerator::Product.instance_method(:each).arity.should == 0 - end - - it "yields each element to a block that takes multiple arguments" do - enum = Enumerator::Product.new([1, 2], [:a, :b]) - - acc = [] - enum.each { |x, y| acc << x } - acc.should == [1, 1, 2, 2] - - acc = [] - enum.each { |x, y| acc << y } - acc.should == [:a, :b, :a, :b] - - acc = [] - enum.each { |x, y, z| acc << z } - acc.should == [nil, nil, nil, nil] - end - end -end diff --git a/spec/ruby/core/enumerator/product/initialize_copy_spec.rb b/spec/ruby/core/enumerator/product/initialize_copy_spec.rb deleted file mode 100644 index 46e8421322..0000000000 --- a/spec/ruby/core/enumerator/product/initialize_copy_spec.rb +++ /dev/null @@ -1,54 +0,0 @@ -require_relative '../../../spec_helper' - -ruby_version_is "3.2" do - describe "Enumerator::Product#initialize_copy" do - it "replaces content of the receiver with content of the other object" do - enum = Enumerator::Product.new([true, false]) - enum2 = Enumerator::Product.new([1, 2], [:a, :b]) - - enum.send(:initialize_copy, enum2) - enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]] - end - - it "returns self" do - enum = Enumerator::Product.new([true, false]) - enum2 = Enumerator::Product.new([1, 2], [:a, :b]) - - enum.send(:initialize_copy, enum2).should.equal?(enum) - end - - it "is a private method" do - Enumerator::Product.should have_private_instance_method(:initialize_copy, false) - end - - it "does nothing if the argument is the same as the receiver" do - enum = Enumerator::Product.new(1..2) - enum.send(:initialize_copy, enum).should.equal?(enum) - - enum.freeze - enum.send(:initialize_copy, enum).should.equal?(enum) - end - - it "raises FrozenError if the receiver is frozen" do - enum = Enumerator::Product.new(1..2) - enum2 = Enumerator::Product.new(3..4) - - -> { enum.freeze.send(:initialize_copy, enum2) }.should raise_error(FrozenError) - end - - it "raises TypeError if the objects are of different class" do - enum = Enumerator::Product.new(1..2) - enum2 = Class.new(Enumerator::Product).new(3..4) - - -> { enum.send(:initialize_copy, enum2) }.should raise_error(TypeError, 'initialize_copy should take same class object') - -> { enum2.send(:initialize_copy, enum) }.should raise_error(TypeError, 'initialize_copy should take same class object') - end - - it "raises ArgumentError if the argument is not initialized yet" do - enum = Enumerator::Product.new(1..2) - enum2 = Enumerator::Product.allocate - - -> { enum.send(:initialize_copy, enum2) }.should raise_error(ArgumentError, 'uninitialized product') - end - end -end diff --git a/spec/ruby/core/enumerator/product/initialize_spec.rb b/spec/ruby/core/enumerator/product/initialize_spec.rb deleted file mode 100644 index 4b60564240..0000000000 --- a/spec/ruby/core/enumerator/product/initialize_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -require_relative '../../../spec_helper' - -ruby_version_is "3.2" do - describe "Enumerator::Product#initialize" do - before :each do - @uninitialized = Enumerator::Product.allocate - end - - it "is a private method" do - Enumerator::Product.should have_private_instance_method(:initialize, false) - end - - it "returns self" do - @uninitialized.send(:initialize).should equal(@uninitialized) - end - - it "accepts many arguments" do - @uninitialized.send(:initialize, 0..1, 2..3, 4..5).should equal(@uninitialized) - end - - it "accepts arguments that are not Enumerable nor responding to :each_entry" do - @uninitialized.send(:initialize, Object.new).should equal(@uninitialized) - end - - describe "on frozen instance" do - it "raises a FrozenError" do - -> { - @uninitialized.freeze.send(:initialize, 0..1) - }.should raise_error(FrozenError) - end - end - end -end diff --git a/spec/ruby/core/enumerator/product/inspect_spec.rb b/spec/ruby/core/enumerator/product/inspect_spec.rb deleted file mode 100644 index 1ea8e9c49b..0000000000 --- a/spec/ruby/core/enumerator/product/inspect_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -require_relative '../../../spec_helper' - -ruby_version_is "3.2" do - describe "Enumerator::Product#inspect" do - it "returns a String including enumerators" do - enum = Enumerator::Product.new([1, 2], [:a, :b]) - enum.inspect.should == "#<Enumerator::Product: [[1, 2], [:a, :b]]>" - end - - it "represents a recursive element with '[...]'" do - enum = [1, 2] - enum_recursive = Enumerator::Product.new(enum) - - enum << enum_recursive - enum_recursive.inspect.should == "#<Enumerator::Product: [[1, 2, #<Enumerator::Product: ...>]]>" - end - - it "returns a not initialized representation if #initialized is not called yet" do - Enumerator::Product.allocate.inspect.should == "#<Enumerator::Product: uninitialized>" - end - end -end diff --git a/spec/ruby/core/enumerator/product/rewind_spec.rb b/spec/ruby/core/enumerator/product/rewind_spec.rb deleted file mode 100644 index e8ee730239..0000000000 --- a/spec/ruby/core/enumerator/product/rewind_spec.rb +++ /dev/null @@ -1,64 +0,0 @@ -require_relative '../../../spec_helper' - -ruby_version_is "3.2" do - describe "Enumerator::Product#rewind" do - before :each do - @enum = Enumerator::Product.new([1, 2].each.to_enum, [:a, :b].each.to_enum) - end - - it "resets the enumerator to its initial state" do - @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]] - @enum.rewind - @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]] - end - - it "returns self" do - @enum.rewind.should.equal? @enum - end - - it "has no effect on a new enumerator" do - @enum.rewind - @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]] - end - - it "has no effect if called multiple, consecutive times" do - @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]] - @enum.rewind - @enum.rewind - @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]] - end - - it "calls the enclosed object's rewind method if one exists" do - obj = mock('rewinder') - enum = Enumerator::Product.new(obj.to_enum) - - obj.should_receive(:rewind) - enum.rewind - end - - it "does nothing if the object doesn't have a #rewind method" do - obj = mock('rewinder') - enum = Enumerator::Product.new(obj.to_enum) - - enum.rewind.should == enum - end - - it "calls a rewind method on each enumerable in direct order" do - ScratchPad.record [] - - object1 = Object.new - def object1.rewind; ScratchPad << :object1; end - - object2 = Object.new - def object2.rewind; ScratchPad << :object2; end - - object3 = Object.new - def object3.rewind; ScratchPad << :object3; end - - enum = Enumerator::Product.new(object1, object2, object3) - enum.rewind - - ScratchPad.recorded.should == [:object1, :object2, :object3] - end - end -end diff --git a/spec/ruby/core/enumerator/product/size_spec.rb b/spec/ruby/core/enumerator/product/size_spec.rb deleted file mode 100644 index fb0efdf748..0000000000 --- a/spec/ruby/core/enumerator/product/size_spec.rb +++ /dev/null @@ -1,64 +0,0 @@ -require_relative '../../../spec_helper' - -ruby_version_is "3.2" do - describe "Enumerator::Product#size" do - it "returns the total size of the enumerator product calculated by multiplying the sizes of enumerables in the product" do - product = Enumerator::Product.new(1..2, 1..3, 1..4) - product.size.should == 24 # 2 * 3 * 4 - end - - it "returns nil if any enumerable reports its size as nil" do - enum = Object.new - def enum.size; nil; end - - product = Enumerator::Product.new(1..2, enum) - product.size.should == nil - end - - it "returns Float::INFINITY if any enumerable reports its size as Float::INFINITY" do - enum = Object.new - def enum.size; Float::INFINITY; end - - product = Enumerator::Product.new(1..2, enum) - product.size.should == Float::INFINITY - end - - it "returns -Float::INFINITY if any enumerable reports its size as -Float::INFINITY" do - enum = Object.new - def enum.size; -Float::INFINITY; end - - product = Enumerator::Product.new(1..2, enum) - product.size.should == -Float::INFINITY - end - - it "returns nil if any enumerable reports its size as Float::NAN" do - enum = Object.new - def enum.size; Float::NAN; end - - product = Enumerator::Product.new(1..2, enum) - product.size.should == nil - end - - it "returns nil if any enumerable doesn't respond to #size" do - enum = Object.new - product = Enumerator::Product.new(1..2, enum) - product.size.should == nil - end - - it "returns nil if any enumerable reports a not-convertible to Integer" do - enum = Object.new - def enum.size; :symbol; end - - product = Enumerator::Product.new(1..2, enum) - product.size.should == nil - end - - it "returns nil if any enumerable reports a non-Integer but convertible to Integer size" do - enum = Object.new - def enum.size; 1.0; end - - product = Enumerator::Product.new(1..2, enum) - product.size.should == nil - end - end -end diff --git a/spec/ruby/core/enumerator/product_spec.rb b/spec/ruby/core/enumerator/product_spec.rb deleted file mode 100644 index 0fb00fc7ee..0000000000 --- a/spec/ruby/core/enumerator/product_spec.rb +++ /dev/null @@ -1,93 +0,0 @@ -require_relative '../../spec_helper' - -ruby_version_is "3.2" do - describe "Enumerator.product" do - it "returns a Cartesian product of enumerators" do - enum = Enumerator.product(1..2, ["A", "B"]) - enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]] - end - - it "accepts a list of enumerators of any length" do - enum = Enumerator.product(1..2) - enum.to_a.should == [[1], [2]] - - enum = Enumerator.product(1..2, ["A"]) - enum.to_a.should == [[1, "A"], [2, "A"]] - - enum = Enumerator.product(1..2, ["A"], ["B"]) - enum.to_a.should == [[1, "A", "B"], [2, "A", "B"]] - - enum = Enumerator.product(2..3, ["A"], ["B"], ["C"]) - enum.to_a.should == [[2, "A", "B", "C"], [3, "A", "B", "C"]] - end - - it "returns an enumerator with an empty array when no arguments passed" do - enum = Enumerator.product - enum.to_a.should == [[]] - end - - it "returns an instance of Enumerator::Product" do - enum = Enumerator.product - enum.class.should == Enumerator::Product - end - - it "accepts infinite enumerators and returns infinite enumerator" do - enum = Enumerator.product(1.., ["A", "B"]) - enum.take(5).should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"], [3, "A"]] - enum.size.should == Float::INFINITY - end - - it "accepts a block" do - elems = [] - enum = Enumerator.product(1..2, ["X", "Y"]) { elems << _1 } - - elems.should == [[1, "X"], [1, "Y"], [2, "X"], [2, "Y"]] - end - - it "returns nil when a block passed" do - Enumerator.product(1..2) {}.should == nil - end - - # https://bugs.ruby-lang.org/issues/19829 - it "reject keyword arguments" do - -> { - Enumerator.product(1..3, foo: 1, bar: 2) - }.should raise_error(ArgumentError, "unknown keywords: :foo, :bar") - end - - it "calls only #each_entry method on arguments" do - object = Object.new - def object.each_entry - yield 1 - yield 2 - end - - enum = Enumerator.product(object, ["A", "B"]) - enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]] - end - - it "raises NoMethodError when argument doesn't respond to #each_entry" do - -> { - Enumerator.product(Object.new).to_a - }.should raise_error(NoMethodError, /undefined method `each_entry' for/) - end - - it "calls #each_entry lazily" do - Enumerator.product(Object.new).should be_kind_of(Enumerator) - end - - it "iterates through consuming enumerator elements only once" do - a = [1, 2, 3] - i = 0 - - enum = Enumerator.new do |y| - while i < a.size - y << a[i] - i += 1 - end - end - - Enumerator.product(['a', 'b'], enum).to_a.should == [["a", 1], ["a", 2], ["a", 3]] - end - end -end diff --git a/spec/ruby/core/enumerator/rewind_spec.rb b/spec/ruby/core/enumerator/rewind_spec.rb index 6ba0edf174..a105f2c619 100644 --- a/spec/ruby/core/enumerator/rewind_spec.rb +++ b/spec/ruby/core/enumerator/rewind_spec.rb @@ -14,7 +14,7 @@ describe "Enumerator#rewind" do end it "returns self" do - @enum.rewind.should.equal? @enum + @enum.rewind.should == @enum end it "has no effect on a new enumerator" do @@ -49,7 +49,7 @@ describe "Enumerator#rewind" do obj = mock('rewinder') enum = obj.to_enum obj.should_receive(:each).at_most(1) - enum.rewind.should == enum + -> { enum.rewind.should == enum }.should_not raise_error 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 1d3681ab50..0ed1645853 100644 --- a/spec/ruby/core/enumerator/yielder/to_proc_spec.rb +++ b/spec/ruby/core/enumerator/yielder/to_proc_spec.rb @@ -1,16 +1,18 @@ require_relative '../../../spec_helper' -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" } +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" } - 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" + result.should == "foobar" + end end end diff --git a/spec/ruby/core/env/clone_spec.rb b/spec/ruby/core/env/clone_spec.rb deleted file mode 100644 index 991e4e6774..0000000000 --- a/spec/ruby/core/env/clone_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -require_relative '../../spec_helper' - -describe "ENV#clone" do - it "raises ArgumentError when keyword argument 'freeze' is neither nil nor boolean" do - -> { - ENV.clone(freeze: 1) - }.should raise_error(ArgumentError) - end - - it "raises ArgumentError when keyword argument is not 'freeze'" do - -> { - ENV.clone(foo: nil) - }.should raise_error(ArgumentError) - end - - ruby_version_is "3.2" do - it "raises TypeError" do - -> { - ENV.clone - }.should raise_error(TypeError, /Cannot clone ENV, use ENV.to_h to get a copy of ENV as a hash/) - end - end -end diff --git a/spec/ruby/core/env/delete_spec.rb b/spec/ruby/core/env/delete_spec.rb index f28ac97911..5e7891f74d 100644 --- a/spec/ruby/core/env/delete_spec.rb +++ b/spec/ruby/core/env/delete_spec.rb @@ -30,9 +30,11 @@ describe "ENV.delete" do ScratchPad.recorded.should == "foo" end - it "returns the result of given block if the named environment variable does not exist" do - ENV.delete("foo") - ENV.delete("foo") { |name| "bar" }.should == "bar" + ruby_version_is "3.0" do + it "returns the result of given block if the named environment variable does not exist" do + ENV.delete("foo") + ENV.delete("foo") { |name| "bar" }.should == "bar" + end end it "does not evaluate the block if the environment variable exists" do @@ -41,14 +43,6 @@ describe "ENV.delete" do ENV["foo"].should == nil end - it "removes the variable coerced with #to_str" do - ENV["foo"] = "bar" - k = mock('key') - k.should_receive(:to_str).and_return("foo") - ENV.delete(k) - ENV["foo"].should == nil - end - it "raises TypeError if the argument is not a String and does not respond to #to_str" do -> { ENV.delete(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String") end diff --git a/spec/ruby/core/env/dup_spec.rb b/spec/ruby/core/env/dup_spec.rb deleted file mode 100644 index 46d125aca8..0000000000 --- a/spec/ruby/core/env/dup_spec.rb +++ /dev/null @@ -1,11 +0,0 @@ -require_relative '../../spec_helper' - -describe "ENV#dup" do - ruby_version_is "3.1" do - it "raises TypeError" do - -> { - ENV.dup - }.should raise_error(TypeError, /Cannot dup ENV, use ENV.to_h to get a copy of ENV as a hash/) - end - end -end diff --git a/spec/ruby/core/env/except_spec.rb b/spec/ruby/core/env/except_spec.rb index fb8f3b7536..cfe5865abe 100644 --- a/spec/ruby/core/env/except_spec.rb +++ b/spec/ruby/core/env/except_spec.rb @@ -1,34 +1,36 @@ require_relative 'spec_helper' require_relative 'shared/to_hash' -describe "ENV.except" do - before do - @orig_hash = ENV.to_hash - end +ruby_version_is "3.0" do + describe "ENV.except" do + before do + @orig_hash = ENV.to_hash + end - after do - ENV.replace @orig_hash - end + after do + ENV.replace @orig_hash + end - # Testing the method without arguments is covered via - it_behaves_like :env_to_hash, :except + # Testing the method without arguments is covered via + it_behaves_like :env_to_hash, :except - it "returns a hash without the requested subset" do - ENV.clear + it "returns a hash without the requested subset" do + ENV.clear - ENV['one'] = '1' - ENV['two'] = '2' - ENV['three'] = '3' + ENV['one'] = '1' + ENV['two'] = '2' + ENV['three'] = '3' - ENV.except('one', 'three').should == { 'two' => '2' } - end + ENV.except('one', 'three').should == { 'two' => '2' } + end - it "ignores keys not present in the original hash" do - ENV.clear + it "ignores keys not present in the original hash" do + ENV.clear - ENV['one'] = '1' - ENV['two'] = '2' + ENV['one'] = '1' + ENV['two'] = '2' - ENV.except('one', 'three').should == { 'two' => '2' } + ENV.except('one', 'three').should == { 'two' => '2' } + end end end diff --git a/spec/ruby/core/env/index_spec.rb b/spec/ruby/core/env/index_spec.rb new file mode 100644 index 0000000000..301a66ab4e --- /dev/null +++ b/spec/ruby/core/env/index_spec.rb @@ -0,0 +1,14 @@ +require_relative '../../spec_helper' +require_relative 'shared/key' + +ruby_version_is ''...'3.0' do + describe "ENV.index" do + it_behaves_like :env_key, :index + + it "warns about deprecation" do + -> do + ENV.index("foo") + end.should complain(/warning: ENV.index is deprecated; use ENV.key/) + end + end +end diff --git a/spec/ruby/core/env/indexes_spec.rb b/spec/ruby/core/env/indexes_spec.rb new file mode 100644 index 0000000000..e724feaa39 --- /dev/null +++ b/spec/ruby/core/env/indexes_spec.rb @@ -0,0 +1 @@ +require_relative '../../spec_helper' diff --git a/spec/ruby/core/env/indices_spec.rb b/spec/ruby/core/env/indices_spec.rb new file mode 100644 index 0000000000..e724feaa39 --- /dev/null +++ b/spec/ruby/core/env/indices_spec.rb @@ -0,0 +1 @@ +require_relative '../../spec_helper' diff --git a/spec/ruby/core/env/key_spec.rb b/spec/ruby/core/env/key_spec.rb index cf70286409..82cfbefa39 100644 --- a/spec/ruby/core/env/key_spec.rb +++ b/spec/ruby/core/env/key_spec.rb @@ -1,39 +1,11 @@ require_relative '../../spec_helper' require_relative 'shared/include' +require_relative 'shared/key' describe "ENV.key?" do it_behaves_like :env_include, :key? end describe "ENV.key" do - before :each do - @saved_foo = ENV["foo"] - end - - after :each do - ENV["foo"] = @saved_foo - end - - it "returns the index associated with the passed value" do - ENV["foo"] = "bar" - ENV.key("bar").should == "foo" - end - - it "returns nil if the passed value is not found" do - ENV.delete("foo") - ENV.key("foo").should be_nil - end - - it "coerces the key element with #to_str" do - ENV["foo"] = "bar" - k = mock('key') - k.should_receive(:to_str).and_return("bar") - ENV.key(k).should == "foo" - end - - it "raises TypeError if the argument is not a String and does not respond to #to_str" do - -> { - ENV.key(Object.new) - }.should raise_error(TypeError, "no implicit conversion of Object into String") - end + it_behaves_like :env_key, :key end diff --git a/spec/ruby/core/env/merge_spec.rb b/spec/ruby/core/env/merge_spec.rb index f10662cf79..b418cd11f4 100644 --- a/spec/ruby/core/env/merge_spec.rb +++ b/spec/ruby/core/env/merge_spec.rb @@ -1,6 +1,8 @@ require_relative '../../spec_helper' require_relative 'shared/update' -describe "ENV.merge!" do - it_behaves_like :env_update, :merge! +ruby_version_is "2.7" do + describe "ENV.merge!" do + it_behaves_like :env_update, :merge! + end end diff --git a/spec/ruby/core/env/shared/include.rb b/spec/ruby/core/env/shared/include.rb index 70aa555301..3efcd523d6 100644 --- a/spec/ruby/core/env/shared/include.rb +++ b/spec/ruby/core/env/shared/include.rb @@ -17,13 +17,6 @@ describe :env_include, shared: true do ENV.send(@method, "foo").should == false end - it "coerces the key with #to_str" do - ENV["foo"] = "bar" - k = mock('key') - k.should_receive(:to_str).and_return("foo") - ENV.send(@method, k).should == true - end - it "raises TypeError if the argument is not a String and does not respond to #to_str" do -> { ENV.send(@method, Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String") end diff --git a/spec/ruby/core/env/shared/key.rb b/spec/ruby/core/env/shared/key.rb new file mode 100644 index 0000000000..93396d2aca --- /dev/null +++ b/spec/ruby/core/env/shared/key.rb @@ -0,0 +1,31 @@ +describe :env_key, shared: true do + before :each do + @saved_foo = ENV["foo"] + end + + after :each do + ENV["foo"] = @saved_foo + end + + it "returns the index associated with the passed value" do + ENV["foo"] = "bar" + suppress_warning { + ENV.send(@method, "bar").should == "foo" + } + end + + it "returns nil if the passed value is not found" do + ENV.delete("foo") + suppress_warning { + ENV.send(@method, "foo").should be_nil + } + end + + it "raises TypeError if the argument is not a String and does not respond to #to_str" do + -> { + suppress_warning { + ENV.send(@method, Object.new) + } + }.should raise_error(TypeError, "no implicit conversion of Object into String") + end +end diff --git a/spec/ruby/core/env/shared/update.rb b/spec/ruby/core/env/shared/update.rb index 7d4799955b..129a56544c 100644 --- a/spec/ruby/core/env/shared/update.rb +++ b/spec/ruby/core/env/shared/update.rb @@ -15,14 +15,6 @@ describe :env_update, shared: true do ENV["bar"].should == "1" end - ruby_version_is "3.2" do - it "adds the multiple parameter hashes to ENV, returning ENV" do - ENV.send(@method, {"foo" => "multi1"}, {"bar" => "multi2"}).should equal(ENV) - ENV["foo"].should == "multi1" - ENV["bar"].should == "multi2" - end - end - it "returns ENV when no block given" do ENV.send(@method, {"foo" => "0", "bar" => "1"}).should equal(ENV) end @@ -47,21 +39,23 @@ describe :env_update, shared: true do ENV["bar"].should == "5" 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 + 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 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" + # 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 end it "returns ENV when block given" do diff --git a/spec/ruby/core/env/shared/value.rb b/spec/ruby/core/env/shared/value.rb index c2b5025465..bef96b5fef 100644 --- a/spec/ruby/core/env/shared/value.rb +++ b/spec/ruby/core/env/shared/value.rb @@ -16,13 +16,6 @@ describe :env_value, shared: true do ENV.send(@method, "foo").should == false end - it "coerces the value element with #to_str" do - ENV["foo"] = "bar" - v = mock('value') - v.should_receive(:to_str).and_return("bar") - ENV.send(@method, v).should == true - end - it "returns nil if the argument is not a String and does not respond to #to_str" do ENV.send(@method, Object.new).should == nil end diff --git a/spec/ruby/core/env/slice_spec.rb b/spec/ruby/core/env/slice_spec.rb index 959239d2b2..e3b6020391 100644 --- a/spec/ruby/core/env/slice_spec.rb +++ b/spec/ruby/core/env/slice_spec.rb @@ -21,16 +21,6 @@ describe "ENV.slice" do ENV.slice("foo", "boo", "bar").should == {"foo" => "0", "bar" => "1"} end - it "returns the values for the keys coerced with #to_str, but keeps the original objects as result keys" do - foo = mock('key 1') - foo.should_receive(:to_str).and_return("foo") - boo = mock('key 2') - boo.should_receive(:to_str).and_return("boo") - bar = mock('key 3') - bar.should_receive(:to_str).and_return("bar") - ENV.slice(foo, boo, bar).should == {foo => "0", bar => "1"} - end - it "raises TypeError if any argument is not a String and does not respond to #to_str" do -> { ENV.slice(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String") end diff --git a/spec/ruby/core/env/to_a_spec.rb b/spec/ruby/core/env/to_a_spec.rb index 2b1649281f..39e3877b48 100644 --- a/spec/ruby/core/env/to_a_spec.rb +++ b/spec/ruby/core/env/to_a_spec.rb @@ -6,10 +6,7 @@ describe "ENV.to_a" do a = ENV.to_a a.is_a?(Array).should == true a.size.should == ENV.size - a.each { |k,v| ENV[k].should == v } - - a.first.should.is_a?(Array) - a.first.size.should == 2 + ENV.each_pair { |k, v| a.should include([k, v])} end it "returns the entries in the locale encoding" do diff --git a/spec/ruby/core/exception/case_compare_spec.rb b/spec/ruby/core/exception/case_compare_spec.rb index 5fd11ae741..87b9dee3ca 100644 --- a/spec/ruby/core/exception/case_compare_spec.rb +++ b/spec/ruby/core/exception/case_compare_spec.rb @@ -26,11 +26,13 @@ describe "SystemCallError.===" do end it "returns true if receiver is generic and arg is kind of SystemCallError" do + unknown_error_number = Errno.constants.size e = SystemCallError.new('foo', @example_errno) SystemCallError.===(e).should == true end it "returns false if receiver is generic and arg is not kind of SystemCallError" do + unknown_error_number = Errno.constants.size e = Object.new SystemCallError.===(e).should == false end diff --git a/spec/ruby/core/exception/detailed_message_spec.rb b/spec/ruby/core/exception/detailed_message_spec.rb deleted file mode 100644 index fbe4443daa..0000000000 --- a/spec/ruby/core/exception/detailed_message_spec.rb +++ /dev/null @@ -1,43 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/common' - -describe "Exception#detailed_message" do - ruby_version_is "3.2" do - it "returns decorated message" do - RuntimeError.new("new error").detailed_message.should == "new error (RuntimeError)" - end - - it "is called by #full_message to allow message customization" do - exception = Exception.new("new error") - def exception.detailed_message(**) - "<prefix>#{message}<suffix>" - end - exception.full_message(highlight: false).should.include? "<prefix>new error<suffix>" - end - - it "accepts highlight keyword argument and adds escape control sequences" do - RuntimeError.new("new error").detailed_message(highlight: true).should == "\e[1mnew error (\e[1;4mRuntimeError\e[m\e[1m)\e[m" - end - - it "allows and ignores other keyword arguments" do - RuntimeError.new("new error").detailed_message(foo: true).should == "new error (RuntimeError)" - end - - it "returns just a message if exception class is anonymous" do - Class.new(RuntimeError).new("message").detailed_message.should == "message" - end - - it "returns 'unhandled exception' for an instance of RuntimeError with empty message" do - RuntimeError.new("").detailed_message.should == "unhandled exception" - end - - it "returns just class name for an instance of RuntimeError subclass with empty message" do - DetailedMessageSpec::C.new("").detailed_message.should == "DetailedMessageSpec::C" - end - - it "returns a generated class name for an instance of RuntimeError anonymous subclass with empty message" do - klass = Class.new(RuntimeError) - klass.new("").detailed_message.should =~ /\A#<Class:0x\h+>\z/ - end - end -end diff --git a/spec/ruby/core/exception/equal_value_spec.rb b/spec/ruby/core/exception/equal_value_spec.rb index e8f3ce0f8d..7f2065511a 100644 --- a/spec/ruby/core/exception/equal_value_spec.rb +++ b/spec/ruby/core/exception/equal_value_spec.rb @@ -22,18 +22,18 @@ describe "Exception#==" do it "returns true if both exceptions have the same class, the same message, and the same backtrace" do one = TypeError.new("message") - one.set_backtrace [__dir__] + one.set_backtrace [File.dirname(__FILE__)] two = TypeError.new("message") - two.set_backtrace [__dir__] + two.set_backtrace [File.dirname(__FILE__)] one.should == two end it "returns false if the two exceptions inherit from Exception but have different classes" do one = RuntimeError.new("message") - one.set_backtrace [__dir__] + one.set_backtrace [File.dirname(__FILE__)] one.should be_kind_of(Exception) two = TypeError.new("message") - two.set_backtrace [__dir__] + two.set_backtrace [File.dirname(__FILE__)] two.should be_kind_of(Exception) one.should_not == two end @@ -52,7 +52,7 @@ describe "Exception#==" do it "returns false if the two exceptions differ only in their backtrace" do one = RuntimeError.new("message") - one.set_backtrace [__dir__] + one.set_backtrace [File.dirname(__FILE__)] two = RuntimeError.new("message") two.set_backtrace nil one.should_not == two @@ -60,9 +60,9 @@ describe "Exception#==" do it "returns false if the two exceptions differ only in their message" do one = RuntimeError.new("message") - one.set_backtrace [__dir__] + one.set_backtrace [File.dirname(__FILE__)] two = RuntimeError.new("message2") - two.set_backtrace [__dir__] + two.set_backtrace [File.dirname(__FILE__)] one.should_not == two end end diff --git a/spec/ruby/core/exception/fixtures/common.rb b/spec/ruby/core/exception/fixtures/common.rb index 1e243098bd..0ffb3ed855 100644 --- a/spec/ruby/core/exception/fixtures/common.rb +++ b/spec/ruby/core/exception/fixtures/common.rb @@ -93,7 +93,3 @@ class NameErrorSpecs end end end - -module DetailedMessageSpec - C = Class.new(RuntimeError) -end diff --git a/spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb b/spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb deleted file mode 100644 index c109ec6247..0000000000 --- a/spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb +++ /dev/null @@ -1,22 +0,0 @@ -ready = false -t = Thread.new do - f = Fiber.new do - begin - Fiber.yield - ensure - STDERR.puts "suspended fiber ensure" - end - end - f.resume - - begin - ready = true - sleep - ensure - STDERR.puts "current fiber ensure" - end -end - -Thread.pass until ready && t.stop? - -# let the program end, it's the same as #exit or an exception for this behavior diff --git a/spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb b/spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb deleted file mode 100644 index 3364ed06d0..0000000000 --- a/spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb +++ /dev/null @@ -1,25 +0,0 @@ -ready = false -t = Thread.new do - f = Fiber.new do - begin - Fiber.yield - ensure - STDERR.puts "suspended fiber ensure" - end - end - f.resume - - f2 = Fiber.new do - begin - ready = true - sleep - ensure - STDERR.puts "current fiber ensure" - end - end - f2.resume -end - -Thread.pass until ready && t.stop? - -# let the program end, it's the same as #exit or an exception for this behavior diff --git a/spec/ruby/core/exception/frozen_error_spec.rb b/spec/ruby/core/exception/frozen_error_spec.rb index 2efdc239d8..f27b33295c 100644 --- a/spec/ruby/core/exception/frozen_error_spec.rb +++ b/spec/ruby/core/exception/frozen_error_spec.rb @@ -1,22 +1,26 @@ require_relative '../../spec_helper' describe "FrozenError.new" do - it "should take optional receiver argument" do - o = Object.new - FrozenError.new("msg", receiver: o).receiver.should equal(o) + 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 end end describe "FrozenError#receiver" 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 + 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 end end end diff --git a/spec/ruby/core/exception/full_message_spec.rb b/spec/ruby/core/exception/full_message_spec.rb index 4fad369936..4cece9ebf9 100644 --- a/spec/ruby/core/exception/full_message_spec.rb +++ b/spec/ruby/core/exception/full_message_spec.rb @@ -15,19 +15,13 @@ 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: :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: 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: :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" + 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)" end it "supports :order option and places the error message and the backtrace at the top or the bottom" do @@ -41,52 +35,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).lines - full_message[0].should.start_with?("#{__FILE__}:#{__LINE__-1}:in `") - full_message[0].should.end_with?("': Some runtime error (RuntimeError)\n") - end - - describe "includes details about whether an exception was handled" do - describe "RuntimeError" do - it "should report as unhandled if message is empty" do - err = RuntimeError.new("") - - err.full_message.should =~ /unhandled exception/ - err.full_message(highlight: true).should =~ /unhandled exception/ - err.full_message(highlight: false).should =~ /unhandled exception/ - end - - it "should not report as unhandled if the message is not empty" do - err = RuntimeError.new("non-empty") - - err.full_message.should !~ /unhandled exception/ - err.full_message(highlight: true).should !~ /unhandled exception/ - err.full_message(highlight: false).should !~ /unhandled exception/ - end - - it "should not report as unhandled if the message is nil" do - err = RuntimeError.new(nil) - - err.full_message.should !~ /unhandled exception/ - err.full_message(highlight: true).should !~ /unhandled exception/ - err.full_message(highlight: false).should !~ /unhandled exception/ - end - - it "should not report as unhandled if the message is not specified" do - err = RuntimeError.new() - - err.full_message.should !~ /unhandled exception/ - err.full_message(highlight: true).should !~ /unhandled exception/ - err.full_message(highlight: false).should !~ /unhandled exception/ - end - end - - describe "generic Error" do - it "should not report as unhandled in any event" do - StandardError.new("").full_message.should !~ /unhandled exception/ - StandardError.new("non-empty").full_message.should !~ /unhandled exception/ - end - end + 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") end it "shows the exception class at the end of the first line of the message when the message contains multiple lines" do @@ -94,24 +45,12 @@ 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.start_with?("#{__FILE__}:#{line}:in `") - full_message[0].should.end_with?(": first line (RuntimeError)\n") + full_message[0].should include("#{__FILE__}:#{line}:in `") + full_message[0].should include(": 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 @@ -146,53 +85,4 @@ describe "Exception#full_message" do exception.full_message.should include "intermediate exception" exception.full_message.should include "origin exception" end - - ruby_version_is "3.2" do - it "relies on #detailed_message" do - e = RuntimeError.new("new error") - e.define_singleton_method(:detailed_message) { |**| "DETAILED MESSAGE" } - - e.full_message.lines.first.should =~ /DETAILED MESSAGE/ - end - - it "passes all its own keyword arguments (with :highlight default value and without :order default value) to #detailed_message" do - e = RuntimeError.new("new error") - options_passed = nil - e.define_singleton_method(:detailed_message) do |**options| - options_passed = options - "DETAILED MESSAGE" - end - - e.full_message(foo: "bar") - options_passed.should == { foo: "bar", highlight: Exception.to_tty? } - end - - it "converts #detailed_message returned value to String if it isn't a String" do - message = Object.new - def message.to_str; "DETAILED MESSAGE"; end - - e = RuntimeError.new("new error") - e.define_singleton_method(:detailed_message) { |**| message } - - e.full_message.lines.first.should =~ /DETAILED MESSAGE/ - end - - it "uses class name if #detailed_message returns nil" do - e = RuntimeError.new("new error") - e.define_singleton_method(:detailed_message) { |**| nil } - - e.full_message(highlight: false).lines.first.should =~ /RuntimeError/ - e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/ - end - - it "uses class name if exception object doesn't respond to #detailed_message" do - e = RuntimeError.new("new error") - class << e - undef :detailed_message - end - - e.full_message(highlight: false).lines.first.should =~ /RuntimeError/ - e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/ - end - end end diff --git a/spec/ruby/core/exception/interrupt_spec.rb b/spec/ruby/core/exception/interrupt_spec.rb index 299b5b81f3..a7501efadc 100644 --- a/spec/ruby/core/exception/interrupt_spec.rb +++ b/spec/ruby/core/exception/interrupt_spec.rb @@ -48,13 +48,4 @@ 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/no_method_error_spec.rb b/spec/ruby/core/exception/no_method_error_spec.rb index 4621e36f44..8428ba0382 100644 --- a/spec/ruby/core/exception/no_method_error_spec.rb +++ b/spec/ruby/core/exception/no_method_error_spec.rb @@ -62,49 +62,26 @@ describe "NoMethodError#message" do NoMethodErrorSpecs::NoMethodErrorC.new.a_private_method rescue Exception => e e.should be_kind_of(NoMethodError) - e.message.lines[0].should =~ /private method `a_private_method' called for / + e.message.lines[0].should =~ /private method `a_private_method' called for #<NoMethodErrorSpecs::NoMethodErrorC:0x[\h]+>/ end end - ruby_version_is ""..."3.3" do - it "calls receiver.inspect only when calling Exception#message" do - ScratchPad.record [] - test_class = Class.new do - def inspect - ScratchPad << :inspect_called - "<inspect>" - end - end - instance = test_class.new - begin - instance.bar - rescue Exception => e - e.name.should == :bar - ScratchPad.recorded.should == [] - e.message.should =~ /undefined method.+\bbar\b/ - ScratchPad.recorded.should == [:inspect_called] + it "calls receiver.inspect only when calling Exception#message" do + ScratchPad.record [] + test_class = Class.new do + def inspect + ScratchPad << :inspect_called + "<inspect>" end end - end - - ruby_version_is "3.3" do - it "does not call receiver.inspect even when calling Exception#message" do - ScratchPad.record [] - test_class = Class.new do - def inspect - ScratchPad << :inspect_called - "<inspect>" - end - end - instance = test_class.new - begin - instance.bar - rescue Exception => e - e.name.should == :bar - ScratchPad.recorded.should == [] - e.message.should =~ /undefined method.+\bbar\b/ - ScratchPad.recorded.should == [] - end + instance = test_class.new + begin + instance.bar + rescue Exception => e + e.name.should == :bar + ScratchPad.recorded.should == [] + e.message.should =~ /undefined method.+\bbar\b/ + ScratchPad.recorded.should == [:inspect_called] end end @@ -125,19 +102,21 @@ describe "NoMethodError#message" do end end - it "uses #name to display the receiver if it is a class or a module" do - klass = Class.new { def self.name; "MyClass"; end } - begin - klass.foo - rescue NoMethodError => error - error.message.lines.first.chomp.should =~ /^undefined method `foo' for / - end + ruby_version_is "3.0" do + it "uses #name to display the receiver if it is a class or a module" do + klass = Class.new { def self.name; "MyClass"; end } + begin + klass.foo + rescue NoMethodError => error + error.message.lines.first.chomp.should == "undefined method `foo' for MyClass:Class" + end - mod = Module.new { def self.name; "MyModule"; end } - begin - mod.foo - rescue NoMethodError => error - error.message.lines.first.chomp.should =~ /^undefined method `foo' for / + mod = Module.new { def self.name; "MyModule"; end } + begin + mod.foo + rescue NoMethodError => error + error.message.lines.first.chomp.should == "undefined method `foo' for MyModule:Module" + end end end end diff --git a/spec/ruby/core/exception/signal_exception_spec.rb b/spec/ruby/core/exception/signal_exception_spec.rb index 1a0940743f..566bcb4672 100644 --- a/spec/ruby/core/exception/signal_exception_spec.rb +++ b/spec/ruby/core/exception/signal_exception_spec.rb @@ -93,7 +93,7 @@ describe "SignalException" do platform_is_not :windows do it "runs after at_exit" do - output = ruby_exe(<<-RUBY, exit_status: :SIGKILL) + output = ruby_exe(<<-RUBY, exit_status: nil) at_exit do puts "hello" $stdout.flush @@ -107,7 +107,7 @@ describe "SignalException" do end it "cannot be trapped with Signal.trap" do - ruby_exe(<<-RUBY, exit_status: :SIGPROF) + ruby_exe(<<-RUBY, exit_status: nil) Signal.trap("PROF") {} raise(SignalException, "PROF") RUBY @@ -116,7 +116,7 @@ describe "SignalException" do end it "self-signals for USR1" do - ruby_exe("raise(SignalException, 'USR1')", exit_status: :SIGUSR1) + ruby_exe("raise(SignalException, 'USR1')", exit_status: nil) $?.termsig.should == Signal.list.fetch('USR1') end end diff --git a/spec/ruby/core/exception/system_exit_spec.rb b/spec/ruby/core/exception/system_exit_spec.rb index d899844c4e..eef9faf271 100644 --- a/spec/ruby/core/exception/system_exit_spec.rb +++ b/spec/ruby/core/exception/system_exit_spec.rb @@ -1,48 +1,6 @@ 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/exception/top_level_spec.rb b/spec/ruby/core/exception/top_level_spec.rb index bcd09205b6..b47648425e 100644 --- a/spec/ruby/core/exception/top_level_spec.rb +++ b/spec/ruby/core/exception/top_level_spec.rb @@ -42,16 +42,4 @@ describe "An Exception reaching the top level" do EOS end end - - describe "kills all threads and fibers, ensure clauses are only run for threads current fibers, not for suspended fibers" do - it "with ensure on the root fiber" do - file = fixture(__FILE__, "thread_fiber_ensure.rb") - ruby_exe(file, args: "2>&1", exit_status: 0).should == "current fiber ensure\n" - end - - it "with ensure on non-root fiber" do - file = fixture(__FILE__, "thread_fiber_ensure_non_root_fiber.rb") - ruby_exe(file, args: "2>&1", exit_status: 0).should == "current fiber ensure\n" - end - end end diff --git a/spec/ruby/core/false/case_compare_spec.rb b/spec/ruby/core/false/case_compare_spec.rb deleted file mode 100644 index 0bd0ab44ae..0000000000 --- a/spec/ruby/core/false/case_compare_spec.rb +++ /dev/null @@ -1,14 +0,0 @@ -require_relative '../../spec_helper' - -describe "FalseClass#===" do - it "returns true for false" do - (false === false).should == true - end - - it "returns false for non-false object" do - (false === 0).should == false - (false === "").should == false - (false === Object).should == false - (false === nil).should == false - end -end diff --git a/spec/ruby/core/false/singleton_method_spec.rb b/spec/ruby/core/false/singleton_method_spec.rb deleted file mode 100644 index 738794b46c..0000000000 --- a/spec/ruby/core/false/singleton_method_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative '../../spec_helper' - -describe "FalseClass#singleton_method" do - ruby_version_is '3.3' do - it "raises regardless of whether FalseClass defines the method" do - -> { false.singleton_method(:foo) }.should raise_error(NameError) - begin - def (false).foo; end - -> { false.singleton_method(:foo) }.should raise_error(NameError) - ensure - FalseClass.send(:remove_method, :foo) - end - end - end -end diff --git a/spec/ruby/core/false/to_s_spec.rb b/spec/ruby/core/false/to_s_spec.rb index 62f67f6f55..4cae278891 100644 --- a/spec/ruby/core/false/to_s_spec.rb +++ b/spec/ruby/core/false/to_s_spec.rb @@ -5,11 +5,13 @@ describe "FalseClass#to_s" do false.to_s.should == "false" end - it "returns a frozen string" do - false.to_s.should.frozen? - end + ruby_version_is "2.7" do + 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) + it "always returns the same string" do + false.to_s.should equal(false.to_s) + end end end diff --git a/spec/ruby/core/fiber/blocking_spec.rb b/spec/ruby/core/fiber/blocking_spec.rb index ebefa116af..5ae5fbd577 100644 --- a/spec/ruby/core/fiber/blocking_spec.rb +++ b/spec/ruby/core/fiber/blocking_spec.rb @@ -1,76 +1,61 @@ require_relative '../../spec_helper' require_relative 'shared/blocking' -require "fiber" +ruby_version_is "3.0" do + require "fiber" -describe "Fiber.blocking?" do - it_behaves_like :non_blocking_fiber, -> { Fiber.blocking? } + describe "Fiber.blocking?" do + it_behaves_like :non_blocking_fiber, -> { Fiber.blocking? } - context "when fiber is blocking" do - context "root Fiber of the main thread" do - it "returns 1 for blocking: true" do - fiber = Fiber.new(blocking: true) { Fiber.blocking? } - blocking = fiber.resume - - blocking.should == 1 - end - end - - context "root Fiber of a new thread" do - it "returns 1 for blocking: true" do - thread = Thread.new do + context "when fiber is blocking" do + context "root Fiber of the main thread" do + it "returns 1 for blocking: true" do fiber = Fiber.new(blocking: true) { Fiber.blocking? } blocking = fiber.resume blocking.should == 1 end - - thread.join end - end - end -end -describe "Fiber#blocking?" do - it_behaves_like :non_blocking_fiber, -> { Fiber.current.blocking? } + context "root Fiber of a new thread" do + it "returns 1 for blocking: true" do + thread = Thread.new do + fiber = Fiber.new(blocking: true) { Fiber.blocking? } + blocking = fiber.resume - context "when fiber is blocking" do - context "root Fiber of the main thread" do - it "returns true for blocking: true" do - fiber = Fiber.new(blocking: true) { Fiber.current.blocking? } - blocking = fiber.resume + blocking.should == 1 + end - blocking.should == true + thread.join + end end end + end + + describe "Fiber#blocking?" do + it_behaves_like :non_blocking_fiber, -> { Fiber.current.blocking? } - context "root Fiber of a new thread" do - it "returns true for blocking: true" do - thread = Thread.new do + context "when fiber is blocking" do + context "root Fiber of the main thread" do + it "returns true for blocking: true" do fiber = Fiber.new(blocking: true) { Fiber.current.blocking? } blocking = fiber.resume blocking.should == true end - - thread.join end - end - end -end -ruby_version_is "3.2" do - describe "Fiber.blocking" do - context "when fiber is non-blocking" do - it "can become blocking" do - fiber = Fiber.new(blocking: false) do - Fiber.blocking do |f| - f.blocking? ? :blocking : :non_blocking + context "root Fiber of a new thread" do + it "returns true for blocking: true" do + thread = Thread.new do + fiber = Fiber.new(blocking: true) { Fiber.current.blocking? } + blocking = fiber.resume + + blocking.should == true end - end - blocking = fiber.resume - blocking.should == :blocking + thread.join + end end end end diff --git a/spec/ruby/core/fiber/inspect_spec.rb b/spec/ruby/core/fiber/inspect_spec.rb deleted file mode 100644 index f20a153fc2..0000000000 --- a/spec/ruby/core/fiber/inspect_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -require_relative '../../spec_helper' -require 'fiber' - -describe "Fiber#inspect" do - describe "status" do - it "is resumed for the root Fiber of a Thread" do - inspected = Thread.new { Fiber.current.inspect }.value - inspected.should =~ /\A#<Fiber:0x\h+ .*\(resumed\)>\z/ - end - - it "is created for a Fiber which did not run yet" do - inspected = Fiber.new {}.inspect - inspected.should =~ /\A#<Fiber:0x\h+ .+ \(created\)>\z/ - end - - it "is resumed for a Fiber which was resumed" do - inspected = Fiber.new { Fiber.current.inspect }.resume - inspected.should =~ /\A#<Fiber:0x\h+ .+ \(resumed\)>\z/ - end - - it "is resumed for a Fiber which was transferred" do - inspected = Fiber.new { Fiber.current.inspect }.transfer - inspected.should =~ /\A#<Fiber:0x\h+ .+ \(resumed\)>\z/ - end - - it "is suspended for a Fiber which was resumed and yielded" do - inspected = Fiber.new { Fiber.yield }.tap(&:resume).inspect - inspected.should =~ /\A#<Fiber:0x\h+ .+ \(suspended\)>\z/ - end - - it "is terminated for a Fiber which has terminated" do - inspected = Fiber.new {}.tap(&:resume).inspect - inspected.should =~ /\A#<Fiber:0x\h+ .+ \(terminated\)>\z/ - end - end -end diff --git a/spec/ruby/core/fiber/kill_spec.rb b/spec/ruby/core/fiber/kill_spec.rb deleted file mode 100644 index 2f4c499280..0000000000 --- a/spec/ruby/core/fiber/kill_spec.rb +++ /dev/null @@ -1,90 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative '../../shared/kernel/raise' - -ruby_version_is "3.3" do - describe "Fiber#kill" do - it "kills a non-resumed fiber" do - fiber = Fiber.new{} - - fiber.alive?.should == true - - fiber.kill - fiber.alive?.should == false - end - - it "kills a resumed fiber" do - fiber = Fiber.new{while true; Fiber.yield; end} - fiber.resume - - fiber.alive?.should == true - - fiber.kill - fiber.alive?.should == false - end - - it "can kill itself" do - fiber = Fiber.new do - Fiber.current.kill - end - - fiber.alive?.should == true - - fiber.resume - fiber.alive?.should == false - end - - it "kills a resumed fiber from a child" do - parent = Fiber.new do - child = Fiber.new do - parent.kill - parent.alive?.should == true - end - - child.resume - end - - parent.resume - parent.alive?.should == false - end - - it "executes the ensure block" do - ensure_executed = false - - fiber = Fiber.new do - while true; Fiber.yield; end - ensure - ensure_executed = true - end - - fiber.resume - fiber.kill - ensure_executed.should == true - end - - it "does not execute rescue block" do - rescue_executed = false - - fiber = Fiber.new do - while true; Fiber.yield; end - rescue Exception - rescue_executed = true - end - - fiber.resume - fiber.kill - rescue_executed.should == false - end - - it "repeatedly kills a fiber" do - fiber = Fiber.new do - while true; Fiber.yield; end - ensure - while true; Fiber.yield; end - end - - fiber.kill - fiber.alive?.should == false - end - end -end diff --git a/spec/ruby/core/fiber/raise_spec.rb b/spec/ruby/core/fiber/raise_spec.rb index eb4b39c8be..2a465c8bfa 100644 --- a/spec/ruby/core/fiber/raise_spec.rb +++ b/spec/ruby/core/fiber/raise_spec.rb @@ -2,104 +2,120 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative '../../shared/kernel/raise' -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) +ruby_version_is "2.7" do + describe "Fiber#raise" do + it_behaves_like :kernel_raise, :raise, FiberSpecs::NewFiberToRaise 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 + describe "Fiber#raise" do + it 'raises RuntimeError by default' do + -> { FiberSpecs::NewFiberToRaise.raise }.should raise_error(RuntimeError) + end - it 'accepts error class' do - -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError }.should raise_error(FiberSpecs::CustomError) - 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 'accepts error message' do - -> { FiberSpecs::NewFiberToRaise.raise "error message" }.should raise_error(RuntimeError, "error message") - 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 'does not accept array of backtrace information only' do - -> { FiberSpecs::NewFiberToRaise.raise ['foo'] }.should raise_error(TypeError) - end + it 'accepts error class' do + -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError }.should raise_error(FiberSpecs::CustomError) + end - it 'does not accept integer' do - -> { FiberSpecs::NewFiberToRaise.raise 100 }.should raise_error(TypeError) - end + it 'accepts error message' do + -> { FiberSpecs::NewFiberToRaise.raise "error message" }.should raise_error(RuntimeError, "error message") + 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 'does not accept array of backtrace information only' do + -> { FiberSpecs::NewFiberToRaise.raise ['foo'] }.should raise_error(TypeError) + 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 integer' do + -> { FiberSpecs::NewFiberToRaise.raise 100 }.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 'accepts error class with error message' do + -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error' }.should raise_error(FiberSpecs::CustomError, 'test error') + end - it "raises a FiberError if invoked from a different Thread" do - fiber = Fiber.new { Fiber.yield } - fiber.resume - Thread.new do + it 'accepts error class with with error message and backtrace information' do -> { - fiber.raise - }.should raise_error(FiberError, "fiber called across threads") - end.join - end + 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 "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 'does not accept only error message and backtrace information' do + -> { FiberSpecs::NewFiberToRaise.raise 'test error', ['foo', 'boo'] }.should raise_error(TypeError) + end - it "returns to calling fiber after raise" do - fiber_one = Fiber.new do - Fiber.yield :yield_one - :unreachable + 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 - fiber_two = Fiber.new do - results = [] - results << fiber_one.resume - begin - fiber_one.raise - rescue - results << :rescued - end - results + 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 - fiber_two.resume.should == [:yield_one, :rescued] + 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 + end + + fiber_two.resume.should == [:yield_one, :rescued] + end end + end +ruby_version_is "2.7"..."3.0" do + describe "Fiber#raise" do + it "raises a FiberError if invoked on a transferring Fiber" do + require "fiber" + root = Fiber.current + fiber = Fiber.new { root.transfer } + fiber.transfer + -> { fiber.raise }.should raise_error(FiberError, "cannot resume transferred Fiber") + end + end +end -describe "Fiber#raise" do - it "transfers and raises on a transferring fiber" do - require "fiber" - root = Fiber.current - fiber = Fiber.new { root.transfer } - fiber.transfer - -> { fiber.raise "msg" }.should raise_error(RuntimeError, "msg") +ruby_version_is "3.0" do + describe "Fiber#raise" do + it "transfers and raises on a transferring fiber" do + require "fiber" + root = Fiber.current + fiber = Fiber.new { root.transfer } + fiber.transfer + -> { fiber.raise "msg" }.should raise_error(RuntimeError, "msg") + end end end diff --git a/spec/ruby/core/fiber/resume_spec.rb b/spec/ruby/core/fiber/resume_spec.rb index ab9a6799ab..273bc866af 100644 --- a/spec/ruby/core/fiber/resume_spec.rb +++ b/spec/ruby/core/fiber/resume_spec.rb @@ -28,9 +28,18 @@ describe "Fiber#resume" do fiber.resume :second end - it "raises a FiberError if the Fiber tries to resume itself" do - fiber = Fiber.new { fiber.resume } - -> { fiber.resume }.should raise_error(FiberError, /current fiber/) + ruby_version_is '3.0' do + it "raises a FiberError if the Fiber tries to resume itself" do + fiber = Fiber.new { fiber.resume } + -> { fiber.resume }.should raise_error(FiberError, /current fiber/) + end + end + + ruby_version_is '' ... '3.0' do + it "raises a FiberError if the Fiber tries to resume itself" do + fiber = Fiber.new { fiber.resume } + -> { fiber.resume }.should raise_error(FiberError, /double resume/) + end end it "returns control to the calling Fiber if called from one" do diff --git a/spec/ruby/core/fiber/storage_spec.rb b/spec/ruby/core/fiber/storage_spec.rb deleted file mode 100644 index 5c87ed5d41..0000000000 --- a/spec/ruby/core/fiber/storage_spec.rb +++ /dev/null @@ -1,158 +0,0 @@ -require_relative '../../spec_helper' - -ruby_version_is "3.2" do - describe "Fiber.new(storage:)" do - it "creates a Fiber with the given storage" do - storage = {life: 42} - fiber = Fiber.new(storage: storage) { Fiber.current.storage } - fiber.resume.should == storage - end - - it "creates a fiber with lazily initialized storage" do - Fiber.new(storage: nil) { Fiber[:x] = 10; Fiber.current.storage }.resume.should == {x: 10} - end - - it "creates a fiber by inheriting the storage of the parent fiber" do - fiber = Fiber.new(storage: {life: 42}) do - Fiber.new { Fiber.current.storage }.resume - end - fiber.resume.should == {life: 42} - end - - it "cannot create a fiber with non-hash storage" do - -> { Fiber.new(storage: 42) {} }.should raise_error(TypeError) - end - - it "cannot create a fiber with a frozen hash as storage" do - -> { Fiber.new(storage: {life: 43}.freeze) {} }.should raise_error(FrozenError) - end - - it "cannot create a fiber with a storage hash with non-symbol keys" do - -> { Fiber.new(storage: {life: 43, Object.new => 44}) {} }.should raise_error(TypeError) - end - end - - describe "Fiber#storage" do - it "cannot be accessed from a different fiber" do - f = Fiber.new(storage: {life: 42}) { nil } - -> { - f.storage - }.should raise_error(ArgumentError, /Fiber storage can only be accessed from the Fiber it belongs to/) - end - end - - describe "Fiber#storage=" do - it "can clear the storage of the fiber" do - fiber = Fiber.new(storage: {life: 42}) do - Fiber.current.storage = nil - Fiber[:x] = 10 - Fiber.current.storage - end - fiber.resume.should == {x: 10} - end - - it "can set the storage of the fiber" do - fiber = Fiber.new(storage: {life: 42}) do - Fiber.current.storage = {life: 43} - Fiber.current.storage - end - fiber.resume.should == {life: 43} - end - - it "can't set the storage of the fiber to non-hash" do - -> { Fiber.current.storage = 42 }.should raise_error(TypeError) - end - - it "can't set the storage of the fiber to a frozen hash" do - -> { Fiber.current.storage = {life: 43}.freeze }.should raise_error(FrozenError) - end - - it "can't set the storage of the fiber to a hash with non-symbol keys" do - -> { Fiber.current.storage = {life: 43, Object.new => 44} }.should raise_error(TypeError) - end - end - - describe "Fiber.[]" do - it "returns the value of the given key in the storage of the current fiber" do - Fiber.new(storage: {life: 42}) { Fiber[:life] }.resume.should == 42 - end - - it "returns nil if the key is not present in the storage of the current fiber" do - Fiber.new(storage: {life: 42}) { Fiber[:death] }.resume.should be_nil - end - - it "returns nil if the current fiber has no storage" do - Fiber.new { Fiber[:life] }.resume.should be_nil - end - - ruby_version_is "3.2.3" do - it "can use dynamically defined keys" do - key = :"#{self.class.name}#.#{self.object_id}" - Fiber.new { Fiber[key] = 42; Fiber[key] }.resume.should == 42 - end - - it "can't use invalid keys" do - invalid_keys = [Object.new, "Foo", 12] - invalid_keys.each do |key| - -> { Fiber[key] }.should raise_error(TypeError) - end - end - end - - it "can access the storage of the parent fiber" do - f = Fiber.new(storage: {life: 42}) do - Fiber.new { Fiber[:life] }.resume - end - f.resume.should == 42 - end - - it "can't access the storage of the fiber with non-symbol keys" do - -> { Fiber[Object.new] }.should raise_error(TypeError) - end - end - - describe "Fiber.[]=" do - it "sets the value of the given key in the storage of the current fiber" do - Fiber.new(storage: {life: 42}) { Fiber[:life] = 43; Fiber[:life] }.resume.should == 43 - end - - it "sets the value of the given key in the storage of the current fiber" do - Fiber.new(storage: {life: 42}) { Fiber[:death] = 43; Fiber[:death] }.resume.should == 43 - end - - it "sets the value of the given key in the storage of the current fiber" do - Fiber.new { Fiber[:life] = 43; Fiber[:life] }.resume.should == 43 - end - - it "does not overwrite the storage of the parent fiber" do - f = Fiber.new(storage: {life: 42}) do - Fiber.yield Fiber.new { Fiber[:life] = 43; Fiber[:life] }.resume - Fiber[:life] - end - f.resume.should == 43 # Value of the inner fiber - f.resume.should == 42 # Value of the outer fiber - end - - it "can't access the storage of the fiber with non-symbol keys" do - -> { Fiber[Object.new] = 44 }.should raise_error(TypeError) - end - - ruby_version_is "3.3" do - it "deletes the fiber storage key when assigning nil" do - Fiber.new(storage: {life: 42}) { - Fiber[:life] = nil - Fiber.current.storage - }.resume.should == {} - end - end - end - - describe "Thread.new" do - it "creates a thread with the storage of the current fiber" do - fiber = Fiber.new(storage: {life: 42}) do - Thread.new { Fiber.current.storage }.value - end - fiber.resume.should == {life: 42} - end - end -end diff --git a/spec/ruby/core/file/absolute_path_spec.rb b/spec/ruby/core/file/absolute_path_spec.rb index 315eead34f..9f39923472 100644 --- a/spec/ruby/core/file/absolute_path_spec.rb +++ b/spec/ruby/core/file/absolute_path_spec.rb @@ -1,52 +1,54 @@ require_relative '../../spec_helper' -describe "File.absolute_path?" do - before :each do - @abs = File.expand_path(__FILE__) - end +ruby_version_is "2.7" do + 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 + 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 - 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 + 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 - 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 + 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 end @@ -85,7 +87,7 @@ describe "File.absolute_path" do end it "accepts a second argument of a directory from which to resolve the path" do - File.absolute_path(__FILE__, __dir__).should == @abs + File.absolute_path(__FILE__, File.dirname(__FILE__)).should == @abs end it "calls #to_path on its argument" do diff --git a/spec/ruby/core/file/atime_spec.rb b/spec/ruby/core/file/atime_spec.rb index 1b47576e6b..cef07ba010 100644 --- a/spec/ruby/core/file/atime_spec.rb +++ b/spec/ruby/core/file/atime_spec.rb @@ -16,10 +16,10 @@ describe "File.atime" do end platform_is :linux, :windows do - unless ENV.key?('TRAVIS') # https://bugs.ruby-lang.org/issues/17926 + platform_is_not :"powerpc64le-linux" do # https://bugs.ruby-lang.org/issues/17926 ## NOTE also that some Linux systems disable atime (e.g. via mount params) for better filesystem speed. it "returns the last access time for the named file with microseconds" do - supports_subseconds = Integer(`stat -c%x '#{__FILE__}'`[/\.(\d{1,6})/, 1], 10) + supports_subseconds = Integer(`stat -c%x '#{__FILE__}'`[/\.(\d+)/, 1], 10) if supports_subseconds != 0 expected_time = Time.at(Time.now.to_i + 0.123456) File.utime expected_time, 0, @file diff --git a/spec/ruby/core/file/ctime_spec.rb b/spec/ruby/core/file/ctime_spec.rb index d17ba1a77f..b16eb13c1e 100644 --- a/spec/ruby/core/file/ctime_spec.rb +++ b/spec/ruby/core/file/ctime_spec.rb @@ -16,7 +16,7 @@ describe "File.ctime" do platform_is :linux, :windows do it "returns the change time for the named file (the time at which directory information about the file was changed, not the file itself) with microseconds." do - supports_subseconds = Integer(`stat -c%z '#{__FILE__}'`[/\.(\d{1,6})/, 1], 10) + supports_subseconds = Integer(`stat -c%z '#{__FILE__}'`[/\.(\d+)/, 1], 10) if supports_subseconds != 0 File.ctime(__FILE__).usec.should > 0 else diff --git a/spec/ruby/core/file/dirname_spec.rb b/spec/ruby/core/file/dirname_spec.rb index 8dd6c4ca88..cf0f909f59 100644 --- a/spec/ruby/core/file/dirname_spec.rb +++ b/spec/ruby/core/file/dirname_spec.rb @@ -12,33 +12,18 @@ describe "File.dirname" do end ruby_version_is '3.1' do - context "when level is passed" do - it "returns all the components of filename except the last parts by the level" do - File.dirname('/home/jason', 2).should == '/' - File.dirname('/home/jason/poot.txt', 2).should == '/home' - end - - it "returns the same String if the level is 0" do - File.dirname('poot.txt', 0).should == 'poot.txt' - File.dirname('/', 0).should == '/' - end - - it "raises ArgumentError if the level is negative" do - -> { - File.dirname('/home/jason', -1) - }.should raise_error(ArgumentError, "negative level: -1") - end - - it "returns '/' when level exceeds the number of segments in the path" do - File.dirname("/home/jason", 100).should == '/' - end - - it "calls #to_int if passed not numeric value" do - object = Object.new - def object.to_int; 2; end - - File.dirname("/a/b/c/d", object).should == '/a/b' - end + it "returns all the components of filename except the last parts by the level" do + File.dirname('/home/jason', 2).should == '/' + File.dirname('/home/jason/poot.txt', 2).should == '/home' + end + + it "returns the same string if the level is 0" do + File.dirname('poot.txt', 0).should == 'poot.txt' + File.dirname('/', 0).should == '/' + end + + it "raises ArgumentError if the level is negative" do + -> {File.dirname('/home/jason', -1)}.should raise_error(ArgumentError) end end diff --git a/spec/ruby/core/file/exist_spec.rb b/spec/ruby/core/file/exist_spec.rb index 2633376880..ddb5febcba 100644 --- a/spec/ruby/core/file/exist_spec.rb +++ b/spec/ruby/core/file/exist_spec.rb @@ -4,11 +4,3 @@ require_relative '../../shared/file/exist' describe "File.exist?" do it_behaves_like :file_exist, :exist?, File end - -ruby_version_is "3.2" do - describe "File.exists?" do - it "has been removed" do - File.should_not.respond_to?(:exists?) - end - end -end diff --git a/spec/ruby/core/file/extname_spec.rb b/spec/ruby/core/file/extname_spec.rb index d20cf813d9..e182ed44f2 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 - platform_is :windows do + guard -> { platform_is :windows or ruby_version_is ""..."2.7" } do it "returns ''" do File.extname(".foo.").should == "" File.extname("foo.").should == "" end end - platform_is_not :windows do + guard -> { platform_is_not :windows and ruby_version_is "2.7" } do it "returns '.'" do File.extname(".foo.").should == "." File.extname("foo.").should == "." diff --git a/spec/ruby/core/file/flock_spec.rb b/spec/ruby/core/file/flock_spec.rb index 070d830bc4..751e99d994 100644 --- a/spec/ruby/core/file/flock_spec.rb +++ b/spec/ruby/core/file/flock_spec.rb @@ -30,7 +30,7 @@ describe "File#flock" do it "returns false if trying to lock an exclusively locked file" do @file.flock File::LOCK_EX - ruby_exe(<<-END_OF_CODE).should == "false" + ruby_exe(<<-END_OF_CODE, escape: true).should == "false" File.open('#{@name}', "w") do |f2| print f2.flock(File::LOCK_EX | File::LOCK_NB).to_s end @@ -40,7 +40,7 @@ describe "File#flock" do it "blocks if trying to lock an exclusively locked file" do @file.flock File::LOCK_EX - out = ruby_exe(<<-END_OF_CODE) + out = ruby_exe(<<-END_OF_CODE, escape: true) running = false t = Thread.new do diff --git a/spec/ruby/core/file/mtime_spec.rb b/spec/ruby/core/file/mtime_spec.rb index 5304bbf057..8d47d3021a 100644 --- a/spec/ruby/core/file/mtime_spec.rb +++ b/spec/ruby/core/file/mtime_spec.rb @@ -16,16 +16,14 @@ describe "File.mtime" do end platform_is :linux, :windows do - unless ENV.key?('TRAVIS') # https://bugs.ruby-lang.org/issues/17926 - it "returns the modification Time of the file with microseconds" do - supports_subseconds = Integer(`stat -c%y '#{__FILE__}'`[/\.(\d{1,6})/, 1], 10) - if supports_subseconds != 0 - expected_time = Time.at(Time.now.to_i + 0.123456) - File.utime 0, expected_time, @filename - File.mtime(@filename).usec.should == expected_time.usec - else - File.mtime(__FILE__).usec.should == 0 - end + it "returns the modification Time of the file with microseconds" do + supports_subseconds = Integer(`stat -c%y '#{__FILE__}'`[/\.(\d+)/, 1], 10) + if supports_subseconds != 0 + expected_time = Time.at(Time.now.to_i + 0.123456) + File.utime 0, expected_time, @filename + File.mtime(@filename).usec.should == expected_time.usec + else + File.mtime(__FILE__).usec.should == 0 end end end diff --git a/spec/ruby/core/file/new_spec.rb b/spec/ruby/core/file/new_spec.rb index 1e82a070b1..004f78503a 100644 --- a/spec/ruby/core/file/new_spec.rb +++ b/spec/ruby/core/file/new_spec.rb @@ -78,29 +78,13 @@ describe "File.new" do File.should.exist?(@file) end - it "returns a new read-only File when mode is not specified" do - @fh = File.new(@file) - - -> { @fh.puts("test") }.should raise_error(IOError) - @fh.read.should == "" - File.should.exist?(@file) - end - - it "returns a new read-only File when mode is not specified but flags option is present" do - @fh = File.new(@file, flags: File::CREAT) - - -> { @fh.puts("test") }.should raise_error(IOError) - @fh.read.should == "" - File.should.exist?(@file) - end - it "creates a new file when use File::EXCL mode" do @fh = File.new(@file, File::EXCL) @fh.should be_kind_of(File) File.should.exist?(@file) end - it "raises an Errno::EEXIST if the file exists when create a new file with File::CREAT|File::EXCL" do + it "raises an Errorno::EEXIST if the file exists when create a new file with File::CREAT|File::EXCL" do -> { @fh = File.new(@file, File::CREAT|File::EXCL) }.should raise_error(Errno::EEXIST) end @@ -128,32 +112,13 @@ describe "File.new" do File.should.exist?(@file) end + it "creates a new file when use File::WRONLY|File::TRUNC mode" do @fh = File.new(@file, File::WRONLY|File::TRUNC) @fh.should be_kind_of(File) File.should.exist?(@file) end - it "returns a new read-only File when use File::RDONLY|File::CREAT mode" do - @fh = File.new(@file, File::RDONLY|File::CREAT) - @fh.should be_kind_of(File) - File.should.exist?(@file) - - # it's read-only - -> { @fh.puts("test") }.should raise_error(IOError) - @fh.read.should == "" - end - - it "returns a new read-only File when use File::CREAT mode" do - @fh = File.new(@file, File::CREAT) - @fh.should be_kind_of(File) - File.should.exist?(@file) - - # it's read-only - -> { @fh.puts("test") }.should raise_error(IOError) - @fh.read.should == "" - end - it "coerces filename using to_str" do name = mock("file") name.should_receive(:to_str).and_return(@file) @@ -168,32 +133,6 @@ describe "File.new" do File.should.exist?(@file) end - it "accepts options as a keyword argument" do - @fh = File.new(@file, 'w', 0755, flags: @flags) - @fh.should be_kind_of(File) - @fh.close - - -> { - @fh = File.new(@file, 'w', 0755, {flags: @flags}) - }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)") - end - - it "bitwise-ORs mode and flags option" do - -> { - @fh = File.new(@file, 'w', flags: File::EXCL) - }.should raise_error(Errno::EEXIST, /File exists/) - - -> { - @fh = File.new(@file, mode: 'w', flags: File::EXCL) - }.should raise_error(Errno::EEXIST, /File exists/) - end - - it "does not use the given block and warns to use File::open" do - -> { - @fh = File.new(@file) { raise } - }.should complain(/warning: File::new\(\) does not take block; use File::open\(\) instead/) - end - it "raises a TypeError if the first parameter can't be coerced to a string" do -> { File.new(true) }.should raise_error(TypeError) -> { File.new(false) }.should raise_error(TypeError) diff --git a/spec/ruby/core/file/open_spec.rb b/spec/ruby/core/file/open_spec.rb index 6bfc16bbf9..c7dd34d5c6 100644 --- a/spec/ruby/core/file/open_spec.rb +++ b/spec/ruby/core/file/open_spec.rb @@ -314,7 +314,7 @@ describe "File.open" do end end - it "raises an IOError when write in a block opened with File::RDONLY|File::APPEND mode" do + it "raises an IOError when read in a block opened with File::RDONLY|File::APPEND mode" do -> { File.open(@file, File::RDONLY|File::APPEND ) do |f| f.puts("writing") @@ -354,7 +354,7 @@ describe "File.open" do end end - it "raises an Errno::EEXIST if the file exists when open with File::CREAT|File::EXCL" do + it "raises an Errorno::EEXIST if the file exists when open with File::CREAT|File::EXCL" do -> { File.open(@file, File::CREAT|File::EXCL) do |f| f.puts("writing") @@ -423,7 +423,7 @@ describe "File.open" do }.should raise_error(IOError) end - it "raises an Errno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do + it "raises an Errorno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do -> { File.open(@file, File::RDONLY|File::TRUNC) do |f| f.puts("writing").should == nil @@ -441,7 +441,7 @@ describe "File.open" do }.should raise_error(Errno::EINVAL) end - it "raises an Errno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do + it "raises an Errorno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do -> { File.open(@file, File::RDONLY|File::TRUNC) do |f| f.puts("writing").should == nil @@ -494,14 +494,6 @@ describe "File.open" do File.open(@file, "w") { |f| f.puts "testing" } File.size(@file).should > 0 File.open(@file, "rb+") do |f| - f.binmode?.should == true - f.external_encoding.should == Encoding::ASCII_8BIT - f.pos.should == 0 - f.should_not.eof? - end - File.open(@file, "r+b") do |f| - f.binmode?.should == true - f.external_encoding.should == Encoding::ASCII_8BIT f.pos.should == 0 f.should_not.eof? end @@ -565,15 +557,6 @@ describe "File.open" do File.open(@file, 'wb+') {|f| f.external_encoding.should == Encoding::BINARY} end - it "accepts options as a keyword argument" do - @fh = File.open(@file, 'w', 0755, flags: File::CREAT) - @fh.should be_an_instance_of(File) - - -> { - File.open(@file, 'w', 0755, {flags: File::CREAT}) - }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)") - end - it "uses the second argument as an options Hash" do @fh = File.open(@file, mode: "r") @fh.should be_an_instance_of(File) diff --git a/spec/ruby/core/file/realpath_spec.rb b/spec/ruby/core/file/realpath_spec.rb index bd25bfdecf..bd27e09da6 100644 --- a/spec/ruby/core/file/realpath_spec.rb +++ b/spec/ruby/core/file/realpath_spec.rb @@ -54,10 +54,6 @@ platform_is_not :windows do File.realpath(@relative_symlink).should == @file end - it "removes the file element when going one level up" do - File.realpath('../', @file).should == @real_dir - end - it "raises an Errno::ELOOP if the symlink points to itself" do File.unlink @link File.symlink(@link, @link) diff --git a/spec/ruby/core/file/shared/fnmatch.rb b/spec/ruby/core/file/shared/fnmatch.rb index db4b5c5d8c..a8488fd30a 100644 --- a/spec/ruby/core/file/shared/fnmatch.rb +++ b/spec/ruby/core/file/shared/fnmatch.rb @@ -75,14 +75,6 @@ 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 @@ -102,7 +94,6 @@ describe :file_fnmatch, shared: true do it "matches ranges of characters using exclusive bracket expression (e.g. [^t] or [!t])" do File.send(@method, 'ca[^t]', 'cat').should == false - File.send(@method, 'ca[^t]', 'cas').should == true File.send(@method, 'ca[!t]', 'cat').should == false end @@ -126,13 +117,6 @@ describe :file_fnmatch, shared: true do end end - it "matches wildcard with characters when flags includes FNM_PATHNAME" do - File.send(@method, '*a', 'aa', File::FNM_PATHNAME).should == true - File.send(@method, 'a*', 'aa', File::FNM_PATHNAME).should == true - File.send(@method, 'a*', 'aaa', File::FNM_PATHNAME).should == true - File.send(@method, '*a', 'aaa', File::FNM_PATHNAME).should == true - end - it "does not match '/' characters with ? or * when flags includes FNM_PATHNAME" do File.send(@method, '?', '/', File::FNM_PATHNAME).should == false File.send(@method, '*', '/', File::FNM_PATHNAME).should == false @@ -167,25 +151,15 @@ describe :file_fnmatch, shared: true do end it "does not match leading periods in filenames with wildcards by default" do - File.should_not.send(@method, '*', '.profile') - File.should.send(@method, '*', 'home/.profile') - File.should.send(@method, '*/*', 'home/.profile') - File.should_not.send(@method, '*/*', 'dave/.profile', File::FNM_PATHNAME) + File.send(@method, '*', '.profile').should == false + File.send(@method, '*', 'home/.profile').should == true + File.send(@method, '*/*', 'home/.profile').should == true + File.send(@method, '*/*', 'dave/.profile', File::FNM_PATHNAME).should == false end - it "matches patterns with leading periods to dotfiles" do + it "matches patterns with leading periods to dotfiles by default" do File.send(@method, '.*', '.profile').should == true - File.send(@method, '.*', '.profile', File::FNM_PATHNAME).should == true File.send(@method, ".*file", "nondotfile").should == false - File.send(@method, ".*file", "nondotfile", File::FNM_PATHNAME).should == false - end - - it "does not match directories with leading periods by default with FNM_PATHNAME" do - File.send(@method, '.*', '.directory/nondotfile', File::FNM_PATHNAME).should == false - File.send(@method, '.*', '.directory/.profile', File::FNM_PATHNAME).should == false - File.send(@method, '.*', 'foo/.directory/nondotfile', File::FNM_PATHNAME).should == false - File.send(@method, '.*', 'foo/.directory/.profile', File::FNM_PATHNAME).should == false - File.send(@method, '**/.dotfile', '.dotsubdir/.dotfile', File::FNM_PATHNAME).should == false end it "matches leading periods in filenames when flags includes FNM_DOTMATCH" do @@ -239,33 +213,6 @@ describe :file_fnmatch, shared: true do File.send(@method, pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true end - it "has special handling for ./ when using * and FNM_PATHNAME" do - File.send(@method, './*', '.', File::FNM_PATHNAME).should be_false - File.send(@method, './*', './', File::FNM_PATHNAME).should be_true - File.send(@method, './*/', './', File::FNM_PATHNAME).should be_false - File.send(@method, './**', './', File::FNM_PATHNAME).should be_true - File.send(@method, './**/', './', File::FNM_PATHNAME).should be_true - File.send(@method, './*', '.', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_false - File.send(@method, './*', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true - File.send(@method, './*/', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_false - File.send(@method, './**', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true - File.send(@method, './**/', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true - end - - it "matches **/* with FNM_PATHNAME to recurse directories" do - File.send(@method, 'nested/**/*', 'nested/subdir', File::FNM_PATHNAME).should be_true - File.send(@method, 'nested/**/*', 'nested/subdir/file', File::FNM_PATHNAME).should be_true - File.send(@method, 'nested/**/*', 'nested/.dotsubdir', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true - File.send(@method, 'nested/**/*', 'nested/.dotsubir/.dotfile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true - end - - it "matches ** with FNM_PATHNAME only in current directory" do - File.send(@method, 'nested/**', 'nested/subdir', File::FNM_PATHNAME).should be_true - File.send(@method, 'nested/**', 'nested/subdir/file', File::FNM_PATHNAME).should be_false - File.send(@method, 'nested/**', 'nested/.dotsubdir', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true - File.send(@method, 'nested/**', 'nested/.dotsubir/.dotfile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_false - end - it "accepts an object that has a #to_path method" do File.send(@method, '\*', mock_to_path('a')).should == false end diff --git a/spec/ruby/core/file/shared/path.rb b/spec/ruby/core/file/shared/path.rb index ee8109ba05..0a5abe33f0 100644 --- a/spec/ruby/core/file/shared/path.rb +++ b/spec/ruby/core/file/shared/path.rb @@ -78,15 +78,13 @@ describe :file_path, shared: true do rm_r @dir end - ruby_version_is ""..."3.1" do - it "raises IOError if file was opened with File::TMPFILE" do - begin - File.open(@dir, File::RDWR | File::TMPFILE) do |f| - -> { f.send(@method) }.should raise_error(IOError) - end - rescue Errno::EOPNOTSUPP, Errno::EINVAL, Errno::EISDIR - skip "no support from the filesystem" + it "raises IOError if file was opened with File::TMPFILE" do + begin + File.open(@dir, File::RDWR | File::TMPFILE) do |f| + -> { f.send(@method) }.should raise_error(IOError) end + rescue Errno::EOPNOTSUPP, Errno::EINVAL, Errno::EISDIR + skip "no support from the filesystem" end end end diff --git a/spec/ruby/core/file/utime_spec.rb b/spec/ruby/core/file/utime_spec.rb index 0b0e4f979c..852fbe2249 100644 --- a/spec/ruby/core/file/utime_spec.rb +++ b/spec/ruby/core/file/utime_spec.rb @@ -77,10 +77,6 @@ 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 or 2486-07-02)" do diff --git a/spec/ruby/core/float/coerce_spec.rb b/spec/ruby/core/float/coerce_spec.rb index baa831dcf6..ea108f3303 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(18446744073709551616.0, TOLERANCE) + a.should be_close(9223372036854775808.0, TOLERANCE) b.should be_close(-0.0, TOLERANCE) a, b = 1.0.coerce(bignum_value) - a.should be_close(18446744073709551616.0, TOLERANCE) + a.should be_close(9223372036854775808.0, TOLERANCE) b.should be_close(1.0, TOLERANCE) end end diff --git a/spec/ruby/core/float/comparison_spec.rb b/spec/ruby/core/float/comparison_spec.rb index 1373b3a1fb..53e7ec332a 100644 --- a/spec/ruby/core/float/comparison_spec.rb +++ b/spec/ruby/core/float/comparison_spec.rb @@ -7,25 +7,9 @@ describe "Float#<=>" do ((bignum_value*1.1) <=> bignum_value).should == 1 end - it "returns nil if one side is NaN" do - [1.0, 42, bignum_value].each { |n| - (nan_value <=> n).should == nil - (n <=> nan_value).should == nil - } - end - - it "handles positive infinity" do - [1.0, 42, bignum_value].each { |n| - (infinity_value <=> n).should == 1 - (n <=> infinity_value).should == -1 - } - end - - it "handles negative infinity" do - [1.0, 42, bignum_value].each { |n| - (-infinity_value <=> n).should == -1 - (n <=> -infinity_value).should == 1 - } + it "returns nil when either argument is NaN" do + (nan_value <=> 71.2).should be_nil + (1771.176 <=> nan_value).should be_nil end it "returns nil when the given argument is not a Float" do @@ -65,10 +49,21 @@ describe "Float#<=>" do }.should raise_error(TypeError, "coerce must return [x, y]") end - it "returns the correct result when one side is infinite" do + # The 4 tests below are taken from matz's revision 23730 for Ruby trunk + # + it "returns 1 when self is Infinity and other is an Integer" do (infinity_value <=> Float::MAX.to_i*2).should == 1 + end + + it "returns -1 when self is negative and other is Infinity" do (-Float::MAX.to_i*2 <=> infinity_value).should == -1 + end + + it "returns -1 when self is -Infinity and other is negative" do (-infinity_value <=> -Float::MAX.to_i*2).should == -1 + end + + it "returns 1 when self is negative and other is -Infinity" do (-Float::MAX.to_i*2 <=> -infinity_value).should == 1 end diff --git a/spec/ruby/core/float/divide_spec.rb b/spec/ruby/core/float/divide_spec.rb index 72ab7527bd..d8f71a6b98 100644 --- a/spec/ruby/core/float/divide_spec.rb +++ b/spec/ruby/core/float/divide_spec.rb @@ -36,8 +36,4 @@ describe "Float#/" do -> { 13.0 / "10" }.should raise_error(TypeError) -> { 13.0 / :symbol }.should raise_error(TypeError) end - - it "divides correctly by Rational numbers" do - (1.2345678901234567 / Rational(1, 10000000000000000000)).should == 1.2345678901234567e+19 - end end diff --git a/spec/ruby/core/float/divmod_spec.rb b/spec/ruby/core/float/divmod_spec.rb index dad45a9b89..ec55dd3681 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(18446744073709551616.0, TOLERANCE) + values[1].should be_close(9223372036854775808.000, TOLERANCE) values = -1.0.divmod(1) values[0].should eql(-1) values[1].should eql(0.0) @@ -23,7 +23,7 @@ describe "Float#divmod" do # Behaviour established as correct in r23953 it "raises a FloatDomainError if other is NaN" do - -> { 1.0.divmod(nan_value) }.should raise_error(FloatDomainError) + -> { 1.divmod(nan_value) }.should raise_error(FloatDomainError) end # Behaviour established as correct in r23953 diff --git a/spec/ruby/core/float/gt_spec.rb b/spec/ruby/core/float/gt_spec.rb index 33078e07ce..0d73f1c3df 100644 --- a/spec/ruby/core/float/gt_spec.rb +++ b/spec/ruby/core/float/gt_spec.rb @@ -14,25 +14,4 @@ describe "Float#>" do -> { 5.0 > "4" }.should raise_error(ArgumentError) -> { 5.0 > mock('x') }.should raise_error(ArgumentError) end - - it "returns false if one side is NaN" do - [1.0, 42, bignum_value].each { |n| - (nan_value > n).should == false - (n > nan_value).should == false - } - end - - it "handles positive infinity" do - [1.0, 42, bignum_value].each { |n| - (infinity_value > n).should == true - (n > infinity_value).should == false - } - end - - it "handles negative infinity" do - [1.0, 42, bignum_value].each { |n| - (-infinity_value > n).should == false - (n > -infinity_value).should == true - } - end end diff --git a/spec/ruby/core/float/gte_spec.rb b/spec/ruby/core/float/gte_spec.rb index 44c0a81b43..98ec60b70b 100644 --- a/spec/ruby/core/float/gte_spec.rb +++ b/spec/ruby/core/float/gte_spec.rb @@ -14,25 +14,4 @@ describe "Float#>=" do -> { 5.0 >= "4" }.should raise_error(ArgumentError) -> { 5.0 >= mock('x') }.should raise_error(ArgumentError) end - - it "returns false if one side is NaN" do - [1.0, 42, bignum_value].each { |n| - (nan_value >= n).should == false - (n >= nan_value).should == false - } - end - - it "handles positive infinity" do - [1.0, 42, bignum_value].each { |n| - (infinity_value >= n).should == true - (n >= infinity_value).should == false - } - end - - it "handles negative infinity" do - [1.0, 42, bignum_value].each { |n| - (-infinity_value >= n).should == false - (n >= -infinity_value).should == true - } - end end diff --git a/spec/ruby/core/float/lt_spec.rb b/spec/ruby/core/float/lt_spec.rb index 94dcfc42f8..c01b6e0e02 100644 --- a/spec/ruby/core/float/lt_spec.rb +++ b/spec/ruby/core/float/lt_spec.rb @@ -14,25 +14,4 @@ describe "Float#<" do -> { 5.0 < "4" }.should raise_error(ArgumentError) -> { 5.0 < mock('x') }.should raise_error(ArgumentError) end - - it "returns false if one side is NaN" do - [1.0, 42, bignum_value].each { |n| - (nan_value < n).should == false - (n < nan_value).should == false - } - end - - it "handles positive infinity" do - [1.0, 42, bignum_value].each { |n| - (infinity_value < n).should == false - (n < infinity_value).should == true - } - end - - it "handles negative infinity" do - [1.0, 42, bignum_value].each { |n| - (-infinity_value < n).should == true - (n < -infinity_value).should == false - } - end end diff --git a/spec/ruby/core/float/lte_spec.rb b/spec/ruby/core/float/lte_spec.rb index 7b5a86ee76..66f2ddc2c7 100644 --- a/spec/ruby/core/float/lte_spec.rb +++ b/spec/ruby/core/float/lte_spec.rb @@ -15,25 +15,4 @@ describe "Float#<=" do -> { 5.0 <= "4" }.should raise_error(ArgumentError) -> { 5.0 <= mock('x') }.should raise_error(ArgumentError) end - - it "returns false if one side is NaN" do - [1.0, 42, bignum_value].each { |n| - (nan_value <= n).should == false - (n <= nan_value).should == false - } - end - - it "handles positive infinity" do - [1.0, 42, bignum_value].each { |n| - (infinity_value <= n).should == false - (n <= infinity_value).should == true - } - end - - it "handles negative infinity" do - [1.0, 42, bignum_value].each { |n| - (-infinity_value <= n).should == true - (n <= -infinity_value).should == false - } - end end diff --git a/spec/ruby/core/float/magnitude_spec.rb b/spec/ruby/core/float/magnitude_spec.rb index 7cdd8ef28a..db577c15c5 100644 --- a/spec/ruby/core/float/magnitude_spec.rb +++ b/spec/ruby/core/float/magnitude_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative 'shared/abs' describe "Float#magnitude" do diff --git a/spec/ruby/core/float/minus_spec.rb b/spec/ruby/core/float/minus_spec.rb index a4281a397b..5626cbdac2 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(-18446744073706991616.0, TOLERANCE) + (2_560_496.1691 - bignum_value).should be_close(-9223372036852215808.000, 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 2adb8796cd..eca0b52c4f 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(4729922269242236862464.0, TOLERANCE) + (256.4096 * bignum_value).should be_close(2364961134621118431232.000, 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 e3e19d7f39..06b136a06b 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(18446744073709551616.0, TOLERANCE) + (9.99 + bignum_value).should be_close(9223372036854775808.000, TOLERANCE) (1001.99 + 5.219).should be_close(1007.209, TOLERANCE) end end diff --git a/spec/ruby/core/float/round_spec.rb b/spec/ruby/core/float/round_spec.rb index 9b4c307f9d..4bd2dc460c 100644 --- a/spec/ruby/core/float/round_spec.rb +++ b/spec/ruby/core/float/round_spec.rb @@ -103,70 +103,6 @@ describe "Float#round" do 5.55.round(1, half: :up).should eql(5.6) 5.55.round(1, half: :down).should eql(5.5) 5.55.round(1, half: :even).should eql(5.6) - -5.55.round(1, half: nil).should eql(-5.6) - -5.55.round(1, half: :up).should eql(-5.6) - -5.55.round(1, half: :down).should eql(-5.5) - -5.55.round(1, half: :even).should eql(-5.6) - end - - it "preserves cases where neighbouring floating pointer number increase the decimal places" do - 4.8100000000000005.round(5, half: nil).should eql(4.81) - 4.8100000000000005.round(5, half: :up).should eql(4.81) - 4.8100000000000005.round(5, half: :down).should eql(4.81) - 4.8100000000000005.round(5, half: :even).should eql(4.81) - -4.8100000000000005.round(5, half: nil).should eql(-4.81) - -4.8100000000000005.round(5, half: :up).should eql(-4.81) - -4.8100000000000005.round(5, half: :down).should eql(-4.81) - -4.8100000000000005.round(5, half: :even).should eql(-4.81) - 4.81.round(5, half: nil).should eql(4.81) - 4.81.round(5, half: :up).should eql(4.81) - 4.81.round(5, half: :down).should eql(4.81) - 4.81.round(5, half: :even).should eql(4.81) - -4.81.round(5, half: nil).should eql(-4.81) - -4.81.round(5, half: :up).should eql(-4.81) - -4.81.round(5, half: :down).should eql(-4.81) - -4.81.round(5, half: :even).should eql(-4.81) - 4.809999999999999.round(5, half: nil).should eql(4.81) - 4.809999999999999.round(5, half: :up).should eql(4.81) - 4.809999999999999.round(5, half: :down).should eql(4.81) - 4.809999999999999.round(5, half: :even).should eql(4.81) - -4.809999999999999.round(5, half: nil).should eql(-4.81) - -4.809999999999999.round(5, half: :up).should eql(-4.81) - -4.809999999999999.round(5, half: :down).should eql(-4.81) - -4.809999999999999.round(5, half: :even).should eql(-4.81) - end - - ruby_bug "#19318", ""..."3.3" do - # These numbers are neighbouring floating point numbers round a - # precise value. They test that the rounding modes work correctly - # round that value and precision is not lost which might cause - # incorrect results. - it "does not lose precision during the rounding process" do - 767573.1875850001.round(5, half: nil).should eql(767573.18759) - 767573.1875850001.round(5, half: :up).should eql(767573.18759) - 767573.1875850001.round(5, half: :down).should eql(767573.18759) - 767573.1875850001.round(5, half: :even).should eql(767573.18759) - -767573.1875850001.round(5, half: nil).should eql(-767573.18759) - -767573.1875850001.round(5, half: :up).should eql(-767573.18759) - -767573.1875850001.round(5, half: :down).should eql(-767573.18759) - -767573.1875850001.round(5, half: :even).should eql(-767573.18759) - 767573.187585.round(5, half: nil).should eql(767573.18759) - 767573.187585.round(5, half: :up).should eql(767573.18759) - 767573.187585.round(5, half: :down).should eql(767573.18758) - 767573.187585.round(5, half: :even).should eql(767573.18758) - -767573.187585.round(5, half: nil).should eql(-767573.18759) - -767573.187585.round(5, half: :up).should eql(-767573.18759) - -767573.187585.round(5, half: :down).should eql(-767573.18758) - -767573.187585.round(5, half: :even).should eql(-767573.18758) - 767573.1875849998.round(5, half: nil).should eql(767573.18758) - 767573.1875849998.round(5, half: :up).should eql(767573.18758) - 767573.1875849998.round(5, half: :down).should eql(767573.18758) - 767573.1875849998.round(5, half: :even).should eql(767573.18758) - -767573.1875849998.round(5, half: nil).should eql(-767573.18758) - -767573.1875849998.round(5, half: :up).should eql(-767573.18758) - -767573.1875849998.round(5, half: :down).should eql(-767573.18758) - -767573.1875849998.round(5, half: :even).should eql(-767573.18758) - end end it "raises FloatDomainError for exceptional values with a half option" do diff --git a/spec/ruby/core/float/shared/equal.rb b/spec/ruby/core/float/shared/equal.rb index 4d524e1cf2..668aa069b5 100644 --- a/spec/ruby/core/float/shared/equal.rb +++ b/spec/ruby/core/float/shared/equal.rb @@ -14,25 +14,4 @@ describe :float_equal, shared: true do 1.0.send(@method, x).should == false 2.0.send(@method, x).should == true end - - it "returns false if one side is NaN" do - [1.0, 42, bignum_value].each { |n| - (nan_value.send(@method, n)).should == false - (n.send(@method, nan_value)).should == false - } - end - - it "handles positive infinity" do - [1.0, 42, bignum_value].each { |n| - (infinity_value.send(@method, n)).should == false - (n.send(@method, infinity_value)).should == false - } - end - - it "handles negative infinity" do - [1.0, 42, bignum_value].each { |n| - ((-infinity_value).send(@method, n)).should == false - (n.send(@method, -infinity_value)).should == false - } - end end diff --git a/spec/ruby/core/float/shared/to_i.rb b/spec/ruby/core/float/shared/to_i.rb index 33b32ca533..960295f095 100644 --- a/spec/ruby/core/float/shared/to_i.rb +++ b/spec/ruby/core/float/shared/to_i.rb @@ -7,8 +7,4 @@ describe :float_to_i, shared: true do -9223372036854775808.1.send(@method).should eql(-9223372036854775808) 9223372036854775808.1.send(@method).should eql(9223372036854775808) end - - it "raises a FloatDomainError for NaN" do - -> { nan_value.send(@method) }.should raise_error(FloatDomainError) - end end diff --git a/spec/ruby/core/gc/auto_compact_spec.rb b/spec/ruby/core/gc/auto_compact_spec.rb index 33ad1cb56c..4f9d043171 100644 --- a/spec/ruby/core/gc/auto_compact_spec.rb +++ b/spec/ruby/core/gc/auto_compact_spec.rb @@ -1,24 +1,26 @@ require_relative '../../spec_helper' -describe "GC.auto_compact" do - it "can set and get a boolean value" do - begin - GC.auto_compact = GC.auto_compact - rescue NotImplementedError # platform does not support autocompact - skip - end +ruby_version_is "3.0" do + describe "GC.auto_compact" do + it "can set and get a boolean value" do + begin + GC.auto_compact = GC.auto_compact + rescue NotImplementedError # platform does not support autocompact + skip + end - original = GC.auto_compact - begin - GC.auto_compact = !original - rescue NotImplementedError # platform does not support autocompact - skip - end + original = GC.auto_compact + begin + GC.auto_compact = !original + rescue NotImplementedError # platform does not support autocompact + skip + end - begin - GC.auto_compact.should == !original - ensure - GC.auto_compact = original + begin + GC.auto_compact.should == !original + ensure + GC.auto_compact = original + end end end end diff --git a/spec/ruby/core/hash/compact_spec.rb b/spec/ruby/core/hash/compact_spec.rb index 76aa43949d..2989afc8b7 100644 --- a/spec/ruby/core/hash/compact_spec.rb +++ b/spec/ruby/core/hash/compact_spec.rb @@ -18,30 +18,6 @@ describe "Hash#compact" do @hash.compact @hash.should == @initial_pairs end - - ruby_version_is '3.3' do - it "retains the default value" do - hash = Hash.new(1) - hash.compact.default.should == 1 - hash[:a] = 1 - hash.compact.default.should == 1 - end - - it "retains the default_proc" do - pr = proc { |h, k| h[k] = [] } - hash = Hash.new(&pr) - hash.compact.default_proc.should == pr - hash[:a] = 1 - hash.compact.default_proc.should == pr - end - - it "retains compare_by_identity_flag" do - hash = {}.compare_by_identity - hash.compact.compare_by_identity?.should == true - hash[:a] = 1 - hash.compact.compare_by_identity?.should == true - end - end end describe "Hash#compact!" do diff --git a/spec/ruby/core/hash/constructor_spec.rb b/spec/ruby/core/hash/constructor_spec.rb index 8d29773909..ad67274802 100644 --- a/spec/ruby/core/hash/constructor_spec.rb +++ b/spec/ruby/core/hash/constructor_spec.rb @@ -42,13 +42,26 @@ describe "Hash.[]" do Hash[ary].should == { a: :b } end - it "raises for elements that are not arrays" do - -> { - Hash[[:a]].should == {} - }.should raise_error(ArgumentError) - -> { - Hash[[:nil]].should == {} - }.should raise_error(ArgumentError) + 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 end it "raises an ArgumentError for arrays of more than 2 elements" do @@ -103,26 +116,8 @@ describe "Hash.[]" do HashSpecs::MyInitializerHash[Hash[1, 2]].should be_an_instance_of(HashSpecs::MyInitializerHash) end - it "removes the default value" do - hash = Hash.new(1) - Hash[hash].default.should be_nil - hash[:a] = 1 - Hash[hash].default.should be_nil - end - it "removes the default_proc" do hash = Hash.new { |h, k| h[k] = [] } Hash[hash].default_proc.should be_nil - hash[:a] = 1 - Hash[hash].default_proc.should be_nil - end - - ruby_version_is '3.3' do - it "does not retain compare_by_identity_flag" do - hash = {}.compare_by_identity - Hash[hash].compare_by_identity?.should == false - hash[:a] = 1 - Hash[hash].compare_by_identity?.should == false - end end end diff --git a/spec/ruby/core/hash/deconstruct_keys_spec.rb b/spec/ruby/core/hash/deconstruct_keys_spec.rb index bbcd8932e5..b265732616 100644 --- a/spec/ruby/core/hash/deconstruct_keys_spec.rb +++ b/spec/ruby/core/hash/deconstruct_keys_spec.rb @@ -1,23 +1,25 @@ require_relative '../../spec_helper' -describe "Hash#deconstruct_keys" do - it "returns self" do - hash = {a: 1, b: 2} +ruby_version_is "2.7" do + 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} + 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 end diff --git a/spec/ruby/core/hash/except_spec.rb b/spec/ruby/core/hash/except_spec.rb index ac84f9975c..82cfced72f 100644 --- a/spec/ruby/core/hash/except_spec.rb +++ b/spec/ruby/core/hash/except_spec.rb @@ -1,32 +1,34 @@ require_relative '../../spec_helper' -describe "Hash#except" do - before :each do - @hash = { a: 1, b: 2, c: 3 } - end +ruby_version_is "3.0" do + describe "Hash#except" do + before :each do + @hash = { a: 1, b: 2, c: 3 } + end - it "returns a new duplicate hash without arguments" do - ret = @hash.except - ret.should_not equal(@hash) - ret.should == @hash - end + it "returns a new duplicate hash without arguments" do + ret = @hash.except + ret.should_not equal(@hash) + ret.should == @hash + end - it "returns a hash without the requested subset" do - @hash.except(:c, :a).should == { b: 2 } - end + it "returns a hash without the requested subset" do + @hash.except(:c, :a).should == { b: 2 } + end - it "ignores keys not present in the original hash" do - @hash.except(:a, :chunky_bacon).should == { b: 2, c: 3 } - end + it "ignores keys not present in the original hash" do + @hash.except(:a, :chunky_bacon).should == { b: 2, c: 3 } + end - it "always returns a Hash without a default" do - klass = Class.new(Hash) - h = klass.new(:default) - h[:bar] = 12 - h[:foo] = 42 - r = h.except(:foo) - r.should == {bar: 12} - r.class.should == Hash - r.default.should == nil + it "always returns a Hash without a default" do + klass = Class.new(Hash) + h = klass.new(:default) + h[:bar] = 12 + h[:foo] = 42 + r = h.except(:foo) + r.should == {bar: 12} + r.class.should == Hash + r.default.should == nil + end end end diff --git a/spec/ruby/core/hash/fetch_spec.rb b/spec/ruby/core/hash/fetch_spec.rb index 6e0d207224..753167f709 100644 --- a/spec/ruby/core/hash/fetch_spec.rb +++ b/spec/ruby/core/hash/fetch_spec.rb @@ -4,7 +4,7 @@ require_relative '../../shared/hash/key_error' describe "Hash#fetch" do context "when the key is not found" do - it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, Hash.new({ a: 5 }) + it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, Hash.new(a: 5) it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, {} it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, Hash.new { 5 } it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, Hash.new(5) diff --git a/spec/ruby/core/hash/fetch_values_spec.rb b/spec/ruby/core/hash/fetch_values_spec.rb index 0cd48565af..af3673f6ef 100644 --- a/spec/ruby/core/hash/fetch_values_spec.rb +++ b/spec/ruby/core/hash/fetch_values_spec.rb @@ -19,7 +19,7 @@ describe "Hash#fetch_values" do end describe "with unmatched keys" do - it_behaves_like :key_error, -> obj, key { obj.fetch_values(key) }, Hash.new({ a: 5 }) + it_behaves_like :key_error, -> obj, key { obj.fetch_values(key) }, Hash.new(a: 5) it "returns the default value from block" do @hash.fetch_values(:z) { |key| "`#{key}' is not found" }.should == ["`z' is not found"] diff --git a/spec/ruby/core/hash/hash_spec.rb b/spec/ruby/core/hash/hash_spec.rb index 19eb806dc4..3649d4d8de 100644 --- a/spec/ruby/core/hash/hash_spec.rb +++ b/spec/ruby/core/hash/hash_spec.rb @@ -41,13 +41,4 @@ describe "Hash#hash" do h.hash.should == {x: [h]}.hash # Like above, because h.eql?(x: [h]) end - - ruby_version_is "3.1" do - it "allows omitting values" do - a = 1 - b = 2 - - eval('{a:, b:}.should == { a: 1, b: 2 }') - end - end end diff --git a/spec/ruby/core/hash/index_spec.rb b/spec/ruby/core/hash/index_spec.rb new file mode 100644 index 0000000000..be4e2cc6ab --- /dev/null +++ b/spec/ruby/core/hash/index_spec.rb @@ -0,0 +1,9 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require_relative 'shared/index' + +ruby_version_is ''...'3.0' do + describe "Hash#index" do + it_behaves_like :hash_index, :index + end +end diff --git a/spec/ruby/core/hash/new_spec.rb b/spec/ruby/core/hash/new_spec.rb index 6279815fd6..6054b69bdd 100644 --- a/spec/ruby/core/hash/new_spec.rb +++ b/spec/ruby/core/hash/new_spec.rb @@ -33,17 +33,4 @@ describe "Hash.new" do -> { Hash.new(5) { 0 } }.should raise_error(ArgumentError) -> { Hash.new(nil) { 0 } }.should raise_error(ArgumentError) end - - ruby_version_is "3.3" do - it "emits a deprecation warning if keyword arguments are passed" do - -> { Hash.new(unknown: true) }.should complain( - Regexp.new(Regexp.escape("Calling Hash.new with keyword arguments is deprecated and will be removed in Ruby 3.4; use Hash.new({ key: value }) instead")) - ) - - -> { Hash.new(1, unknown: true) }.should raise_error(ArgumentError) - -> { Hash.new(unknown: true) { 0 } }.should raise_error(ArgumentError) - - Hash.new({ unknown: true }).default.should == { unknown: true } - end - end end diff --git a/spec/ruby/core/hash/reject_spec.rb b/spec/ruby/core/hash/reject_spec.rb index dd8e817237..397000ab67 100644 --- a/spec/ruby/core/hash/reject_spec.rb +++ b/spec/ruby/core/hash/reject_spec.rb @@ -31,6 +31,13 @@ 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 7dbb9c0a98..005886a482 100644 --- a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb +++ b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb @@ -1,83 +1,47 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -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 +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 "copies the hash internals" do - h = {a: 1} - kw = Hash.ruby2_keywords_hash(h) - h[:a] = 2 - kw[:a].should == 1 - 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) + it "raises TypeError for non-Hash" do + -> { Hash.ruby2_keywords_hash?(nil) }.should raise_error(TypeError) + end end - it "retains the default value" do - hash = Hash.new(1) - Hash.ruby2_keywords_hash(hash).default.should == 1 - hash[:a] = 1 - Hash.ruby2_keywords_hash(hash).default.should == 1 - 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 "retains the default_proc" do - pr = proc { |h, k| h[k] = [] } - hash = Hash.new(&pr) - Hash.ruby2_keywords_hash(hash).default_proc.should == pr - hash[:a] = 1 - Hash.ruby2_keywords_hash(hash).default_proc.should == pr - 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 - ruby_version_is '3.3' do - it "retains compare_by_identity_flag" do - hash = {}.compare_by_identity - Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true - hash[:a] = 1 - Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true + it "raises TypeError for non-Hash" do + -> { Hash.ruby2_keywords_hash(nil) }.should raise_error(TypeError) end end end diff --git a/spec/ruby/core/hash/shared/each.rb b/spec/ruby/core/hash/shared/each.rb index f9839ff58f..b2483c8116 100644 --- a/spec/ruby/core/hash/shared/each.rb +++ b/spec/ruby/core/hash/shared/each.rb @@ -21,18 +21,37 @@ describe :hash_each, shared: true do ary.sort.should == ["a", "b", "c"] end - it "always yields an Array of 2 elements, even when given a callable of arity 2" do - obj = Object.new - def obj.foo(key, value) - end + ruby_version_is ""..."3.0" do + it "yields 2 values and not an Array of 2 elements when given a callable of arity 2" do + obj = Object.new + def obj.foo(key, value) + ScratchPad << key << value + end - -> { + ScratchPad.record([]) { "a" => 1 }.send(@method, &obj.method(:foo)) - }.should raise_error(ArgumentError) + ScratchPad.recorded.should == ["a", 1] - -> { - { "a" => 1 }.send(@method, &-> key, value { }) - }.should raise_error(ArgumentError) + ScratchPad.record([]) + { "a" => 1 }.send(@method, &-> key, value { ScratchPad << key << value }) + ScratchPad.recorded.should == ["a", 1] + end + end + + ruby_version_is "3.0" do + it "always yields an Array of 2 elements, even when given a callable of arity 2" do + obj = Object.new + def obj.foo(key, value) + end + + -> { + { "a" => 1 }.send(@method, &obj.method(:foo)) + }.should raise_error(ArgumentError) + + -> { + { "a" => 1 }.send(@method, &-> key, value { }) + }.should raise_error(ArgumentError) + end end it "yields an Array of 2 elements when given a callable of arity 1" do diff --git a/spec/ruby/core/hash/shared/eql.rb b/spec/ruby/core/hash/shared/eql.rb index 68db49f76d..e294edd764 100644 --- a/spec/ruby/core/hash/shared/eql.rb +++ b/spec/ruby/core/hash/shared/eql.rb @@ -149,34 +149,80 @@ describe :hash_eql_additional, shared: true do h.send(@method, HashSpecs::MyHash[h]).should be_true end - # 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 + 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 end - obj - end + { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_false - { 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) - a = Array.new(2) do - obj = mock('0') - obj.should_receive(:hash).at_least(1).and_return(0) + def obj.eql?(o) + true + end - def obj.eql?(o) - true + obj end - obj + { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_true 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) + + # 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 + + obj + end - { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_true + { 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 + end end it "compares the values in self to values in other hash" do diff --git a/spec/ruby/core/hash/shared/equal.rb b/spec/ruby/core/hash/shared/equal.rb new file mode 100644 index 0000000000..43606437fe --- /dev/null +++ b/spec/ruby/core/hash/shared/equal.rb @@ -0,0 +1,90 @@ +describe :hash_equal, shared: true do + it "does not compare values when keys don't match" do + value = mock('x') + value.should_not_receive(:==) + value.should_not_receive(:eql?) + { 1 => value }.send(@method, { 2 => value }).should be_false + end + + it "returns false when the numbers of keys differ without comparing any elements" do + obj = mock('x') + h = { obj => obj } + + obj.should_not_receive(:==) + obj.should_not_receive(:eql?) + + {}.send(@method, h).should be_false + h.send(@method, {}).should be_false + end + + it "first compares keys via hash" do + x = mock('x') + x.should_receive(:hash).and_return(0) + y = mock('y') + y.should_receive(:hash).and_return(0) + + { x => 1 }.send(@method, { y => 1 }).should be_false + end + + it "does not compare keys with different hash codes via eql?" do + x = mock('x') + y = mock('y') + x.should_not_receive(:eql?) + y.should_not_receive(:eql?) + + x.should_receive(:hash).and_return(0) + y.should_receive(:hash).and_return(1) + + def x.hash() 0 end + def y.hash() 1 end + + { x => 1 }.send(@method, { y => 1 }).should be_false + end + + it "computes equality for recursive hashes" do + h = {} + h[:a] = h + h.send(@method, h[:a]).should be_true + (h == h[:a]).should be_true + end + + it "computes equality for complex recursive hashes" do + a, b = {}, {} + a.merge! self: a, other: b + b.merge! self: b, other: a + a.send(@method, b).should be_true # they both have the same structure! + + c = {} + c.merge! other: c, self: c + c.send(@method, a).should be_true # subtle, but they both have the same structure! + a[:delta] = c[:delta] = a + c.send(@method, a).should be_false # not quite the same structure, as a[:other][:delta] = nil + c[:delta] = 42 + c.send(@method, a).should be_false + a[:delta] = 42 + c.send(@method, a).should be_false + b[:delta] = 42 + c.send(@method, a).should be_true + end + + it "computes equality for recursive hashes & arrays" do + x, y, z = [], [], [] + a, b, c = {foo: x, bar: 42}, {foo: y, bar: 42}, {foo: z, bar: 42} + x << a + y << c + z << b + b.send(@method, c).should be_true # they clearly have the same structure! + y.send(@method, z).should be_true + a.send(@method, b).should be_true # subtle, but they both have the same structure! + x.send(@method, y).should be_true + y << x + y.send(@method, z).should be_false + z << x + y.send(@method, z).should be_true + + a[:foo], a[:bar] = a[:bar], a[:foo] + a.send(@method, b).should be_false + b[:bar] = b[:foo] + b.send(@method, c).should be_false + end +end diff --git a/spec/ruby/core/hash/shared/to_s.rb b/spec/ruby/core/hash/shared/to_s.rb index 2db3a96583..b0e3705d01 100644 --- a/spec/ruby/core/hash/shared/to_s.rb +++ b/spec/ruby/core/hash/shared/to_s.rb @@ -2,6 +2,7 @@ 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 } @@ -76,14 +77,22 @@ 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 ea36488a04..9d43e640f5 100644 --- a/spec/ruby/core/hash/shift_spec.rb +++ b/spec/ruby/core/hash/shift_spec.rb @@ -30,45 +30,23 @@ describe "Hash#shift" do h.should == {} end - 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 + 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 it "returns nil from an empty hash" do {}.shift.should == nil end - 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 + 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 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 5baf677929..46f871389a 100644 --- a/spec/ruby/core/hash/to_a_spec.rb +++ b/spec/ruby/core/hash/to_a_spec.rb @@ -26,4 +26,14 @@ describe "Hash#to_a" do ent.should be_kind_of(Array) 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 + end + + it "returns an untrusted array if self is untrusted" do + {}.untrust.to_a.untrusted?.should be_true + end + end end diff --git a/spec/ruby/core/hash/to_proc_spec.rb b/spec/ruby/core/hash/to_proc_spec.rb index 9dbc79e5eb..8f5d21beb5 100644 --- a/spec/ruby/core/hash/to_proc_spec.rb +++ b/spec/ruby/core/hash/to_proc_spec.rb @@ -19,12 +19,20 @@ describe "Hash#to_proc" do @proc = @hash.to_proc end - it "is a lambda" do - @proc.should.lambda? + ruby_version_is ""..."3.0" do + it "is not a lambda" do + @proc.should_not.lambda? + end end - it "has an arity of 1" do - @proc.arity.should == 1 + ruby_version_is "3.0" do + it "is a lambda" do + @proc.should.lambda? + end + + it "has an arity of 1" do + @proc.arity.should == 1 + end end it "raises ArgumentError if not passed exactly one argument" do diff --git a/spec/ruby/core/hash/transform_keys_spec.rb b/spec/ruby/core/hash/transform_keys_spec.rb index 2fbb17a8e2..8ee1a2cd6d 100644 --- a/spec/ruby/core/hash/transform_keys_spec.rb +++ b/spec/ruby/core/hash/transform_keys_spec.rb @@ -43,16 +43,18 @@ describe "Hash#transform_keys" do r.class.should == Hash end - it "allows a hash argument" do - @hash.transform_keys({ a: :A, b: :B, c: :C }).should == { A: 1, B: 2, C: 3 } - end + ruby_version_is "3.0" do + it "allows a hash argument" do + @hash.transform_keys({ a: :A, b: :B, c: :C }).should == { A: 1, B: 2, C: 3 } + end - it "allows a partial transformation of keys when using a hash argument" do - @hash.transform_keys({ a: :A, c: :C }).should == { A: 1, b: 2, C: 3 } - end + it "allows a partial transformation of keys when using a hash argument" do + @hash.transform_keys({ a: :A, c: :C }).should == { A: 1, b: 2, C: 3 } + end - it "allows a combination of hash and block argument" do - @hash.transform_keys({ a: :A }, &:to_s).should == { A: 1, 'b' => 2, 'c' => 3 } + it "allows a combination of hash and block argument" do + @hash.transform_keys({ a: :A }, &:to_s).should == { A: 1, 'b' => 2, 'c' => 3 } + end end end @@ -71,13 +73,14 @@ 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 break from the block" do + it "returns the processed keys if we broke from the block" do @hash.transform_keys! do |v| break if v == :c v.succ @@ -87,7 +90,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 break from the block" do + it "returns the processed keys and non evaluated keys if we broke from the block" do @hash.transform_keys! do |v| break if v == :c v.succ @@ -109,9 +112,11 @@ describe "Hash#transform_keys!" do end end - it "allows a hash argument" do - @hash.transform_keys!({ a: :A, b: :B, c: :C, d: :D }) - @hash.should == { A: 1, B: 2, C: 3, D: 4 } + ruby_version_is "3.0" do + it "allows a hash argument" do + @hash.transform_keys!({ a: :A, b: :B, c: :C, d: :D }) + @hash.should == { A: 1, B: 2, C: 3, D: 4 } + end end describe "on frozen instance" do @@ -128,8 +133,10 @@ describe "Hash#transform_keys!" do @hash.should == @initial_pairs end - it "raises a FrozenError on hash argument" do - ->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should raise_error(FrozenError) + ruby_version_is "3.0" do + it "raises a FrozenError on hash argument" do + ->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should raise_error(FrozenError) + end end context "when no block is given" do diff --git a/spec/ruby/core/hash/try_convert_spec.rb b/spec/ruby/core/hash/try_convert_spec.rb index d359ae49d8..44195c5010 100644 --- a/spec/ruby/core/hash/try_convert_spec.rb +++ b/spec/ruby/core/hash/try_convert_spec.rb @@ -39,7 +39,7 @@ describe "Hash.try_convert" do it "sends #to_hash to the argument and raises TypeError if it's not a kind of Hash" do obj = mock("to_hash") obj.should_receive(:to_hash).and_return(Object.new) - -> { Hash.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Hash (MockObject#to_hash gives Object)") + -> { Hash.try_convert obj }.should raise_error(TypeError) end it "does not rescue exceptions raised by #to_hash" do diff --git a/spec/ruby/core/integer/bit_and_spec.rb b/spec/ruby/core/integer/bit_and_spec.rb index e7face39ac..15a8026855 100644 --- a/spec/ruby/core/integer/bit_and_spec.rb +++ b/spec/ruby/core/integer/bit_and_spec.rb @@ -30,7 +30,7 @@ describe "Integer#&" do it "coerces the rhs and calls #coerce" do obj = mock("fixnum bit and") - obj.should_receive(:coerce).with(6).and_return([6, 3]) + obj.should_receive(:coerce).with(6).and_return([3, 6]) (6 & obj).should == 2 end @@ -55,24 +55,24 @@ describe "Integer#&" do @bignum = bignum_value(5) (@bignum & 3).should == 1 (@bignum & 52).should == 4 - (@bignum & bignum_value(9921)).should == 18446744073709551617 + (@bignum & bignum_value(9921)).should == 9223372036854775809 ((2*bignum_value) & 1).should == 0 - ((2*bignum_value) & (2*bignum_value)).should == 36893488147419103232 + ((2*bignum_value) & (2*bignum_value)).should == 18446744073709551616 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 == 18446744073709551617 + (@bignum & -0xffffffffffffff5).should == 9223372036854775809 (@bignum & -@bignum).should == 1 - (@bignum & -0x8000000000000000).should == 18446744073709551616 + (@bignum & -0x8000000000000000).should == 9223372036854775808 end it "returns self bitwise AND other when both operands are negative" do - (-@bignum & -0x4000000000000005).should == -23058430092136939525 - (-@bignum & -@bignum).should == -18446744073709551621 - (-@bignum & -0x4000000000000000).should == -23058430092136939520 + (-@bignum & -0x4000000000000005).should == -13835058055282163717 + (-@bignum & -@bignum).should == -9223372036854775813 + (-@bignum & -0x4000000000000000).should == -13835058055282163712 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 fdf8a191e5..e486eeec10 100644 --- a/spec/ruby/core/integer/bit_or_spec.rb +++ b/spec/ruby/core/integer/bit_or_spec.rb @@ -7,34 +7,13 @@ describe "Integer#|" do (5 | 4).should == 5 (5 | 6).should == 7 (248 | 4096).should == 4344 - (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 + (0xffff | bignum_value + 0xf0f0).should == 0x8000_0000_0000_ffff 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 or") - obj.should_receive(:coerce).with(6).and_return([6, 3]) - (6 | obj).should == 7 - end - it "raises a TypeError when passed a Float" do -> { (3 | 3.4) }.should raise_error(TypeError) end @@ -53,20 +32,20 @@ describe "Integer#|" do end it "returns self bitwise OR other" do - (@bignum | 2).should == 18446744073709551627 - (@bignum | 9).should == 18446744073709551627 - (@bignum | bignum_value).should == 18446744073709551627 + (@bignum | 2).should == 9223372036854775819 + (@bignum | 9).should == 9223372036854775819 + (@bignum | bignum_value).should == 9223372036854775819 end it "returns self bitwise OR other when one operand is negative" do - (@bignum | -0x40000000000000000).should == -55340232221128654837 + (@bignum | -0x40000000000000000).should == -64563604257983430645 (@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 == -18446744073709551627 + (-@bignum | -@bignum).should == -9223372036854775819 (-@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 1f46bc52f3..ac8826a52f 100644 --- a/spec/ruby/core/integer/bit_xor_spec.rb +++ b/spec/ruby/core/integer/bit_xor_spec.rb @@ -5,34 +5,13 @@ 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 == 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 + (5 ^ bignum_value + 0xffff_ffff).should == 0x8000_0000_ffff_fffa 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 xor") - obj.should_receive(:coerce).with(6).and_return([6, 3]) - (6 ^ obj).should == 5 - end - it "raises a TypeError when passed a Float" do -> { (3 ^ 3.4) }.should raise_error(TypeError) end @@ -51,21 +30,21 @@ describe "Integer#^" do end it "returns self bitwise EXCLUSIVE OR other" do - (@bignum ^ 2).should == 18446744073709551632 + (@bignum ^ 2).should == 9223372036854775824 (@bignum ^ @bignum).should == 0 - (@bignum ^ 14).should == 18446744073709551644 + (@bignum ^ 14).should == 9223372036854775836 end it "returns self bitwise EXCLUSIVE OR other when one operand is negative" do - (@bignum ^ -0x40000000000000000).should == -55340232221128654830 + (@bignum ^ -0x40000000000000000).should == -64563604257983430638 (@bignum ^ -@bignum).should == -4 - (@bignum ^ -0x8000000000000000).should == -27670116110564327406 + (@bignum ^ -0x8000000000000000).should == -18446744073709551598 end it "returns self bitwise EXCLUSIVE OR other when both operands are negative" do - (-@bignum ^ -0x40000000000000000).should == 55340232221128654830 + (-@bignum ^ -0x40000000000000000).should == 64563604257983430638 (-@bignum ^ -@bignum).should == 0 - (-@bignum ^ -0x4000000000000000).should == 23058430092136939502 + (-@bignum ^ -0x4000000000000000).should == 13835058055282163694 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/ceildiv_spec.rb b/spec/ruby/core/integer/ceildiv_spec.rb deleted file mode 100644 index 18d07c66d0..0000000000 --- a/spec/ruby/core/integer/ceildiv_spec.rb +++ /dev/null @@ -1,22 +0,0 @@ -require_relative '../../spec_helper' - -describe "Integer#ceildiv" do - ruby_version_is '3.2' do - it "returns a quotient of division which is rounded up to the nearest integer" do - 0.ceildiv(3).should eql(0) - 1.ceildiv(3).should eql(1) - 3.ceildiv(3).should eql(1) - 4.ceildiv(3).should eql(2) - - 4.ceildiv(-3).should eql(-1) - -4.ceildiv(3).should eql(-1) - -4.ceildiv(-3).should eql(2) - - 3.ceildiv(1.2).should eql(3) - 3.ceildiv(6/5r).should eql(3) - - (10**100-11).ceildiv(10**99-1).should eql(10) - (10**100-9).ceildiv(10**99-1).should eql(11) - end - end -end diff --git a/spec/ruby/core/integer/chr_spec.rb b/spec/ruby/core/integer/chr_spec.rb index 8fe20ff812..9f105e4241 100644 --- a/spec/ruby/core/integer/chr_spec.rb +++ b/spec/ruby/core/integer/chr_spec.rb @@ -11,11 +11,7 @@ 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) - end - - it "raises a RangeError if self is too large" do - -> { 2206368128.chr(Encoding::UTF_8) }.should raise_error(RangeError) + -> { -bignum_value.chr }.should raise_error(RangeError) end describe "when Encoding.default_internal is nil" do @@ -166,7 +162,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 @@ -223,35 +219,38 @@ describe "Integer#chr with an encoding argument" do # #5864 it "raises RangeError if self is invalid as a codepoint in the specified encoding" do - -> { 0x80.chr("US-ASCII") }.should raise_error(RangeError) - -> { 0x0100.chr("BINARY") }.should raise_error(RangeError) - -> { 0x0100.chr("EUC-JP") }.should raise_error(RangeError) - -> { 0xA1A0.chr("EUC-JP") }.should raise_error(RangeError) - -> { 0xA1.chr("EUC-JP") }.should raise_error(RangeError) - -> { 0x80.chr("SHIFT_JIS") }.should raise_error(RangeError) - -> { 0xE0.chr("SHIFT_JIS") }.should raise_error(RangeError) - -> { 0x0100.chr("ISO-8859-9") }.should raise_error(RangeError) - -> { 620.chr("TIS-620") }.should raise_error(RangeError) - # UTF-16 surrogate range - -> { 0xD800.chr("UTF-8") }.should raise_error(RangeError) - -> { 0xDBFF.chr("UTF-8") }.should raise_error(RangeError) - -> { 0xDC00.chr("UTF-8") }.should raise_error(RangeError) - -> { 0xDFFF.chr("UTF-8") }.should raise_error(RangeError) - # UTF-16 surrogate range - -> { 0xD800.chr("UTF-16") }.should raise_error(RangeError) - -> { 0xDBFF.chr("UTF-16") }.should raise_error(RangeError) - -> { 0xDC00.chr("UTF-16") }.should raise_error(RangeError) - -> { 0xDFFF.chr("UTF-16") }.should raise_error(RangeError) + [ [0x80, "US-ASCII"], + [0x0100, "BINARY"], + [0x0100, "EUC-JP"], + [0xA1A0, "EUC-JP"], + [0xA1, "EUC-JP"], + [0x80, "SHIFT_JIS"], + [0xE0, "SHIFT_JIS"], + [0x0100, "ISO-8859-9"], + [620, "TIS-620"], + [0xD800, "UTF-8"], + [0xDBFF, "UTF-8"], + [0xDC00, "UTF-8"], + [0xDFFF, "UTF-8"], + [0xD800, "UTF-16"], + [0xDBFF, "UTF-16"], + [0xDC00, "UTF-16"], + [0xDFFF, "UTF-16"], + ].each do |integer, encoding_name| + -> { integer.chr(encoding_name) }.should raise_error(RangeError) + end end - 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 + 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 - # 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] + # 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 end diff --git a/spec/ruby/core/integer/complement_spec.rb b/spec/ruby/core/integer/complement_spec.rb index baf5e6c457..eafa5c263f 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 == -18446744073709551665 - (~(-bignum_value(21))).should == 18446744073709551636 - (~bignum_value(1)).should == -18446744073709551618 + (~bignum_value(48)).should == -9223372036854775857 + (~(-bignum_value(21))).should == 9223372036854775828 + (~bignum_value(1)).should == -9223372036854775810 end end end diff --git a/spec/ruby/core/integer/constants_spec.rb b/spec/ruby/core/integer/constants_spec.rb index 2077ad451e..3b8b01e330 100644 --- a/spec/ruby/core/integer/constants_spec.rb +++ b/spec/ruby/core/integer/constants_spec.rb @@ -1,41 +1,25 @@ require_relative '../../spec_helper' describe "Fixnum" do - 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/) + it "is unified into Integer" do + suppress_warning do + Fixnum.should equal(Integer) end end - ruby_version_is "3.2" do - it "is no longer defined" do - Object.should_not.const_defined?(:Fixnum) - end + it "is deprecated" do + -> { Fixnum }.should complain(/constant ::Fixnum is deprecated/) end end describe "Bignum" do - 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/) + it "is unified into Integer" do + suppress_warning do + Bignum.should equal(Integer) end end - ruby_version_is "3.2" do - it "is no longer defined" do - Object.should_not.const_defined?(:Bignum) - end + it "is deprecated" do + -> { Bignum }.should complain(/constant ::Bignum is deprecated/) end end diff --git a/spec/ruby/core/integer/div_spec.rb b/spec/ruby/core/integer/div_spec.rb index 344e095179..bc1c4363d4 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 == 4611686018427387926 - @bignum.div(Rational(4, 1)).should == 4611686018427387926 + @bignum.div(4).should == 2305843009213693974 + @bignum.div(Rational(4, 1)).should == 2305843009213693974 @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(4294967296) + @bignum.div(4294967295.5).should eql(2147483648) not_supported_on :opal do - @bignum.div(4294967295.0).should eql(4294967297) + @bignum.div(4294967295.0).should eql(2147483648) @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 a878c4668c..5ac2dc538d 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 == 4611686018427387926 + (@bignum / 4).should == 2305843009213693974 (@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(4294967297.0, TOLERANCE) + (bignum_value(88) / 4294967295.0).should be_close(2147483648.5, TOLERANCE) end - (bignum_value(88) / 4294967295.5).should be_close(4294967296.5, TOLERANCE) + (bignum_value(88) / 4294967295.5).should be_close(2147483648.25, TOLERANCE) end it "returns result the same class as the argument" do - (@bignum / 4).should == 4611686018427387926 - (@bignum / 4.0).should be_close(4611686018427387926, TOLERANCE) - (@bignum / Rational(4, 1)).should == Rational(4611686018427387926, 1) + (@bignum / 4).should == 2305843009213693974 + (@bignum / 4.0).should be_close(2305843009213693974, TOLERANCE) + (@bignum / Rational(4, 1)).should == Rational(2305843009213693974, 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 7a489e9344..d88925caad 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 == [4611686018427387917, 3] - @bignum.divmod(13).should == [1418980313362273205, 6] + @bignum.divmod(4).should == [2305843009213693965, 3] + @bignum.divmod(13).should == [709490156681136604, 11] - @bignum.divmod(4.5).should == [4099276460824344576, 2.5] + @bignum.divmod(4.5).should == [2049638230412172288, 3.5] not_supported_on :opal do - @bignum.divmod(4.0).should == [4611686018427387904, 0.0] - @bignum.divmod(13.0).should == [1418980313362273280, 3.0] + @bignum.divmod(4.0).should == [2305843009213693952, 0.0] + @bignum.divmod(13.0).should == [709490156681136640, 8.0] - @bignum.divmod(2.0).should == [9223372036854775808, 0.0] + @bignum.divmod(2.0).should == [4611686018427387904, 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 cb7e0dc9b0..7197ecdc03 100644 --- a/spec/ruby/core/integer/element_reference_spec.rb +++ b/spec/ruby/core/integer/element_reference_spec.rb @@ -79,79 +79,81 @@ describe "Integer#[]" do 3[bignum_value.to_f].should == 0 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 + 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 - 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 "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 "ignores negative length" do - 0b101001101[1, -1].should == 0b10100110 - 0b101001101[2, -1].should == 0b1010011 - 0b101001101[3, -1].should == 0b101001 + 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 - 0b101001101[3, -5].should == 0b101001 - 0b101001101[3, -15].should == 0b101001 - 0b101001101[3, -125].should == 0b101001 - end - end + it "ignores negative length" do + 0b101001101[1, -1].should == 0b10100110 + 0b101001101[2, -1].should == 0b1010011 + 0b101001101[3, -1].should == 0b101001 - 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 + 0b101001101[3, -5].should == 0b101001 + 0b101001101[3, -15].should == 0b101001 + 0b101001101[3, -125].should == 0b101001 + end 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 + 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..] equals to (n >> i)" do - eval("0b101001101[3..]").should == 0b101001101 >> 3 - 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 "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 "ensures n[i..] equals to (n >> i)" do + eval("0b101001101[3..]").should == 0b101001101 >> 3 + 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 "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 "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 "ignores upper boundary smaller than lower boundary" do + 0b101001101[4..1].should == 0b10100 + 0b101001101[4..2].should == 0b10100 + 0b101001101[-4..-5].should == 0b1010011010000 + 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 + 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 ArgumentError if any of i bit equals 1" do - -> { - eval("0b111110[..3]") - }.should raise_error(ArgumentError, /The beginless range for Integer#\[\] results in 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 + + 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 end diff --git a/spec/ruby/core/integer/fdiv_spec.rb b/spec/ruby/core/integer/fdiv_spec.rb index d9ea2fdf8d..6de170278f 100644 --- a/spec/ruby/core/integer/fdiv_spec.rb +++ b/spec/ruby/core/integer/fdiv_spec.rb @@ -9,57 +9,6 @@ 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 "rounds to the correct float for bignum denominators" do - 1.fdiv(10**324).should == 0.0 - 1.fdiv(10**323).should == 1.0e-323 - 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 0781371d93..4efcbef334 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 a Bignum == fixnum_max * 2 when fixnum_max << 1 and n > 0" do + it "returns an 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 a Bignum == fixnum_min * 2 when fixnum_min << 1 and n < 0" do + it "returns an 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 * 8 # 2 ** 67 + @bignum = bignum_value * 16 end it "returns n shifted left m bits when n > 0, m > 0" do @@ -127,6 +127,10 @@ 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) @@ -161,53 +165,4 @@ 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 - - it "raises RangeError when m > 0 and n != 0" do - # https://bugs.ruby-lang.org/issues/18518#note-9 - limit = RUBY_ENGINE == 'ruby' ? 2**67 : 2**32 - - coerce_long = mock("long") - coerce_long.stub!(:to_int).and_return(limit) - coerce_bignum = mock("bignum") - coerce_bignum.stub!(:to_int).and_return(bignum_value) - exps = [limit, coerce_long] - exps << bignum_value << coerce_bignum if bignum_value >= limit - - exps.each { |exp| - -> { (1 << exp) }.should raise_error(RangeError, 'shift width too big') - -> { (-1 << exp) }.should raise_error(RangeError, 'shift width too big') - -> { (bignum_value << exp) }.should raise_error(RangeError, 'shift width too big') - -> { (-bignum_value << exp) }.should raise_error(RangeError, 'shift width too big') - } - end - end end diff --git a/spec/ruby/core/integer/minus_spec.rb b/spec/ruby/core/integer/minus_spec.rb index aadf416a05..ce50c8752f 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 == -18446744073706991120 + (2_560_496 - bignum_value).should == -9223372036852215312 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 == 18446744073709551921 - (@bignum - 12.57).should be_close(18446744073709551917.43, TOLERANCE) + (@bignum - 9).should == 9223372036854776113 + (@bignum - 12.57).should be_close(9223372036854776109.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 5037d27458..d1e9c2640d 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 == 4722366482869645213696 + (256 * bignum_value).should == 2361183241434822606848 (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 == 184467440737095523880 - (@bignum * (@bignum - 40)).should == 340282366920938491207277694290934407024 + (@bignum * 10).should == 92233720368547765800 + (@bignum * (@bignum - 40)).should == 85070591730234629737795195287525433200 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 d01a76ab58..511a436872 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 == 18446744073709551625 + (9 + bignum_value).should == 9223372036854775817 (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 == 18446744073709551696 - (@bignum + 4.2).should be_close(18446744073709551696.2, TOLERANCE) - (@bignum + bignum_value(3)).should == 36893488147419103311 + (@bignum + 4).should == 9223372036854775888 + (@bignum + 4.2).should be_close(9223372036854775888.2, TOLERANCE) + (@bignum + bignum_value(3)).should == 18446744073709551695 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 96268b3af5..cd10dad6f2 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(93.1349992295444, TOLERANCE) + a.remainder(97.345).should be_close(46.5674996147722, 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 e91613d8d1..6abcd8d714 100644 --- a/spec/ruby/core/integer/right_shift_spec.rb +++ b/spec/ruby/core/integer/right_shift_spec.rb @@ -52,13 +52,17 @@ describe "Integer#>> (with n >> m)" do (-7 >> 64).should == -1 end - it "returns a Bignum == fixnum_max * 2 when fixnum_max >> -1 and n > 0" do + 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 result = fixnum_max >> -1 result.should be_an_instance_of(Integer) result.should == fixnum_max * 2 end - it "returns a Bignum == fixnum_min * 2 when fixnum_min >> -1 and n < 0" do + it "returns an 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 @@ -92,7 +96,7 @@ describe "Integer#>> (with n >> m)" do context "bignum" do before :each do - @bignum = bignum_value * 8 # 2 ** 67 + @bignum = bignum_value * 16 end it "returns n shifted right m bits when n > 0, m > 0" do @@ -149,6 +153,10 @@ 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) @@ -183,53 +191,4 @@ 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 - - it "raises RangeError when m < 0 and n != 0" do - # https://bugs.ruby-lang.org/issues/18518#note-9 - limit = RUBY_ENGINE == 'ruby' ? 2**67 : 2**32 - - coerce_long = mock("long") - coerce_long.stub!(:to_int).and_return(-limit) - coerce_bignum = mock("bignum") - coerce_bignum.stub!(:to_int).and_return(-bignum_value) - exps = [-limit, coerce_long] - exps << -bignum_value << coerce_bignum if bignum_value >= limit - - exps.each { |exp| - -> { (1 >> exp) }.should raise_error(RangeError, 'shift width too big') - -> { (-1 >> exp) }.should raise_error(RangeError, 'shift width too big') - -> { (bignum_value >> exp) }.should raise_error(RangeError, 'shift width too big') - -> { (-bignum_value >> exp) }.should raise_error(RangeError, 'shift width too big') - } - end - end end diff --git a/spec/ruby/core/integer/shared/abs.rb b/spec/ruby/core/integer/shared/abs.rb index 43844c9065..946aa21864 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 == 18446744073709551655 - (-bignum_value(18)).send(@method).should == 18446744073709551634 + bignum_value(39).send(@method).should == 9223372036854775847 + (-bignum_value(18)).send(@method).should == 9223372036854775826 end end end diff --git a/spec/ruby/core/integer/shared/arithmetic_coerce.rb b/spec/ruby/core/integer/shared/arithmetic_coerce.rb index 1260192df1..4c0cbcb999 100644 --- a/spec/ruby/core/integer/shared/arithmetic_coerce.rb +++ b/spec/ruby/core/integer/shared/arithmetic_coerce.rb @@ -1,5 +1,25 @@ require_relative '../fixtures/classes' +describe :integer_arithmetic_coerce_rescue, shared: true do + it "rescues exception (StandardError and subclasses) raised in other#coerce and raises TypeError" do + b = mock("numeric with failed #coerce") + b.should_receive(:coerce).and_raise(IntegerSpecs::CoerceError) + + # e.g. 1 + b + -> { 1.send(@method, b) }.should raise_error(TypeError, /MockObject can't be coerced into Integer/) + end + + it "does not rescue Exception and StandardError siblings raised in other#coerce" do + [Exception, NoMemoryError].each do |exception| + b = mock("numeric with failed #coerce") + b.should_receive(:coerce).and_raise(exception) + + # e.g. 1 + b + -> { 1.send(@method, b) }.should raise_error(exception) + end + end +end + describe :integer_arithmetic_coerce_not_rescue, shared: true do it "does not rescue exception raised in other#coerce" do b = mock("numeric with failed #coerce") diff --git a/spec/ruby/core/integer/shared/exponent.rb b/spec/ruby/core/integer/shared/exponent.rb index 15df518b7e..f949c514c8 100644 --- a/spec/ruby/core/integer/shared/exponent.rb +++ b/spec/ruby/core/integer/shared/exponent.rb @@ -30,13 +30,11 @@ 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 @@ -98,8 +96,8 @@ describe :integer_exponent, shared: true do end it "returns self raised to other power" do - (@bignum.send(@method, 4)).should == 115792089237316196603666111261383895964500887398800252671052694326794607293761 - (@bignum.send(@method, 1.3)).should be_close(11109528802438156839288832.0, TOLERANCE) + (@bignum.send(@method, 4)).should == 7237005577332262361485077344629993318496048279512298547155833600056910050625 + (@bignum.send(@method, 1.2)).should be_close(57262152889751597425762.57804, TOLERANCE) end it "raises a TypeError when given a non-Integer" do @@ -118,9 +116,8 @@ describe :integer_exponent, shared: true do end it "returns a complex number when negative and raised to a fractional power" do - (-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) + ((-@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) end end end diff --git a/spec/ruby/core/integer/shared/modulo.rb b/spec/ruby/core/integer/shared/modulo.rb index f678a10806..b06d81e17d 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 == 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 + @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 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 9f1df9ada9..06092eaa92 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(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) + 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) 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 ca08dad95c..7988bfde7a 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 == "18446744073709551625" - bignum_value.to_s.should == "18446744073709551616" - (-bignum_value(675)).to_s.should == "-18446744073709552291" + bignum_value(9).to_s.should == "9223372036854775817" + bignum_value.to_s.should == "9223372036854775808" + (-bignum_value(675)).to_s.should == "-9223372036854776483" end end diff --git a/spec/ruby/core/integer/try_convert_spec.rb b/spec/ruby/core/integer/try_convert_spec.rb index 4bc7d3851a..45c66eec79 100644 --- a/spec/ruby/core/integer/try_convert_spec.rb +++ b/spec/ruby/core/integer/try_convert_spec.rb @@ -28,17 +28,7 @@ ruby_version_is "3.1" do it "sends #to_int to the argument and raises TypeError if it's not a kind of Integer" do obj = mock("to_int") obj.should_receive(:to_int).and_return(Object.new) - -> { - Integer.try_convert obj - }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Object)") - end - - it "responds with a different error message when it raises a TypeError, depending on the type of the non-Integer object :to_int returns" do - obj = mock("to_int") - obj.should_receive(:to_int).and_return("A String") - -> { - Integer.try_convert obj - }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives String)") + -> { Integer.try_convert obj }.should raise_error(TypeError) end it "does not rescue exceptions raised by #to_int" do diff --git a/spec/ruby/core/integer/uminus_spec.rb b/spec/ruby/core/integer/uminus_spec.rb index 7a9cfe89bf..b6b110dec4 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 == -18446744073709551616 - (-bignum_value).send(:-@).should == 18446744073709551616 + bignum_value.send(:-@).should == -9223372036854775808 + (-bignum_value).send(:-@).should == 9223372036854775808 - bignum_value(921).send(:-@).should == -18446744073709552537 - (-bignum_value(921).send(:-@)).should == 18446744073709552537 + bignum_value(921).send(:-@).should == -9223372036854776729 + (-bignum_value(921).send(:-@)).should == 9223372036854776729 end end end diff --git a/spec/ruby/core/integer/zero_spec.rb b/spec/ruby/core/integer/zero_spec.rb index bd362c4181..2dac50c406 100644 --- a/spec/ruby/core/integer/zero_spec.rb +++ b/spec/ruby/core/integer/zero_spec.rb @@ -7,7 +7,15 @@ describe "Integer#zero?" do -1.should_not.zero? end - it "Integer#zero? overrides Numeric#zero?" do - 42.method(:zero?).owner.should == Integer + ruby_version_is "3.0" do + it "Integer#zero? overrides Numeric#zero?" do + 42.method(:zero?).owner.should == Integer + end + end + + ruby_version_is ""..."3.0" do + it "Integer#zero? uses Numeric#zero?" do + 42.method(:zero?).owner.should == Numeric + end end end diff --git a/spec/ruby/core/io/advise_spec.rb b/spec/ruby/core/io/advise_spec.rb index 651fc52378..0a845487e2 100644 --- a/spec/ruby/core/io/advise_spec.rb +++ b/spec/ruby/core/io/advise_spec.rb @@ -73,9 +73,19 @@ describe "IO#advise" do end end - guard -> { platform_is :linux and kernel_version_is '3.6' } do # [ruby-core:65355] tmpfs is not supported + platform_is :linux do it "supports the willneed advice type" do - @io.advise(:willneed).should be_nil + require 'etc' + uname = if Etc.respond_to?(:uname) + Etc.uname[:release] + else + `uname -r`.chomp + end + if (uname.split('.').map(&:to_i) <=> [3,6]) < 0 + skip "[ruby-core:65355] tmpfs is not supported" + else + @io.advise(:willneed).should be_nil + end end end diff --git a/spec/ruby/core/io/binread_spec.rb b/spec/ruby/core/io/binread_spec.rb index 418e89213b..a3f752d8f9 100644 --- a/spec/ruby/core/io/binread_spec.rb +++ b/spec/ruby/core/io/binread_spec.rb @@ -44,14 +44,4 @@ describe "IO.binread" do it "raises an Errno::EINVAL when not passed a valid offset" do -> { IO.binread @fname, 0, -1 }.should raise_error(Errno::EINVAL) end - - ruby_version_is "3.3" do - # https://bugs.ruby-lang.org/issues/19630 - it "warns about deprecation given a path with a pipe" do - cmd = "|echo ok" - -> { - IO.binread(cmd) - }.should complain(/IO process creation with a leading '\|'/) - end - end end diff --git a/spec/ruby/core/io/bytes_spec.rb b/spec/ruby/core/io/bytes_spec.rb new file mode 100644 index 0000000000..6e328983f2 --- /dev/null +++ b/spec/ruby/core/io/bytes_spec.rb @@ -0,0 +1,47 @@ +# -*- encoding: utf-8 -*- +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is ''...'3.0' do + describe "IO#bytes" do + before :each do + @io = IOSpecs.io_fixture "lines.txt" + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + @io.close unless @io.closed? + end + + it "returns an enumerator of the next bytes from the stream" do + enum = @io.bytes + enum.should be_an_instance_of(Enumerator) + @io.readline.should == "Voici la ligne une.\n" + enum.first(5).should == [81, 117, 105, 32, 195] + end + + it "yields each byte" do + count = 0 + ScratchPad.record [] + @io.each_byte do |byte| + ScratchPad << byte + break if 4 < count += 1 + end + + ScratchPad.recorded.should == [86, 111, 105, 99, 105] + end + + it "raises an IOError on closed stream" do + enum = IOSpecs.closed_io.bytes + -> { enum.first }.should raise_error(IOError) + end + + it "raises an IOError on an enumerator for a stream that has been closed" do + enum = @io.bytes + enum.first.should == 86 + @io.close + -> { enum.first }.should raise_error(IOError) + end + end +end diff --git a/spec/ruby/core/io/chars_spec.rb b/spec/ruby/core/io/chars_spec.rb new file mode 100644 index 0000000000..15db595aed --- /dev/null +++ b/spec/ruby/core/io/chars_spec.rb @@ -0,0 +1,30 @@ +# -*- encoding: utf-8 -*- +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require_relative 'shared/chars' + +ruby_version_is ''...'3.0' do + describe "IO#chars" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :io_chars, :chars + end + + describe "IO#chars" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :io_chars_empty, :chars + end +end diff --git a/spec/ruby/core/io/close_spec.rb b/spec/ruby/core/io/close_spec.rb index 3a44cc8b17..eb560eaf67 100644 --- a/spec/ruby/core/io/close_spec.rb +++ b/spec/ruby/core/io/close_spec.rb @@ -44,12 +44,6 @@ 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/codepoints_spec.rb b/spec/ruby/core/io/codepoints_spec.rb new file mode 100644 index 0000000000..04c115dd3f --- /dev/null +++ b/spec/ruby/core/io/codepoints_spec.rb @@ -0,0 +1,38 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require_relative 'shared/codepoints' + +ruby_version_is ''...'3.0' do + + # See redmine #1667 + describe "IO#codepoints" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :io_codepoints, :codepoints + end + + describe "IO#codepoints" do + before :each do + @io = IOSpecs.io_fixture "lines.txt" + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + @io.close unless @io.closed? + end + + it "calls the given block" do + r = [] + @io.codepoints { |c| r << c } + r[24].should == 232 + r.last.should == 10 + end + end +end diff --git a/spec/ruby/core/io/copy_stream_spec.rb b/spec/ruby/core/io/copy_stream_spec.rb index ffa2ea992c..df9c5c7390 100644 --- a/spec/ruby/core/io/copy_stream_spec.rb +++ b/spec/ruby/core/io/copy_stream_spec.rb @@ -69,12 +69,9 @@ describe :io_copy_stream_to_io, shared: true do end it "raises an IOError if the destination IO is not open for writing" do - to_io = new_io __FILE__, "r" - begin - -> { IO.copy_stream @object.from, to_io }.should raise_error(IOError) - ensure - to_io.close - end + @to_io.close + @to_io = new_io @to_name, "r" + -> { IO.copy_stream @object.from, @to_io }.should raise_error(IOError) end it "does not close the destination IO" do @@ -112,8 +109,7 @@ describe "IO.copy_stream" do end after :each do - rm_r @to_name if @to_name - rm_r @from_bigfile + rm_r @to_name, @from_bigfile end describe "from an IO" do @@ -168,25 +164,6 @@ describe "IO.copy_stream" do it_behaves_like :io_copy_stream_to_io, nil, IOSpecs::CopyStream it_behaves_like :io_copy_stream_to_io_with_offset, nil, IOSpecs::CopyStream end - - describe "to a Tempfile" do - before :all do - require 'tempfile' - end - - before :each do - @to_io = Tempfile.new("rubyspec_copy_stream", encoding: Encoding::BINARY, mode: File::RDONLY) - @to_name = @to_io.path - end - - after :each do - @to_io.close! - @to_name = nil # do not rm_r it, already done by Tempfile#close! - end - - it_behaves_like :io_copy_stream_to_io, nil, IOSpecs::CopyStream - it_behaves_like :io_copy_stream_to_io_with_offset, nil, IOSpecs::CopyStream - end end describe "from a file name" do @@ -300,8 +277,10 @@ describe "IO.copy_stream" do @io.should_not_receive(:pos) IO.copy_stream(@io, @to_name) end + end + describe "with a destination that does partial reads" do before do @from_out, @from_in = IO.pipe diff --git a/spec/ruby/core/io/eof_spec.rb b/spec/ruby/core/io/eof_spec.rb index b4850df437..315345d942 100644 --- a/spec/ruby/core/io/eof_spec.rb +++ b/spec/ruby/core/io/eof_spec.rb @@ -76,7 +76,7 @@ describe "IO#eof?" do end it "returns true on one-byte stream after single-byte read" do - File.open(__dir__ + '/fixtures/one_byte.txt') { |one_byte| + File.open(File.dirname(__FILE__) + '/fixtures/one_byte.txt') { |one_byte| one_byte.read(1) one_byte.should.eof? } diff --git a/spec/ruby/core/io/fixtures/classes.rb b/spec/ruby/core/io/fixtures/classes.rb index 204a2a101b..5d81d5fcd9 100644 --- a/spec/ruby/core/io/fixtures/classes.rb +++ b/spec/ruby/core/io/fixtures/classes.rb @@ -7,18 +7,6 @@ module IOSpecs class SubIO < IO end - class SubIOWithRedefinedNew < IO - def self.new(...) - ScratchPad << :redefined_new_called - super - end - - def initialize(...) - ScratchPad << :call_original_initialize - super - end - end - def self.collector Proc.new { |x| ScratchPad << x } end @@ -120,14 +108,6 @@ module IOSpecs "linha ", "cinco.\nHere ", "is ", "line ", "six.\n" ] end - def self.lines_space_separator_without_trailing_spaces - [ "Voici", "la", "ligne", "une.\nQui", - "\303\250", "la", "linea", "due.\n\n\nAqu\303\255", - "est\303\241", "la", "l\303\255nea", "tres.\nHier", - "ist", "Zeile", "vier.\n\nEst\303\241", "aqui", "a", - "linha", "cinco.\nHere", "is", "line", "six.\n" ] - end - def self.lines_arbitrary_separator [ "Voici la ligne une.\nQui \303\250", " la linea due.\n\n\nAqu\303\255 est\303\241 la l\303\255nea tres.\nHier ist Zeile vier.\n\nEst\303\241 aqui a linha cinco.\nHere is line six.\n" ] @@ -139,12 +119,6 @@ module IOSpecs "Est\303\241 aqui a linha cinco.\nHere is line six.\n" ] end - def self.paragraphs_without_trailing_new_line_characters - [ "Voici la ligne une.\nQui \303\250 la linea due.", - "Aqu\303\255 est\303\241 la l\303\255nea tres.\nHier ist Zeile vier.", - "Est\303\241 aqui a linha cinco.\nHere is line six.\n" ] - end - # Creates an IO instance for an existing fixture file. The # file should obviously not be deleted. def self.io_fixture(name, mode = "r:utf-8") diff --git a/spec/ruby/core/io/flush_spec.rb b/spec/ruby/core/io/flush_spec.rb index f7d5ba77fc..34cf42c425 100644 --- a/spec/ruby/core/io/flush_spec.rb +++ b/spec/ruby/core/io/flush_spec.rb @@ -19,11 +19,11 @@ describe "IO#flush" do end end - # [ruby-core:90895] RJIT worker may leave fd open in a forked child. - # For instance, RJIT creates a worker before @r.close with fork(), @r.close happens, - # and the RJIT worker keeps the pipe open until the worker execve(). - # TODO: consider acquiring GVL from RJIT worker. - guard_not -> { defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? } do + # [ruby-core:90895] MJIT worker may leave fd open in a forked child. + # 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::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/foreach_spec.rb b/spec/ruby/core/io/foreach_spec.rb index c361d27879..c2276cf544 100644 --- a/spec/ruby/core/io/foreach_spec.rb +++ b/spec/ruby/core/io/foreach_spec.rb @@ -20,10 +20,7 @@ describe "IO.foreach" do platform_is :windows do cmd = "|cmd.exe /C echo hello&echo line2" end - - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - IO.foreach(cmd) { |l| ScratchPad << l } - end + IO.foreach(cmd) { |l| ScratchPad << l } ScratchPad.recorded.should == ["hello\n", "line2\n"] end @@ -31,9 +28,7 @@ describe "IO.foreach" do it "gets data from a fork when passed -" do parent_pid = $$ - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - IO.foreach("|-") { |l| ScratchPad << l } - end + IO.foreach("|-") { |l| ScratchPad << l } if $$ == parent_pid ScratchPad.recorded.should == ["hello\n", "from a fork\n"] @@ -44,16 +39,6 @@ describe "IO.foreach" do end end end - - ruby_version_is "3.3" do - # https://bugs.ruby-lang.org/issues/19630 - it "warns about deprecation given a path with a pipe" do - cmd = "|echo ok" - -> { - IO.foreach(cmd).to_a - }.should complain(/IO process creation with a leading '\|'/) - end - end end end diff --git a/spec/ruby/core/io/getbyte_spec.rb b/spec/ruby/core/io/getbyte_spec.rb index b4351160e6..6ba8f0a3e0 100644 --- a/spec/ruby/core/io/getbyte_spec.rb +++ b/spec/ruby/core/io/getbyte_spec.rb @@ -40,19 +40,3 @@ describe "IO#getbyte" do @io.getbyte.should == nil end end - -describe "IO#getbyte" do - before :each do - @name = tmp("io_getbyte.txt") - @io = new_io(@name, 'w') - end - - after :each do - @io.close if @io - rm_r @name if @name - end - - it "raises an IOError if the stream is not readable" do - -> { @io.getbyte }.should raise_error(IOError) - end -end diff --git a/spec/ruby/core/io/gets_spec.rb b/spec/ruby/core/io/gets_spec.rb index ca64bf860e..a3cd180b66 100644 --- a/spec/ruby/core/io/gets_spec.rb +++ b/spec/ruby/core/io/gets_spec.rb @@ -24,12 +24,6 @@ describe "IO#gets" do end end - it "sets $_ to nil after the last line has been read" do - while @io.gets - end - $_.should be_nil - end - it "returns nil if called at the end of the stream" do IOSpecs.lines.length.times { @io.gets } @io.gets.should == nil @@ -44,6 +38,14 @@ 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 @@ -62,6 +64,14 @@ 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 @@ -90,6 +100,14 @@ 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 @@ -108,6 +126,14 @@ 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 @@ -119,49 +145,12 @@ describe "IO#gets" do $..should == @count += 1 end end - - describe "that consists of multiple bytes" do - platform_is_not :windows do - it "should match the separator even if the buffer is filled over successive reads" do - IO.pipe do |read, write| - - # Write part of the string with the separator split between two write calls. We want - # the read to intertwine such that when the read starts the full data isn't yet - # available in the buffer. - write.write("Aquí está la línea tres\r\n") - - t = Thread.new do - # Continue reading until the separator is encountered or the pipe is closed. - read.gets("\r\n\r\n") - end - - # Write the other half of the separator, which should cause the `gets` call to now - # match. Explicitly close the pipe for good measure so a bug in `gets` doesn't block forever. - Thread.pass until t.stop? - - write.write("\r\nelse\r\n\r\n") - write.close - - t.value.bytes.should == "Aquí está la línea tres\r\n\r\n".bytes - read.read(8).bytes.should == "else\r\n\r\n".bytes - end - end - end - end end describe "when passed chomp" do it "returns the first line without a trailing newline character" do @io.gets(chomp: true).should == IOSpecs.lines_without_newline_characters[0] end - - it "raises exception when options passed as Hash" do - -> { @io.gets({ chomp: true }) }.should raise_error(TypeError) - - -> { - @io.gets("\n", 1, { chomp: true }) - }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)") - end end end @@ -243,16 +232,6 @@ describe "IO#gets" do it "reads all bytes when pass a separator and reading more than all bytes" do @io.gets("\t", 100).should == "one\n\ntwo\n\nthree\nfour\n" end - - it "returns empty string when 0 passed as a limit" do - @io.gets(0).should == "" - @io.gets(nil, 0).should == "" - @io.gets("", 0).should == "" - end - - it "does not accept limit that doesn't fit in a C off_t" do - -> { @io.gets(2**128) }.should raise_error(RangeError) - end end describe "IO#gets" do @@ -338,23 +317,11 @@ describe "IO#gets" do @io.gets.encoding.should == Encoding::BINARY end - ruby_version_is ''...'3.3' do - it "transcodes to internal encoding if the IO object's external encoding is BINARY" do - Encoding.default_external = Encoding::BINARY - Encoding.default_internal = Encoding::UTF_8 - @io = new_io @name, 'r' - @io.set_encoding Encoding::BINARY, Encoding::UTF_8 - @io.gets.encoding.should == Encoding::UTF_8 - end - end - - ruby_version_is '3.3' do - it "ignores the internal encoding if the IO object's external encoding is BINARY" do - Encoding.default_external = Encoding::BINARY - Encoding.default_internal = Encoding::UTF_8 - @io = new_io @name, 'r' - @io.set_encoding Encoding::BINARY, Encoding::UTF_8 - @io.gets.encoding.should == Encoding::BINARY - end + it "transcodes to internal encoding if the IO object's external encoding is BINARY" do + Encoding.default_external = Encoding::BINARY + Encoding.default_internal = Encoding::UTF_8 + @io = new_io @name, 'r' + @io.set_encoding Encoding::BINARY, Encoding::UTF_8 + @io.gets.encoding.should == Encoding::UTF_8 end end diff --git a/spec/ruby/core/io/initialize_spec.rb b/spec/ruby/core/io/initialize_spec.rb index 026252a13d..ba5bc117b7 100644 --- a/spec/ruby/core/io/initialize_spec.rb +++ b/spec/ruby/core/io/initialize_spec.rb @@ -27,17 +27,6 @@ describe "IO#initialize" do @io.fileno.should == fd end - it "accepts options as keyword arguments" do - fd = new_fd @name, "w:utf-8" - - @io.send(:initialize, fd, "w", flags: File::CREAT) - @io.fileno.should == fd - - -> { - @io.send(:initialize, fd, "w", {flags: File::CREAT}) - }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 1..2)") - end - it "raises a TypeError when passed an IO" do -> { @io.send :initialize, STDOUT, 'w' }.should raise_error(TypeError) end diff --git a/spec/ruby/core/io/lineno_spec.rb b/spec/ruby/core/io/lineno_spec.rb index 9a4ad90880..99266ecca1 100644 --- a/spec/ruby/core/io/lineno_spec.rb +++ b/spec/ruby/core/io/lineno_spec.rb @@ -92,13 +92,8 @@ describe "IO#lineno=" do @io.lineno.should == 92233 end - it "raises TypeError if cannot convert argument to Integer implicitly" do - -> { @io.lineno = "1" }.should raise_error(TypeError, 'no implicit conversion of String into Integer') - -> { @io.lineno = nil }.should raise_error(TypeError, 'no implicit conversion from nil to integer') - end - - it "does not accept Integers that don't fit in a C int" do - -> { @io.lineno = 2**32 }.should raise_error(RangeError) + it "raises TypeError on nil argument" do + -> { @io.lineno = nil }.should raise_error(TypeError) end it "sets the current line number to the given value" do diff --git a/spec/ruby/core/io/lines_spec.rb b/spec/ruby/core/io/lines_spec.rb new file mode 100644 index 0000000000..5b29a1d07e --- /dev/null +++ b/spec/ruby/core/io/lines_spec.rb @@ -0,0 +1,46 @@ +# -*- encoding: utf-8 -*- +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is ''...'3.0' do + describe "IO#lines" do + before :each do + @io = IOSpecs.io_fixture "lines.txt" + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + @io.close if @io + end + + it "returns an Enumerator" do + @io.lines.should be_an_instance_of(Enumerator) + end + + describe "when no block is given" do + it "returns an Enumerator" do + @io.lines.should be_an_instance_of(Enumerator) + end + + describe "returned Enumerator" do + describe "size" do + it "should return nil" do + @io.lines.size.should == nil + end + end + end + end + + it "returns a line when accessed" do + enum = @io.lines + enum.first.should == IOSpecs.lines[0] + end + + it "yields each line to the passed block" do + ScratchPad.record [] + @io.lines { |s| ScratchPad << s } + ScratchPad.recorded.should == IOSpecs.lines + end + end +end diff --git a/spec/ruby/core/io/new_spec.rb b/spec/ruby/core/io/new_spec.rb index 979ac0efcb..3597098caf 100644 --- a/spec/ruby/core/io/new_spec.rb +++ b/spec/ruby/core/io/new_spec.rb @@ -1,16 +1,8 @@ require_relative '../../spec_helper' require_relative 'shared/new' -# NOTE: should be synchronized with library/stringio/initialize_spec.rb - describe "IO.new" do it_behaves_like :io_new, :new - - it "does not use the given block and warns to use IO::open" do - -> { - @io = IO.send(@method, @fd) { raise } - }.should complain(/warning: IO::new\(\) does not take block; use IO::open\(\) instead/) - end end describe "IO.new" do diff --git a/spec/ruby/core/io/nonblock_spec.rb b/spec/ruby/core/io/nonblock_spec.rb index 99dc0cafd0..e81ac10c58 100644 --- a/spec/ruby/core/io/nonblock_spec.rb +++ b/spec/ruby/core/io/nonblock_spec.rb @@ -12,21 +12,43 @@ platform_is_not :windows do end end - it "returns true for pipe by default" do - r, w = IO.pipe - begin - r.nonblock?.should == true - w.nonblock?.should == true - ensure - r.close - w.close + ruby_version_is ""..."3.0" do + it "returns false for pipe by default" do + r, w = IO.pipe + begin + r.nonblock?.should == false + w.nonblock?.should == false + ensure + r.close + w.close + end + end + + it "returns false for socket by default" do + require 'socket' + TCPServer.open(0) do |socket| + socket.nonblock?.should == false + end end end - it "returns true for socket by default" do - require 'socket' - TCPServer.open(0) do |socket| - socket.nonblock?.should == true + ruby_version_is "3.0" do + it "returns true for pipe by default" do + r, w = IO.pipe + begin + r.nonblock?.should == true + w.nonblock?.should == true + ensure + r.close + w.close + end + end + + it "returns true for socket by default" do + require 'socket' + TCPServer.open(0) do |socket| + socket.nonblock?.should == true + end end end end diff --git a/spec/ruby/core/io/open_spec.rb b/spec/ruby/core/io/open_spec.rb index d151da9ce5..d3a3961df7 100644 --- a/spec/ruby/core/io/open_spec.rb +++ b/spec/ruby/core/io/open_spec.rb @@ -37,19 +37,6 @@ describe "IO.open" do ScratchPad.recorded.should == :called end - it "propagate an exception in the block after calling #close" do - -> do - IO.open(@fd, "w") do |io| - IOSpecs.io_mock(io, :close) do - super() - ScratchPad.record :called - end - raise Exception - end - end.should raise_error(Exception) - ScratchPad.recorded.should == :called - end - it "propagates an exception raised by #close that is not a StandardError" do -> do IO.open(@fd, "w") do |io| diff --git a/spec/ruby/core/io/path_spec.rb b/spec/ruby/core/io/path_spec.rb deleted file mode 100644 index 8145c32f39..0000000000 --- a/spec/ruby/core/io/path_spec.rb +++ /dev/null @@ -1,14 +0,0 @@ -require_relative '../../spec_helper' - -describe "IO#path" do - ruby_version_is "3.2" do - it "returns the path of the file associated with the IO object" do - path = tmp("io_path.txt") - File.open(path, "w") do |file| - IO.new(file.fileno, path: file.path, autoclose: false).path.should == file.path - end - ensure - File.unlink(path) - end - end -end diff --git a/spec/ruby/core/io/pipe_spec.rb b/spec/ruby/core/io/pipe_spec.rb index aee0d9003f..2f2cf06f4d 100644 --- a/spec/ruby/core/io/pipe_spec.rb +++ b/spec/ruby/core/io/pipe_spec.rb @@ -25,17 +25,6 @@ describe "IO.pipe" do @r.should be_an_instance_of(IOSpecs::SubIO) @w.should be_an_instance_of(IOSpecs::SubIO) end - - it "does not use IO.new method to create pipes and allows its overriding" do - ScratchPad.record [] - - # so redefined .new is not called, but original #initialize is - @r, @w = IOSpecs::SubIOWithRedefinedNew.pipe - ScratchPad.recorded.should == [:call_original_initialize, :call_original_initialize] # called 2 times - for each pipe (r and w) - - @r.should be_an_instance_of(IOSpecs::SubIOWithRedefinedNew) - @w.should be_an_instance_of(IOSpecs::SubIOWithRedefinedNew) - end end describe "IO.pipe" do diff --git a/spec/ruby/core/io/pread_spec.rb b/spec/ruby/core/io/pread_spec.rb index aa496ee803..43071d6a31 100644 --- a/spec/ruby/core/io/pread_spec.rb +++ b/spec/ruby/core/io/pread_spec.rb @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- require_relative '../../spec_helper' -guard -> { platform_is_not :windows or ruby_version_is "3.3" } do +platform_is_not :windows do describe "IO#pread" do before :each do @fname = tmp("io_pread.txt") @@ -26,88 +26,11 @@ guard -> { platform_is_not :windows or ruby_version_is "3.3" } do buffer.should == "567" end - it "shrinks the buffer in case of less bytes read" do - buffer = "foo" - @file.pread(1, 0, buffer) - buffer.should == "1" - end - - it "grows the buffer in case of more bytes read" do - buffer = "foo" - @file.pread(5, 0, buffer) - buffer.should == "12345" - end - it "does not advance the file pointer" do @file.pread(4, 0).should == "1234" @file.read.should == "1234567890" end - it "ignores the current offset" do - @file.pos = 3 - @file.pread(4, 0).should == "1234" - end - - it "returns an empty string for maxlen = 0" do - @file.pread(0, 4).should == "" - end - - it "ignores the offset for maxlen = 0, even if it is out of file bounds" do - @file.pread(0, 400).should == "" - end - - it "does not reset the buffer when reading with maxlen = 0" do - buffer = "foo" - @file.pread(0, 4, buffer) - buffer.should == "foo" - - @file.pread(0, 400, buffer) - buffer.should == "foo" - end - - it "converts maxlen to Integer using #to_int" do - maxlen = mock('maxlen') - maxlen.should_receive(:to_int).and_return(4) - @file.pread(maxlen, 0).should == "1234" - end - - it "converts offset to Integer using #to_int" do - offset = mock('offset') - offset.should_receive(:to_int).and_return(0) - @file.pread(4, offset).should == "1234" - end - - it "converts a buffer to String using to_str" do - buffer = mock('buffer') - buffer.should_receive(:to_str).at_least(1).and_return("foo") - @file.pread(4, 0, buffer) - buffer.should_not.is_a?(String) - buffer.to_str.should == "1234" - end - - it "raises TypeError if maxlen is not an Integer and cannot be coerced into Integer" do - maxlen = Object.new - -> { @file.pread(maxlen, 0) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer') - end - - it "raises TypeError if offset is not an Integer and cannot be coerced into Integer" do - offset = Object.new - -> { @file.pread(4, offset) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer') - end - - it "raises ArgumentError for negative values of maxlen" do - -> { @file.pread(-4, 0) }.should raise_error(ArgumentError, 'negative string size (or size too big)') - end - - it "raised Errno::EINVAL for negative values of offset" do - -> { @file.pread(4, -1) }.should raise_error(Errno::EINVAL, /Invalid argument/) - end - - it "raises TypeError if the buffer is not a String and cannot be coerced into String" do - buffer = Object.new - -> { @file.pread(4, 0, buffer) }.should raise_error(TypeError, 'no implicit conversion of Object into String') - end - it "raises EOFError if end-of-file is reached" do -> { @file.pread(1, 10) }.should raise_error(EOFError) end diff --git a/spec/ruby/core/io/print_spec.rb b/spec/ruby/core/io/print_spec.rb index 085852024c..04e971ef6d 100644 --- a/spec/ruby/core/io/print_spec.rb +++ b/spec/ruby/core/io/print_spec.rb @@ -3,27 +3,16 @@ require_relative 'fixtures/classes' describe "IO#print" do before :each do - @old_record_separator = $\ - @old_field_separator = $, - suppress_warning { - $\ = '->' - $, = '^^' - } + @old_separator = $\ + suppress_warning {$\ = '->'} @name = tmp("io_print") end after :each do - suppress_warning { - $\ = @old_record_separator - $, = @old_field_separator - } + suppress_warning {$\ = @old_separator} rm_r @name end - it "returns nil" do - touch(@name) { |f| f.print.should be_nil } - end - it "writes $_.to_s followed by $\\ (if any) to the stream if no arguments given" do o = mock('o') o.should_receive(:to_s).and_return("mockmockmock") @@ -49,15 +38,13 @@ describe "IO#print" do IO.read(@name).should == "hello#{$\}" end - it "writes each obj.to_s to the stream separated by $, (if any) and appends $\\ (if any) given multiple objects" do + it "writes each obj.to_s to the stream and appends $\\ (if any) given multiple objects" do o, o2 = Object.new, Object.new def o.to_s(); 'o'; end def o2.to_s(); 'o2'; end - suppress_warning { - touch(@name) { |f| f.print(o, o2) } - } - IO.read(@name).should == "#{o.to_s}#{$,}#{o2.to_s}#{$\}" + touch(@name) { |f| f.print(o, o2) } + IO.read(@name).should == "#{o.to_s}#{o2.to_s}#{$\}" end it "raises IOError on closed stream" do diff --git a/spec/ruby/core/io/pwrite_spec.rb b/spec/ruby/core/io/pwrite_spec.rb index 00d40db28d..fe29d1e1f6 100644 --- a/spec/ruby/core/io/pwrite_spec.rb +++ b/spec/ruby/core/io/pwrite_spec.rb @@ -1,7 +1,7 @@ # -*- encoding: utf-8 -*- require_relative '../../spec_helper' -guard -> { platform_is_not :windows or ruby_version_is "3.3" } do +platform_is_not :windows do describe "IO#pwrite" do before :each do @fname = tmp("io_pwrite.txt") @@ -28,42 +28,16 @@ guard -> { platform_is_not :windows or ruby_version_is "3.3" } do @file.pread(6, 0).should == "foobar" end - it "calls #to_s on the object to be written" do - object = mock("to_s") - object.should_receive(:to_s).and_return("foo") - @file.pwrite(object, 0) - @file.pread(3, 0).should == "foo" - end - - it "calls #to_int on the offset" do - offset = mock("to_int") - offset.should_receive(:to_int).and_return(2) - @file.pwrite("foo", offset) - @file.pread(3, 2).should == "foo" - end - it "raises IOError when file is not open in write mode" do File.open(@fname, "r") do |file| - -> { file.pwrite("foo", 1) }.should raise_error(IOError, "not opened for writing") + -> { file.pwrite("foo", 1) }.should raise_error(IOError) end end it "raises IOError when file is closed" do file = File.open(@fname, "w+") file.close - -> { file.pwrite("foo", 1) }.should raise_error(IOError, "closed stream") - end - - it "raises a NoMethodError if object does not respond to #to_s" do - -> { - @file.pwrite(BasicObject.new, 0) - }.should raise_error(NoMethodError, /undefined method `to_s'/) - end - - it "raises a TypeError if the offset cannot be converted to an Integer" do - -> { - @file.pwrite("foo", Object.new) - }.should raise_error(TypeError, "no implicit conversion of Object into Integer") + -> { file.pwrite("foo", 1) }.should raise_error(IOError) end end end diff --git a/spec/ruby/core/io/read_nonblock_spec.rb b/spec/ruby/core/io/read_nonblock_spec.rb index a62b75274c..e50531d336 100644 --- a/spec/ruby/core/io/read_nonblock_spec.rb +++ b/spec/ruby/core/io/read_nonblock_spec.rb @@ -55,27 +55,6 @@ describe "IO#read_nonblock" do @read.read_nonblock(4).should == "hell" end - it "reads after ungetc with data in the buffer" do - @write.write("foobar") - @read.set_encoding( - 'utf-8', universal_newline: false - ) - c = @read.getc - @read.ungetc(c) - @read.read_nonblock(3).should == "foo" - @read.read_nonblock(3).should == "bar" - end - - it "raises an exception after ungetc with data in the buffer and character conversion enabled" do - @write.write("foobar") - @read.set_encoding( - 'utf-8', universal_newline: true - ) - c = @read.getc - @read.ungetc(c) - -> { @read.read_nonblock(3).should == "foo" }.should raise_error(IOError) - end - it "returns less data if that is all that is available" do @write << "hello" @read.read_nonblock(10).should == "hello" @@ -91,10 +70,6 @@ describe "IO#read_nonblock" do @read.read_nonblock(1).should == "1" end - it "raises ArgumentError when length is less than 0" do - -> { @read.read_nonblock(-1) }.should raise_error(ArgumentError) - end - it "reads into the passed buffer" do buffer = "" @write.write("1") @@ -109,21 +84,6 @@ describe "IO#read_nonblock" do output.should equal(buffer) end - it "discards the existing buffer content upon successful read" do - buffer = "existing content" - @write.write("hello world") - @write.close - @read.read_nonblock(11, buffer) - buffer.should == "hello world" - end - - it "discards the existing buffer content upon error" do - buffer = "existing content" - @write.close - -> { @read.read_nonblock(1, buffer) }.should raise_error(EOFError) - buffer.should be_empty - end - it "raises IOError on closed stream" do -> { IOSpecs.closed_io.read_nonblock(5) }.should raise_error(IOError) end @@ -136,13 +96,4 @@ describe "IO#read_nonblock" do -> { @read.read_nonblock(5) }.should raise_error(EOFError) end - - it "preserves the encoding of the given buffer" do - buffer = ''.encode(Encoding::ISO_8859_1) - @write.write("abc") - @write.close - @read.read_nonblock(10, buffer) - - buffer.encoding.should == Encoding::ISO_8859_1 - end end diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb index db11468ea4..841e693f37 100644 --- a/spec/ruby/core/io/read_spec.rb +++ b/spec/ruby/core/io/read_spec.rb @@ -23,15 +23,6 @@ describe "IO.read" do IO.read(p) end - # https://bugs.ruby-lang.org/issues/19354 - it "accepts options as keyword arguments" do - IO.read(@fname, 3, 0, mode: "r+").should == @contents[0, 3] - - -> { - IO.read(@fname, 3, 0, {mode: "r+"}) - }.should raise_error(ArgumentError, /wrong number of arguments/) - end - it "accepts an empty options Hash" do IO.read(@fname, **{}).should == @contents end @@ -64,33 +55,6 @@ describe "IO.read" do IO.read(@fname, mode: "a+").should == @contents end - platform_is_not :windows do - ruby_version_is ""..."3.3" do - it "uses an :open_args option" do - string = IO.read(@fname, nil, 0, open_args: ["r", nil, {encoding: Encoding::US_ASCII}]) - string.encoding.should == Encoding::US_ASCII - - string = IO.read(@fname, nil, 0, open_args: ["r", nil, {}]) - string.encoding.should == Encoding::UTF_8 - end - end - end - - it "disregards other options if :open_args is given" do - string = IO.read(@fname,mode: "w", encoding: Encoding::UTF_32LE, open_args: ["r", encoding: Encoding::UTF_8]) - string.encoding.should == Encoding::UTF_8 - end - - it "doesn't require mode to be specified in :open_args" do - string = IO.read(@fname, nil, 0, open_args: [{encoding: Encoding::US_ASCII}]) - string.encoding.should == Encoding::US_ASCII - end - - it "doesn't require mode to be specified in :open_args even if flags option passed" do - string = IO.read(@fname, nil, 0, open_args: [{encoding: Encoding::US_ASCII, flags: File::CREAT}]) - string.encoding.should == Encoding::US_ASCII - end - it "treats second nil argument as no length limit" do IO.read(@fname, nil).should == @contents IO.read(@fname, nil, 5).should == IO.read(@fname, @contents.length, 5) @@ -113,15 +77,6 @@ describe "IO.read" do IO.read(@fname, 1, 10).should == nil end - it "returns an empty string when reading zero bytes" do - IO.read(@fname, 0).should == '' - end - - it "returns a String in BINARY when passed a size" do - IO.read(@fname, 1).encoding.should == Encoding::BINARY - IO.read(@fname, 0).encoding.should == Encoding::BINARY - end - it "raises an Errno::ENOENT when the requested file does not exist" do rm_r @fname -> { IO.read @fname }.should raise_error(Errno::ENOENT) @@ -135,18 +90,9 @@ describe "IO.read" do -> { IO.read @fname, -1 }.should raise_error(ArgumentError) end - ruby_version_is ''...'3.3' do - it "raises an Errno::EINVAL when not passed a valid offset" do - -> { IO.read @fname, 0, -1 }.should raise_error(Errno::EINVAL) - -> { IO.read @fname, -1, -1 }.should raise_error(Errno::EINVAL) - end - end - - ruby_version_is '3.3' do - it "raises an ArgumentError when not passed a valid offset" do - -> { IO.read @fname, 0, -1 }.should raise_error(ArgumentError) - -> { IO.read @fname, -1, -1 }.should raise_error(ArgumentError) - end + it "raises an Errno::EINVAL when not passed a valid offset" do + -> { IO.read @fname, 0, -1 }.should raise_error(Errno::EINVAL) + -> { IO.read @fname, -1, -1 }.should raise_error(Errno::EINVAL) end it "uses the external encoding specified via the :external_encoding option" do @@ -158,14 +104,6 @@ describe "IO.read" do str = IO.read(@fname, encoding: Encoding::ISO_8859_1) str.encoding.should == Encoding::ISO_8859_1 end - - platform_is :windows do - it "reads the file in text mode" do - # 0x1A is CTRL+Z and is EOF in Windows text mode. - File.binwrite(@fname, "\x1Abbb") - IO.read(@fname).should.empty? - end - end end describe "IO.read from a pipe" do @@ -174,19 +112,12 @@ describe "IO.read from a pipe" do platform_is :windows do cmd = "|cmd.exe /C echo hello" end - - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - IO.read(cmd).should == "hello\n" - end + IO.read(cmd).should == "hello\n" end platform_is_not :windows do it "opens a pipe to a fork if the rest is -" do - str = nil - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - str = IO.read("|-") - end - + str = IO.read("|-") if str # parent str.should == "hello from child\n" else #child @@ -201,18 +132,13 @@ describe "IO.read from a pipe" do platform_is :windows do cmd = "|cmd.exe /C echo hello" end - - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - IO.read(cmd, 1).should == "h" - end + IO.read(cmd, 1).should == "h" end platform_is_not :windows do it "raises Errno::ESPIPE if passed an offset" do -> { - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - IO.read("|sh -c 'echo hello'", 1, 1) - end + IO.read("|sh -c 'echo hello'", 1, 1) }.should raise_error(Errno::ESPIPE) end end @@ -223,23 +149,11 @@ quarantine! do # The process tried to write to a nonexistent pipe. # once https://bugs.ruby-lang.org/issues/12230 is fixed. it "raises Errno::EINVAL if passed an offset" do -> { - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - IO.read("|cmd.exe /C echo hello", 1, 1) - end + IO.read("|cmd.exe /C echo hello", 1, 1) }.should raise_error(Errno::EINVAL) end end end - - ruby_version_is "3.3" do - # https://bugs.ruby-lang.org/issues/19630 - it "warns about deprecation given a path with a pipe" do - cmd = "|echo ok" - -> { - IO.read(cmd) - }.should complain(/IO process creation with a leading '\|'/) - end - end end describe "IO.read on an empty file" do @@ -283,14 +197,6 @@ describe "IO#read" do @io.read(4).should == '7890' end - it "treats first nil argument as no length limit" do - @io.read(nil).should == @contents - end - - it "raises an ArgumentError when not passed a valid length" do - -> { @io.read(-1) }.should raise_error(ArgumentError) - end - it "clears the output buffer if there is nothing to read" do @io.pos = 10 @@ -299,32 +205,6 @@ describe "IO#read" do @io.read(10, buf).should == nil buf.should == '' - - buf = 'non-empty string' - - @io.read(nil, buf).should == "" - - buf.should == '' - - buf = 'non-empty string' - - @io.read(0, buf).should == "" - - buf.should == '' - end - - it "raise FrozenError if the output buffer is frozen" do - @io.read - -> { @io.read(0, 'frozen-string'.freeze) }.should raise_error(FrozenError) - -> { @io.read(1, 'frozen-string'.freeze) }.should raise_error(FrozenError) - -> { @io.read(nil, 'frozen-string'.freeze) }.should raise_error(FrozenError) - end - - ruby_bug "", ""..."3.3" do - it "raise FrozenError if the output buffer is frozen (2)" do - @io.read - -> { @io.read(1, ''.freeze) }.should raise_error(FrozenError) - end end it "consumes zero bytes when reading zero bytes" do @@ -382,13 +262,6 @@ describe "IO#read" do @io.read(nil, buf).should equal buf end - it "returns the given buffer when there is nothing to read" do - buf = "" - - @io.read - @io.read(nil, buf).should equal buf - end - it "coerces the second argument to string and uses it as a buffer" do buf = "ABCDE" obj = mock("buff") @@ -431,9 +304,6 @@ describe "IO#read" do -> { IOSpecs.closed_io.read }.should raise_error(IOError) end - it "raises ArgumentError when length is less than 0" do - -> { @io.read(-1) }.should raise_error(ArgumentError) - end platform_is_not :windows do it "raises IOError when stream is closed by another thread" do @@ -514,6 +384,13 @@ describe "IO#read in binary mode" do xE2 = [226].pack('C*') result.should == ("abc" + xE2 + "def").force_encoding(Encoding::BINARY) end + + it "does not transcode file contents when an internal encoding is specified" do + result = File.open(@name, "r:binary:utf-8") { |f| f.read }.chomp + result.encoding.should == Encoding::BINARY + xE2 = [226].pack('C*') + result.should == ("abc" + xE2 + "def").force_encoding(Encoding::BINARY) + end end describe "IO#read in text mode" do @@ -608,7 +485,6 @@ describe :io_read_size_internal_encoding, shared: true do it "returns a String in BINARY when passed a size" do @io.read(4).encoding.should equal(Encoding::BINARY) - @io.read(0).encoding.should equal(Encoding::BINARY) end it "does not change the buffer's encoding when passed a limit" do diff --git a/spec/ruby/core/io/readchar_spec.rb b/spec/ruby/core/io/readchar_spec.rb index a66773851a..b5f762a846 100644 --- a/spec/ruby/core/io/readchar_spec.rb +++ b/spec/ruby/core/io/readchar_spec.rb @@ -1,16 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -describe :io_readchar_internal_encoding, shared: true do - it "returns a transcoded String" do - @io.readchar.should == "あ" - end - - it "sets the String encoding to the internal encoding" do - @io.readchar.encoding.should equal(Encoding::UTF_8) - end -end - describe "IO#readchar" do before :each do @io = IOSpecs.io_fixture "lines.txt" @@ -39,62 +29,6 @@ describe "IO#readchar" do end end -describe "IO#readchar with internal encoding" do - after :each do - @io.close if @io - end - - describe "not specified" do - before :each do - @io = IOSpecs.io_fixture "read_euc_jp.txt", "r:euc-jp" - end - - it "does not transcode the String" do - @io.readchar.should == ("あ").encode(Encoding::EUC_JP) - end - - it "sets the String encoding to the external encoding" do - @io.readchar.encoding.should equal(Encoding::EUC_JP) - end - end - - describe "specified by open mode" do - before :each do - @io = IOSpecs.io_fixture "read_euc_jp.txt", "r:euc-jp:utf-8" - end - - it_behaves_like :io_readchar_internal_encoding, nil - end - - describe "specified by mode: option" do - before :each do - @io = IOSpecs.io_fixture "read_euc_jp.txt", mode: "r:euc-jp:utf-8" - end - - it_behaves_like :io_readchar_internal_encoding, nil - end - - describe "specified by internal_encoding: option" do - before :each do - options = { mode: "r", - internal_encoding: "utf-8", - external_encoding: "euc-jp" } - @io = IOSpecs.io_fixture "read_euc_jp.txt", options - end - - it_behaves_like :io_readchar_internal_encoding, nil - end - - describe "specified by encoding: option" do - before :each do - options = { mode: "r", encoding: "euc-jp:utf-8" } - @io = IOSpecs.io_fixture "read_euc_jp.txt", options - end - - it_behaves_like :io_readchar_internal_encoding, nil - end -end - describe "IO#readchar" do before :each do @io = IOSpecs.io_fixture "empty.txt" diff --git a/spec/ruby/core/io/readline_spec.rb b/spec/ruby/core/io/readline_spec.rb index a814c1be90..7cb1601816 100644 --- a/spec/ruby/core/io/readline_spec.rb +++ b/spec/ruby/core/io/readline_spec.rb @@ -43,42 +43,9 @@ describe "IO#readline" do end end - describe "when passed limit" do - it "reads limit bytes" do - @io.readline(3).should == "Voi" - end - - it "returns an empty string when passed 0 as a limit" do - @io.readline(0).should == "" - end - - it "does not accept Integers that don't fit in a C off_t" do - -> { @io.readline(2**128) }.should raise_error(RangeError) - end - end - - describe "when passed separator and limit" do - it "reads limit bytes till the separator" do - # Voici la ligne une.\ - @io.readline(" ", 4).should == "Voic" - @io.readline(" ", 4).should == "i " - @io.readline(" ", 4).should == "la " - @io.readline(" ", 4).should == "lign" - @io.readline(" ", 4).should == "e " - end - end - describe "when passed chomp" do it "returns the first line without a trailing newline character" do @io.readline(chomp: true).should == IOSpecs.lines_without_newline_characters[0] end - - it "raises exception when options passed as Hash" do - -> { @io.readline({ chomp: true }) }.should raise_error(TypeError) - - -> { - @io.readline("\n", 1, { chomp: true }) - }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)") - end end end diff --git a/spec/ruby/core/io/readlines_spec.rb b/spec/ruby/core/io/readlines_spec.rb index 3a6ff3d0f3..254f2927b5 100644 --- a/spec/ruby/core/io/readlines_spec.rb +++ b/spec/ruby/core/io/readlines_spec.rb @@ -101,36 +101,6 @@ describe "IO#readlines" do @io.readlines(obj).should == IOSpecs.lines_r_separator end end - - describe "when passed limit" do - it "raises ArgumentError when passed 0 as a limit" do - -> { @io.readlines(0) }.should raise_error(ArgumentError) - end - - it "does not accept Integers that don't fit in a C off_t" do - -> { @io.readlines(2**128) }.should raise_error(RangeError) - end - end - - describe "when passed chomp" do - it "returns the first line without a trailing newline character" do - @io.readlines(chomp: true).should == IOSpecs.lines_without_newline_characters - end - - it "raises exception when options passed as Hash" do - -> { @io.readlines({ chomp: true }) }.should raise_error(TypeError) - - -> { - @io.readlines("\n", 1, { chomp: true }) - }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)") - end - end - - describe "when passed arbitrary keyword argument" do - it "tolerates it" do - @io.readlines(chomp: true, foo: :bar).should == IOSpecs.lines_without_newline_characters - end - end end describe "IO#readlines" do @@ -180,20 +150,13 @@ describe "IO.readlines" do platform_is :windows do cmd = "|cmd.exe /C echo hello&echo line2" end - - lines = nil - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - lines = IO.readlines(cmd) - end + lines = IO.readlines(cmd) lines.should == ["hello\n", "line2\n"] end platform_is_not :windows do it "gets data from a fork when passed -" do - lines = nil - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - lines = IO.readlines("|-") - end + lines = IO.readlines("|-") if lines # parent lines.should == ["hello\n", "from a fork\n"] @@ -206,16 +169,6 @@ describe "IO.readlines" do end end - ruby_version_is "3.3" do - # https://bugs.ruby-lang.org/issues/19630 - it "warns about deprecation given a path with a pipe" do - cmd = "|echo ok" - -> { - IO.readlines(cmd) - }.should complain(/IO process creation with a leading '\|'/) - end - end - it_behaves_like :io_readlines, :readlines it_behaves_like :io_readlines_options_19, :readlines end diff --git a/spec/ruby/core/io/readpartial_spec.rb b/spec/ruby/core/io/readpartial_spec.rb index 2901b429c2..2b33a0d5b1 100644 --- a/spec/ruby/core/io/readpartial_spec.rb +++ b/spec/ruby/core/io/readpartial_spec.rb @@ -59,7 +59,7 @@ describe "IO#readpartial" do end it "discards the existing buffer content upon successful read" do - buffer = "existing content" + buffer = "existing" @wr.write("hello world") @wr.close @rd.readpartial(11, buffer) @@ -93,19 +93,4 @@ describe "IO#readpartial" do @rd.readpartial(0).should == "" end - ruby_bug "#18421", ""..."3.0.4" do - it "clears and returns the given buffer if the length argument is 0" do - buffer = "existing content" - @rd.readpartial(0, buffer).should == buffer - buffer.should == "" - end - end - - it "preserves the encoding of the given buffer" do - buffer = ''.encode(Encoding::ISO_8859_1) - @wr.write("abc") - @wr.close - @rd.readpartial(10, buffer) - buffer.encoding.should == Encoding::ISO_8859_1 - end end diff --git a/spec/ruby/core/io/rewind_spec.rb b/spec/ruby/core/io/rewind_spec.rb index 5579cbd988..649041afaf 100644 --- a/spec/ruby/core/io/rewind_spec.rb +++ b/spec/ruby/core/io/rewind_spec.rb @@ -18,17 +18,6 @@ describe "IO#rewind" do @io.readline.should == "Voici la ligne une.\n" end - it "positions the instance to the beginning of output for write-only IO" do - name = tmp("io_rewind_spec") - io = File.open(name, "w") - io.write("Voici la ligne une.\n") - io.rewind - io.pos.should == 0 - ensure - io.close - rm_r name - end - it "positions the instance to the beginning of input and clears EOF" do value = @io.read @io.rewind @@ -43,10 +32,6 @@ describe "IO#rewind" do @io.lineno.should == 0 end - it "returns 0" do - @io.rewind.should == 0 - end - it "raises IOError on closed stream" do -> { IOSpecs.closed_io.rewind }.should raise_error(IOError) end diff --git a/spec/ruby/core/io/select_spec.rb b/spec/ruby/core/io/select_spec.rb index 1e4e50a81b..4603c1fbbc 100644 --- a/spec/ruby/core/io/select_spec.rb +++ b/spec/ruby/core/io/select_spec.rb @@ -55,8 +55,8 @@ describe "IO.select" do end end - it "returns supplied objects correctly when monitoring the same object in different arrays" do - filename = tmp("IO_select_pipe_file") + it "returns supplied objects correctly even when monitoring the same object in different arrays" do + filename = tmp("IO_select_pipe_file") + $$.to_s io = File.open(filename, 'w+') result = IO.select [io], [io], nil, 0 result.should == [[io], [io], []] @@ -64,17 +64,6 @@ describe "IO.select" do rm_r filename end - it "returns the pipe read end in read set if the pipe write end is closed concurrently" do - main = Thread.current - t = Thread.new { - Thread.pass until main.stop? - @wr.close - } - IO.select([@rd]).should == [[@rd], [], []] - ensure - t.join - end - it "invokes to_io on supplied objects that are not IO and returns the supplied objects" do # make some data available @wr.write("foobar") 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 92433d6640..7368ec7677 100644 --- a/spec/ruby/core/io/set_encoding_by_bom_spec.rb +++ b/spec/ruby/core/io/set_encoding_by_bom_spec.rb @@ -12,251 +12,66 @@ describe "IO#set_encoding_by_bom" do rm_r @name end - it "returns nil if not readable" do - not_readable_io = new_io(@name, 'wb') + ruby_version_is "2.7" do + it "returns the result encoding if found BOM UTF-8 sequence" do + File.binwrite(@name, "\u{FEFF}abc") - not_readable_io.set_encoding_by_bom.should be_nil - not_readable_io.external_encoding.should == Encoding::ASCII_8BIT - ensure - not_readable_io.close - end - - it "returns the result encoding if found BOM UTF-8 sequence" do - File.binwrite(@name, "\u{FEFF}") - - @io.set_encoding_by_bom.should == Encoding::UTF_8 - @io.external_encoding.should == Encoding::UTF_8 - @io.read.b.should == "".b - @io.rewind - @io.set_encoding(Encoding::ASCII_8BIT) - - File.binwrite(@name, "\u{FEFF}abc") - - @io.set_encoding_by_bom.should == Encoding::UTF_8 - @io.external_encoding.should == Encoding::UTF_8 - @io.read.b.should == "abc".b - end - - it "returns the result encoding if found BOM UTF_16LE sequence" do - File.binwrite(@name, "\xFF\xFE") - - @io.set_encoding_by_bom.should == Encoding::UTF_16LE - @io.external_encoding.should == Encoding::UTF_16LE - @io.read.b.should == "".b - @io.rewind - @io.set_encoding(Encoding::ASCII_8BIT) - - File.binwrite(@name, "\xFF\xFEabc") - - @io.set_encoding_by_bom.should == Encoding::UTF_16LE - @io.external_encoding.should == Encoding::UTF_16LE - @io.read.b.should == "abc".b - end - - it "returns the result encoding if found BOM UTF_16BE sequence" do - File.binwrite(@name, "\xFE\xFF") - - @io.set_encoding_by_bom.should == Encoding::UTF_16BE - @io.external_encoding.should == Encoding::UTF_16BE - @io.read.b.should == "".b - @io.rewind - @io.set_encoding(Encoding::ASCII_8BIT) - - File.binwrite(@name, "\xFE\xFFabc") - - @io.set_encoding_by_bom.should == Encoding::UTF_16BE - @io.external_encoding.should == Encoding::UTF_16BE - @io.read.b.should == "abc".b - end - - it "returns the result encoding if found BOM UTF_32LE sequence" do - File.binwrite(@name, "\xFF\xFE\x00\x00") - - @io.set_encoding_by_bom.should == Encoding::UTF_32LE - @io.external_encoding.should == Encoding::UTF_32LE - @io.read.b.should == "".b - @io.rewind - @io.set_encoding(Encoding::ASCII_8BIT) - - File.binwrite(@name, "\xFF\xFE\x00\x00abc") - - @io.set_encoding_by_bom.should == Encoding::UTF_32LE - @io.external_encoding.should == Encoding::UTF_32LE - @io.read.b.should == "abc".b - end - - it "returns the result encoding if found BOM UTF_32BE sequence" do - File.binwrite(@name, "\x00\x00\xFE\xFF") - - @io.set_encoding_by_bom.should == Encoding::UTF_32BE - @io.external_encoding.should == Encoding::UTF_32BE - @io.read.b.should == "".b - @io.rewind - @io.set_encoding(Encoding::ASCII_8BIT) - - File.binwrite(@name, "\x00\x00\xFE\xFFabc") - - @io.set_encoding_by_bom.should == Encoding::UTF_32BE - @io.external_encoding.should == Encoding::UTF_32BE - @io.read.b.should == "abc".b - end - - it "returns nil if io is empty" do - @io.set_encoding_by_bom.should be_nil - @io.external_encoding.should == Encoding::ASCII_8BIT - end - - it "returns nil if UTF-8 BOM sequence is incomplete" do - File.write(@name, "\xEF") - - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read.b.should == "\xEF".b - @io.rewind - - File.write(@name, "\xEFa") + @io.set_encoding_by_bom.should == Encoding::UTF_8 + @io.external_encoding.should == Encoding::UTF_8 + end - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read.b.should == "\xEFa".b - @io.rewind + it "returns the result encoding if found BOM UTF_16LE sequence" do + File.binwrite(@name, "\xFF\xFEabc") - File.write(@name, "\xEF\xBB") + @io.set_encoding_by_bom.should == Encoding::UTF_16LE + @io.external_encoding.should == Encoding::UTF_16LE + end - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read.b.should == "\xEF\xBB".b - @io.rewind + it "returns the result encoding if found BOM UTF_16BE sequence" do + File.binwrite(@name, "\xFE\xFFabc") - File.write(@name, "\xEF\xBBa") + @io.set_encoding_by_bom.should == Encoding::UTF_16BE + @io.external_encoding.should == Encoding::UTF_16BE + end - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read.b.should == "\xEF\xBBa".b - end - - it "returns nil if UTF-16BE BOM sequence is incomplete" do - File.write(@name, "\xFE") - - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read.b.should == "\xFE".b - @io.rewind - - File.write(@name, "\xFEa") - - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read.b.should == "\xFEa".b - end - - it "returns nil if UTF-16LE/UTF-32LE BOM sequence is incomplete" do - File.write(@name, "\xFF") - - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read.b.should == "\xFF".b - @io.rewind + it "returns the result encoding if found BOM UTF_32LE sequence" do + File.binwrite(@name, "\xFF\xFE\x00\x00abc") - File.write(@name, "\xFFa") + @io.set_encoding_by_bom.should == Encoding::UTF_32LE + @io.external_encoding.should == Encoding::UTF_32LE + end - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read.b.should == "\xFFa".b - end - - it "returns UTF-16LE if UTF-32LE BOM sequence is incomplete" do - File.write(@name, "\xFF\xFE") - - @io.set_encoding_by_bom.should == Encoding::UTF_16LE - @io.external_encoding.should == Encoding::UTF_16LE - @io.read.b.should == "".b - @io.rewind - @io.set_encoding(Encoding::ASCII_8BIT) - - File.write(@name, "\xFF\xFE\x00") - - @io.set_encoding_by_bom.should == Encoding::UTF_16LE - @io.external_encoding.should == Encoding::UTF_16LE - @io.read.b.should == "\x00".b - @io.rewind - @io.set_encoding(Encoding::ASCII_8BIT) - - File.write(@name, "\xFF\xFE\x00a") - - @io.set_encoding_by_bom.should == Encoding::UTF_16LE - @io.external_encoding.should == Encoding::UTF_16LE - @io.read.b.should == "\x00a".b - end + it "returns the result encoding if found BOM UTF_32BE sequence" do + File.binwrite(@name, "\x00\x00\xFE\xFFabc") - it "returns nil if UTF-32BE BOM sequence is incomplete" do - File.write(@name, "\x00") + @io.set_encoding_by_bom.should == Encoding::UTF_32BE + @io.external_encoding.should == Encoding::UTF_32BE + end - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read.b.should == "\x00".b - @io.rewind + it "returns nil if found BOM sequence not provided" do + File.write(@name, "abc") - File.write(@name, "\x00a") + @io.set_encoding_by_bom.should == nil + end - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read.b.should == "\x00a".b - @io.rewind + it 'returns exception if io not in binary mode' do + not_binary_io = new_io(@name, 'r') - File.write(@name, "\x00\x00") + -> { not_binary_io.set_encoding_by_bom }.should raise_error(ArgumentError, 'ASCII incompatible encoding needs binmode') + ensure + not_binary_io.close + end - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read.b.should == "\x00\x00".b - @io.rewind + it 'returns exception if encoding already set' do + @io.set_encoding("utf-8") - File.write(@name, "\x00\x00a") - - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read.b.should == "\x00\x00a".b - @io.rewind - - File.write(@name, "\x00\x00\xFE") - - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read.b.should == "\x00\x00\xFE".b - @io.rewind - - File.write(@name, "\x00\x00\xFEa") - - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read.b.should == "\x00\x00\xFEa".b - end - - it "returns nil if found BOM sequence not provided" do - File.write(@name, "abc") - - @io.set_encoding_by_bom.should == nil - @io.external_encoding.should == Encoding::ASCII_8BIT - @io.read(3).should == "abc".b - end - - 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 - - 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') + -> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding conversion is set') + end end end diff --git a/spec/ruby/core/io/set_encoding_spec.rb b/spec/ruby/core/io/set_encoding_spec.rb index 22d9017635..5aec6a96c3 100644 --- a/spec/ruby/core/io/set_encoding_spec.rb +++ b/spec/ruby/core/io/set_encoding_spec.rb @@ -1,7 +1,7 @@ require_relative '../../spec_helper' describe :io_set_encoding_write, shared: true do - it "sets the encodings to nil when they were set previously" do + it "sets the encodings to nil" do @io = new_io @name, "#{@object}:ibm437:ibm866" @io.set_encoding nil, nil @@ -9,19 +9,6 @@ describe :io_set_encoding_write, shared: true do @io.internal_encoding.should be_nil end - it "sets the encodings to nil when the IO is built with no explicit encoding" do - @io = new_io @name, @object - - # Checking our assumptions first - @io.external_encoding.should be_nil - @io.internal_encoding.should be_nil - - @io.set_encoding nil, nil - - @io.external_encoding.should be_nil - @io.internal_encoding.should be_nil - end - it "prevents the encodings from changing when Encoding defaults are changed" do @io = new_io @name, "#{@object}:utf-8:us-ascii" @io.set_encoding nil, nil @@ -51,7 +38,6 @@ describe "IO#set_encoding when passed nil, nil" do @external = Encoding.default_external @internal = Encoding.default_internal - # The defaults Encoding.default_external = Encoding::UTF_8 Encoding.default_internal = nil @@ -127,22 +113,6 @@ describe "IO#set_encoding when passed nil, nil" do describe "with 'a+' mode" do it_behaves_like :io_set_encoding_write, nil, "a+" end - - describe "with standard IOs" do - it "correctly resets them" do - STDOUT.external_encoding.should == nil - STDOUT.internal_encoding.should == nil - - begin - STDOUT.set_encoding(Encoding::US_ASCII, Encoding::ISO_8859_1) - ensure - STDOUT.set_encoding(nil, nil) - end - - STDOUT.external_encoding.should == nil - STDOUT.internal_encoding.should == nil - end - end end describe "IO#set_encoding" do @@ -218,21 +188,4 @@ describe "IO#set_encoding" do @io.external_encoding.should == Encoding::UTF_8 @io.internal_encoding.should == Encoding::UTF_16BE end - - it "saves encoding options passed as a hash in the last argument" do - File.write(@name, "\xff") - io = File.open(@name) - io.set_encoding(Encoding::EUC_JP, Encoding::SHIFT_JIS, invalid: :replace, replace: ".") - io.read.should == "." - ensure - io.close - end - - it "raises ArgumentError when no arguments are given" do - -> { @io.set_encoding() }.should raise_error(ArgumentError) - end - - it "raises ArgumentError when too many arguments are given" do - -> { @io.set_encoding(1, 2, 3) }.should raise_error(ArgumentError) - end end diff --git a/spec/ruby/core/io/shared/binwrite.rb b/spec/ruby/core/io/shared/binwrite.rb index e51093329b..3649bb47ff 100644 --- a/spec/ruby/core/io/shared/binwrite.rb +++ b/spec/ruby/core/io/shared/binwrite.rb @@ -21,14 +21,6 @@ describe :io_binwrite, shared: true do IO.send(@method, @filename, "abcde").should == 5 end - it "accepts options as a keyword argument" do - IO.send(@method, @filename, "hi", 0, flags: File::CREAT).should == 2 - - -> { - IO.send(@method, @filename, "hi", 0, {flags: File::CREAT}) - }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 2..3)") - end - it "creates a file if missing" do fn = @filename + "xxx" begin @@ -75,11 +67,6 @@ describe :io_binwrite, shared: true do File.read(@filename).should == "\0\0foo" end - it "accepts a :flags option without :mode one" do - IO.send(@method, @filename, "hello, world!", flags: File::CREAT) - File.read(@filename).should == "hello, world!" - end - it "raises an error if readonly mode is specified" do -> { IO.send(@method, @filename, "abcde", mode: "r") }.should raise_error(IOError) end diff --git a/spec/ruby/core/io/shared/each.rb b/spec/ruby/core/io/shared/each.rb index aca622834f..91766fbe03 100644 --- a/spec/ruby/core/io/shared/each.rb +++ b/spec/ruby/core/io/shared/each.rb @@ -33,6 +33,10 @@ describe :io_each, shared: true do $_.should == "test" end + it "returns self" do + @io.send(@method) { |l| l }.should equal(@io) + end + it "raises an IOError when self is not readable" do -> { IOSpecs.closed_io.send(@method) {} }.should raise_error(IOError) end @@ -73,10 +77,6 @@ describe :io_each, shared: true do -> { @io.send(@method, 0){} }.should raise_error(ArgumentError) end end - - it "does not accept Integers that don't fit in a C off_t" do - -> { @io.send(@method, 2**128){} }.should raise_error(RangeError) - end end describe "when passed a String containing one space as a separator" do @@ -113,13 +113,6 @@ describe :io_each, shared: true do @io.send(@method, "") { |s| ScratchPad << s } ScratchPad.recorded.should == IOSpecs.paragraphs end - - it "discards leading newlines" do - @io.readline - @io.readline - @io.send(@method, "") { |s| ScratchPad << s } - ScratchPad.recorded.should == IOSpecs.paragraphs[1..-1] - end end describe "with both separator and limit" do @@ -159,13 +152,6 @@ describe :io_each, shared: true do @io.send(@method, "", 1024) { |s| ScratchPad << s } ScratchPad.recorded.should == IOSpecs.paragraphs end - - it "discards leading newlines" do - @io.readline - @io.readline - @io.send(@method, "", 1024) { |s| ScratchPad << s } - ScratchPad.recorded.should == IOSpecs.paragraphs[1..-1] - end end end end @@ -175,70 +161,6 @@ describe :io_each, shared: true do @io.send(@method, chomp: true) { |s| ScratchPad << s } ScratchPad.recorded.should == IOSpecs.lines_without_newline_characters end - - it "raises exception when options passed as Hash" do - -> { - @io.send(@method, { chomp: true }) { |s| } - }.should raise_error(TypeError) - - -> { - @io.send(@method, "\n", 1, { chomp: true }) { |s| } - }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)") - end - end - - describe "when passed chomp and a separator" do - it "yields each line without separator to the passed block" do - @io.send(@method, " ", chomp: true) { |s| ScratchPad << s } - ScratchPad.recorded.should == IOSpecs.lines_space_separator_without_trailing_spaces - end - end - - describe "when passed chomp and empty line as a separator" do - it "yields each paragraph without trailing new line characters" do - @io.send(@method, "", 1024, chomp: true) { |s| ScratchPad << s } - ScratchPad.recorded.should == IOSpecs.paragraphs_without_trailing_new_line_characters - end - end - - describe "when passed chomp and nil as a separator" do - ruby_version_is "3.2" do - it "yields self's content" do - @io.pos = 100 - @io.send(@method, nil, chomp: true) { |s| ScratchPad << s } - ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six.\n"] - end - end - - ruby_version_is ""..."3.2" do - it "yields self's content without trailing new line character" do - @io.pos = 100 - @io.send(@method, nil, chomp: true) { |s| ScratchPad << s } - ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six."] - end - end - end - - describe "when passed chomp, nil as a separator, and a limit" do - it "yields each line of limit size without truncating trailing new line character" do - # 43 - is a size of the 1st paragraph in the file - @io.send(@method, nil, 43, chomp: true) { |s| ScratchPad << s } - - ScratchPad.recorded.should == [ - "Voici la ligne une.\nQui è la linea due.\n\n\n", - "Aquí está la línea tres.\n" + "Hier ist Zeile ", - "vier.\n\nEstá aqui a linha cinco.\nHere is li", - "ne six.\n" - ] - end - end - - describe "when passed too many arguments" do - it "raises ArgumentError" do - -> { - @io.send(@method, "", 1, "excess argument", chomp: true) {} - }.should raise_error(ArgumentError) - end end end diff --git a/spec/ruby/core/io/shared/new.rb b/spec/ruby/core/io/shared/new.rb index cba5f33ebf..f2a0970a40 100644 --- a/spec/ruby/core/io/shared/new.rb +++ b/spec/ruby/core/io/shared/new.rb @@ -1,7 +1,5 @@ require_relative '../fixtures/classes' -# NOTE: should be synchronized with library/stringio/initialize_spec.rb - # This group of specs may ONLY contain specs that do successfully create # an IO instance from the file descriptor returned by #new_fd helper. describe :io_new, shared: true do @@ -64,15 +62,6 @@ describe :io_new, shared: true do @io.should be_an_instance_of(IO) end - it "accepts options as keyword arguments" do - @io = IO.send(@method, @fd, "w", flags: File::CREAT) - @io.write("foo").should == 3 - - -> { - IO.send(@method, @fd, "w", {flags: File::CREAT}) - }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 1..2)") - end - it "accepts a :mode option" do @io = IO.send(@method, @fd, mode: "w") @io.write("foo").should == 3 @@ -208,10 +197,21 @@ describe :io_new, shared: true do @io.internal_encoding.to_s.should == 'IBM866' end - it "raises ArgumentError for nil options" do - -> { - IO.send(@method, @fd, 'w', nil) - }.should raise_error(ArgumentError) + ruby_version_is ''...'3.0' do + it "accepts nil options" do + @io = suppress_keyword_warning do + IO.send(@method, @fd, 'w', nil) + end + @io.write("foo").should == 3 + end + end + + ruby_version_is '3.0' do + it "raises ArgumentError for nil options" do + -> { + IO.send(@method, @fd, 'w', nil) + }.should raise_error(ArgumentError) + end end it "coerces mode with #to_str" do @@ -382,9 +382,21 @@ describe :io_new_errors, shared: true do }.should raise_error(ArgumentError) end - it "raises ArgumentError if passed a hash for mode and nil for options" do - -> { - @io = IO.send(@method, @fd, {mode: 'w'}, nil) - }.should raise_error(ArgumentError) + ruby_version_is ''...'3.0' do + it "raises TypeError if passed a hash for mode and nil for options" do + -> { + suppress_keyword_warning do + @io = IO.send(@method, @fd, {mode: 'w'}, nil) + end + }.should raise_error(TypeError) + end + end + + ruby_version_is '3.0' do + it "raises ArgumentError if passed a hash for mode and nil for options" do + -> { + @io = IO.send(@method, @fd, {mode: 'w'}, nil) + }.should raise_error(ArgumentError) + end end end diff --git a/spec/ruby/core/io/shared/pos.rb b/spec/ruby/core/io/shared/pos.rb index 3fdd3eb2b3..d83a6c6692 100644 --- a/spec/ruby/core/io/shared/pos.rb +++ b/spec/ruby/core/io/shared/pos.rb @@ -60,13 +60,7 @@ describe :io_set_pos, shared: true do end end - it "raises TypeError when cannot convert implicitly argument to Integer" do - File.open @fname do |io| - -> { io.send @method, Object.new }.should raise_error(TypeError, "no implicit conversion of Object into Integer") - end - end - - it "does not accept Integers that don't fit in a C off_t" do + it "does not accept Integers that don't fit in a C long" do File.open @fname do |io| -> { io.send @method, 2**128 }.should raise_error(RangeError) end diff --git a/spec/ruby/core/io/shared/readlines.rb b/spec/ruby/core/io/shared/readlines.rb index d2b604bba3..8e4a73bb98 100644 --- a/spec/ruby/core/io/shared/readlines.rb +++ b/spec/ruby/core/io/shared/readlines.rb @@ -73,23 +73,6 @@ 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 - - it "does not accept Integers that don't fit in a C off_t" do - -> { IO.send(@method, @name, 2**128, &@object) }.should raise_error(RangeError) - end - - ruby_bug "#18767", ""..."3.3" do - describe "when passed limit" do - it "raises ArgumentError when passed 0 as a limit" do - -> { IO.send(@method, @name, 0, &@object) }.should raise_error(ArgumentError) - end - end - end end describe "when the object is a String" do @@ -104,33 +87,31 @@ describe :io_readlines_options_19, shared: true do end end - describe "when the object is an options Hash" do - it "raises TypeError exception" do - -> { - IO.send(@method, @name, { chomp: true }, &@object) - }.should raise_error(TypeError) + describe "when the object is a Hash" do + it "uses the value as the options hash" do + result = IO.send(@method, @name, mode: "r", &@object) + (result ? result : ScratchPad.recorded).should == IOSpecs.lines end end + end - describe "when the object is neither Integer nor String" do - it "raises TypeError exception" do - obj = mock("not io readlines limit") - - -> { - IO.send(@method, @name, obj, &@object) - }.should raise_error(TypeError) + describe "when passed name, object, object" do + describe "when the first object is an Integer" do + it "uses the second object as an options Hash" do + -> do + IO.send(@method, @filename, 10, mode: "w", &@object) + end.should raise_error(IOError) end - end - end - describe "when passed name, keyword arguments" do - it "uses the keyword arguments as options" do - result = IO.send(@method, @name, mode: "r", &@object) - (result ? result : ScratchPad.recorded).should == IOSpecs.lines + it "calls #to_hash to convert the second object to a Hash" do + options = mock("io readlines options Hash") + options.should_receive(:to_hash).and_return({ mode: "w" }) + -> do + IO.send(@method, @filename, 10, **options, &@object) + end.should raise_error(IOError) + end end - end - describe "when passed name, object, object" do describe "when the first object is a String" do it "uses the second object as a limit if it is an Integer" do result = IO.send(@method, @name, " ", 10, &@object) @@ -143,18 +124,32 @@ describe :io_readlines_options_19, shared: true do result = IO.send(@method, @name, " ", limit, &@object) (result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit end + + it "uses the second object as an options Hash" do + -> do + IO.send(@method, @filename, " ", mode: "w", &@object) + end.should raise_error(IOError) + end + + it "calls #to_hash to convert the second object to a Hash" do + options = mock("io readlines options Hash") + options.should_receive(:to_hash).and_return({ mode: "w" }) + -> do + IO.send(@method, @filename, " ", **options, &@object) + end.should raise_error(IOError) + end end describe "when the first object is not a String or Integer" do it "calls #to_str to convert the object to a String" do sep = mock("io readlines separator") sep.should_receive(:to_str).at_least(1).and_return(" ") - result = IO.send(@method, @name, sep, 10, &@object) + result = IO.send(@method, @name, sep, 10, mode: "r", &@object) (result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit end it "uses the second object as a limit if it is an Integer" do - result = IO.send(@method, @name, " ", 10, &@object) + result = IO.send(@method, @name, " ", 10, mode: "r", &@object) (result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit end @@ -164,57 +159,24 @@ describe :io_readlines_options_19, shared: true do result = IO.send(@method, @name, " ", limit, &@object) (result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit end - end - - describe "when the second object is neither Integer nor String" do - it "raises TypeError exception" do - obj = mock("not io readlines limit") - - -> { - IO.send(@method, @name, " ", obj, &@object) - }.should raise_error(TypeError) - end - end - describe "when the second object is an options Hash" do - it "raises TypeError exception" do - -> { - IO.send(@method, @name, "", { chomp: true }, &@object) - }.should raise_error(TypeError) - end - end - end - - describe "when passed name, object, keyword arguments" do - describe "when the first object is an Integer" do - it "uses the keyword arguments as options" do - -> do - IO.send(@method, @filename, 10, mode: "w", &@object) - end.should raise_error(IOError) - end - end - - describe "when the first object is a String" do - it "uses the keyword arguments as options" do + it "uses the second object as an options Hash" do -> do IO.send(@method, @filename, " ", mode: "w", &@object) end.should raise_error(IOError) end - end - - describe "when the first object is not a String or Integer" do - it "uses the keyword arguments as options" do - sep = mock("io readlines separator") - sep.should_receive(:to_str).at_least(1).and_return(" ") + it "calls #to_hash to convert the second object to a Hash" do + options = mock("io readlines options Hash") + options.should_receive(:to_hash).and_return({ mode: "w" }) -> do - IO.send(@method, @filename, sep, mode: "w", &@object) + IO.send(@method, @filename, " ", **options, &@object) end.should raise_error(IOError) end end end - describe "when passed name, separator, limit, keyword arguments" do + describe "when passed name, separator, limit, options" do it "calls #to_path to convert the name object" do name = mock("io name to_path") name.should_receive(:to_path).and_return(@name) @@ -236,24 +198,12 @@ describe :io_readlines_options_19, shared: true do (result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit end - it "uses the keyword arguments as options" do + it "calls #to_hash to convert the options object" do + options = mock("io readlines options Hash") + options.should_receive(:to_hash).and_return({ mode: "w" }) -> do - IO.send(@method, @filename, " ", 10, mode: "w", &@object) + IO.send(@method, @filename, " ", 10, **options, &@object) end.should raise_error(IOError) end - - describe "when passed chomp, nil as a separator, and a limit" do - it "yields each line of limit size without truncating trailing new line character" do - # 43 - is a size of the 1st paragraph in the file - result = IO.send(@method, @name, nil, 43, chomp: true, &@object) - - (result ? result : ScratchPad.recorded).should == [ - "Voici la ligne une.\nQui è la linea due.\n\n\n", - "Aquí está la línea tres.\n" + "Hier ist Zeile ", - "vier.\n\nEstá aqui a linha cinco.\nHere is li", - "ne six.\n" - ] - end - end end end diff --git a/spec/ruby/core/io/shared/write.rb b/spec/ruby/core/io/shared/write.rb index 964064746a..270b84ac39 100644 --- a/spec/ruby/core/io/shared/write.rb +++ b/spec/ruby/core/io/shared/write.rb @@ -69,6 +69,16 @@ describe :io_write, shared: true do -> { IOSpecs.closed_io.send(@method, "hello") }.should raise_error(IOError) end + it "does not modify the passed argument" do + File.open(@filename, "w") do |f| + f.set_encoding(Encoding::IBM437) + # A character whose codepoint differs between UTF-8 and IBM437 + f.write "ƒ".freeze + end + + File.binread(@filename).bytes.should == [159] + end + describe "on a pipe" do before :each do @r, @w = IO.pipe @@ -85,11 +95,11 @@ describe :io_write, shared: true do @r.read.should == "foo" end - # [ruby-core:90895] RJIT worker may leave fd open in a forked child. - # For instance, RJIT creates a worker before @r.close with fork(), @r.close happens, - # and the RJIT worker keeps the pipe open until the worker execve(). - # TODO: consider acquiring GVL from RJIT worker. - guard_not -> { defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? } do + # [ruby-core:90895] MJIT worker may leave fd open in a forked child. + # 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::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/) @@ -97,58 +107,3 @@ describe :io_write, shared: true do end end end - -describe :io_write_transcode, shared: true do - before :each do - @transcode_filename = tmp("io_write_transcode") - end - - after :each do - rm_r @transcode_filename - end - - it "transcodes the given string when the external encoding is set and neither is BINARY" do - utf8_str = "hello" - - File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file| - file.external_encoding.should == Encoding::UTF_16BE - file.send(@method, utf8_str) - end - - result = File.binread(@transcode_filename) - expected = [0, 104, 0, 101, 0, 108, 0, 108, 0, 111] # UTF-16BE bytes for "hello" - - result.bytes.should == expected - end - - it "transcodes the given string when the external encoding is set and the string encoding is BINARY" do - str = "été".b - - File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file| - file.external_encoding.should == Encoding::UTF_16BE - -> { file.send(@method, str) }.should raise_error(Encoding::UndefinedConversionError) - end - end -end - -describe :io_write_no_transcode, shared: true do - before :each do - @transcode_filename = tmp("io_write_no_transcode") - end - - after :each do - rm_r @transcode_filename - end - - it "does not transcode the given string even when the external encoding is set" do - utf8_str = "hello" - - File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file| - file.external_encoding.should == Encoding::UTF_16BE - file.send(@method, utf8_str) - end - - result = File.binread(@transcode_filename) - result.bytes.should == utf8_str.bytes - end -end diff --git a/spec/ruby/core/io/sysread_spec.rb b/spec/ruby/core/io/sysread_spec.rb index e7f63cefec..8201ad47ca 100644 --- a/spec/ruby/core/io/sysread_spec.rb +++ b/spec/ruby/core/io/sysread_spec.rb @@ -6,7 +6,7 @@ describe "IO#sysread on a file" do @file_name = tmp("IO_sysread_file") + $$.to_s File.open(@file_name, "w") do |f| # write some stuff - f.write("012345678901234567890123456789\nabcdef") + f.write("012345678901234567890123456789") end @file = File.open(@file_name, "r+") end @@ -84,29 +84,6 @@ describe "IO#sysread on a file" do it "raises IOError on closed stream" do -> { IOSpecs.closed_io.sysread(5) }.should raise_error(IOError) end - - it "immediately returns an empty string if the length argument is 0" do - @file.sysread(0).should == "" - end - - it "immediately returns the given buffer if the length argument is 0" do - buffer = "existing content" - @file.sysread(0, buffer).should == buffer - buffer.should == "existing content" - end - - it "discards the existing buffer content upon successful read" do - buffer = "existing content" - @file.sysread(11, buffer) - buffer.should == "01234567890" - end - - it "discards the existing buffer content upon error" do - buffer = "existing content" - @file.seek(0, :END) - -> { @file.sysread(1, buffer) }.should raise_error(EOFError) - buffer.should be_empty - end end describe "IO#sysread" do @@ -123,10 +100,4 @@ describe "IO#sysread" do @write.syswrite "ab" @read.sysread(3).should == "ab" end - - guard_not -> { platform_is :windows and ruby_version_is ""..."3.2" } do # https://bugs.ruby-lang.org/issues/18880 - it "raises ArgumentError when length is less than 0" do - -> { @read.sysread(-1) }.should raise_error(ArgumentError) - end - end end diff --git a/spec/ruby/core/io/sysseek_spec.rb b/spec/ruby/core/io/sysseek_spec.rb index 002f2a14eb..e631939bce 100644 --- a/spec/ruby/core/io/sysseek_spec.rb +++ b/spec/ruby/core/io/sysseek_spec.rb @@ -4,7 +4,7 @@ require_relative 'fixtures/classes' require_relative 'shared/pos' describe "IO#sysseek" do - it_behaves_like :io_set_pos, :sysseek + it_behaves_like :io_set_pos, :seek end describe "IO#sysseek" do diff --git a/spec/ruby/core/io/syswrite_spec.rb b/spec/ruby/core/io/syswrite_spec.rb index 8bf61a27c3..a28cc62174 100644 --- a/spec/ruby/core/io/syswrite_spec.rb +++ b/spec/ruby/core/io/syswrite_spec.rb @@ -29,16 +29,6 @@ describe "IO#syswrite on a file" do end end - it "does not modify the passed argument" do - File.open(@filename, "w") do |f| - f.set_encoding(Encoding::IBM437) - # A character whose codepoint differs between UTF-8 and IBM437 - f.syswrite("ƒ".freeze) - end - - File.binread(@filename).bytes.should == [198, 146] - end - it "warns if called immediately after a buffered IO#write" do @file.write("abcde") -> { @file.syswrite("fghij") }.should complain(/syswrite/) @@ -78,5 +68,4 @@ end describe "IO#syswrite" do it_behaves_like :io_write, :syswrite - it_behaves_like :io_write_no_transcode, :syswrite end diff --git a/spec/ruby/core/io/try_convert_spec.rb b/spec/ruby/core/io/try_convert_spec.rb index a9e99de7aa..5fbd10b6fa 100644 --- a/spec/ruby/core/io/try_convert_spec.rb +++ b/spec/ruby/core/io/try_convert_spec.rb @@ -38,7 +38,7 @@ describe "IO.try_convert" do it "raises a TypeError if the object does not return an IO from #to_io" do obj = mock("io") obj.should_receive(:to_io).and_return("io") - -> { IO.try_convert(obj) }.should raise_error(TypeError, "can't convert MockObject to IO (MockObject#to_io gives String)") + -> { IO.try_convert(obj) }.should raise_error(TypeError) end it "propagates an exception raised by #to_io" do diff --git a/spec/ruby/core/io/ungetbyte_spec.rb b/spec/ruby/core/io/ungetbyte_spec.rb index 716743a6af..776707205a 100644 --- a/spec/ruby/core/io/ungetbyte_spec.rb +++ b/spec/ruby/core/io/ungetbyte_spec.rb @@ -36,10 +36,20 @@ describe "IO#ungetbyte" do @io.getbyte.should == 97 end - it "never raises RangeError" do - for i in [4095, 0x4f7574206f6620636861722072616e67ff] do - @io.ungetbyte(i).should be_nil - @io.getbyte.should == 255 + 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 end end diff --git a/spec/ruby/core/io/ungetc_spec.rb b/spec/ruby/core/io/ungetc_spec.rb index 47a4e99ebf..a05d80ee9c 100644 --- a/spec/ruby/core/io/ungetc_spec.rb +++ b/spec/ruby/core/io/ungetc_spec.rb @@ -103,9 +103,19 @@ describe "IO#ungetc" do -> { @io.sysread(1) }.should raise_error(IOError) end - it "raises TypeError if passed nil" do - @io.getc.should == ?V - proc{@io.ungetc(nil)}.should raise_error(TypeError) + ruby_version_is "0"..."3.0" do + it "does not affect the stream and returns nil when passed nil" do + @io.getc.should == ?V + @io.ungetc(nil) + @io.getc.should == ?o + end + end + + ruby_version_is "3.0" do + it "raises TypeError if passed nil" do + @io.getc.should == ?V + proc{@io.ungetc(nil)}.should raise_error(TypeError) + end end it "puts one or more characters back in the stream" do diff --git a/spec/ruby/core/io/write_nonblock_spec.rb b/spec/ruby/core/io/write_nonblock_spec.rb index c403c864fd..a8b9ce0a36 100644 --- a/spec/ruby/core/io/write_nonblock_spec.rb +++ b/spec/ruby/core/io/write_nonblock_spec.rb @@ -31,16 +31,6 @@ platform_is_not :windows do end end - it "does not modify the passed argument" do - File.open(@filename, "w") do |f| - f.set_encoding(Encoding::IBM437) - # A character whose codepoint differs between UTF-8 and IBM437 - f.write_nonblock("ƒ".freeze) - end - - File.binread(@filename).bytes.should == [198, 146] - end - it "checks if the file is writable if writing zero bytes" do -> { @readonly_file.write_nonblock("") @@ -50,7 +40,6 @@ platform_is_not :windows do describe "IO#write_nonblock" do it_behaves_like :io_write, :write_nonblock - it_behaves_like :io_write_no_transcode, :write_nonblock end end diff --git a/spec/ruby/core/io/write_spec.rb b/spec/ruby/core/io/write_spec.rb index 4a26f8dbaf..60e66e998f 100644 --- a/spec/ruby/core/io/write_spec.rb +++ b/spec/ruby/core/io/write_spec.rb @@ -24,6 +24,10 @@ describe "IO#write on a file" do -> { @readonly_file.write("") }.should_not raise_error end + it "returns a length of 0 when writing a blank string" do + @file.write('').should == 0 + end + before :each do @external = Encoding.default_external @internal = Encoding.default_internal @@ -36,44 +40,10 @@ describe "IO#write on a file" do Encoding.default_internal = @internal end - it "returns a length of 0 when writing a blank string" do - @file.write('').should == 0 - end - - it "returns a length of 0 when writing blank strings" do - @file.write('', '', '').should == 0 - end - - it "returns a length of 0 when passed no arguments" do - @file.write().should == 0 - end - it "returns the number of bytes written" do @file.write("hellø").should == 6 end - it "does not modify the passed argument" do - File.open(@filename, "w") do |f| - f.set_encoding(Encoding::IBM437) - # A character whose codepoint differs between UTF-8 and IBM437 - f.write("ƒ".freeze) - end - - File.binread(@filename).bytes.should == [159] - end - - it "does not modify arguments when passed multiple arguments and external encoding not set" do - a, b = "a".freeze, "b".freeze - - File.open(@filename, "w") do |f| - f.write(a, b) - end - - File.binread(@filename).bytes.should == [97, 98] - a.encoding.should == Encoding::UTF_8 - b.encoding.should == Encoding::UTF_8 - end - it "uses the encoding from the given option for non-ascii encoding" do File.open(@filename, "w", encoding: Encoding::UTF_32LE) do |file| file.write("hi").should == 8 @@ -81,25 +51,8 @@ describe "IO#write on a file" do File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000" end - it "uses the encoding from the given option for non-ascii encoding even if in binary mode" do - File.open(@filename, "w", encoding: Encoding::UTF_32LE, binmode: true) do |file| - file.should.binmode? - file.write("hi").should == 8 - end - File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000" - - File.open(@filename, "wb", encoding: Encoding::UTF_32LE) do |file| - file.should.binmode? - file.write("hi").should == 8 - end - File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000" - end - - it "uses the encoding from the given option for non-ascii encoding when multiple arguments passes" do - File.open(@filename, "w", encoding: Encoding::UTF_32LE) do |file| - file.write("h", "i").should == 8 - end - File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000" + it "uses an :open_args option" do + IO.write(@filename, 'hi', open_args: ["w", nil, {encoding: Encoding::UTF_32LE}]).should == 8 end it "raises a invalid byte sequence error if invalid bytes are being written" do @@ -119,20 +72,6 @@ describe "IO#write on a file" do res = "H#{ë}ll#{ö}" File.binread(@filename).should == res.force_encoding(Encoding::BINARY) end - - platform_is_not :windows do - it "writes binary data if no encoding is given and multiple arguments passed" do - File.open(@filename, "w") do |file| - file.write("\x87".b, "ą") # 0x87 isn't a valid UTF-8 binary representation of a character - end - File.binread(@filename).bytes.should == [0x87, 0xC4, 0x85] - - File.open(@filename, "w") do |file| - file.write("\x61".encode("utf-32le"), "ą") - end - File.binread(@filename).bytes.should == [0x61, 0x00, 0x00, 0x00, 0xC4, 0x85] - end - end end describe "IO.write" do @@ -147,38 +86,10 @@ describe "IO.write" do File.read(@filename).should == "\0\0hi" end - it "requires mode to be specified in :open_args" do - -> { - IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true}]) - }.should raise_error(IOError, "not opened for writing") - - IO.write(@filename, 'hi', open_args: ["w", {encoding: Encoding::UTF_32LE, binmode: true}]).should == 8 - IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true, mode: "w"}]).should == 8 - end - - it "requires mode to be specified in :open_args even if flags option passed" do - -> { - IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true, flags: File::CREAT}]) - }.should raise_error(IOError, "not opened for writing") - - IO.write(@filename, 'hi', open_args: ["w", {encoding: Encoding::UTF_32LE, binmode: true, flags: File::CREAT}]).should == 8 - IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true, flags: File::CREAT, mode: "w"}]).should == 8 - end - it "uses the given encoding and returns the number of bytes written" do IO.write(@filename, 'hi', mode: "w", encoding: Encoding::UTF_32LE).should == 8 end - it "raises ArgumentError if encoding is specified in mode parameter and is given as :encoding option" do - -> { - IO.write(@filename, 'hi', mode: "w:UTF-16LE:UTF-16BE", encoding: Encoding::UTF_32LE) - }.should raise_error(ArgumentError, "encoding specified twice") - - -> { - IO.write(@filename, 'hi', mode: "w:UTF-16BE", encoding: Encoding::UTF_32LE) - }.should raise_error(ArgumentError, "encoding specified twice") - end - it "writes the file with the permissions in the :perm parameter" do rm_r @filename IO.write(@filename, 'write :perm spec', mode: "w", perm: 0o755).should == 16 @@ -203,31 +114,16 @@ describe "IO.write" do rm_r @fifo end - # rb_cloexec_open() is currently missing a retry on EINTR. - # @ioquatix is looking into fixing it. Quarantined until it's done. - quarantine! do - it "writes correctly" do - thr = Thread.new do - IO.read(@fifo) - end - begin - string = "hi" - IO.write(@fifo, string).should == string.length - ensure - thr.join - end + it "writes correctly" do + thr = Thread.new do + IO.read(@fifo) + end + begin + string = "hi" + IO.write(@fifo, string).should == string.length + ensure + thr.join end - end - end - - ruby_version_is "3.3" do - # https://bugs.ruby-lang.org/issues/19630 - it "warns about deprecation given a path with a pipe" do - -> { - -> { - IO.write("|cat", "xxx") - }.should output_to_fd("xxx") - }.should complain(/IO process creation with a leading '\|'/) end end end @@ -235,7 +131,6 @@ end describe "IO#write" do it_behaves_like :io_write, :write - it_behaves_like :io_write_transcode, :write it "accepts multiple arguments" do IO.pipe do |r, w| @@ -273,25 +168,3 @@ platform_is :windows do end end end - -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 diff --git a/spec/ruby/core/kernel/Complex_spec.rb b/spec/ruby/core/kernel/Complex_spec.rb index 346d50ab5e..4f043526b8 100644 --- a/spec/ruby/core/kernel/Complex_spec.rb +++ b/spec/ruby/core/kernel/Complex_spec.rb @@ -1,6 +1,4 @@ require_relative '../../spec_helper' -require_relative '../../shared/kernel/complex' -require_relative 'fixtures/Complex' describe "Kernel.Complex()" do describe "when passed [Complex, Complex]" do @@ -60,92 +58,7 @@ describe "Kernel.Complex()" do end end - describe "when passed [String]" do - it_behaves_like :kernel_complex, :Complex_method, KernelSpecs - - context "invalid argument" do - it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do - -> { - Complex("79+4i".encode("UTF-16")) - }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16") - end - - it "raises ArgumentError for unrecognised Strings" do - -> { - Complex("ruby") - }.should raise_error(ArgumentError, 'invalid value for convert(): "ruby"') - end - - it "raises ArgumentError for trailing garbage" do - -> { - Complex("79+4iruby") - }.should raise_error(ArgumentError, 'invalid value for convert(): "79+4iruby"') - end - - it "does not understand Float::INFINITY" do - -> { - Complex("Infinity") - }.should raise_error(ArgumentError, 'invalid value for convert(): "Infinity"') - - -> { - Complex("-Infinity") - }.should raise_error(ArgumentError, 'invalid value for convert(): "-Infinity"') - end - - it "does not understand Float::NAN" do - -> { - Complex("NaN") - }.should raise_error(ArgumentError, 'invalid value for convert(): "NaN"') - end - - it "does not understand a sequence of _" do - -> { - Complex("7__9+4__0i") - }.should raise_error(ArgumentError, 'invalid value for convert(): "7__9+4__0i"') - end - - it "does not allow null-byte" do - -> { - Complex("1-2i\0") - }.should raise_error(ArgumentError, "string contains null byte") - end - end - - context "invalid argument and exception: false passed" do - it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do - -> { - Complex("79+4i".encode("UTF-16"), exception: false) - }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16") - end - - it "returns nil for unrecognised Strings" do - Complex("ruby", exception: false).should == nil - end - - it "returns nil when trailing garbage" do - Complex("79+4iruby", exception: false).should == nil - end - - it "returns nil for Float::INFINITY" do - Complex("Infinity", exception: false).should == nil - Complex("-Infinity", exception: false).should == nil - end - - it "returns nil for Float::NAN" do - Complex("NaN", exception: false).should == nil - end - - it "returns nil when there is a sequence of _" do - Complex("7__9+4__0i", exception: false).should == nil - end - - it "returns nil when String contains null-byte" do - Complex("1-2i\0", exception: false).should == nil - end - end - end - - describe "when passes [String, String]" do + describe "when passed a String" do it "needs to be reviewed for spec completeness" end @@ -269,8 +182,4 @@ describe "Kernel.Complex()" do end end end - - it "freezes its result" do - Complex(1).frozen?.should == true - end end diff --git a/spec/ruby/core/kernel/Integer_spec.rb b/spec/ruby/core/kernel/Integer_spec.rb index 74dd3e0dd2..2c78e27428 100644 --- a/spec/ruby/core/kernel/Integer_spec.rb +++ b/spec/ruby/core/kernel/Integer_spec.rb @@ -145,7 +145,7 @@ describe :kernel_integer, shared: true do end end -describe :kernel_integer_string, shared: true do +describe "Integer() given a String", shared: true do it "raises an ArgumentError if the String is a null byte" do -> { Integer("\0") }.should raise_error(ArgumentError) end @@ -348,7 +348,7 @@ describe :kernel_integer_string, shared: true do end end -describe :kernel_integer_string_base, shared: true do +describe "Integer() given a String and base", shared: true do it "raises an ArgumentError if the String is a null byte" do -> { Integer("\0", 2) }.should raise_error(ArgumentError) end @@ -573,31 +573,9 @@ describe :kernel_integer_string_base, shared: true do -> { Integer("0#{d}1", base) }.should raise_error(ArgumentError) end end - end - - it "raises an ArgumentError if a base is given for a non-String value" do - -> { Integer(98, 15) }.should raise_error(ArgumentError) - end - - it "tries to convert the base to an integer using to_int" do - obj = mock('8') - obj.should_receive(:to_int).and_return(8) - - Integer("777", obj).should == 0777 - end - - # https://bugs.ruby-lang.org/issues/19349 - ruby_version_is ''...'3.3' do - it "ignores the base if it is not an integer and does not respond to #to_i" do - Integer("777", "8").should == 777 - end - end - ruby_version_is '3.3' do - it "raises a TypeError if it is not an integer and does not respond to #to_i" do - -> { - Integer("777", "8") - }.should raise_error(TypeError, "no implicit conversion of String into Integer") + it "raises an ArgumentError if a base is given for a non-String value" do + -> { Integer(98, 15) }.should raise_error(ArgumentError) end end @@ -799,9 +777,9 @@ describe "Kernel.Integer" do # TODO: fix these specs it_behaves_like :kernel_integer, :Integer, Kernel - it_behaves_like :kernel_integer_string, :Integer + it_behaves_like "Integer() given a String", :Integer - it_behaves_like :kernel_integer_string_base, :Integer + it_behaves_like "Integer() given a String and base", :Integer it "is a public method" do Kernel.Integer(10).should == 10 @@ -813,9 +791,9 @@ describe "Kernel#Integer" do # TODO: fix these specs it_behaves_like :kernel_integer, :Integer, Object.new - it_behaves_like :kernel_integer_string, :Integer + it_behaves_like "Integer() given a String", :Integer - it_behaves_like :kernel_integer_string_base, :Integer + it_behaves_like "Integer() given a String and base", :Integer it "is a private method" do Kernel.should have_private_instance_method(:Integer) diff --git a/spec/ruby/core/kernel/__dir___spec.rb b/spec/ruby/core/kernel/__dir___spec.rb index 242adbf48b..324792a408 100644 --- a/spec/ruby/core/kernel/__dir___spec.rb +++ b/spec/ruby/core/kernel/__dir___spec.rb @@ -19,9 +19,19 @@ describe "Kernel#__dir__" do end end - context "when used in eval with top level binding" do - it "returns nil" do - eval("__dir__", binding).should == nil + ruby_version_is ""..."3.0" do + context "when used in eval with top level binding" do + it "returns the real name of the directory containing the currently-executing file" do + eval("__dir__", binding).should == File.realpath(File.dirname(__FILE__)) + end + end + end + + ruby_version_is "3.0" do + context "when used in eval with top level binding" do + it "returns nil" do + eval("__dir__", binding).should == nil + end end end end diff --git a/spec/ruby/core/kernel/at_exit_spec.rb b/spec/ruby/core/kernel/at_exit_spec.rb index ebd9a71d15..a784c1ae17 100644 --- a/spec/ruby/core/kernel/at_exit_spec.rb +++ b/spec/ruby/core/kernel/at_exit_spec.rb @@ -1,16 +1,67 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -require_relative '../../shared/kernel/at_exit' describe "Kernel.at_exit" do - it_behaves_like :kernel_at_exit, :at_exit - it "is a private method" do Kernel.should have_private_instance_method(:at_exit) end - it "raises ArgumentError if called without a block" do - -> { at_exit }.should raise_error(ArgumentError, "called without a block") + it "runs after all other code" do + ruby_exe("at_exit {print 5}; print 6").should == "65" + end + + it "runs in reverse order of registration" do + code = "at_exit {print 4};at_exit {print 5}; print 6; at_exit {print 7}" + ruby_exe(code).should == "6754" + end + + it "allows calling exit inside at_exit handler" do + code = "at_exit {print 3}; at_exit {print 4; exit; print 5}; at_exit {print 6}" + ruby_exe(code).should == "643" + end + + it "gives access to the last raised exception" do + code = <<-EOC + at_exit do + puts "The exception matches: \#{$! == $exception} (message=\#{$!.message})" + end + + begin + raise "foo" + rescue => $exception + raise + end + EOC + + result = ruby_exe(code, args: "2>&1", exit_status: 1) + result.lines.should.include?("The exception matches: true (message=foo)\n") + end + + it "both exceptions in at_exit and in the main script are printed" do + code = 'at_exit { raise "at_exit_error" }; raise "main_script_error"' + result = ruby_exe(code, args: "2>&1", exit_status: 1) + result.should.include?('at_exit_error (RuntimeError)') + result.should.include?('main_script_error (RuntimeError)') + end + + it "decides the exit status if both at_exit and the main script raise SystemExit" do + ruby_exe('at_exit { exit 43 }; exit 42', args: "2>&1", exit_status: 43) + $?.exitstatus.should == 43 + end + + it "runs all at_exit even if some raise exceptions" do + code = 'at_exit { STDERR.puts "last" }; at_exit { exit 43 }; at_exit { STDERR.puts "first" }; exit 42' + result = ruby_exe(code, args: "2>&1", exit_status: 43) + result.should == "first\nlast\n" + $?.exitstatus.should == 43 + end + + it "runs at_exit handlers even if the main script fails to parse" do + script = fixture(__FILE__, "at_exit.rb") + result = ruby_exe('{', options: "-r#{script}", args: "2>&1", exit_status: 1) + $?.should_not.success? + result.should.include?("at_exit ran\n") + result.should.include?("syntax error") end end diff --git a/spec/ruby/core/kernel/caller_locations_spec.rb b/spec/ruby/core/kernel/caller_locations_spec.rb index 5994b28fa3..3ec8f0f432 100644 --- a/spec/ruby/core/kernel/caller_locations_spec.rb +++ b/spec/ruby/core/kernel/caller_locations_spec.rb @@ -34,10 +34,12 @@ describe 'Kernel#caller_locations' do locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s) 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..)")] + 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 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 f1ff7044b8..dba65ddcb0 100644 --- a/spec/ruby/core/kernel/caller_spec.rb +++ b/spec/ruby/core/kernel/caller_spec.rb @@ -50,10 +50,12 @@ describe 'Kernel#caller' do locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s) 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..)")] + 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 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 5adcbbe603..38ae1984c0 100644 --- a/spec/ruby/core/kernel/clone_spec.rb +++ b/spec/ruby/core/kernel/clone_spec.rb @@ -45,18 +45,26 @@ describe "Kernel#clone" do end describe "with freeze: nil" do - it "copies frozen state from the original, like #clone without arguments" do - o2 = @obj.clone(freeze: nil) - o2.should_not.frozen? - - @obj.freeze - o3 = @obj.clone(freeze: nil) - o3.should.frozen? + ruby_version_is ""..."3.0" do + it "raises ArgumentError" do + -> { @obj.clone(freeze: nil) }.should raise_error(ArgumentError, /unexpected value for freeze: NilClass/) + end end - it "copies frozen?" do - o = "".freeze.clone(freeze: nil) - o.frozen?.should be_true + ruby_version_is "3.0" do + it "copies frozen state from the original, like #clone without arguments" do + o2 = @obj.clone(freeze: nil) + o2.should_not.frozen? + + @obj.freeze + o3 = @obj.clone(freeze: nil) + o3.should.frozen? + end + + it "copies frozen?" do + o = "".freeze.clone(freeze: nil) + o.frozen?.should be_true + end end end @@ -66,19 +74,33 @@ describe "Kernel#clone" do @obj.clone(freeze: true).should.frozen? end - it 'freezes the copy even if the original was not frozen' do - @obj.clone(freeze: true).should.frozen? - end + ruby_version_is ''...'3.0' do + it 'does not freeze the copy even if the original is not frozen' do + @obj.clone(freeze: true).should_not.frozen? + end - it "calls #initialize_clone with kwargs freeze: true" do - obj = KernelSpecs::CloneFreeze.new - obj.clone(freeze: true) - ScratchPad.recorded.should == [obj, { freeze: true }] + it "calls #initialize_clone with no kwargs" do + obj = KernelSpecs::CloneFreeze.new + obj.clone(freeze: true) + ScratchPad.recorded.should == [obj, {}] + end end - it "calls #initialize_clone with kwargs freeze: true even if #initialize_clone only takes a single argument" do - obj = KernelSpecs::Clone.new - -> { obj.clone(freeze: true) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)') + ruby_version_is '3.0' do + it 'freezes the copy even if the original was not frozen' do + @obj.clone(freeze: true).should.frozen? + end + + it "calls #initialize_clone with kwargs freeze: true" do + obj = KernelSpecs::CloneFreeze.new + obj.clone(freeze: true) + ScratchPad.recorded.should == [obj, { freeze: true }] + end + + it "calls #initialize_clone with kwargs freeze: true even if #initialize_clone only takes a single argument" do + obj = KernelSpecs::Clone.new + -> { obj.clone(freeze: true) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)') + end end end @@ -92,15 +114,25 @@ describe "Kernel#clone" do @obj.clone(freeze: false).should_not.frozen? end - it "calls #initialize_clone with kwargs freeze: false" do - obj = KernelSpecs::CloneFreeze.new - obj.clone(freeze: false) - ScratchPad.recorded.should == [obj, { freeze: false }] + ruby_version_is ''...'3.0' do + it "calls #initialize_clone with no kwargs" do + obj = KernelSpecs::CloneFreeze.new + obj.clone(freeze: false) + ScratchPad.recorded.should == [obj, {}] + end end - it "calls #initialize_clone with kwargs freeze: false even if #initialize_clone only takes a single argument" do - obj = KernelSpecs::Clone.new - -> { obj.clone(freeze: false) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)') + ruby_version_is '3.0' do + it "calls #initialize_clone with kwargs freeze: false" do + obj = KernelSpecs::CloneFreeze.new + obj.clone(freeze: false) + ScratchPad.recorded.should == [obj, { freeze: false }] + end + + it "calls #initialize_clone with kwargs freeze: false even if #initialize_clone only takes a single argument" do + obj = KernelSpecs::Clone.new + -> { obj.clone(freeze: false) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)') + end end end @@ -174,4 +206,11 @@ 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 24acec84f5..dc77c3e6f8 100644 --- a/spec/ruby/core/kernel/define_singleton_method_spec.rb +++ b/spec/ruby/core/kernel/define_singleton_method_spec.rb @@ -96,25 +96,4 @@ 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 - - it "cannot define a singleton method with a frozen singleton class" do - o = Object.new - o.freeze - -> { o.define_singleton_method(:foo) { 1 } }.should raise_error(FrozenError) - end end diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb index 3dfc863368..9be0f2dfd3 100644 --- a/spec/ruby/core/kernel/eval_spec.rb +++ b/spec/ruby/core/kernel/eval_spec.rb @@ -159,7 +159,24 @@ describe "Kernel#eval" do end end - ruby_version_is ""..."3.3" do + ruby_version_is ""..."3.0" do + it "uses the filename of the binding if none is provided" do + eval("__FILE__").should == "(eval)" + suppress_warning {eval("__FILE__", binding)}.should == __FILE__ + eval("__FILE__", binding, "success").should == "success" + suppress_warning {eval("eval '__FILE__', binding")}.should == "(eval)" + suppress_warning {eval("eval '__FILE__', binding", binding)}.should == __FILE__ + suppress_warning {eval("eval '__FILE__', binding", binding, 'success')}.should == 'success' + end + + it 'uses the given binding file and line for __FILE__ and __LINE__' do + suppress_warning { + eval("[__FILE__, __LINE__]", binding).should == [__FILE__, __LINE__] + } + end + end + + ruby_version_is "3.0" do it "uses (eval) filename if none is provided" do eval("__FILE__").should == "(eval)" eval("__FILE__", binding).should == "(eval)" @@ -175,21 +192,6 @@ describe "Kernel#eval" do end end - ruby_version_is "3.3" do - it "uses (eval at __FILE__:__LINE__) if none is provided" do - eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})" - eval("__FILE__", binding).should == "(eval at #{__FILE__}:#{__LINE__})" - eval("__FILE__", binding, "success").should == "success" - eval("eval '__FILE__', binding").should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)" - eval("eval '__FILE__', binding", binding).should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)" - eval("eval '__FILE__', binding", binding, 'success').should == "(eval at success:1)" - eval("eval '__FILE__', binding, 'success'", binding).should == 'success' - end - - it 'uses (eval at __FILE__:__LINE__) for __FILE__ and 1 for __LINE__ with a binding argument' do - eval("[__FILE__, __LINE__]", binding).should == ["(eval at #{__FILE__}:#{__LINE__})", 1] - end - end # Found via Rubinius bug github:#149 it "does not alter the value of __FILE__ in the binding" do first_time = EvalSpecs.call_eval @@ -226,20 +228,6 @@ describe "Kernel#eval" do -> { eval("return :eval") }.call.should == :eval end - it "returns from the method calling #eval when evaluating 'return'" do - def eval_return(n) - eval("return n*2") - end - -> { eval_return(3) }.call.should == 6 - end - - it "returns from the method calling #eval when evaluating 'return' in BEGIN" do - def eval_return(n) - eval("BEGIN {return n*3}") - end - -> { eval_return(4) }.call.should == 12 - end - it "unwinds through a Proc-style closure and returns from a lambda-style closure in the closure chain" do code = fixture __FILE__, "eval_return_with_lambda.rb" ruby_exe(code).chomp.should == "a,b,c,eval,f" diff --git a/spec/ruby/core/kernel/exec_spec.rb b/spec/ruby/core/kernel/exec_spec.rb index 3d9520ad67..1b4a7ae6f4 100644 --- a/spec/ruby/core/kernel/exec_spec.rb +++ b/spec/ruby/core/kernel/exec_spec.rb @@ -7,12 +7,12 @@ describe "Kernel#exec" do end it "runs the specified command, replacing current process" do - ruby_exe('exec "echo hello"; puts "fail"').should == "hello\n" + ruby_exe('exec "echo hello"; puts "fail"', escape: true).should == "hello\n" end end describe "Kernel.exec" do it "runs the specified command, replacing current process" do - ruby_exe('Kernel.exec "echo hello"; puts "fail"').should == "hello\n" + ruby_exe('Kernel.exec "echo hello"; puts "fail"', escape: true).should == "hello\n" end end diff --git a/spec/ruby/core/kernel/exit_spec.rb b/spec/ruby/core/kernel/exit_spec.rb index 93cec3fee5..f168cb375e 100644 --- a/spec/ruby/core/kernel/exit_spec.rb +++ b/spec/ruby/core/kernel/exit_spec.rb @@ -10,10 +10,6 @@ describe "Kernel#exit" do it_behaves_like :process_exit, :exit, KernelSpecs::Method.new end -describe "Kernel.exit" do - it_behaves_like :process_exit, :exit, Kernel -end - describe "Kernel#exit!" do it "is a private method" do Kernel.should have_private_instance_method(:exit!) @@ -22,6 +18,10 @@ describe "Kernel#exit!" do it_behaves_like :process_exit!, :exit!, "self" end +describe "Kernel.exit" do + it_behaves_like :process_exit, :exit, Kernel +end + describe "Kernel.exit!" do - it_behaves_like :process_exit!, :exit!, "Kernel" + it_behaves_like :process_exit!, :exit!, Kernel end diff --git a/spec/ruby/core/kernel/fixtures/Complex.rb b/spec/ruby/core/kernel/fixtures/Complex.rb deleted file mode 100644 index bf14d55ad5..0000000000 --- a/spec/ruby/core/kernel/fixtures/Complex.rb +++ /dev/null @@ -1,5 +0,0 @@ -module KernelSpecs - def self.Complex_method(string) - Complex(string) - end -end diff --git a/spec/ruby/core/kernel/fixtures/at_exit.rb b/spec/ruby/core/kernel/fixtures/at_exit.rb new file mode 100644 index 0000000000..9c11a7ad6c --- /dev/null +++ b/spec/ruby/core/kernel/fixtures/at_exit.rb @@ -0,0 +1,3 @@ +at_exit do + STDERR.puts "at_exit ran" +end diff --git a/spec/ruby/core/kernel/fixtures/warn_core_method.rb b/spec/ruby/core/kernel/fixtures/warn_core_method.rb index fd82562404..f5dee6b668 100644 --- a/spec/ruby/core/kernel/fixtures/warn_core_method.rb +++ b/spec/ruby/core/kernel/fixtures/warn_core_method.rb @@ -1,6 +1,6 @@ raise 'should be run without RubyGems' if defined?(Gem) -public def deprecated(n=1) +def deprecated(n=1) # puts nil, caller(0), nil warn "use X instead", uplevel: n end diff --git a/spec/ruby/core/kernel/initialize_clone_spec.rb b/spec/ruby/core/kernel/initialize_clone_spec.rb index 21a90c19f0..2d889f5aad 100644 --- a/spec/ruby/core/kernel/initialize_clone_spec.rb +++ b/spec/ruby/core/kernel/initialize_clone_spec.rb @@ -18,9 +18,11 @@ describe "Kernel#initialize_clone" do a.send(:initialize_clone, b) end - it "accepts a :freeze keyword argument for obj.clone(freeze: value)" do - a = Object.new - b = Object.new - a.send(:initialize_clone, b, freeze: true).should == a + ruby_version_is "3.0" do + it "accepts a :freeze keyword argument for obj.clone(freeze: value)" do + a = Object.new + b = Object.new + a.send(:initialize_clone, b, freeze: true).should == a + end end end diff --git a/spec/ruby/core/kernel/initialize_copy_spec.rb b/spec/ruby/core/kernel/initialize_copy_spec.rb index d71ca9f60f..fe08d184ad 100644 --- a/spec/ruby/core/kernel/initialize_copy_spec.rb +++ b/spec/ruby/core/kernel/initialize_copy_spec.rb @@ -1,18 +1,11 @@ require_relative '../../spec_helper' describe "Kernel#initialize_copy" do - it "returns self" do - obj = Object.new - obj.send(:initialize_copy, obj).should.equal?(obj) - end - it "does nothing if the argument is the same as the receiver" do obj = Object.new obj.send(:initialize_copy, obj).should.equal?(obj) - - obj = Object.new.freeze + obj.freeze obj.send(:initialize_copy, obj).should.equal?(obj) - 1.send(:initialize_copy, 1).should.equal?(1) end diff --git a/spec/ruby/core/kernel/inspect_spec.rb b/spec/ruby/core/kernel/inspect_spec.rb index 1f9ce834ab..e6fca8bf6f 100644 --- a/spec/ruby/core/kernel/inspect_spec.rb +++ b/spec/ruby/core/kernel/inspect_spec.rb @@ -6,6 +6,16 @@ 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_get_spec.rb b/spec/ruby/core/kernel/instance_variable_get_spec.rb index f1d2a45df8..bb6f03d3bf 100644 --- a/spec/ruby/core/kernel/instance_variable_get_spec.rb +++ b/spec/ruby/core/kernel/instance_variable_get_spec.rb @@ -67,12 +67,6 @@ describe "Kernel#instance_variable_get when passed Symbol" do it "raises a NameError when the passed Symbol is an invalid instance variable name" do -> { @obj.instance_variable_get(:"@0") }.should raise_error(NameError) end - - it "returns nil or raises for frozen objects" do - nil.instance_variable_get(:@foo).should == nil - -> { nil.instance_variable_get(:foo) }.should raise_error(NameError) - :foo.instance_variable_get(:@foo).should == nil - end end describe "Kernel#instance_variable_get when passed String" do diff --git a/spec/ruby/core/kernel/instance_variable_set_spec.rb b/spec/ruby/core/kernel/instance_variable_set_spec.rb index 2c25f4366f..7fda30f72c 100644 --- a/spec/ruby/core/kernel/instance_variable_set_spec.rb +++ b/spec/ruby/core/kernel/instance_variable_set_spec.rb @@ -89,17 +89,5 @@ 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 - - it "raises for frozen objects" do - -> { nil.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError) - -> { nil.instance_variable_set(:foo, 42) }.should raise_error(NameError) - -> { :foo.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError) - end end end diff --git a/spec/ruby/core/kernel/iterator_spec.rb b/spec/ruby/core/kernel/iterator_spec.rb new file mode 100644 index 0000000000..3fe8317f26 --- /dev/null +++ b/spec/ruby/core/kernel/iterator_spec.rb @@ -0,0 +1,14 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is ""..."3.0" do + describe "Kernel#iterator?" do + it "is a private method" do + Kernel.should have_private_instance_method(:iterator?) + end + end + + describe "Kernel.iterator?" do + it "needs to be reviewed for spec completeness" + end +end diff --git a/spec/ruby/core/kernel/lambda_spec.rb b/spec/ruby/core/kernel/lambda_spec.rb index 565536ac0d..2aa4d4f2fb 100644 --- a/spec/ruby/core/kernel/lambda_spec.rb +++ b/spec/ruby/core/kernel/lambda_spec.rb @@ -26,44 +26,42 @@ describe "Kernel.lambda" do l.lambda?.should be_true end - ruby_version_is ""..."3.3" do - it "creates a lambda-style Proc if given a literal block via Kernel.public_send" do - suppress_warning do - l = Kernel.public_send(:lambda) { 42 } - l.lambda?.should be_true - end + it "creates a lambda-style Proc if given a literal block via Kernel.public_send" do + suppress_warning do + l = Kernel.public_send(:lambda) { 42 } + l.lambda?.should be_true end + end - it "returns the passed Proc if given an existing Proc" do - some_proc = proc {} - l = suppress_warning {lambda(&some_proc)} - l.should equal(some_proc) - l.lambda?.should be_false - end + it "returns the passed Proc if given an existing Proc" do + some_proc = proc {} + l = suppress_warning {lambda(&some_proc)} + l.should equal(some_proc) + l.lambda?.should be_false + end - it "creates a lambda-style Proc when called with zsuper" do - suppress_warning do - l = KernelSpecs::LambdaSpecs::ForwardBlockWithZSuper.new.lambda { 42 } - l.lambda?.should be_true - l.call.should == 42 + it "creates a lambda-style Proc when called with zsuper" do + suppress_warning do + l = KernelSpecs::LambdaSpecs::ForwardBlockWithZSuper.new.lambda { 42 } + l.lambda?.should be_true + l.call.should == 42 - lambda { l.call(:extra) }.should raise_error(ArgumentError) - end + lambda { l.call(:extra) }.should raise_error(ArgumentError) end + end - it "returns the passed Proc if given an existing Proc through super" do - some_proc = proc { } - l = KernelSpecs::LambdaSpecs::SuperAmpersand.new.lambda(&some_proc) - l.should equal(some_proc) - l.lambda?.should be_false - end + it "returns the passed Proc if given an existing Proc through super" do + some_proc = proc { } + l = KernelSpecs::LambdaSpecs::SuperAmpersand.new.lambda(&some_proc) + l.should equal(some_proc) + l.lambda?.should be_false + end - it "does not create lambda-style Procs when captured with #method" do - kernel_lambda = method(:lambda) - l = suppress_warning {kernel_lambda.call { 42 }} - l.lambda?.should be_false - l.call(:extra).should == 42 - end + it "does not create lambda-style Procs when captured with #method" do + kernel_lambda = method(:lambda) + l = suppress_warning {kernel_lambda.call { 42 }} + l.lambda?.should be_false + l.call(:extra).should == 42 end it "checks the arity of the call when no args are specified" do @@ -138,21 +136,15 @@ describe "Kernel.lambda" do klass.new.ret.should == 1 end - context "when called without a literal block" do - ruby_version_is ""..."3.3" do + ruby_version_is "3.0" do + context "when called without a literal block" do it "warns when proc isn't a lambda" do -> { lambda(&proc{}) }.should complain("#{__FILE__}:#{__LINE__}: warning: lambda without a literal block is deprecated; use the proc without lambda instead\n") end - end - ruby_version_is "3.3" do - it "raises when proc isn't a lambda" do - -> { lambda(&proc{}) }.should raise_error(ArgumentError, /the lambda method requires a literal block/) + it "doesn't warn when proc is lambda" do + -> { lambda(&lambda{}) }.should_not complain(verbose: true) end end - - it "doesn't warn when proc is lambda" do - -> { lambda(&lambda{}) }.should_not complain(verbose: true) - end end end diff --git a/spec/ruby/core/kernel/match_spec.rb b/spec/ruby/core/kernel/match_spec.rb index aa25006163..fbfc77f959 100644 --- a/spec/ruby/core/kernel/match_spec.rb +++ b/spec/ruby/core/kernel/match_spec.rb @@ -1,30 +1,22 @@ require_relative '../../spec_helper' describe "Kernel#=~" do - ruby_version_is ''...'3.2' do - it "returns nil matching any object" do - o = Object.new + 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 - end - end - - it "is deprecated" do - -> do - Object.new =~ /regexp/ - end.should complain(/deprecated Object#=~ is called on Object/, verbose: true) + 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 - ruby_version_is '3.2' do - it "is no longer defined" do - Object.new.should_not.respond_to?(:=~) - end + it "is deprecated" do + -> do + Object.new =~ /regexp/ + end.should complain(/deprecated Object#=~ is called on Object/, verbose: true) end end diff --git a/spec/ruby/core/kernel/method_spec.rb b/spec/ruby/core/kernel/method_spec.rb index 3fc566d6a6..25c6691e10 100644 --- a/spec/ruby/core/kernel/method_spec.rb +++ b/spec/ruby/core/kernel/method_spec.rb @@ -29,52 +29,9 @@ describe "Kernel#method" do m.call.should == :defined end - it "can be called even if we only respond_to_missing? method, true" do + it "can be called even if we only repond_to_missing? method, true" do m = KernelSpecs::RespondViaMissing.new.method(:handled_privately) 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 - - describe "converts the given name to a String using #to_str" do - it "calls #to_str to convert the given name to a String" do - name = mock("method-name") - name.should_receive(:to_str).and_return("hash") - Object.method(name).should == Object.method(:hash) - end - - it "raises a TypeError if the given name can't be converted to a String" do - -> { Object.method(nil) }.should raise_error(TypeError) - -> { Object.method([]) }.should raise_error(TypeError) - end - - it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do - name = mock("method-name") - name.should_receive(:to_str).and_raise(NoMethodError) - -> { Object.method(name) }.should raise_error(NoMethodError) - end - end end diff --git a/spec/ruby/core/kernel/open_spec.rb b/spec/ruby/core/kernel/open_spec.rb index bb42c31f31..569f2f6a7f 100644 --- a/spec/ruby/core/kernel/open_spec.rb +++ b/spec/ruby/core/kernel/open_spec.rb @@ -27,11 +27,9 @@ describe "Kernel#open" do open(@name, "r") { |f| f.gets }.should == @content end - platform_is_not :windows, :wasi do + platform_is_not :windows do it "opens an io when path starts with a pipe" do - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - @io = open("|date") - end + @io = open("|date") begin @io.should be_kind_of(IO) @io.read @@ -41,27 +39,21 @@ describe "Kernel#open" do end it "opens an io when called with a block" do - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - @output = open("|date") { |f| f.read } - end + @output = open("|date") { |f| f.read } @output.should_not == '' end it "opens an io for writing" do - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - -> { - bytes = open("|cat", "w") { |io| io.write(".") } - bytes.should == 1 - }.should output_to_fd(".") - end + -> do + bytes = open("|cat", "w") { |io| io.write(".") } + bytes.should == 1 + end.should output_to_fd(".") end end platform_is :windows do it "opens an io when path starts with a pipe" do - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - @io = open("|date /t") - end + @io = open("|date /t") begin @io.should be_kind_of(IO) @io.read @@ -71,36 +63,15 @@ describe "Kernel#open" do end it "opens an io when called with a block" do - suppress_warning do # https://bugs.ruby-lang.org/issues/19630 - @output = open("|date /t") { |f| f.read } - end + @output = open("|date /t") { |f| f.read } @output.should_not == '' end end - ruby_version_is "3.3" do - # https://bugs.ruby-lang.org/issues/19630 - it "warns about deprecation given a path with a pipe" do - cmd = "|echo ok" - -> { - open(cmd) { |f| f.read } - }.should complain(/Kernel#open with a leading '\|'/) - end - end - it "raises an ArgumentError if not passed one argument" do -> { open }.should raise_error(ArgumentError) end - it "accepts options as keyword arguments" do - @file = open(@name, "r", 0666, flags: File::CREAT) - @file.should be_kind_of(File) - - -> { - open(@name, "r", 0666, {flags: File::CREAT}) - }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)") - end - describe "when given an object that responds to to_open" do before :each do ScratchPad.clear @@ -138,19 +109,9 @@ describe "Kernel#open" do it "passes its arguments onto #to_open" do obj = mock('to_open') - obj.should_receive(:to_open).with(1, 2, 3) - open(obj, 1, 2, 3) - end - - it "passes keyword arguments onto #to_open as keyword arguments if to_open accepts them" do - obj = Object.new - def obj.to_open(*args, **kw) - ScratchPad << {args: args, kw: kw} - end + obj.should_receive(:to_open).with(1,2,3) - ScratchPad.record [] - open(obj, 1, 2, 3, a: "b") - ScratchPad.recorded.should == [args: [1, 2, 3], kw: {a: "b"}] + open(obj, 1, 2, 3) end it "passes the return value from #to_open to a block" do @@ -176,14 +137,28 @@ describe "Kernel#open" do open(@name, nil, nil) { |f| f.gets }.should == @content end - it "is not redefined by open-uri" do - code = <<~RUBY - before = Kernel.instance_method(:open) + ruby_version_is ""..."3.0" do + it "works correctly when redefined by open-uri" do + code = <<~RUBY require 'open-uri' - after = Kernel.instance_method(:open) - p before == after - RUBY - ruby_exe(code, args: "2>&1").should == "true\n" + obj = Object.new + def obj.to_open; self; end + p open(obj) == obj + RUBY + ruby_exe(code, args: "2>&1").should == "true\n" + end + end + + ruby_version_is "3.0" do + it "is not redefined by open-uri" do + code = <<~RUBY + before = Kernel.instance_method(:open) + require 'open-uri' + after = Kernel.instance_method(:open) + p before == after + RUBY + ruby_exe(code, args: "2>&1").should == "true\n" + end end end diff --git a/spec/ruby/core/kernel/p_spec.rb b/spec/ruby/core/kernel/p_spec.rb index eae191aa54..1bdd1740ca 100644 --- a/spec/ruby/core/kernel/p_spec.rb +++ b/spec/ruby/core/kernel/p_spec.rb @@ -76,8 +76,10 @@ describe "Kernel#p" do -> { p(*[]) }.should output("") end - # Not sure how to spec this, but wanted to note the behavior here - it "does not flush if receiver is not a TTY or a File" +=begin Not sure how to spec this, but wanted to note the behavior here + it "does not flush if receiver is not a TTY or a File" do + end +=end end describe "Kernel.p" do diff --git a/spec/ruby/core/kernel/printf_spec.rb b/spec/ruby/core/kernel/printf_spec.rb index 61bf955c25..d8f93ce429 100644 --- a/spec/ruby/core/kernel/printf_spec.rb +++ b/spec/ruby/core/kernel/printf_spec.rb @@ -31,13 +31,6 @@ describe "Kernel.printf" do object.should_receive(:write).with("string") Kernel.printf(object, "%s", "string") end - - it "calls #to_str to convert the format object to a String" do - object = mock('format string') - object.should_receive(:to_str).and_return("to_str: %i") - $stdout.should_receive(:write).with("to_str: 42") - Kernel.printf($stdout, object, 42) - end end describe "Kernel.printf" do diff --git a/spec/ruby/core/kernel/proc_spec.rb b/spec/ruby/core/kernel/proc_spec.rb index 6553b8fd04..dfe178420b 100644 --- a/spec/ruby/core/kernel/proc_spec.rb +++ b/spec/ruby/core/kernel/proc_spec.rb @@ -40,9 +40,27 @@ describe "Kernel#proc" do proc end - it "raises an ArgumentError when passed no block" do - -> { - some_method { "hello" } - }.should raise_error(ArgumentError, 'tried to create Proc object without a block') + 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 + it "can be created when called with no block" do + -> { + some_method { "hello" } + }.should complain(/Capturing the given block using Kernel#proc is deprecated/) + end + end + + ruby_version_is "3.0" do + it "raises an ArgumentError when passed no block" do + -> { + some_method { "hello" } + }.should raise_error(ArgumentError, 'tried to create Proc object without a block') + end end end diff --git a/spec/ruby/core/kernel/remove_instance_variable_spec.rb b/spec/ruby/core/kernel/remove_instance_variable_spec.rb index 4e5ba5e018..e90efc8aed 100644 --- a/spec/ruby/core/kernel/remove_instance_variable_spec.rb +++ b/spec/ruby/core/kernel/remove_instance_variable_spec.rb @@ -41,19 +41,6 @@ describe "Kernel#remove_instance_variable" do end.should raise_error(TypeError) end - it "raises a FrozenError if self is frozen" do - o = Object.new - o.freeze - -> { o.remove_instance_variable(:@foo) }.should raise_error(FrozenError) - -> { o.remove_instance_variable(:foo) }.should raise_error(NameError) - end - - it "raises for frozen objects" do - -> { nil.remove_instance_variable(:@foo) }.should raise_error(FrozenError) - -> { nil.remove_instance_variable(:foo) }.should raise_error(NameError) - -> { :foo.remove_instance_variable(:@foo) }.should raise_error(FrozenError) - end - describe "when passed a String" do it_behaves_like :kernel_remove_instance_variable, nil, "@greeting" end diff --git a/spec/ruby/core/kernel/require_relative_spec.rb b/spec/ruby/core/kernel/require_relative_spec.rb index 6188d13a4e..d4146eb3c8 100644 --- a/spec/ruby/core/kernel/require_relative_spec.rb +++ b/spec/ruby/core/kernel/require_relative_spec.rb @@ -5,9 +5,9 @@ describe "Kernel#require_relative with a relative path" do before :each do CodeLoadingSpecs.spec_setup @dir = "../../fixtures/code" - @abs_dir = File.realpath(@dir, __dir__) + @abs_dir = File.realpath(@dir, File.dirname(__FILE__)) @path = "#{@dir}/load_fixture.rb" - @abs_path = File.realpath(@path, __dir__) + @abs_path = File.realpath(@path, File.dirname(__FILE__)) end after :each do @@ -92,7 +92,7 @@ describe "Kernel#require_relative with a relative path" do it "raises a LoadError that includes the missing path" do missing_path = "#{@dir}/nonexistent.rb" - expanded_missing_path = File.expand_path(missing_path, __dir__) + expanded_missing_path = File.expand_path(missing_path, File.dirname(__FILE__)) -> { require_relative(missing_path) }.should raise_error(LoadError) { |e| e.message.should include(expanded_missing_path) e.path.should == expanded_missing_path @@ -207,7 +207,7 @@ describe "Kernel#require_relative with a relative path" do $LOADED_FEATURES.should include(@abs_path) end - platform_is_not :windows, :wasi do + platform_is_not :windows do describe "with symlinks" do before :each do @symlink_to_code_dir = tmp("codesymlink") @@ -277,7 +277,7 @@ end describe "Kernel#require_relative with an absolute path" do before :each do CodeLoadingSpecs.spec_setup - @dir = File.expand_path "../../fixtures/code", __dir__ + @dir = File.expand_path "../../fixtures/code", File.dirname(__FILE__) @abs_dir = @dir @path = File.join @dir, "load_fixture.rb" @abs_path = @path diff --git a/spec/ruby/core/kernel/require_spec.rb b/spec/ruby/core/kernel/require_spec.rb index 896afb840a..dc3da4b7e6 100644 --- a/spec/ruby/core/kernel/require_spec.rb +++ b/spec/ruby/core/kernel/require_spec.rb @@ -16,26 +16,6 @@ describe "Kernel#require" do Kernel.should have_private_instance_method(:require) end - provided = %w[complex enumerator rational thread ruby2_keywords] - ruby_version_is "3.1" do - provided << "fiber" - end - - it "#{provided.join(', ')} are already required" do - out = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems --disable-did-you-mean') - features = out.lines.map { |line| File.basename(line.chomp, '.*') } - - # Ignore CRuby internals - features -= %w[encdb transdb windows_1252] - features.reject! { |feature| feature.end_with?('-fake') } - - features.sort.should == provided.sort - - code = provided.map { |f| "puts require #{f.inspect}\n" }.join - required = ruby_exe(code, options: '--disable-gems') - required.should == "false\n" * provided.size - end - it_behaves_like :kernel_require_basic, :require, CodeLoadingSpecs::Method.new it_behaves_like :kernel_require, :require, CodeLoadingSpecs::Method.new end diff --git a/spec/ruby/core/kernel/shared/dup_clone.rb b/spec/ruby/core/kernel/shared/dup_clone.rb index 4fac6006e1..84ad49cbde 100644 --- a/spec/ruby/core/kernel/shared/dup_clone.rb +++ b/spec/ruby/core/kernel/shared/dup_clone.rb @@ -52,6 +52,18 @@ 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 @@ -59,6 +71,18 @@ 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/load.rb b/spec/ruby/core/kernel/shared/load.rb index 0fe2d5ce16..120619abef 100644 --- a/spec/ruby/core/kernel/shared/load.rb +++ b/spec/ruby/core/kernel/shared/load.rb @@ -1,6 +1,5 @@ main = self -# The big difference is Kernel#load does not attempt to add an extension to the passed path, unlike Kernel#require describe :kernel_load, shared: true do before :each do CodeLoadingSpecs.spec_setup @@ -11,31 +10,22 @@ describe :kernel_load, shared: true do CodeLoadingSpecs.spec_cleanup end - describe "(path resolution)" do - # This behavior is specific to Kernel#load, it differs for Kernel#require - it "loads a non-extensioned file as a Ruby source file" do - path = File.expand_path "load_fixture", CODE_LOADING_DIR - @object.load(path).should be_true - ScratchPad.recorded.should == [:no_ext] - end - - it "loads a non .rb extensioned file as a Ruby source file" do - path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR - @object.load(path).should be_true - ScratchPad.recorded.should == [:no_rb_ext] - end + it "loads a non-extensioned file as a Ruby source file" do + path = File.expand_path "load_fixture", CODE_LOADING_DIR + @object.load(path).should be_true + ScratchPad.recorded.should == [:no_ext] + end - it "loads from the current working directory" do - Dir.chdir CODE_LOADING_DIR do - @object.load("load_fixture.rb").should be_true - ScratchPad.recorded.should == [:loaded] - end - end + it "loads a non .rb extensioned file as a Ruby source file" do + path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR + @object.load(path).should be_true + ScratchPad.recorded.should == [:no_rb_ext] + end - # This behavior is specific to Kernel#load, it differs for Kernel#require - it "does not look for a c-extension file when passed a path without extension (when no .rb is present)" do - path = File.join CODE_LOADING_DIR, "a", "load_fixture" - -> { @object.send(@method, path) }.should raise_error(LoadError) + it "loads from the current working directory" do + Dir.chdir CODE_LOADING_DIR do + @object.load("load_fixture.rb").should be_true + ScratchPad.recorded.should == [:loaded] end end @@ -98,12 +88,12 @@ describe :kernel_load, shared: true do describe "when passed true for 'wrap'" do it "loads from an existing path" do - path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR + path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR @object.load(path, true).should be_true end it "sets the enclosing scope to an anonymous module" do - path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR + path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR @object.load(path, true) Object.const_defined?(:LoadSpecWrap).should be_false @@ -113,14 +103,14 @@ describe :kernel_load, shared: true do end it "allows referencing outside namespaces" do - path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR + path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR @object.load(path, true) ScratchPad.recorded[0].should equal(String) end it "sets self as a copy of the top-level main" do - path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR + path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR @object.load(path, true) top_level = ScratchPad.recorded[2] @@ -137,7 +127,7 @@ describe :kernel_load, shared: true do main_ancestors = main.singleton_class.ancestors[1..-1] main_ancestors.first.should == mod - path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR + path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR @object.load(path, true) top_level = ScratchPad.recorded[2] @@ -164,41 +154,6 @@ describe :kernel_load, shared: true do end end - describe "when passed a module for 'wrap'" do - ruby_version_is "3.1" do - it "sets the enclosing scope to the supplied module" do - path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR - mod = Module.new - @object.load(path, mod) - - Object.const_defined?(:LoadSpecWrap).should be_false - mod.const_defined?(:LoadSpecWrap).should be_true - - wrap_module = ScratchPad.recorded[1] - wrap_module.should == mod - end - - it "makes constants and instance methods in the source file reachable with the supplied module" do - path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR - mod = Module.new - @object.load(path, mod) - - mod::LOAD_WRAP_SPECS_TOP_LEVEL_CONSTANT.should == 1 - obj = Object.new - obj.extend(mod) - obj.send(:load_wrap_specs_top_level_method).should == :load_wrap_specs_top_level_method - end - - it "makes instance methods in the source file private" do - path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR - mod = Module.new - @object.load(path, mod) - - mod.private_instance_methods.include?(:load_wrap_specs_top_level_method).should == true - end - end - end - describe "(shell expansion)" do before :each do @env_home = ENV["HOME"] diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb index 250813191b..f4645b0242 100644 --- a/spec/ruby/core/kernel/shared/require.rb +++ b/spec/ruby/core/kernel/shared/require.rb @@ -212,34 +212,6 @@ end describe :kernel_require, shared: true do describe "(path resolution)" do - it "loads .rb file when passed absolute path without extension" do - path = File.expand_path "load_fixture", CODE_LOADING_DIR - @object.send(@method, path).should be_true - # This should _not_ be [:no_ext] - ScratchPad.recorded.should == [:loaded] - end - - platform_is :linux, :darwin do - it "loads c-extension file when passed absolute path without extension when no .rb is present" do - # the error message is specific to what dlerror() returns - path = File.join CODE_LOADING_DIR, "a", "load_fixture" - -> { @object.send(@method, path) }.should raise_error(Exception, /file too short|not a mach-o file/) - end - end - - platform_is :darwin do - it "loads .bundle file when passed absolute path with .so" do - # the error message is specific to what dlerror() returns - path = File.join CODE_LOADING_DIR, "a", "load_fixture.so" - -> { @object.send(@method, path) }.should raise_error(Exception, /load_fixture\.bundle.+(file too short|not a mach-o file)/) - end - end - - it "does not try an extra .rb if the path already ends in .rb" do - path = File.join CODE_LOADING_DIR, "d", "load_fixture.rb" - -> { @object.send(@method, path) }.should raise_error(LoadError) - end - # For reference see [ruby-core:24155] in which matz confirms this feature is # intentional for security reasons. it "does not load a bare filename unless the current working directory is in $LOAD_PATH" do @@ -290,11 +262,13 @@ describe :kernel_require, shared: true do ScratchPad.recorded.should == [:loaded] end - 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 - $LOAD_PATH.replace [File.expand_path("b", CODE_LOADING_DIR), CODE_LOADING_DIR] - @object.require("load_fixture").should be_false + ruby_bug "#16926", "2.7"..."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 + $LOAD_PATH.replace [File.expand_path("b", CODE_LOADING_DIR), CODE_LOADING_DIR] + @object.require("load_fixture").should be_false + end end end @@ -583,6 +557,22 @@ describe :kernel_require, shared: true do ScratchPad.recorded.should == [] end + provided = %w[complex enumerator rational thread] + ruby_version_is "2.7" do + provided << 'ruby2_keywords' + end + + it "#{provided.join(', ')} are already required" do + features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems') + provided.each { |feature| + features.should =~ /\b#{feature}\.(rb|so|jar)$/ + } + + code = provided.map { |f| "puts require #{f.inspect}\n" }.join + required = ruby_exe(code, options: '--disable-gems') + required.should == "false\n" * provided.size + end + it "unicode_normalize is part of core and not $LOADED_FEATURES" do features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems') features.lines.each { |feature| @@ -591,23 +581,6 @@ describe :kernel_require, shared: true do -> { @object.require("unicode_normalize") }.should raise_error(LoadError) end - - it "does not load a file earlier on the $LOAD_PATH when other similar features were already loaded" do - Dir.chdir CODE_LOADING_DIR do - @object.send(@method, "../code/load_fixture").should be_true - end - ScratchPad.recorded.should == [:loaded] - - $LOAD_PATH.unshift "#{CODE_LOADING_DIR}/b" - # This loads because the above load was not on the $LOAD_PATH - @object.send(@method, "load_fixture").should be_true - ScratchPad.recorded.should == [:loaded, :loaded] - - $LOAD_PATH.unshift "#{CODE_LOADING_DIR}/c" - # This does not load because the above load was on the $LOAD_PATH - @object.send(@method, "load_fixture").should be_false - ScratchPad.recorded.should == [:loaded, :loaded] - end end describe "(shell expansion)" do diff --git a/spec/ruby/core/kernel/shared/sprintf.rb b/spec/ruby/core/kernel/shared/sprintf.rb index 13dc6e97f0..84d472b0d1 100644 --- a/spec/ruby/core/kernel/shared/sprintf.rb +++ b/spec/ruby/core/kernel/shared/sprintf.rb @@ -289,80 +289,21 @@ describe :kernel_sprintf, shared: true do @method.call("%c", "a").should == "a" end - ruby_version_is ""..."3.2" do - it "raises ArgumentError if argument is a string of several characters" do - -> { - @method.call("%c", "abc") - }.should raise_error(ArgumentError, /%c requires a character/) - end - - it "raises ArgumentError if argument is an empty string" do - -> { - @method.call("%c", "") - }.should raise_error(ArgumentError, /%c requires a character/) - end - end - - ruby_version_is "3.2" do - it "displays only the first character if argument is a string of several characters" do - @method.call("%c", "abc").should == "a" - end - - it "displays no characters if argument is an empty string" do - @method.call("%c", "").should == "" - end - end - - it "raises TypeError if argument is not String or Integer and cannot be converted to them" do + it "raises ArgumentError if argument is a string of several characters" do -> { - @method.call("%c", []) - }.should raise_error(TypeError, /no implicit conversion of Array into Integer/) - end - - it "raises TypeError if argument is nil" do - -> { - @method.call("%c", nil) - }.should raise_error(TypeError, /no implicit conversion from nil to integer/) - end - - it "tries to convert argument to String with to_str" do - obj = BasicObject.new - def obj.to_str - "a" - end - - @method.call("%c", obj).should == "a" - end - - it "tries to convert argument to Integer with to_int" do - obj = BasicObject.new - def obj.to_int - 90 - end - - @method.call("%c", obj).should == "Z" + @method.call("%c", "abc") + }.should raise_error(ArgumentError) end - it "raises TypeError if converting to String with to_str returns non-String" do - obj = BasicObject.new - def obj.to_str - :foo - end - + it "raises ArgumentError if argument is an empty string" do -> { - @method.call("%c", obj) - }.should raise_error(TypeError, /can't convert BasicObject to String/) + @method.call("%c", "") + }.should raise_error(ArgumentError) end - it "raises TypeError if converting to Integer with to_int returns non-Integer" do - obj = BasicObject.new - def obj.to_int - :foo - end - - -> { - @method.call("%c", obj) - }.should raise_error(TypeError, /can't convert BasicObject to Integer/) + it "supports Unicode characters" do + @method.call("%c", 1286).should == "Ԇ" + @method.call("%c", "ش").should == "ش" end end @@ -421,11 +362,11 @@ describe :kernel_sprintf, shared: true do @method.call("%4.6s", "abcdefg").should == "abcdef" end - it "formats nil with width" do + it "formats nli with width" do @method.call("%6s", nil).should == " " end - it "formats nil with precision" do + it "formats nli with precision" do @method.call("%.6s", nil).should == "" end @@ -986,8 +927,4 @@ describe :kernel_sprintf, shared: true do } end end - - it "does not raise error when passed more arguments than needed" do - sprintf("%s %d %c", "string", 2, "c", []).should == "string 2 c" - end end diff --git a/spec/ruby/core/kernel/shared/sprintf_encoding.rb b/spec/ruby/core/kernel/shared/sprintf_encoding.rb index 9cedb8b662..5ca66b9083 100644 --- a/spec/ruby/core/kernel/shared/sprintf_encoding.rb +++ b/spec/ruby/core/kernel/shared/sprintf_encoding.rb @@ -1,5 +1,3 @@ -# Keep encoding-related specs in a separate shared example to be able to skip them in IO/File/StringIO specs. -# It's difficult to check result's encoding in the test after writing to a file/io buffer. describe :kernel_sprintf_encoding, shared: true do it "can produce a string with valid encoding" do string = @method.call("good day %{valid}", valid: "e") @@ -27,7 +25,7 @@ describe :kernel_sprintf_encoding, shared: true do result.encoding.should equal(Encoding::UTF_8) end - it "raises Encoding::CompatibilityError if both encodings are ASCII compatible and there are not ASCII characters" do + it "raises Encoding::CompatibilityError if both encodings are ASCII compatible and there ano not ASCII characters" do string = "Ä %s".encode('windows-1252') argument = "Ђ".encode('windows-1251') @@ -35,33 +33,4 @@ describe :kernel_sprintf_encoding, shared: true do @method.call(string, argument) }.should raise_error(Encoding::CompatibilityError) end - - describe "%c" do - it "supports Unicode characters" do - result = @method.call("%c", 1286) - result.should == "Ԇ" - result.bytes.should == [212, 134] - - result = @method.call("%c", "ش") - result.should == "ش" - result.bytes.should == [216, 180] - end - - it "raises error when a codepoint isn't representable in an encoding of a format string" do - format = "%c".encode("ASCII") - - -> { - @method.call(format, 1286) - }.should raise_error(RangeError, /out of char range/) - end - - it "uses the encoding of the format string to interpret codepoints" do - format = "%c".force_encoding("euc-jp") - result = @method.call(format, 9415601) - - result.encoding.should == Encoding::EUC_JP - result.should == "é".encode(Encoding::EUC_JP) - result.bytes.should == [143, 171, 177] - end - end end diff --git a/spec/ruby/core/kernel/singleton_class_spec.rb b/spec/ruby/core/kernel/singleton_class_spec.rb index 23c400f9bd..a8bcd916d1 100644 --- a/spec/ruby/core/kernel/singleton_class_spec.rb +++ b/spec/ruby/core/kernel/singleton_class_spec.rb @@ -1,6 +1,3 @@ -# truffleruby_primitives: true -require_relative '../../spec_helper' - describe "Kernel#singleton_class" do it "returns class extended from an object" do x = Object.new @@ -21,54 +18,10 @@ describe "Kernel#singleton_class" do end it "raises TypeError for Integer" do - -> { 123.singleton_class }.should raise_error(TypeError, "can't define singleton") - end - - it "raises TypeError for Float" do - -> { 3.14.singleton_class }.should raise_error(TypeError, "can't define singleton") + -> { 123.singleton_class }.should raise_error(TypeError) end it "raises TypeError for Symbol" do - -> { :foo.singleton_class }.should raise_error(TypeError, "can't define singleton") - end - - it "raises TypeError for a frozen deduplicated String" do - -> { (-"string").singleton_class }.should raise_error(TypeError, "can't define singleton") - -> { a = -"string"; a.singleton_class }.should raise_error(TypeError, "can't define singleton") - -> { a = "string"; (-a).singleton_class }.should raise_error(TypeError, "can't define singleton") - end - - it "returns a frozen singleton class if object is frozen" do - obj = Object.new - obj.freeze - obj.singleton_class.frozen?.should be_true - end - - context "for an IO object with a replaced singleton class" do - it "looks up singleton methods from the fresh singleton class after an object instance got a new one" do - proxy = -> io { io.foo } - if RUBY_ENGINE == 'truffleruby' - # We need an inline cache with only this object seen, the best way to do that is to use a Primitive - sclass = -> io { Primitive.singleton_class(io) } - else - sclass = -> io { io.singleton_class } - end - - io = File.new(__FILE__) - io.define_singleton_method(:foo) { "old" } - sclass1 = sclass.call(io) - proxy.call(io).should == "old" - - # IO#reopen is the only method which can replace an object's singleton class - io2 = File.new(__FILE__) - io.reopen(io2) - io.define_singleton_method(:foo) { "new" } - sclass2 = sclass.call(io) - sclass2.should_not.equal?(sclass1) - proxy.call(io).should == "new" - ensure - io2.close - io.close - end + -> { :foo.singleton_class }.should raise_error(TypeError) end end diff --git a/spec/ruby/core/kernel/sleep_spec.rb b/spec/ruby/core/kernel/sleep_spec.rb index 0570629723..32da6344c1 100644 --- a/spec/ruby/core/kernel/sleep_spec.rb +++ b/spec/ruby/core/kernel/sleep_spec.rb @@ -1,4 +1,5 @@ require_relative '../../spec_helper' +require_relative 'fixtures/classes' describe "Kernel#sleep" do it "is a private method" do @@ -32,6 +33,10 @@ describe "Kernel#sleep" do -> { sleep(-1) }.should raise_error(ArgumentError) end + it "raises a TypeError when passed nil" do + -> { sleep(nil) }.should raise_error(TypeError) + end + it "raises a TypeError when passed a String" do -> { sleep('2') }.should raise_error(TypeError) end @@ -50,29 +55,6 @@ describe "Kernel#sleep" do t.wakeup t.value.should == 5 end - - ruby_version_is ""..."3.3" do - it "raises a TypeError when passed nil" do - -> { sleep(nil) }.should raise_error(TypeError) - end - end - - ruby_version_is "3.3" do - it "accepts a nil duration" do - running = false - t = Thread.new do - running = true - sleep(nil) - 5 - end - - Thread.pass until running - Thread.pass while t.status and t.status != "sleep" - - t.wakeup - t.value.should == 5 - end - end end describe "Kernel.sleep" do diff --git a/spec/ruby/core/kernel/sprintf_spec.rb b/spec/ruby/core/kernel/sprintf_spec.rb index 9ef7f86f16..7adf71be76 100644 --- a/spec/ruby/core/kernel/sprintf_spec.rb +++ b/spec/ruby/core/kernel/sprintf_spec.rb @@ -3,14 +3,6 @@ require_relative 'fixtures/classes' require_relative 'shared/sprintf' require_relative 'shared/sprintf_encoding' -describe :kernel_sprintf_to_str, shared: true do - it "calls #to_str to convert the format object to a String" do - obj = mock('format string') - obj.should_receive(:to_str).and_return("to_str: %i") - @method.call(obj, 42).should == "to_str: 42" - end -end - describe "Kernel#sprintf" do it_behaves_like :kernel_sprintf, -> format, *args { sprintf(format, *args) @@ -19,10 +11,6 @@ describe "Kernel#sprintf" do it_behaves_like :kernel_sprintf_encoding, -> format, *args { sprintf(format, *args) } - - it_behaves_like :kernel_sprintf_to_str, -> format, *args { - sprintf(format, *args) - } end describe "Kernel.sprintf" do @@ -33,8 +21,4 @@ describe "Kernel.sprintf" do it_behaves_like :kernel_sprintf_encoding, -> format, *args { Kernel.sprintf(format, *args) } - - it_behaves_like :kernel_sprintf_to_str, -> format, *args { - Kernel.sprintf(format, *args) - } end diff --git a/spec/ruby/core/kernel/taint_spec.rb b/spec/ruby/core/kernel/taint_spec.rb index 0c16b1dbbf..8ba9869af2 100644 --- a/spec/ruby/core/kernel/taint_spec.rb +++ b/spec/ruby/core/kernel/taint_spec.rb @@ -2,15 +2,56 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Kernel#taint" do - ruby_version_is ""..."3.2" do - it "is a no-op" do - suppress_warning do - o = Object.new - o.taint - o.should_not.tainted? + 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 + it "is a no-op" do + o = Object.new + o.taint + o.should_not.tainted? + end + it "warns in verbose mode" do -> { obj = mock("tainted") @@ -18,10 +59,4 @@ describe "Kernel#taint" do }.should complain(/Object#taint is deprecated and will be removed in Ruby 3.2/, verbose: true) end end - - ruby_version_is "3.2" do - it "has been removed" do - Object.new.should_not.respond_to?(:taint) - end - end end diff --git a/spec/ruby/core/kernel/tainted_spec.rb b/spec/ruby/core/kernel/tainted_spec.rb index fcae433069..022938bfc1 100644 --- a/spec/ruby/core/kernel/tainted_spec.rb +++ b/spec/ruby/core/kernel/tainted_spec.rb @@ -2,15 +2,23 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Kernel#tainted?" do - ruby_version_is ""..."3.2" 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 it "is a no-op" do - suppress_warning do - o = mock('o') - p = mock('p') - p.taint - o.should_not.tainted? - p.should_not.tainted? - end + o = mock('o') + p = mock('p') + p.taint + o.should_not.tainted? + p.should_not.tainted? end it "warns in verbose mode" do @@ -20,10 +28,4 @@ describe "Kernel#tainted?" do }.should complain(/Object#tainted\? is deprecated and will be removed in Ruby 3.2/, verbose: true) end end - - ruby_version_is "3.2" do - it "has been removed" do - Object.new.should_not.respond_to?(:tainted?) - end - end end diff --git a/spec/ruby/core/kernel/test_spec.rb b/spec/ruby/core/kernel/test_spec.rb index d26dc06361..abb365aed2 100644 --- a/spec/ruby/core/kernel/test_spec.rb +++ b/spec/ruby/core/kernel/test_spec.rb @@ -3,8 +3,8 @@ require_relative 'fixtures/classes' describe "Kernel#test" do before :all do - @file = __dir__ + '/fixtures/classes.rb' - @dir = __dir__ + '/fixtures' + @file = File.dirname(__FILE__) + '/fixtures/classes.rb' + @dir = File.dirname(__FILE__) + '/fixtures' end it "is a private method" do diff --git a/spec/ruby/core/kernel/to_s_spec.rb b/spec/ruby/core/kernel/to_s_spec.rb index ea4b00151e..64b40f46e5 100644 --- a/spec/ruby/core/kernel/to_s_spec.rb +++ b/spec/ruby/core/kernel/to_s_spec.rb @@ -5,4 +5,14 @@ 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 db6f17e0fb..399983f74d 100644 --- a/spec/ruby/core/kernel/trust_spec.rb +++ b/spec/ruby/core/kernel/trust_spec.rb @@ -2,14 +2,35 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Kernel#trust" do - ruby_version_is ""..."3.2" 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 it "is a no-op" do - suppress_warning do - o = Object.new.untrust - o.should_not.untrusted? - o.trust - o.should_not.untrusted? - end + o = Object.new.untrust + o.should_not.untrusted? + o.trust + o.should_not.untrusted? end it "warns in verbose mode" do @@ -19,10 +40,4 @@ describe "Kernel#trust" do }.should complain(/Object#trust is deprecated and will be removed in Ruby 3.2/, verbose: true) end end - - ruby_version_is "3.2" do - it "has been removed" do - Object.new.should_not.respond_to?(:trust) - end - end end diff --git a/spec/ruby/core/kernel/untaint_spec.rb b/spec/ruby/core/kernel/untaint_spec.rb index 26b2aabbe9..44d87da5d5 100644 --- a/spec/ruby/core/kernel/untaint_spec.rb +++ b/spec/ruby/core/kernel/untaint_spec.rb @@ -2,14 +2,35 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Kernel#untaint" do - ruby_version_is ""..."3.2" 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 it "is a no-op" do - suppress_warning do - o = Object.new.taint - o.should_not.tainted? - o.untaint - o.should_not.tainted? - end + o = Object.new.taint + o.should_not.tainted? + o.untaint + o.should_not.tainted? end it "warns in verbose mode" do @@ -19,10 +40,4 @@ describe "Kernel#untaint" do }.should complain(/Object#untaint is deprecated and will be removed in Ruby 3.2/, verbose: true) end end - - ruby_version_is "3.2" do - it "has been removed" do - Object.new.should_not.respond_to?(:untaint) - end - end end diff --git a/spec/ruby/core/kernel/untrust_spec.rb b/spec/ruby/core/kernel/untrust_spec.rb index 5310cd8eb4..aff0fec57b 100644 --- a/spec/ruby/core/kernel/untrust_spec.rb +++ b/spec/ruby/core/kernel/untrust_spec.rb @@ -2,13 +2,34 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Kernel#untrust" do - ruby_version_is ""..."3.2" 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 it "is a no-op" do - suppress_warning do - o = Object.new - o.untrust - o.should_not.untrusted? - end + o = Object.new + o.untrust + o.should_not.untrusted? end it "warns in verbose mode" do @@ -18,10 +39,4 @@ describe "Kernel#untrust" do }.should complain(/Object#untrust is deprecated and will be removed in Ruby 3.2/, verbose: true) end end - - ruby_version_is "3.2" do - it "has been removed" do - Object.new.should_not.respond_to?(:untrust) - end - end end diff --git a/spec/ruby/core/kernel/untrusted_spec.rb b/spec/ruby/core/kernel/untrusted_spec.rb index ea36d6c98c..5347c90093 100644 --- a/spec/ruby/core/kernel/untrusted_spec.rb +++ b/spec/ruby/core/kernel/untrusted_spec.rb @@ -2,14 +2,38 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Kernel#untrusted?" do - ruby_version_is ""..."3.2" 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 it "is a no-op" do - suppress_warning do - o = mock('o') - o.should_not.untrusted? - o.untrust - o.should_not.untrusted? - end + o = mock('o') + o.should_not.untrusted? + o.untrust + o.should_not.untrusted? end it "warns in verbose mode" do @@ -19,10 +43,4 @@ describe "Kernel#untrusted?" do }.should complain(/Object#untrusted\? is deprecated and will be removed in Ruby 3.2/, verbose: true) end end - - ruby_version_is "3.2" do - it "has been removed" do - Object.new.should_not.respond_to?(:untrusted?) - end - end end diff --git a/spec/ruby/core/kernel/warn_spec.rb b/spec/ruby/core/kernel/warn_spec.rb index 00164ad90b..7df6fa72d1 100644 --- a/spec/ruby/core/kernel/warn_spec.rb +++ b/spec/ruby/core/kernel/warn_spec.rb @@ -128,34 +128,36 @@ describe "Kernel#warn" do end end - it "accepts :category keyword with a symbol" do - -> { - $VERBOSE = true - warn("message", category: :deprecated) - }.should output(nil, "message\n") - end + ruby_version_is "3.0" do + it "accepts :category keyword with a symbol" do + -> { + $VERBOSE = true + warn("message", category: :deprecated) + }.should output(nil, "message\n") + end - it "accepts :category keyword with nil" do - -> { - $VERBOSE = true - warn("message", category: nil) - }.should output(nil, "message\n") - end + it "accepts :category keyword with nil" do + -> { + $VERBOSE = true + warn("message", category: nil) + }.should output(nil, "message\n") + end - it "accepts :category keyword with object convertible to symbol" do - o = Object.new - def o.to_sym; :deprecated; end - -> { - $VERBOSE = true - warn("message", category: o) - }.should output(nil, "message\n") - end + it "accepts :category keyword with object convertible to symbol" do + o = Object.new + def o.to_sym; :deprecated; end + -> { + $VERBOSE = true + warn("message", category: o) + }.should output(nil, "message\n") + end - it "raises if :category keyword is not nil and not convertible to symbol" do - -> { - $VERBOSE = true - warn("message", category: Object.new) - }.should raise_error(TypeError) + it "raises if :category keyword is not nil and not convertible to symbol" do + -> { + $VERBOSE = true + warn("message", category: Object.new) + }.should raise_error(TypeError) + end end it "converts first arg using to_s" do @@ -210,52 +212,67 @@ describe "Kernel#warn" do -> { warn('foo', **h) }.should complain("foo\n") end - it "calls Warning.warn without keyword arguments if Warning.warn does not accept keyword arguments" do - verbose = $VERBOSE - $VERBOSE = false - class << Warning - alias_method :_warn, :warn - def warn(message) - ScratchPad.record(message) + ruby_version_is '3.0' do + it "calls Warning.warn without keyword arguments if Warning.warn does not accept keyword arguments" do + verbose = $VERBOSE + $VERBOSE = false + class << Warning + alias_method :_warn, :warn + def warn(message) + ScratchPad.record(message) + end end - end - begin - ScratchPad.clear - Kernel.warn("Chunky bacon!") - ScratchPad.recorded.should == "Chunky bacon!\n" + begin + ScratchPad.clear + Kernel.warn("Chunky bacon!") + ScratchPad.recorded.should == "Chunky bacon!\n" + + Kernel.warn("Deprecated bacon!", category: :deprecated) + ScratchPad.recorded.should == "Deprecated bacon!\n" + ensure + class << Warning + remove_method :warn + alias_method :warn, :_warn + remove_method :_warn + end + $VERBOSE = verbose + end + end - Kernel.warn("Deprecated bacon!", category: :deprecated) - ScratchPad.recorded.should == "Deprecated bacon!\n" - ensure - class << Warning - remove_method :warn - alias_method :warn, :_warn - remove_method :_warn + it "calls Warning.warn with category: nil if Warning.warn accepts keyword arguments" do + Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil) + verbose = $VERBOSE + $VERBOSE = false + begin + Kernel.warn("Chunky bacon!") + ensure + $VERBOSE = verbose end - $VERBOSE = verbose end - end - it "calls Warning.warn with category: nil if Warning.warn accepts keyword arguments" do - Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil) - verbose = $VERBOSE - $VERBOSE = false - begin - Kernel.warn("Chunky bacon!") - ensure - $VERBOSE = verbose + it "calls Warning.warn with given category keyword converted to a symbol" do + Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated) + verbose = $VERBOSE + $VERBOSE = false + begin + Kernel.warn("Chunky bacon!", category: 'deprecated') + ensure + $VERBOSE = verbose + end end end - it "calls Warning.warn with given category keyword converted to a symbol" do - Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated) - verbose = $VERBOSE - $VERBOSE = false - begin - Kernel.warn("Chunky bacon!", category: 'deprecated') - ensure - $VERBOSE = verbose + ruby_version_is ''...'3.0' do + it "calls Warning.warn with no keyword arguments" do + Warning.should_receive(:warn).with("Chunky bacon!\n") + verbose = $VERBOSE + $VERBOSE = false + begin + Kernel.warn("Chunky bacon!") + ensure + $VERBOSE = verbose + end end end diff --git a/spec/ruby/core/main/fixtures/using.rb b/spec/ruby/core/main/fixtures/using.rb deleted file mode 100644 index 30713ef309..0000000000 --- a/spec/ruby/core/main/fixtures/using.rb +++ /dev/null @@ -1 +0,0 @@ -using Module.new diff --git a/spec/ruby/core/main/fixtures/using_in_main.rb b/spec/ruby/core/main/fixtures/using_in_main.rb deleted file mode 100644 index a4a71c89cc..0000000000 --- a/spec/ruby/core/main/fixtures/using_in_main.rb +++ /dev/null @@ -1,5 +0,0 @@ -MAIN = self - -module X - MAIN.send(:using, Module.new) -end diff --git a/spec/ruby/core/main/fixtures/using_in_method.rb b/spec/ruby/core/main/fixtures/using_in_method.rb deleted file mode 100644 index d9ea2e9ef0..0000000000 --- a/spec/ruby/core/main/fixtures/using_in_method.rb +++ /dev/null @@ -1,5 +0,0 @@ -def foo - using Module.new -end - -foo diff --git a/spec/ruby/core/main/private_spec.rb b/spec/ruby/core/main/private_spec.rb index e8c1f3f44c..cac0645b40 100644 --- a/spec/ruby/core/main/private_spec.rb +++ b/spec/ruby/core/main/private_spec.rb @@ -22,11 +22,13 @@ describe "main#private" do end end - context "when single argument is passed and is an array" do - it "sets the visibility of the given methods to private" do - eval "private [:main_public_method, :main_public_method2]", TOPLEVEL_BINDING - Object.should have_private_method(:main_public_method) - Object.should have_private_method(:main_public_method2) + ruby_version_is "3.0" do + context "when single argument is passed and is an array" do + it "sets the visibility of the given methods to private" do + eval "private [:main_public_method, :main_public_method2]", TOPLEVEL_BINDING + Object.should have_private_method(:main_public_method) + Object.should have_private_method(:main_public_method2) + end end end diff --git a/spec/ruby/core/main/public_spec.rb b/spec/ruby/core/main/public_spec.rb index 31baad4583..91f045dbab 100644 --- a/spec/ruby/core/main/public_spec.rb +++ b/spec/ruby/core/main/public_spec.rb @@ -22,11 +22,13 @@ describe "main#public" do end end - context "when single argument is passed and is an array" do - it "sets the visibility of the given methods to public" do - eval "public [:main_private_method, :main_private_method2]", TOPLEVEL_BINDING - Object.should_not have_private_method(:main_private_method) - Object.should_not have_private_method(:main_private_method2) + ruby_version_is "3.0" do + context "when single argument is passed and is an array" do + it "sets the visibility of the given methods to public" do + eval "public [:main_private_method, :main_private_method2]", TOPLEVEL_BINDING + Object.should_not have_private_method(:main_private_method) + Object.should_not have_private_method(:main_private_method2) + end end end diff --git a/spec/ruby/core/main/ruby2_keywords_spec.rb b/spec/ruby/core/main/ruby2_keywords_spec.rb index 27ceae3253..0999cddeed 100644 --- a/spec/ruby/core/main/ruby2_keywords_spec.rb +++ b/spec/ruby/core/main/ruby2_keywords_spec.rb @@ -1,9 +1,11 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -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) +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 end end diff --git a/spec/ruby/core/main/using_spec.rb b/spec/ruby/core/main/using_spec.rb index 8a23970c4b..f9f709f7dc 100644 --- a/spec/ruby/core/main/using_spec.rb +++ b/spec/ruby/core/main/using_spec.rb @@ -129,24 +129,4 @@ describe "main.using" do x.call_bar(cls2.new).should == 'bar' end - - it "raises error when called from method in wrapped script" do - -> do - load File.expand_path('../fixtures/using_in_method.rb', __FILE__), true - end.should raise_error(RuntimeError) - end - - it "raises error when called on toplevel from module" do - -> do - load File.expand_path('../fixtures/using_in_main.rb', __FILE__), true - end.should raise_error(RuntimeError) - end - - ruby_version_is "3.2" do - it "does not raise error when wrapped with module" do - -> do - load File.expand_path('../fixtures/using.rb', __FILE__), true - end.should_not raise_error - end - end end diff --git a/spec/ruby/core/marshal/dump_spec.rb b/spec/ruby/core/marshal/dump_spec.rb index eaf238bbd9..a54a4c6735 100644 --- a/spec/ruby/core/marshal/dump_spec.rb +++ b/spec/ruby/core/marshal/dump_spec.rb @@ -1,6 +1,5 @@ # -*- encoding: binary -*- require_relative '../../spec_helper' -require_relative 'fixtures/classes' require_relative 'fixtures/marshal_data' describe "Marshal.dump" do @@ -104,76 +103,25 @@ describe "Marshal.dump" do UserMarshal.should_not_receive(:name) Marshal.dump(UserMarshal.new) end - - it "raises TypeError if an Object is an instance of an anonymous class" do - -> { Marshal.dump(Class.new(UserMarshal).new) }.should raise_error(TypeError, /can't dump anonymous class/) - end end describe "with an object responding to #_dump" do - it "dumps the String returned by #_dump" do + it "dumps the object returned by #marshal_dump" do Marshal.dump(UserDefined.new).should == "\004\bu:\020UserDefined\022\004\b[\a:\nstuff;\000" end - it "dumps the String in non US-ASCII and non UTF-8 encoding" do - object = UserDefinedString.new("a".encode("windows-1251")) - Marshal.dump(object).should == "\x04\bIu:\x16UserDefinedString\x06a\x06:\rencoding\"\x11Windows-1251" - end - - it "dumps the String in multibyte encoding" do - object = UserDefinedString.new("a".encode("utf-32le")) - Marshal.dump(object).should == "\x04\bIu:\x16UserDefinedString\ta\x00\x00\x00\x06:\rencoding\"\rUTF-32LE" - end - - it "ignores overridden name method" do - obj = MarshalSpec::UserDefinedWithOverriddenName.new - Marshal.dump(obj).should == "\x04\bu:/MarshalSpec::UserDefinedWithOverriddenName\x12\x04\b[\a:\nstuff;\x00" - end - it "raises a TypeError if _dump returns a non-string" do m = mock("marshaled") m.should_receive(:_dump).and_return(0) -> { Marshal.dump(m) }.should raise_error(TypeError) end - it "raises TypeError if an Object is an instance of an anonymous class" do - -> { Marshal.dump(Class.new(UserDefined).new) }.should raise_error(TypeError, /can't dump anonymous class/) - end - it "favors marshal_dump over _dump" do m = mock("marshaled") m.should_receive(:marshal_dump).and_return(0) m.should_not_receive(:_dump) Marshal.dump(m) end - - it "indexes instance variables of a String returned by #_dump at first and then indexes the object itself" do - class MarshalSpec::M1::A - def _dump(level) - s = "<dump>" - s.instance_variable_set(:@foo, "bar") - s - end - end - - a = MarshalSpec::M1::A.new - - # 0-based index of the object a = 2, that is encoded as \x07 and printed as "\a" character. - # Objects are serialized in the following order: Array, a, "bar". - # But they are indexed in different order: Array (index=0), "bar" (index=1), a (index=2) - # So the second occurenc of the object a is encoded as an index 2. - reference = "@\a" - Marshal.dump([a, a]).should == "\x04\b[\aIu:\x17MarshalSpec::M1::A\v<dump>\x06:\t@foo\"\bbar#{reference}" - end - - describe "Core library classes with #_dump returning a String with instance variables" do - it "indexes instance variables and then a Time object itself" do - t = Time.utc(2022) - reference = "@\a" - - Marshal.dump([t, t]).should == "\x04\b[\aIu:\tTime\r \x80\x1E\xC0\x00\x00\x00\x00\x06:\tzoneI\"\bUTC\x06:\x06EF#{reference}" - end - end end describe "with a Class" do @@ -189,17 +137,8 @@ describe "Marshal.dump" do Marshal.dump(UserDefined::Nested).should == "\004\bc\030UserDefined::Nested" end - it "ignores overridden name method" do - Marshal.dump(MarshalSpec::ClassWithOverriddenName).should == "\x04\bc)MarshalSpec::ClassWithOverriddenName" - end - - it "dumps a class with multibyte characters in name" do - source_object = eval("MarshalSpec::MultibyteぁあぃいClass".force_encoding(Encoding::UTF_8)) - Marshal.dump(source_object).should == "\x04\bc,MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Class" - end - it "raises TypeError with an anonymous Class" do - -> { Marshal.dump(Class.new) }.should raise_error(TypeError, /can't dump anonymous class/) + -> { Marshal.dump(Class.new) }.should raise_error(TypeError) end it "raises TypeError with a singleton Class" do @@ -212,17 +151,8 @@ describe "Marshal.dump" do Marshal.dump(Marshal).should == "\004\bm\fMarshal" end - it "ignores overridden name method" do - Marshal.dump(MarshalSpec::ModuleWithOverriddenName).should == "\x04\bc*MarshalSpec::ModuleWithOverriddenName" - end - - it "dumps a module with multibyte characters in name" do - source_object = eval("MarshalSpec::MultibyteけげこごModule".force_encoding(Encoding::UTF_8)) - Marshal.dump(source_object).should == "\x04\bm-MarshalSpec::Multibyte\xE3\x81\x91\xE3\x81\x92\xE3\x81\x93\xE3\x81\x94Module" - end - it "raises TypeError with an anonymous Module" do - -> { Marshal.dump(Module.new) }.should raise_error(TypeError, /can't dump anonymous module/) + -> { Marshal.dump(Module.new) }.should raise_error(TypeError) end end @@ -255,32 +185,6 @@ describe "Marshal.dump" do [Marshal, -2**64, "\004\bl-\n\000\000\000\000\000\000\000\000\001\000"], ].should be_computed_by(:dump) end - - it "increases the object links counter" do - obj = Object.new - object_1_link = "\x06" # representing of (0-based) index=1 (by adding 5 for small Integers) - object_2_link = "\x07" # representing of index=2 - - # objects: Array, Object, Object - Marshal.dump([obj, obj]).should == "\x04\b[\ao:\vObject\x00@#{object_1_link}" - - # objects: Array, Bignum, Object, Object - Marshal.dump([2**64, obj, obj]).should == "\x04\b[\bl+\n\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00o:\vObject\x00@#{object_2_link}" - Marshal.dump([2**48, obj, obj]).should == "\x04\b[\bl+\t\x00\x00\x00\x00\x00\x00\x01\x00o:\vObject\x00@#{object_2_link}" - Marshal.dump([2**32, obj, obj]).should == "\x04\b[\bl+\b\x00\x00\x00\x00\x01\x00o:\vObject\x00@#{object_2_link}" - end - end - - describe "with a Rational" do - it "dumps a Rational" do - Marshal.dump(Rational(2, 3)).should == "\x04\bU:\rRational[\ai\ai\b" - end - end - - describe "with a Complex" do - it "dumps a Complex" do - Marshal.dump(Complex(2, 3)).should == "\x04\bU:\fComplex[\ai\ai\b" - end end describe "with a String" do @@ -308,11 +212,6 @@ describe "Marshal.dump" do Marshal.dump(UserString.new.extend(Meths).force_encoding("binary")).should == "\004\be:\nMethsC:\017UserString\"\000" end - it "ignores overridden name method when dumps a String subclass" do - obj = MarshalSpec::StringWithOverriddenName.new - Marshal.dump(obj).should == "\x04\bC:*MarshalSpec::StringWithOverriddenName\"\x00" - end - it "dumps a String with instance variables" do str = "" str.instance_variable_set("@foo", "bar") @@ -368,42 +267,14 @@ describe "Marshal.dump" do Marshal.dump(o).should == "\x04\b/\x00\x10" end - it "dumps an ascii-compatible Regexp" do - o = Regexp.new("a".encode("us-ascii"), Regexp::FIXEDENCODING) - Marshal.dump(o).should == "\x04\bI/\x06a\x10\x06:\x06EF" - - o = Regexp.new("a".encode("us-ascii")) - Marshal.dump(o).should == "\x04\bI/\x06a\x00\x06:\x06EF" - - o = Regexp.new("a".encode("windows-1251"), Regexp::FIXEDENCODING) - Marshal.dump(o).should == "\x04\bI/\x06a\x10\x06:\rencoding\"\x11Windows-1251" - - o = Regexp.new("a".encode("windows-1251")) - Marshal.dump(o).should == "\x04\bI/\x06a\x00\x06:\x06EF" - end - it "dumps a UTF-8 Regexp" do o = Regexp.new("".force_encoding("utf-8"), Regexp::FIXEDENCODING) Marshal.dump(o).should == "\x04\bI/\x00\x10\x06:\x06ET" - - o = Regexp.new("a".force_encoding("utf-8"), Regexp::FIXEDENCODING) - Marshal.dump(o).should == "\x04\bI/\x06a\x10\x06:\x06ET" - - o = Regexp.new("\u3042".force_encoding("utf-8"), Regexp::FIXEDENCODING) - Marshal.dump(o).should == "\x04\bI/\b\xE3\x81\x82\x10\x06:\x06ET" end it "dumps a Regexp in another encoding" do o = Regexp.new("".force_encoding("utf-16le"), Regexp::FIXEDENCODING) Marshal.dump(o).should == "\x04\bI/\x00\x10\x06:\rencoding\"\rUTF-16LE" - - o = Regexp.new("a".encode("utf-16le"), Regexp::FIXEDENCODING) - Marshal.dump(o).should == "\x04\bI/\aa\x00\x10\x06:\rencoding\"\rUTF-16LE" - end - - it "ignores overridden name method when dumps a Regexp subclass" do - obj = MarshalSpec::RegexpWithOverriddenName.new("") - Marshal.dump(obj).should == "\x04\bIC:*MarshalSpec::RegexpWithOverriddenName/\x00\x00\x06:\x06EF" end end @@ -435,11 +306,6 @@ describe "Marshal.dump" do it "dumps an extended Array" do Marshal.dump([].extend(Meths)).should == "\004\be:\nMeths[\000" end - - it "ignores overridden name method when dumps an Array subclass" do - obj = MarshalSpec::ArrayWithOverriddenName.new - Marshal.dump(obj).should == "\x04\bC:)MarshalSpec::ArrayWithOverriddenName[\x00" - end end describe "with a Hash" do @@ -447,10 +313,6 @@ describe "Marshal.dump" do Marshal.dump({}).should == "\004\b{\000" end - it "dumps a non-empty Hash" do - Marshal.dump({a: 1}).should == "\x04\b{\x06:\x06ai\x06" - end - it "dumps a Hash subclass" do Marshal.dump(UserHash.new).should == "\004\bC:\rUserHash{\000" end @@ -459,24 +321,8 @@ describe "Marshal.dump" do Marshal.dump(Hash.new(1)).should == "\004\b}\000i\006" end - ruby_version_is "3.1" do - it "dumps a Hash with compare_by_identity" do - h = {} - h.compare_by_identity - - Marshal.dump(h).should == "\004\bC:\tHash{\x00" - end - - it "dumps a Hash subclass with compare_by_identity" do - h = UserHash.new - h.compare_by_identity - - Marshal.dump(h).should == "\x04\bC:\rUserHashC:\tHash{\x00" - end - end - it "raises a TypeError with hash having default proc" do - -> { Marshal.dump(Hash.new {}) }.should raise_error(TypeError, "can't dump hash with default proc") + -> { Marshal.dump(Hash.new {}) }.should raise_error(TypeError) end it "dumps a Hash with instance variables" do @@ -492,11 +338,6 @@ describe "Marshal.dump" do it "dumps an Hash subclass with a parameter to initialize" do Marshal.dump(UserHashInitParams.new(1)).should == "\004\bIC:\027UserHashInitParams{\000\006:\a@ai\006" end - - it "ignores overridden name method when dumps a Hash subclass" do - obj = MarshalSpec::HashWithOverriddenName.new - Marshal.dump(obj).should == "\x04\bC:(MarshalSpec::HashWithOverriddenName{\x00" - end end describe "with a Struct" do @@ -525,15 +366,6 @@ describe "Marshal.dump" do Marshal.dump(obj).should == "\004\be:\nMethsS:\025Struct::Extended\a:\006a[\a;\a\"\ahi:\006b[\a;\000@\a" Struct.send(:remove_const, :Extended) end - - it "ignores overridden name method" do - obj = MarshalSpec::StructWithOverriddenName.new("member") - Marshal.dump(obj).should == "\x04\bS:*MarshalSpec::StructWithOverriddenName\x06:\x06a\"\vmember" - end - - it "raises TypeError with an anonymous Struct" do - -> { Marshal.dump(Struct.new(:a).new(1)) }.should raise_error(TypeError, /can't dump anonymous class/) - end end describe "with an Object" do @@ -565,18 +397,13 @@ describe "Marshal.dump" do Marshal.dump(obj).should == "\004\bo:\x0BObject\x00" end - it "dumps an Object if it has a singleton class but no singleton methods and no singleton instance variables" do + it "dumps an Object if it has a singleton class but no singleton methods" do obj = Object.new obj.singleton_class Marshal.dump(obj).should == "\004\bo:\x0BObject\x00" end - it "ignores overridden name method" do - obj = MarshalSpec::ClassWithOverriddenName.new - Marshal.dump(obj).should == "\x04\bo:)MarshalSpec::ClassWithOverriddenName\x00" - end - - it "raises TypeError if an Object has a singleton class and singleton methods" do + it "raises if an Object has a singleton class and singleton methods" do obj = Object.new def obj.foo; end -> { @@ -584,45 +411,10 @@ describe "Marshal.dump" do }.should raise_error(TypeError, "singleton can't be dumped") end - it "raises TypeError if an Object has a singleton class and singleton instance variables" do - obj = Object.new - class << obj - @v = 1 - end - - -> { - Marshal.dump(obj) - }.should raise_error(TypeError, "singleton can't be dumped") - end - - it "raises TypeError if an Object is an instance of an anonymous class" do - anonymous_class = Class.new - obj = anonymous_class.new - - -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/) - end - - it "raises TypeError if an Object extends an anonymous module" do - anonymous_module = Module.new - obj = Object.new - obj.extend(anonymous_module) - - -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/) - end - it "dumps a BasicObject subclass if it defines respond_to?" do obj = MarshalSpec::BasicObjectSubWithRespondToFalse.new Marshal.dump(obj).should == "\x04\bo:2MarshalSpec::BasicObjectSubWithRespondToFalse\x00" end - - it "dumps without marshaling any attached finalizer" do - obj = Object.new - finalizer = Object.new - def finalizer.noop(_) - end - ObjectSpace.define_finalizer(obj, finalizer.method(:noop)) - Marshal.load(Marshal.dump(obj)).class.should == Object - end end describe "with a Range" do @@ -638,8 +430,15 @@ describe "Marshal.dump" do load.should == (1...2) end - it "raises TypeError with an anonymous Range subclass" do - -> { Marshal.dump(Class.new(Range).new(1, 2)) }.should raise_error(TypeError, /can't dump anonymous class/) + ruby_version_is ""..."3.0" do + it "dumps a Range with extra instance variables" do + range = (1...3) + range.instance_variable_set :@foo, 42 + dump = Marshal.dump(range) + load = Marshal.load(dump) + load.should == range + load.instance_variable_get(:@foo).should == 42 + end end end @@ -678,20 +477,6 @@ describe "Marshal.dump" do zone = ":\tzoneI\"\bUTC\x06:\x06EF" # Last is 'F' (US-ASCII) dump.should == "\x04\bIu:\tTime\r#{@utc_dump}\x06#{zone}" end - - it "ignores overridden name method" do - obj = MarshalSpec::TimeWithOverriddenName.new - Marshal.dump(obj).should include("MarshalSpec::TimeWithOverriddenName") - end - - it "dumps a Time subclass with multibyte characters in name" do - source_object = eval("MarshalSpec::MultibyteぁあぃいTime".force_encoding(Encoding::UTF_8)) - Marshal.dump(source_object).should == "\x04\bc+MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Time" - end - - it "raises TypeError with an anonymous Time subclass" do - -> { Marshal.dump(Class.new(Time).now) }.should raise_error(TypeError) - end end describe "with an Exception" do @@ -732,23 +517,6 @@ describe "Marshal.dump" do reloaded.cause.should be_an_instance_of(StandardError) reloaded.cause.message.should == "the cause" end - - # NoMethodError uses an exception formatter on TruffleRuby and computes a message lazily - it "dumps the message for the raised NoMethodError exception" do - begin - "".foo - rescue => e - end - - Marshal.dump(e).should =~ /undefined method `foo' for ("":String|an instance of String)/ - end - - it "raises TypeError if an Object is an instance of an anonymous class" do - anonymous_class = Class.new(Exception) - obj = anonymous_class.new - - -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/) - end end it "dumps subsequent appearances of a symbol as a link" do @@ -781,6 +549,7 @@ describe "Marshal.dump" do end describe "when passed an IO" do + it "writes the serialized data to the IO-Object" do (obj = mock('test')).should_receive(:write).at_least(1) Marshal.dump("test", obj) @@ -803,6 +572,8 @@ describe "Marshal.dump" do obj.should_receive(:binmode).at_least(1) Marshal.dump("test", obj) end + + end describe "when passed a StringIO" do @@ -833,4 +604,30 @@ 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/fixtures/classes.rb b/spec/ruby/core/marshal/fixtures/classes.rb deleted file mode 100644 index 7c81c64927..0000000000 --- a/spec/ruby/core/marshal/fixtures/classes.rb +++ /dev/null @@ -1,4 +0,0 @@ -module MarshalSpec - # empty modules - module M1 end -end diff --git a/spec/ruby/core/marshal/fixtures/marshal_data.rb b/spec/ruby/core/marshal/fixtures/marshal_data.rb index 680cb08ac7..9373ef7ba8 100644 --- a/spec/ruby/core/marshal/fixtures/marshal_data.rb +++ b/spec/ruby/core/marshal/fixtures/marshal_data.rb @@ -78,22 +78,6 @@ class UserDefinedImmediate end end -class UserDefinedString - attr_reader :string - - def initialize(string) - @string = string - end - - def _dump(depth) - @string - end - - def self._load(data) - new(data) - end -end - class UserPreviouslyDefinedWithInitializedIvar attr_accessor :field1, :field2 end @@ -183,17 +167,12 @@ module MarshalSpec end end - StructToDump = Struct.new(:a, :b) - class BasicObjectSubWithRespondToFalse < BasicObject def respond_to?(method_name, include_all=false) false end end - module ModuleToExtendBy - end - def self.random_data randomizer = Random.new(42) 1000.times{randomizer.rand} # Make sure we exhaust his first state of 624 random words @@ -213,81 +192,6 @@ module MarshalSpec set_swapped_class(nil) end - class ClassWithOverriddenName - def self.name - "Foo" - end - end - - class ModuleWithOverriddenName - def self.name - "Foo" - end - end - - class TimeWithOverriddenName < Time - def self.name - "Foo" - end - end - - class StructWithOverriddenName < Struct.new(:a) - def self.name - "Foo" - end - end - - class UserDefinedWithOverriddenName < UserDefined - def self.name - "Foo" - end - end - - class StringWithOverriddenName < String - def self.name - "Foo" - end - end - - class ArrayWithOverriddenName < Array - def self.name - "Foo" - end - end - - class HashWithOverriddenName < Hash - def self.name - "Foo" - end - end - - class RegexpWithOverriddenName < Regexp - def self.name - "Foo" - end - end - - module_eval(<<~ruby.force_encoding(Encoding::UTF_8)) - class MultibyteぁあぃいClass - end - - module MultibyteけげこごModule - end - - class MultibyteぁあぃいTime < Time - end - ruby - - class ObjectWithFreezeRaisingException < Object - def freeze - raise - end - end - - class ObjectWithoutFreeze < Object - undef freeze - end - DATA = { "nil" => [nil, "\004\b0"], "1..2" => [(1..2), diff --git a/spec/ruby/core/marshal/shared/load.rb b/spec/ruby/core/marshal/shared/load.rb index b70fb7a974..0a940c9e65 100644 --- a/spec/ruby/core/marshal/shared/load.rb +++ b/spec/ruby/core/marshal/shared/load.rb @@ -8,11 +8,7 @@ describe :marshal_load, shared: true do it "raises an ArgumentError when the dumped data is truncated" do obj = {first: 1, second: 2, third: 3} - -> { Marshal.send(@method, Marshal.dump(obj)[0, 5]) }.should raise_error(ArgumentError, "marshal data too short") - end - - it "raises an ArgumentError when the argument is empty String" do - -> { Marshal.send(@method, "") }.should raise_error(ArgumentError, "marshal data too short") + -> { Marshal.send(@method, Marshal.dump(obj)[0, 5]) }.should raise_error(ArgumentError) end it "raises an ArgumentError when the dumped class is missing" do @@ -54,132 +50,25 @@ describe :marshal_load, shared: true do regexp.should.frozen? end - it "returns frozen structs" do - struct = Marshal.send(@method, Marshal.dump(MarshalSpec::StructToDump.new(1, 2)), freeze: true) - struct.should == MarshalSpec::StructToDump.new(1, 2) - struct.should.frozen? - end - it "returns frozen objects" do source_object = Object.new + source_object.instance_variable_set(:@foo, "bar") object = Marshal.send(@method, Marshal.dump(source_object), freeze: true) object.should.frozen? - end - - describe "deep freezing" do - it "returns hashes with frozen keys and values" do - key = Object.new - value = Object.new - source_object = {key => value} - - hash = Marshal.send(@method, Marshal.dump(source_object), freeze: true) - hash.size.should == 1 - hash.keys[0].should.frozen? - hash.values[0].should.frozen? - end - - it "returns arrays with frozen elements" do - object = Object.new - source_object = [object] - - array = Marshal.send(@method, Marshal.dump(source_object), freeze: true) - array.size.should == 1 - array[0].should.frozen? - end - - it "returns structs with frozen members" do - object1 = Object.new - object2 = Object.new - source_object = MarshalSpec::StructToDump.new(object1, object2) - - struct = Marshal.send(@method, Marshal.dump(source_object), freeze: true) - struct.a.should.frozen? - struct.b.should.frozen? - end - - it "returns objects with frozen instance variables" do - source_object = Object.new - instance_variable = Object.new - source_object.instance_variable_set(:@a, instance_variable) - - object = Marshal.send(@method, Marshal.dump(source_object), freeze: true) - object.instance_variable_get(:@a).should != nil - object.instance_variable_get(:@a).should.frozen? - end - - it "deduplicates frozen strings" do - source_object = ["foo" + "bar", "foobar"] - object = Marshal.send(@method, Marshal.dump(source_object), freeze: true) - - object[0].should equal(object[1]) - end + object.instance_variable_get(:@foo).should.frozen? end it "does not freeze modules" do - object = Marshal.send(@method, Marshal.dump(Kernel), freeze: true) - object.should_not.frozen? + Marshal.send(@method, Marshal.dump(Kernel), freeze: true) Kernel.should_not.frozen? end it "does not freeze classes" do - object = Marshal.send(@method, Marshal.dump(Object), freeze: true) - object.should_not.frozen? + Marshal.send(@method, Marshal.dump(Object), freeze: true) Object.should_not.frozen? end - ruby_bug "#19427", ""..."3.3" do - it "does freeze extended objects" do - object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", freeze: true) - object.should.frozen? - end - - it "does freeze extended objects with instance variables" do - object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x06:\n@ivarT", freeze: true) - object.should.frozen? - end - end - - ruby_bug "#19427", "3.1"..."3.3" do - it "returns frozen object having #_dump method" do - object = Marshal.send(@method, Marshal.dump(UserDefined.new), freeze: true) - object.should.frozen? - end - - it "returns frozen object responding to #marshal_dump and #marshal_load" do - object = Marshal.send(@method, Marshal.dump(UserMarshal.new), freeze: true) - object.should.frozen? - end - - it "returns frozen object extended by a module" do - object = Object.new - object.extend(MarshalSpec::ModuleToExtendBy) - - object = Marshal.send(@method, Marshal.dump(object), freeze: true) - object.should.frozen? - end - end - - it "does not call freeze method" do - object = MarshalSpec::ObjectWithFreezeRaisingException.new - object = Marshal.send(@method, Marshal.dump(object), freeze: true) - object.should.frozen? - end - - it "returns frozen object even if object does not respond to freeze method" do - object = MarshalSpec::ObjectWithoutFreeze.new - object = Marshal.send(@method, Marshal.dump(object), freeze: true) - object.should.frozen? - end - - it "returns a frozen object when is an instance of String/Array/Regexp/Hash subclass and has instance variables" do - source_object = UserString.new - source_object.instance_variable_set(:@foo, "bar") - - object = Marshal.send(@method, Marshal.dump(source_object), freeze: true) - object.should.frozen? - end - describe "when called with a proc" do it "call the proc with frozen objects" do arr = [] @@ -243,14 +132,6 @@ describe :marshal_load, shared: true do end end - ruby_bug "#19427", ""..."3.3" do - it "call the proc with extended objects" do - objs = [] - obj = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", Proc.new { |o| objs << o; o }) - objs.should == [obj] - end - end - it "returns the value of the proc" do Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4] end @@ -314,19 +195,7 @@ describe :marshal_load, shared: true do marshaled_obj.field2.should be_nil end - it "loads the String in non US-ASCII and non UTF-8 encoding" do - source_object = UserDefinedString.new("a".encode("windows-1251")) - object = Marshal.send(@method, Marshal.dump(source_object)) - object.string.should == "a".encode("windows-1251") - end - - it "loads the String in multibyte encoding" do - source_object = UserDefinedString.new("a".encode("utf-32le")) - object = Marshal.send(@method, Marshal.dump(source_object)) - object.string.should == "a".encode("utf-32le") - end - - describe "that returns an immediate value" do + describe "that return an immediate value" do it "loads an array containing an instance of the object, followed by multiple instances of another object" do str = "string" @@ -437,6 +306,89 @@ 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 @@ -525,38 +477,6 @@ describe :marshal_load, shared: true do unmarshalled.instance_variable_get(:@hash_ivar).should == 'hash ivar' unmarshalled[:key].instance_variable_get(:@string_ivar).should == 'string ivar' end - - ruby_version_is "3.1" do - it "preserves compare_by_identity behaviour" do - h = { a: 1 } - h.compare_by_identity - unmarshalled = Marshal.send(@method, Marshal.dump(h)) - unmarshalled.should.compare_by_identity? - - h = { a: 1 } - unmarshalled = Marshal.send(@method, Marshal.dump(h)) - unmarshalled.should_not.compare_by_identity? - end - - it "preserves compare_by_identity behaviour for a Hash subclass" do - h = UserHash.new({ a: 1 }) - h.compare_by_identity - unmarshalled = Marshal.send(@method, Marshal.dump(h)) - unmarshalled.should.compare_by_identity? - - h = UserHash.new({ a: 1 }) - unmarshalled = Marshal.send(@method, Marshal.dump(h)) - unmarshalled.should_not.compare_by_identity? - end - end - - it "allocates an instance of the proper class when Hash subclass with compare_by_identity behaviour" do - h = UserHash.new({ a: 1 }) - h.compare_by_identity - - unmarshalled = Marshal.send(@method, Marshal.dump(h)) - unmarshalled.should.kind_of?(UserHash) - end end describe "for a Symbol" do @@ -623,14 +543,6 @@ describe :marshal_load, shared: true do value.map(&:encoding).should == [Encoding::UTF_8, Encoding::UTF_8, Encoding::UTF_8] value.should == [*expected, expected[0]] end - - it "raises ArgumentError when end of byte sequence reached before symbol characters end" do - Marshal.dump(:hello).should == "\x04\b:\nhello" - - -> { - Marshal.send(@method, "\x04\b:\nhel") - }.should raise_error(ArgumentError, "marshal data too short") - end end describe "for a String" do @@ -646,12 +558,6 @@ describe :marshal_load, shared: true do Marshal.send(@method, StringIO.new(Marshal.dump(obj))).should == obj end - it "sets binmode if it is loading through StringIO stream" do - io = StringIO.new("\004\b:\vsymbol") - def io.binmode; raise "binmode"; end - -> { Marshal.load(io) }.should raise_error(RuntimeError, "binmode") - end - it "loads a string with an ivar" do str = Marshal.send(@method, "\x04\bI\"\x00\x06:\t@fooI\"\bbar\x06:\x06EF") str.instance_variable_get("@foo").should == "bar" @@ -693,14 +599,6 @@ describe :marshal_load, shared: true do result.encoding.should == Encoding::BINARY result.should == str end - - it "raises ArgumentError when end of byte sequence reached before string characters end" do - Marshal.dump("hello").should == "\x04\b\"\nhello" - - -> { - Marshal.send(@method, "\x04\b\"\nhel") - }.should raise_error(ArgumentError, "marshal data too short") - end end describe "for a Struct" do @@ -835,14 +733,6 @@ describe :marshal_load, shared: true do Marshal.send(@method, "\x04\bo:\tFile\001\001:\001\005@path\"\x10/etc/passwd") end.should raise_error(ArgumentError) end - - it "raises ArgumentError when end of byte sequence reached before class name end" do - Marshal.dump(Object.new).should == "\x04\bo:\vObject\x00" - - -> { - Marshal.send(@method, "\x04\bo:\vObj") - }.should raise_error(ArgumentError, "marshal data too short") - end end describe "for an object responding to #marshal_dump and #marshal_load" do @@ -901,7 +791,7 @@ describe :marshal_load, shared: true do [Meths, MethsMore, Regexp] end - it "loads a Regexp subclass instance variables when it is extended with a module" do + it "loads a extended_user_regexp having ivar" do obj = UserRegexp.new('').extend(Meths) obj.instance_variable_set(:@noise, 'much') @@ -914,7 +804,7 @@ describe :marshal_load, shared: true do [Meths, UserRegexp, Regexp] end - ruby_bug "#19439", ""..."3.3" do + ruby_bug "#19439", ""..."3.1" do it "restore the regexp instance variables" do obj = Regexp.new("hello") obj.instance_variable_set(:@regexp_ivar, [42]) @@ -924,22 +814,6 @@ describe :marshal_load, shared: true do new_obj.instance_variable_get(:@regexp_ivar).should == [42] end end - - it "preserves Regexp encoding" do - source_object = Regexp.new("a".encode("utf-32le")) - regexp = Marshal.send(@method, Marshal.dump(source_object)) - - regexp.encoding.should == Encoding::UTF_32LE - regexp.source.should == "a".encode("utf-32le") - end - - it "raises ArgumentError when end of byte sequence reached before source string end" do - Marshal.dump(/hello world/).should == "\x04\bI/\x10hello world\x00\x06:\x06EF" - - -> { - Marshal.send(@method, "\x04\bI/\x10hel") - }.should raise_error(ArgumentError, "marshal data too short") - end end describe "for a Float" do @@ -961,14 +835,6 @@ describe :marshal_load, shared: true do obj = 1.1867345e+22 Marshal.send(@method, "\004\bf\0361.1867344999999999e+22\000\344@").should == obj end - - it "raises ArgumentError when end of byte sequence reached before float string representation end" do - Marshal.dump(1.3).should == "\x04\bf\b1.3" - - -> { - Marshal.send(@method, "\004\bf\v1") - }.should raise_error(ArgumentError, "marshal data too short") - end end describe "for an Integer" do @@ -1034,17 +900,13 @@ describe :marshal_load, shared: true do describe "for a Rational" do it "loads" do - r = Marshal.send(@method, Marshal.dump(Rational(1, 3))) - r.should == Rational(1, 3) - r.should.frozen? + Marshal.send(@method, Marshal.dump(Rational(1, 3))).should == Rational(1, 3) end end describe "for a Complex" do it "loads" do - c = Marshal.send(@method, Marshal.dump(Complex(4, 3))) - c.should == Complex(4, 3) - c.should.frozen? + Marshal.send(@method, Marshal.dump(Complex(4, 3))).should == Complex(4, 3) end end @@ -1085,47 +947,17 @@ describe :marshal_load, shared: true do t1.should equal t2 end - it "keeps the local zone" do + it "loads the zone" do with_timezone 'AST', 3 do t = Time.local(2012, 1, 1) Marshal.send(@method, Marshal.dump(t)).zone.should == t.zone end end - it "keeps UTC zone" do - t = Time.now.utc - t2 = Marshal.send(@method, Marshal.dump(t)) - t2.should.utc? - end - - it "keeps the zone" do - t = nil - - with_timezone 'AST', 4 do - t = Time.local(2012, 1, 1) - end - - with_timezone 'EET', -2 do - Marshal.send(@method, Marshal.dump(t)).zone.should == 'AST' - end - end - - it "keeps utc offset" do - t = Time.new(2007,11,1,15,25,0, "+09:00") - t2 = Marshal.send(@method, Marshal.dump(t)) - t2.utc_offset.should == 32400 - end - - it "keeps nanoseconds" do + it "loads nanoseconds" do t = Time.now Marshal.send(@method, Marshal.dump(t)).nsec.should == t.nsec end - - it "does not add any additional instance variable" do - t = Time.now - t2 = Marshal.send(@method, Marshal.dump(t)) - t2.instance_variables.should.empty? - end end describe "for nil" do @@ -1158,14 +990,6 @@ describe :marshal_load, shared: true do it "raises ArgumentError if given a nonexistent class" do -> { Marshal.send(@method, "\x04\bc\vStrung") }.should raise_error(ArgumentError) end - - it "raises ArgumentError when end of byte sequence reached before class name end" do - Marshal.dump(String).should == "\x04\bc\vString" - - -> { - Marshal.send(@method, "\x04\bc\vStr") - }.should raise_error(ArgumentError, "marshal data too short") - end end describe "for a Module" do @@ -1180,14 +1004,6 @@ describe :marshal_load, shared: true do it "loads an old module" do Marshal.send(@method, "\x04\bM\vKernel").should == Kernel end - - it "raises ArgumentError when end of byte sequence reached before module name end" do - Marshal.dump(Kernel).should == "\x04\bm\vKernel" - - -> { - Marshal.send(@method, "\x04\bm\vKer") - }.should raise_error(ArgumentError, "marshal data too short") - end end describe "for a wrapped C pointer" do diff --git a/spec/ruby/core/matchdata/allocate_spec.rb b/spec/ruby/core/matchdata/allocate_spec.rb index 142ce639c2..9f3ada4018 100644 --- a/spec/ruby/core/matchdata/allocate_spec.rb +++ b/spec/ruby/core/matchdata/allocate_spec.rb @@ -1,8 +1,10 @@ require_relative '../../spec_helper' describe "MatchData.allocate" do - it "is undefined" do - # https://bugs.ruby-lang.org/issues/16294 - -> { MatchData.allocate }.should raise_error(NoMethodError) + ruby_version_is "2.7" do + it "is undefined" do + # https://bugs.ruby-lang.org/issues/16294 + -> { MatchData.allocate }.should raise_error(NoMethodError) + end end end diff --git a/spec/ruby/core/matchdata/byteoffset_spec.rb b/spec/ruby/core/matchdata/byteoffset_spec.rb deleted file mode 100644 index 6036097834..0000000000 --- a/spec/ruby/core/matchdata/byteoffset_spec.rb +++ /dev/null @@ -1,95 +0,0 @@ -require_relative '../../spec_helper' - -describe "MatchData#byteoffset" do - ruby_version_is "3.2" do - it "returns beginning and ending byte-based offset of whole matched substring for 0 element" do - m = /(.)(.)(\d+)(\d)/.match("THX1138.") - m.byteoffset(0).should == [1, 7] - end - - it "returns beginning and ending byte-based offset of n-th match, all the subsequent elements are capturing groups" do - m = /(.)(.)(\d+)(\d)/.match("THX1138.") - - m.byteoffset(2).should == [2, 3] - m.byteoffset(3).should == [3, 6] - m.byteoffset(4).should == [6, 7] - end - - it "accepts String as a reference to a named capture" do - m = /(?<f>foo)(?<b>bar)/.match("foobar") - - m.byteoffset("f").should == [0, 3] - m.byteoffset("b").should == [3, 6] - end - - it "accepts Symbol as a reference to a named capture" do - m = /(?<f>foo)(?<b>bar)/.match("foobar") - - m.byteoffset(:f).should == [0, 3] - m.byteoffset(:b).should == [3, 6] - end - - it "returns [nil, nil] if a capturing group is optional and doesn't match" do - m = /(?<x>q..)?/.match("foobarbaz") - - m.byteoffset("x").should == [nil, nil] - m.byteoffset(1).should == [nil, nil] - end - - it "returns correct beginning and ending byte-based offset for multi-byte strings" do - m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044") - - m.byteoffset(1).should == [3, 6] - m.byteoffset(3).should == [6, 9] - end - - it "returns [nil, nil] if a capturing group is optional and doesn't match for multi-byte string" do - m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044") - - m.byteoffset(2).should == [nil, nil] - end - - it "converts argument into integer if is not String nor Symbol" do - m = /(?<f>foo)(?<b>bar)/.match("foobar") - - obj = Object.new - def obj.to_int; 2; end - - m.byteoffset(1r).should == [0, 3] - m.byteoffset(1.1).should == [0, 3] - m.byteoffset(obj).should == [3, 6] - end - - it "raises IndexError if there is no group with provided name" do - m = /(?<f>foo)(?<b>bar)/.match("foobar") - - -> { - m.byteoffset("y") - }.should raise_error(IndexError, "undefined group name reference: y") - - -> { - m.byteoffset(:y) - }.should raise_error(IndexError, "undefined group name reference: y") - end - - it "raises IndexError if index is out of matches" do - m = /(?<f>foo)(?<b>bar)/.match("foobar") - - -> { - m.byteoffset(-1) - }.should raise_error(IndexError, "index -1 out of matches") - - -> { - m.byteoffset(3) - }.should raise_error(IndexError, "index 3 out of matches") - end - - it "raises TypeError if can't convert argument into Integer" do - m = /(?<f>foo)(?<b>bar)/.match("foobar") - - -> { - m.byteoffset([]) - }.should raise_error(TypeError, "no implicit conversion of Array into Integer") - end - end -end diff --git a/spec/ruby/core/matchdata/captures_spec.rb b/spec/ruby/core/matchdata/captures_spec.rb index f829a25481..58d4620709 100644 --- a/spec/ruby/core/matchdata/captures_spec.rb +++ b/spec/ruby/core/matchdata/captures_spec.rb @@ -1,6 +1,15 @@ require_relative '../../spec_helper' -require_relative 'shared/captures' +require_relative 'fixtures/classes' describe "MatchData#captures" do - it_behaves_like :matchdata_captures, :captures + it "returns an array of the match captures" do + /(.)(.)(\d+)(\d)/.match("THX1138.").captures.should == ["H","X","113","8"] + end + + ruby_version_is "3.0" do + it "returns instances of String when given a String subclass" do + str = MatchDataSpecs::MyString.new("THX1138: The Movie") + /(.)(.)(\d+)(\d)/.match(str).captures.each { |c| c.should be_an_instance_of(String) } + end + end end diff --git a/spec/ruby/core/matchdata/deconstruct_keys_spec.rb b/spec/ruby/core/matchdata/deconstruct_keys_spec.rb deleted file mode 100644 index 5b68f886c7..0000000000 --- a/spec/ruby/core/matchdata/deconstruct_keys_spec.rb +++ /dev/null @@ -1,65 +0,0 @@ -require_relative '../../spec_helper' - -describe "MatchData#deconstruct_keys" do - ruby_version_is "3.2" do - it "returns whole hash for nil as an argument" do - m = /(?<f>foo)(?<b>bar)/.match("foobar") - - m.deconstruct_keys(nil).should == { f: "foo", b: "bar" } - end - - it "returns only specified keys" do - m = /(?<f>foo)(?<b>bar)/.match("foobar") - - m.deconstruct_keys([:f]).should == { f: "foo" } - end - - it "requires one argument" do - m = /l/.match("l") - - -> { - m.deconstruct_keys - }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1)") - end - - it "it raises error when argument is neither nil nor array" do - m = /(?<f>foo)(?<b>bar)/.match("foobar") - - -> { m.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array)") - -> { m.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array)") - -> { m.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array)") - -> { m.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array)") - end - - it "returns {} when passed []" do - m = /(?<f>foo)(?<b>bar)/.match("foobar") - - m.deconstruct_keys([]).should == {} - end - - it "does not accept non-Symbol keys" do - m = /(?<f>foo)(?<b>bar)/.match("foobar") - - -> { - m.deconstruct_keys(['year', :foo]) - }.should raise_error(TypeError, "wrong argument type String (expected Symbol)") - end - - it "process keys till the first non-existing one" do - m = /(?<f>foo)(?<b>bar)(?<c>baz)/.match("foobarbaz") - - m.deconstruct_keys([:f, :a, :b]).should == { f: "foo" } - end - - it "returns {} when there are no named captured groups at all" do - m = /foo.+/.match("foobar") - - m.deconstruct_keys(nil).should == {} - end - - it "returns {} when passed more keys than named captured groups" do - m = /(?<f>foo)(?<b>bar)/.match("foobar") - m.deconstruct_keys([:f, :b, :c]).should == {} - end - end -end diff --git a/spec/ruby/core/matchdata/deconstruct_spec.rb b/spec/ruby/core/matchdata/deconstruct_spec.rb deleted file mode 100644 index 6af55113b6..0000000000 --- a/spec/ruby/core/matchdata/deconstruct_spec.rb +++ /dev/null @@ -1,8 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'shared/captures' - -describe "MatchData#deconstruct" do - ruby_version_is "3.2" do - it_behaves_like :matchdata_captures, :deconstruct - end -end diff --git a/spec/ruby/core/matchdata/element_reference_spec.rb b/spec/ruby/core/matchdata/element_reference_spec.rb index 1be399cfe1..3b976cb1c4 100644 --- a/spec/ruby/core/matchdata/element_reference_spec.rb +++ b/spec/ruby/core/matchdata/element_reference_spec.rb @@ -16,41 +16,17 @@ 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| - - /(.)(.)(\d+)(\d)/.match("THX1138.")[3, 0].should == [] - - /(.)(.)(\d+)(\d)/.match("THX1138.")[3, -1].should == nil - /(.)(.)(\d+)(\d)/.match("THX1138.")[3, -30].should == nil end it "supports ranges [start..end]" do /(.)(.)(\d+)(\d)/.match("THX1138.")[1..3].should == %w|H X 113| - /(.)(.)(\d+)(\d)/.match("THX1138.")[3..10].should == %w|113 8| - /(.)(.)(\d+)(\d)/.match("THX1138.")[-30..2].should == nil - /(.)(.)(\d+)(\d)/.match("THX1138.")[3..1].should == [] - end - - it "supports endless ranges [start..]" do - /(.)(.)(\d+)(\d)/.match("THX1138.")[3..].should == %w|113 8| - end - - it "supports beginningless ranges [..end]" do - /(.)(.)(\d+)(\d)/.match("THX1138.")[..1].should == %w|HX1138 H| - end - - it "supports beginningless endless ranges [nil..nil]" do - /(.)(.)(\d+)(\d)/.match("THX1138.")[nil..nil].should == %w|HX1138 H X 113 8| end - it "returns instances of String when given a String subclass" do - str = MatchDataSpecs::MyString.new("THX1138.") - /(.)(.)(\d+)(\d)/.match(str)[0..-1].each { |m| m.should be_an_instance_of(String) } + ruby_version_is "3.0" do + it "returns instances of String when given a String subclass" do + str = MatchDataSpecs::MyString.new("THX1138.") + /(.)(.)(\d+)(\d)/.match(str)[0..-1].each { |m| m.should be_an_instance_of(String) } + end end end diff --git a/spec/ruby/core/matchdata/named_captures_spec.rb b/spec/ruby/core/matchdata/named_captures_spec.rb index 5e4693d62d..9b1e324a24 100644 --- a/spec/ruby/core/matchdata/named_captures_spec.rb +++ b/spec/ruby/core/matchdata/named_captures_spec.rb @@ -12,16 +12,4 @@ describe 'MatchData#named_captures' do it 'returns the latest matched capture, even if a later one that does not match exists' do /\A(?<a>.)(?<b>.)(?<b>.)(?<a>.)?\z/.match('012').named_captures.should == { 'a' => '0', 'b' => '2' } end - - ruby_version_is "3.3" do - it 'returns a Hash with Symbol keys when symbolize_names is provided a true value' do - /(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: true).should == { a: '0', b: nil } - /(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: "truly").should == { a: '0', b: nil } - end - - it 'returns a Hash with String keys when symbolize_names is provided a false value' do - /(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: false).should == { 'a' => '0', 'b' => '2' } - /(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: nil).should == { 'a' => '0', 'b' => '2' } - end - end end diff --git a/spec/ruby/core/matchdata/post_match_spec.rb b/spec/ruby/core/matchdata/post_match_spec.rb index b8d1e032eb..1a4ca0a83f 100644 --- a/spec/ruby/core/matchdata/post_match_spec.rb +++ b/spec/ruby/core/matchdata/post_match_spec.rb @@ -7,6 +7,24 @@ 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) @@ -17,8 +35,10 @@ describe "MatchData#post_match" do str.match(/c/).post_match.encoding.should equal(Encoding::ISO_8859_1) end - it "returns an instance of String when given a String subclass" do - str = MatchDataSpecs::MyString.new("THX1138: The Movie") - /(.)(.)(\d+)(\d)/.match(str).post_match.should be_an_instance_of(String) + ruby_version_is "3.0" do + it "returns an instance of String when given a String subclass" do + str = MatchDataSpecs::MyString.new("THX1138: The Movie") + /(.)(.)(\d+)(\d)/.match(str).post_match.should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/matchdata/pre_match_spec.rb b/spec/ruby/core/matchdata/pre_match_spec.rb index 741cb6e923..9b50336c7d 100644 --- a/spec/ruby/core/matchdata/pre_match_spec.rb +++ b/spec/ruby/core/matchdata/pre_match_spec.rb @@ -7,6 +7,24 @@ 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) @@ -17,8 +35,10 @@ describe "MatchData#pre_match" do str.match(/a/).pre_match.encoding.should equal(Encoding::ISO_8859_1) end - it "returns an instance of String when given a String subclass" do - str = MatchDataSpecs::MyString.new("THX1138: The Movie") - /(.)(.)(\d+)(\d)/.match(str).pre_match.should be_an_instance_of(String) + ruby_version_is "3.0" do + it "returns an instance of String when given a String subclass" do + str = MatchDataSpecs::MyString.new("THX1138: The Movie") + /(.)(.)(\d+)(\d)/.match(str).pre_match.should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/matchdata/shared/captures.rb b/spec/ruby/core/matchdata/shared/captures.rb deleted file mode 100644 index 33f834561a..0000000000 --- a/spec/ruby/core/matchdata/shared/captures.rb +++ /dev/null @@ -1,13 +0,0 @@ -require_relative '../../../spec_helper' -require_relative '../fixtures/classes' - -describe :matchdata_captures, shared: true do - it "returns an array of the match captures" do - /(.)(.)(\d+)(\d)/.match("THX1138.").send(@method).should == ["H","X","113","8"] - end - - it "returns instances of String when given a String subclass" do - str = MatchDataSpecs::MyString.new("THX1138: The Movie") - /(.)(.)(\d+)(\d)/.match(str).send(@method).each { |c| c.should be_an_instance_of(String) } - end -end diff --git a/spec/ruby/core/matchdata/to_a_spec.rb b/spec/ruby/core/matchdata/to_a_spec.rb index 4fa11ff604..50f5a161a5 100644 --- a/spec/ruby/core/matchdata/to_a_spec.rb +++ b/spec/ruby/core/matchdata/to_a_spec.rb @@ -6,8 +6,10 @@ describe "MatchData#to_a" do /(.)(.)(\d+)(\d)/.match("THX1138.").to_a.should == ["HX1138", "H", "X", "113", "8"] end - it "returns instances of String when given a String subclass" do - str = MatchDataSpecs::MyString.new("THX1138.") - /(.)(.)(\d+)(\d)/.match(str)[0..-1].to_a.each { |m| m.should be_an_instance_of(String) } + ruby_version_is "3.0" do + it "returns instances of String when given a String subclass" do + str = MatchDataSpecs::MyString.new("THX1138.") + /(.)(.)(\d+)(\d)/.match(str)[0..-1].to_a.each { |m| m.should be_an_instance_of(String) } + end end end diff --git a/spec/ruby/core/matchdata/to_s_spec.rb b/spec/ruby/core/matchdata/to_s_spec.rb index cd1c4dbca2..aab0955ae1 100644 --- a/spec/ruby/core/matchdata/to_s_spec.rb +++ b/spec/ruby/core/matchdata/to_s_spec.rb @@ -6,8 +6,10 @@ describe "MatchData#to_s" do /(.)(.)(\d+)(\d)/.match("THX1138.").to_s.should == "HX1138" end - it "returns an instance of String when given a String subclass" do - str = MatchDataSpecs::MyString.new("THX1138.") - /(.)(.)(\d+)(\d)/.match(str).to_s.should be_an_instance_of(String) + ruby_version_is "3.0" do + it "returns an instance of String when given a String subclass" do + str = MatchDataSpecs::MyString.new("THX1138.") + /(.)(.)(\d+)(\d)/.match(str).to_s.should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/matchdata/values_at_spec.rb b/spec/ruby/core/matchdata/values_at_spec.rb index 535719a2ee..8f7fdf557c 100644 --- a/spec/ruby/core/matchdata/values_at_spec.rb +++ b/spec/ruby/core/matchdata/values_at_spec.rb @@ -1,76 +1,21 @@ require_relative '../../spec_helper' describe "MatchData#values_at" do - # Should be synchronized with core/array/values_at_spec.rb and core/struct/values_at_spec.rb - # - # /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").to_a # => ["HX1138", "H", "X", "113", "8"] - - context "when passed a list of Integers" do - it "returns an array containing each value given by one of integers" do - /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(0, 2, -2).should == ["HX1138", "X", "113"] - end - - it "returns nil value for any integer that is out of range" do - /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(5).should == [nil] - /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(-6).should == [nil] - end + it "returns an array of the matching value" do + /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(0, 2, -2).should == ["HX1138", "X", "113"] end - context "when passed an integer Range" do - it "returns an array containing each value given by the elements of the range" do - /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(0..2).should == ["HX1138", "H", "X"] - end - - it "fills with nil values for range elements larger than the captured values number" do - /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(0..5).should == ["HX1138", "H", "X", "113", "8", nil] - end - - it "raises RangeError if any element of the range is negative and out of range" do - -> { /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(-6..3) }.should raise_error(RangeError, "-6..3 out of range") - end - - it "supports endless Range" do - /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(0..).should == ["HX1138", "H", "X", "113", "8"] - end - - it "supports beginningless Range" do - /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(..2).should == ["HX1138", "H", "X"] - end - - it "returns an empty Array when Range is empty" do - /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(2..0).should == [] - end - end - - context "when passed names" do - it 'slices captures with the given names' do - /(?<a>.)(?<b>.)(?<c>.)/.match('012').values_at(:c, :a).should == ['2', '0'] - end - - it 'slices captures with the given String names' do - /(?<a>.)(?<b>.)(?<c>.)/.match('012').values_at('c', 'a').should == ['2', '0'] + describe "when passed a Range" do + it "returns an array of the matching value" do + /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(2..4, 0..1).should == ["X", "113", "8", "HX1138", "H"] end end - it "supports multiple integer Ranges" do - /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(1..2, 2..3).should == ["H", "X", "X", "113"] + it 'slices captures with the given names' do + /(?<a>.)(?<b>.)(?<c>.)/.match('012').values_at(:c, :a).should == ['2', '0'] end - it "supports mixing integer Ranges and Integers" do - /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(1..2, 4).should == ["H", "X", "8"] - end - - it 'supports mixing of names and indices' do + it 'takes names and indices' do /\A(?<a>.)(?<b>.)\z/.match('01').values_at(0, 1, 2, :a, :b).should == ['01', '0', '1', '0', '1'] end - - it "returns a new empty Array if no arguments given" do - /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at().should == [] - end - - it "fails when passed arguments of unsupported types" do - -> { - /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(Object.new) - }.should raise_error(TypeError, "no implicit conversion of Object into Integer") - end end diff --git a/spec/ruby/core/math/cos_spec.rb b/spec/ruby/core/math/cos_spec.rb index 006afeb2cc..3ba7a54c38 100644 --- a/spec/ruby/core/math/cos_spec.rb +++ b/spec/ruby/core/math/cos_spec.rb @@ -15,6 +15,7 @@ describe "Math.cos" do Math.cos(2*Math::PI).should be_close(1.0, TOLERANCE) end + it "raises a TypeError unless the argument is Numeric and has #to_f" do -> { Math.cos("test") }.should raise_error(TypeError) end @@ -23,23 +24,14 @@ describe "Math.cos" do Math.cos(nan_value).nan?.should be_true end - describe "coerces its argument with #to_f" do - it "coerces its argument with #to_f" do - f = mock_numeric('8.2') - f.should_receive(:to_f).and_return(8.2) - Math.cos(f).should == Math.cos(8.2) - end - - it "raises a TypeError if the given argument can't be converted to a Float" do - -> { Math.cos(nil) }.should raise_error(TypeError) - -> { Math.cos(:abc) }.should raise_error(TypeError) - end - - it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a Float" do - object = mock_numeric('mock-float') - object.should_receive(:to_f).and_raise(NoMethodError) - -> { Math.cos(object) }.should raise_error(NoMethodError) - end + it "raises a TypeError if the argument is nil" do + -> { Math.cos(nil) }.should raise_error(TypeError) + end + + it "coerces its argument with #to_f" do + f = mock_numeric('8.2') + f.should_receive(:to_f).and_return(8.2) + Math.cos(f).should == Math.cos(8.2) end end diff --git a/spec/ruby/core/math/ldexp_spec.rb b/spec/ruby/core/math/ldexp_spec.rb index 6dcf94a663..fb7799cf26 100644 --- a/spec/ruby/core/math/ldexp_spec.rb +++ b/spec/ruby/core/math/ldexp_spec.rb @@ -45,12 +45,6 @@ describe "Math.ldexp" do it "accepts any second argument that can be coerced with Integer()" do Math.ldexp(3.23, MathSpecs::Integer.new).should be_close(12.92, TOLERANCE) end - - it "returns correct value that closes to the max value of double type" do - Math.ldexp(0.5122058490966879, 1024).should == 9.207889385574391e+307 - Math.ldexp(0.9999999999999999, 1024).should == 1.7976931348623157e+308 - Math.ldexp(0.99999999999999999, 1024).should == Float::INFINITY - end end describe "Math#ldexp" do diff --git a/spec/ruby/core/math/log2_spec.rb b/spec/ruby/core/math/log2_spec.rb index 3d4d41d130..1594f2d7af 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 Math::DomainError if the argument is less than 0" do + it "raises an Errno::EDOM 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 918e7c3a17..779aea2a0a 100644 --- a/spec/ruby/core/math/sqrt_spec.rb +++ b/spec/ruby/core/math/sqrt_spec.rb @@ -27,10 +27,6 @@ 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/clone_spec.rb b/spec/ruby/core/method/clone_spec.rb index b0eb5751a9..3fe4000fb7 100644 --- a/spec/ruby/core/method/clone_spec.rb +++ b/spec/ruby/core/method/clone_spec.rb @@ -1,13 +1,14 @@ require_relative '../../spec_helper' -require_relative 'shared/dup' +require_relative 'fixtures/classes' describe "Method#clone" do - it_behaves_like :method_dup, :clone + it "returns a copy of the method" do + m1 = MethodSpecs::Methods.new.method(:foo) + m2 = m1.clone - it "preserves frozen status" do - method = Object.new.method(:method) - method.freeze - method.frozen?.should == true - method.clone.frozen?.should == true + m1.should == m2 + m1.should_not equal(m2) + + m1.call.should == m2.call end end diff --git a/spec/ruby/core/method/compose_spec.rb b/spec/ruby/core/method/compose_spec.rb index 7506e33ea8..87cf61f7ad 100644 --- a/spec/ruby/core/method/compose_spec.rb +++ b/spec/ruby/core/method/compose_spec.rb @@ -38,7 +38,8 @@ describe "Method#<<" do double = proc { |x| x + x } (pow_2 << double).is_a?(Proc).should == true - (pow_2 << double).should_not.lambda? + ruby_version_is(''...'3.0') { (pow_2 << double).should.lambda? } + ruby_version_is('3.0') { (pow_2 << double).should_not.lambda? } end it "may accept multiple arguments" do diff --git a/spec/ruby/core/method/dup_spec.rb b/spec/ruby/core/method/dup_spec.rb deleted file mode 100644 index e3e29d8a68..0000000000 --- a/spec/ruby/core/method/dup_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'shared/dup' - -describe "Method#dup" do - ruby_version_is "3.4" do - it_behaves_like :method_dup, :dup - - it "resets frozen status" do - method = Object.new.method(:method) - method.freeze - method.frozen?.should == true - method.dup.frozen?.should == false - end - end -end diff --git a/spec/ruby/core/method/fixtures/classes.rb b/spec/ruby/core/method/fixtures/classes.rb index 464a519aea..50daa773e1 100644 --- a/spec/ruby/core/method/fixtures/classes.rb +++ b/spec/ruby/core/method/fixtures/classes.rb @@ -84,12 +84,6 @@ module MethodSpecs def two_req_one_opt_with_splat_and_block(a, b, c=nil, *d, &blk); end def one_req_two_opt_with_splat_and_block(a, b=nil, c=nil, *d, &blk); end - def my_public_method; end - def my_protected_method; end - def my_private_method; end - protected :my_protected_method - private :my_private_method - define_method(:zero_defined_method, Proc.new {||}) define_method(:zero_with_splat_defined_method, Proc.new {|*x|}) define_method(:one_req_defined_method, Proc.new {|x|}) diff --git a/spec/ruby/core/method/parameters_spec.rb b/spec/ruby/core/method/parameters_spec.rb index 7d2b37fac7..3fdaf9ce6f 100644 --- a/spec/ruby/core/method/parameters_spec.rb +++ b/spec/ruby/core/method/parameters_spec.rb @@ -7,7 +7,6 @@ describe "Method#parameters" do def one_keyrest(**a); end def one_keyreq(a:); end - def one_nokey(**nil); end def one_splat_one_req(*a,b); end def one_splat_two_req(*a,b,c); end @@ -16,14 +15,11 @@ describe "Method#parameters" do def one_opt_with_stabby(a=-> b { true }); end def one_unnamed_splat(*); end - def one_unnamed_keyrest(**); end def one_splat_one_block(*args, &block) local_is_not_parameter = {} end - def underscore_parameters(_, _, _ = 1, *_, _:, _: 2, **_, &_); end - define_method(:one_optional_defined_method) {|x = 1|} end @@ -180,11 +176,6 @@ describe "Method#parameters" do m.parameters.should == [[:keyreq,:a]] end - it "returns [[:nokey]] for a method with a single **nil parameter" do - m = MethodSpecs::Methods.instance_method(:one_nokey) - m.parameters.should == [[:nokey]] - end - it "works with ->(){} as the value of an optional argument" do m = MethodSpecs::Methods.instance_method(:one_opt_with_stabby) m.parameters.should == [[:opt,:a]] @@ -231,40 +222,9 @@ describe "Method#parameters" do m.method(:handled_via_method_missing).parameters.should == [[:rest]] end - ruby_version_is '3.2' do - it "adds rest arg with name * for \"star\" argument" do - m = MethodSpecs::Methods.new - m.method(:one_unnamed_splat).parameters.should == [[:rest, :*]] - end - - it "adds keyrest arg with ** as a name for \"double star\" argument" do - m = MethodSpecs::Methods.new - m.method(:one_unnamed_keyrest).parameters.should == [[:keyrest, :**]] - 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 - - it "adds nameless keyrest arg for \"double star\" argument" do - m = MethodSpecs::Methods.new - m.method(:one_unnamed_keyrest).parameters.should == [[:keyrest]] - end - end - - ruby_version_is '3.1' do - it "adds block arg with name & for anonymous block argument" do - object = Object.new - - eval(<<~RUBY).should == [[:block, :&]] - def object.foo(&) - end - object.method(:foo).parameters - RUBY - end + it "adds nameless rest arg for \"star\" argument" do + m = MethodSpecs::Methods.new + m.method(:one_unnamed_splat).parameters.should == [[:rest]] end it "returns the args and block for a splat and block argument" do @@ -282,20 +242,6 @@ describe "Method#parameters" do m.method(:writer=).parameters.should == [[:req]] end - it "returns all parameters defined with the name _ as _" do - m = MethodSpecs::Methods.instance_method(:underscore_parameters) - m.parameters.should == [ - [:req, :_], - [:req, :_], - [:opt, :_], - [:rest, :_], - [:keyreq, :_], - [:key, :_], - [:keyrest, :_], - [:block, :_] - ] - end - it "returns [[:rest]] for core methods with variable-length argument lists" do # delete! takes rest args "foo".method(:delete!).parameters.should == [[:rest]] diff --git a/spec/ruby/core/method/private_spec.rb b/spec/ruby/core/method/private_spec.rb deleted file mode 100644 index fd550036a3..0000000000 --- a/spec/ruby/core/method/private_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/classes' - -describe "Method#private?" do - ruby_version_is "3.1"..."3.2" do - it "returns false when the method is public" do - obj = MethodSpecs::Methods.new - obj.method(:my_public_method).private?.should == false - end - - it "returns false when the method is protected" do - obj = MethodSpecs::Methods.new - obj.method(:my_protected_method).private?.should == false - end - - it "returns true when the method is private" do - obj = MethodSpecs::Methods.new - obj.method(:my_private_method).private?.should == true - end - end - - ruby_version_is "3.2" do - it "has been removed" do - obj = MethodSpecs::Methods.new - obj.method(:my_private_method).should_not.respond_to?(:private?) - end - end -end diff --git a/spec/ruby/core/method/protected_spec.rb b/spec/ruby/core/method/protected_spec.rb deleted file mode 100644 index 8423e8c64c..0000000000 --- a/spec/ruby/core/method/protected_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/classes' - -describe "Method#protected?" do - ruby_version_is "3.1"..."3.2" do - it "returns false when the method is public" do - obj = MethodSpecs::Methods.new - obj.method(:my_public_method).protected?.should == false - end - - it "returns true when the method is protected" do - obj = MethodSpecs::Methods.new - obj.method(:my_protected_method).protected?.should == true - end - - it "returns false when the method is private" do - obj = MethodSpecs::Methods.new - obj.method(:my_private_method).protected?.should == false - end - end - - ruby_version_is "3.2" do - it "has been removed" do - obj = MethodSpecs::Methods.new - obj.method(:my_protected_method).should_not.respond_to?(:protected?) - end - end -end diff --git a/spec/ruby/core/method/public_spec.rb b/spec/ruby/core/method/public_spec.rb deleted file mode 100644 index 20d0081a27..0000000000 --- a/spec/ruby/core/method/public_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/classes' - -describe "Method#public?" do - ruby_version_is "3.1"..."3.2" do - it "returns true when the method is public" do - obj = MethodSpecs::Methods.new - obj.method(:my_public_method).public?.should == true - end - - it "returns false when the method is protected" do - obj = MethodSpecs::Methods.new - obj.method(:my_protected_method).public?.should == false - end - - it "returns false when the method is private" do - obj = MethodSpecs::Methods.new - obj.method(:my_private_method).public?.should == false - end - end - - ruby_version_is "3.2" do - it "has been removed" do - obj = MethodSpecs::Methods.new - obj.method(:my_public_method).should_not.respond_to?(:public?) - end - end -end diff --git a/spec/ruby/core/method/shared/dup.rb b/spec/ruby/core/method/shared/dup.rb deleted file mode 100644 index 1a10b90689..0000000000 --- a/spec/ruby/core/method/shared/dup.rb +++ /dev/null @@ -1,32 +0,0 @@ -describe :method_dup, shared: true do - it "returns a copy of self" do - a = Object.new.method(:method) - b = a.send(@method) - - a.should == b - a.should_not equal(b) - end - - ruby_version_is "3.4" do - it "copies instance variables" do - method = Object.new.method(:method) - method.instance_variable_set(:@ivar, 1) - cl = method.send(@method) - cl.instance_variables.should == [:@ivar] - end - - it "copies the finalizer" do - code = <<-RUBY - obj = Object.new.method(:method) - - ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" }) - - obj.clone - - exit 0 - RUBY - - ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"] - end - end -end diff --git a/spec/ruby/core/method/shared/to_s.rb b/spec/ruby/core/method/shared/to_s.rb index b2d27d370f..0dcae41b59 100644 --- a/spec/ruby/core/method/shared/to_s.rb +++ b/spec/ruby/core/method/shared/to_s.rb @@ -24,17 +24,19 @@ describe :method_to_s, shared: true do @string.should =~ /\#bar/ 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)") + 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 end it "returns a String containing the Module the method is defined in" do @@ -53,18 +55,20 @@ describe :method_to_s, shared: true do MethodSpecs::A.new.method(:baz).send(@method).should.start_with? "#<Method: MethodSpecs::A#baz" end - it "returns a String containing the Module containing the method if object has a singleton class but method is not defined in the singleton class" do - obj = MethodSpecs::MySub.new - obj.singleton_class - @m = obj.method(:bar) - @string = @m.send(@method) - @string.should.start_with? "#<Method: MethodSpecs::MySub(MethodSpecs::MyMod)#bar" + ruby_version_is '3.0' do + it "returns a String containing the Module containing the method if object has a singleton class but method is not defined in the singleton class" do + obj = MethodSpecs::MySub.new + obj.singleton_class + @m = obj.method(:bar) + @string = @m.send(@method) + @string.should.start_with? "#<Method: MethodSpecs::MySub(MethodSpecs::MyMod)#bar" - c = MethodSpecs::MySub.dup - m = Module.new{def bar; end} - c.extend(m) - @string = c.method(:bar).send(@method) - @string.should.start_with? "#<Method: #<Class:#{c.inspect}>(#{m.inspect})#bar" + c = MethodSpecs::MySub.dup + m = Module.new{def bar; end} + c.extend(m) + @string = c.method(:bar).send(@method) + @string.should.start_with? "#<Method: #<Class:#{c.inspect}>(#{m.inspect})#bar" + end end it "returns a String containing the singleton class if method is defined in the singleton class" do @@ -75,7 +79,11 @@ describe :method_to_s, shared: true do @string.should.start_with? "#<Method: #<MethodSpecs::MySub:0xXXXXXX>.bar" end - 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") + 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 + end end end diff --git a/spec/ruby/core/method/source_location_spec.rb b/spec/ruby/core/method/source_location_spec.rb index c5b296f6e2..1f476aaa9b 100644 --- a/spec/ruby/core/method/source_location_spec.rb +++ b/spec/ruby/core/method/source_location_spec.rb @@ -13,7 +13,7 @@ describe "Method#source_location" do it "sets the first value to the path of the file in which the method was defined" do file = @method.source_location.first file.should be_an_instance_of(String) - file.should == File.realpath('fixtures/classes.rb', __dir__) + file.should == File.realpath('../fixtures/classes.rb', __FILE__) end it "sets the last value to an Integer representing the line on which the method was defined" do @@ -104,13 +104,6 @@ describe "Method#source_location" do end end - it "works for eval with a given line" do - c = Class.new do - eval('def self.m; end', nil, "foo", 100) - end - c.method(:m).source_location.should == ["foo", 100] - end - describe "for a Method generated by respond_to_missing?" do it "returns nil" do m = MethodSpecs::Methods.new diff --git a/spec/ruby/core/method/unbind_spec.rb b/spec/ruby/core/method/unbind_spec.rb index bdedd513ce..cdd3a808f2 100644 --- a/spec/ruby/core/method/unbind_spec.rb +++ b/spec/ruby/core/method/unbind_spec.rb @@ -27,16 +27,8 @@ describe "Method#unbind" do @string.should =~ /MethodSpecs::MyMod/ end - ruby_version_is ""..."3.2" do - it "returns a String containing the Module the method is referenced from" do - @string.should =~ /MethodSpecs::MySub/ - end - end - - ruby_version_is "3.2" do - it "returns a String containing the Module the method is referenced from" do - @string.should =~ /MethodSpecs::MyMod/ - end + it "returns a String containing the Module the method is referenced from" do + @string.should =~ /MethodSpecs::MySub/ end end diff --git a/spec/ruby/core/module/alias_method_spec.rb b/spec/ruby/core/module/alias_method_spec.rb index c36dedd2d8..5d3d0c23d9 100644 --- a/spec/ruby/core/module/alias_method_spec.rb +++ b/spec/ruby/core/module/alias_method_spec.rb @@ -81,20 +81,22 @@ describe "Module#alias_method" do -> { @class.make_alias mock('x'), :public_one }.should raise_error(TypeError) end - it "raises a NoMethodError if the given name raises a NoMethodError during type coercion using to_str" do - obj = mock("mock-name") - obj.should_receive(:to_str).and_raise(NoMethodError) - -> { @class.make_alias obj, :public_one }.should raise_error(NoMethodError) - end - it "is a public method" do Module.should have_public_instance_method(:alias_method, false) end describe "returned value" do - it "returns symbol of the defined method name" do - @class.send(:alias_method, :checking_return_value, :public_one).should equal(:checking_return_value) - @class.send(:alias_method, 'checking_return_value', :public_one).should equal(:checking_return_value) + ruby_version_is ""..."3.0" do + it "returns self" do + @class.send(:alias_method, :checking_return_value, :public_one).should equal(@class) + end + end + + ruby_version_is "3.0" do + it "returns symbol of the defined method name" do + @class.send(:alias_method, :checking_return_value, :public_one).should equal(:checking_return_value) + @class.send(:alias_method, 'checking_return_value', :public_one).should equal(:checking_return_value) + end end end diff --git a/spec/ruby/core/module/append_features_spec.rb b/spec/ruby/core/module/append_features_spec.rb index 1724cde5d6..d960798eef 100644 --- a/spec/ruby/core/module/append_features_spec.rb +++ b/spec/ruby/core/module/append_features_spec.rb @@ -47,6 +47,20 @@ 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/attr_accessor_spec.rb b/spec/ruby/core/module/attr_accessor_spec.rb index eea5b4b64b..ba5289cbea 100644 --- a/spec/ruby/core/module/attr_accessor_spec.rb +++ b/spec/ruby/core/module/attr_accessor_spec.rb @@ -80,9 +80,19 @@ describe "Module#attr_accessor" do Module.should have_public_instance_method(:attr_accessor, false) end - it "returns an array of defined method names as symbols" do - Class.new do - (attr_accessor :foo, 'bar').should == [:foo, :foo=, :bar, :bar=] + ruby_version_is ""..."3.0" do + it "returns nil" do + Class.new do + (attr_accessor :foo, 'bar').should == nil + end + end + end + + ruby_version_is "3.0" do + it "returns an array of defined method names as symbols" do + Class.new do + (attr_accessor :foo, 'bar').should == [:foo, :foo=, :bar, :bar=] + end end end diff --git a/spec/ruby/core/module/attr_reader_spec.rb b/spec/ruby/core/module/attr_reader_spec.rb index 0b6d996719..b0ae906ab5 100644 --- a/spec/ruby/core/module/attr_reader_spec.rb +++ b/spec/ruby/core/module/attr_reader_spec.rb @@ -62,9 +62,19 @@ describe "Module#attr_reader" do Module.should have_public_instance_method(:attr_reader, false) end - it "returns an array of defined method names as symbols" do - Class.new do - (attr_reader :foo, 'bar').should == [:foo, :bar] + ruby_version_is ""..."3.0" do + it "returns nil" do + Class.new do + (attr_reader :foo, 'bar').should == nil + end + end + end + + ruby_version_is "3.0" do + it "returns an array of defined method names as symbols" do + Class.new do + (attr_reader :foo, 'bar').should == [:foo, :bar] + end end end end diff --git a/spec/ruby/core/module/attr_spec.rb b/spec/ruby/core/module/attr_spec.rb index 72a6646b1e..33e0eb8628 100644 --- a/spec/ruby/core/module/attr_spec.rb +++ b/spec/ruby/core/module/attr_spec.rb @@ -146,11 +146,23 @@ describe "Module#attr" do Module.should have_public_instance_method(:attr, false) end - it "returns an array of defined method names as symbols" do - Class.new do - (attr :foo, 'bar').should == [:foo, :bar] - (attr :baz, false).should == [:baz] - (attr :qux, true).should == [:qux, :qux=] + ruby_version_is ""..."3.0" do + it "returns nil" do + Class.new do + (attr :foo, 'bar').should == nil + (attr :baz, false).should == nil + (attr :qux, true).should == nil + end + end + end + + ruby_version_is "3.0" do + it "returns an array of defined method names as symbols" do + Class.new do + (attr :foo, 'bar').should == [:foo, :bar] + (attr :baz, false).should == [:baz] + (attr :qux, true).should == [:qux, :qux=] + end end end end diff --git a/spec/ruby/core/module/attr_writer_spec.rb b/spec/ruby/core/module/attr_writer_spec.rb index aaea0ce43f..0e9d201317 100644 --- a/spec/ruby/core/module/attr_writer_spec.rb +++ b/spec/ruby/core/module/attr_writer_spec.rb @@ -72,9 +72,19 @@ describe "Module#attr_writer" do Module.should have_public_instance_method(:attr_writer, false) end - it "returns an array of defined method names as symbols" do - Class.new do - (attr_writer :foo, 'bar').should == [:foo=, :bar=] + ruby_version_is ""..."3.0" do + it "returns nil" do + Class.new do + (attr_writer :foo, 'bar').should == nil + end + end + end + + ruby_version_is "3.0" do + it "returns an array of defined method names as symbols" do + Class.new do + (attr_writer :foo, 'bar').should == [:foo=, :bar=] + end end end end diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb index af04ab26c8..1d61646db5 100644 --- a/spec/ruby/core/module/autoload_spec.rb +++ b/spec/ruby/core/module/autoload_spec.rb @@ -18,14 +18,16 @@ describe "Module#autoload?" do ModuleSpecs::Autoload::Child.autoload?(:AnotherAutoload).should == "another_autoload.rb" 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 + 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 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" + 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 end @@ -512,7 +514,9 @@ 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 - ModuleSpecs::Autoload.const_defined?("P").should be_true + ruby_bug "[Bug #15780]", ""..."2.7" do + ModuleSpecs::Autoload.const_defined?("P").should be_true + end end it "loads the file when opening a module that is the autoloaded constant" do @@ -577,36 +581,6 @@ describe "Module#autoload" do end end - ruby_version_is "3.2" do - it "warns once in verbose mode if the constant was defined in a parent scope" do - ScratchPad.record -> { - ModuleSpecs::DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent - } - - module ModuleSpecs - module Autoload - autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb") - self.autoload?(:DeclaredInCurrentDefinedInParent).should == fixture(__FILE__, "autoload_callback.rb") - const_defined?(:DeclaredInCurrentDefinedInParent).should == true - - -> { - DeclaredInCurrentDefinedInParent - }.should complain( - /Expected .*autoload_callback.rb to define ModuleSpecs::Autoload::DeclaredInCurrentDefinedInParent but it didn't/, - verbose: true, - ) - - -> { - DeclaredInCurrentDefinedInParent - }.should_not complain(/.*/, verbose: true) - self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil - const_defined?(:DeclaredInCurrentDefinedInParent).should == false - ModuleSpecs.const_defined?(:DeclaredInCurrentDefinedInParent).should == true - end - end - end - end - ruby_version_is "3.1" do it "looks up in parent scope after failed autoload" do @remove << :DeclaredInCurrentDefinedInParent diff --git a/spec/ruby/core/module/class_variables_spec.rb b/spec/ruby/core/module/class_variables_spec.rb index e155f1deac..fd7aa93aa8 100644 --- a/spec/ruby/core/module/class_variables_spec.rb +++ b/spec/ruby/core/module/class_variables_spec.rb @@ -23,12 +23,4 @@ describe "Module#class_variables" do c.extend ModuleSpecs::MVars c.class_variables.should_not include(:@@mvar) end - - it "returns the correct class variables when inherit is given" do - ModuleSpecs::SubCVars.class_variables(false).should == [:@@sub] - ModuleSpecs::SubCVars.new.singleton_class.class_variables(false).should == [] - - ModuleSpecs::SubCVars.class_variables(true).should == [:@@sub, :@@cls, :@@meta] - ModuleSpecs::SubCVars.new.singleton_class.class_variables(true).should == [:@@sub, :@@cls, :@@meta] - end end diff --git a/spec/ruby/core/module/const_added_spec.rb b/spec/ruby/core/module/const_added_spec.rb deleted file mode 100644 index f9edda3a07..0000000000 --- a/spec/ruby/core/module/const_added_spec.rb +++ /dev/null @@ -1,160 +0,0 @@ -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 - - it "is called when the constant is already assigned a value" do - ScratchPad.record [] - - mod = Module.new do - def self.const_added(name) - ScratchPad.record const_get(name) - end - end - - mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1) - TEST = 123 - RUBY - - ScratchPad.recorded.should == 123 - end - - it "records re-definition of existing constants" do - ScratchPad.record [] - - mod = Module.new do - def self.const_added(name) - ScratchPad << const_get(name) - end - end - - -> { - mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1) - TEST = 123 - TEST = 456 - RUBY - }.should complain(/warning: already initialized constant .+::TEST/) - - ScratchPad.recorded.should == [123, 456] - end - end -end diff --git a/spec/ruby/core/module/const_defined_spec.rb b/spec/ruby/core/module/const_defined_spec.rb index 027cf5a245..75730395e8 100644 --- a/spec/ruby/core/module/const_defined_spec.rb +++ b/spec/ruby/core/module/const_defined_spec.rb @@ -17,16 +17,11 @@ describe "Module#const_defined?" do ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4).should be_true end - it "returns true if the constant is defined in a mixed-in module of the receiver's parent" do + it "returns true if the constant is defined in a mixed-in module of the receiver" do # CS_CONST10 is defined in a module included by ChildA ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST10).should be_true end - it "returns true if the constant is defined in a mixed-in module (with prepends) of the receiver" do - # CS_CONST11 is defined in the module included by ContainerPrepend - ConstantSpecs::ContainerPrepend.const_defined?(:CS_CONST11).should be_true - end - it "returns true if the constant is defined in Object and the receiver is a module" do # CS_CONST1 is defined in Object ConstantSpecs::ModuleA.const_defined?(:CS_CONST1).should be_true @@ -80,23 +75,10 @@ describe "Module#const_defined?" do ConstantSpecs::ClassA.const_defined?(:CS_CONSTX).should == false end - describe "converts the given name to a String using #to_str" do - 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_defined?(name).should == true - end - - it "raises a TypeError if the given name can't be converted to a String" do - -> { ConstantSpecs.const_defined?(nil) }.should raise_error(TypeError) - -> { ConstantSpecs.const_defined?([]) }.should raise_error(TypeError) - end - - it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do - name = mock("classA") - name.should_receive(:to_str).and_raise(NoMethodError) - -> { ConstantSpecs.const_defined?(name) }.should raise_error(NoMethodError) - 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_defined?(name).should == true end it "special cases Object and checks it's included Modules" do diff --git a/spec/ruby/core/module/const_get_spec.rb b/spec/ruby/core/module/const_get_spec.rb index 0233118f4b..9f9fafe5bb 100644 --- a/spec/ruby/core/module/const_get_spec.rb +++ b/spec/ruby/core/module/const_get_spec.rb @@ -100,16 +100,6 @@ 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 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 @@ -150,10 +140,6 @@ 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_set_spec.rb b/spec/ruby/core/module/const_set_spec.rb index 5bdfd7b68f..ba7810d17b 100644 --- a/spec/ruby/core/module/const_set_spec.rb +++ b/spec/ruby/core/module/const_set_spec.rb @@ -20,10 +20,20 @@ describe "Module#const_set" do m.name.should == "ConstantSpecs::CS_CONST1000" end - it "sets the name of a module scoped by an anonymous module" do - a, b = Module.new, Module.new - a.const_set :B, b - b.name.should.end_with? '::B' + ruby_version_is ""..."3.0" do + it "does not set the name of a module scoped by an anonymous module" do + a, b = Module.new, Module.new + a.const_set :B, b + b.name.should be_nil + end + end + + ruby_version_is "3.0" do + it "sets the name of a module scoped by an anonymous module" do + a, b = Module.new, Module.new + a.const_set :B, b + b.name.should.end_with? '::B' + end end it "sets the name of contained modules when assigning a toplevel anonymous module" do diff --git a/spec/ruby/core/module/const_source_location_spec.rb b/spec/ruby/core/module/const_source_location_spec.rb index ded2aa51d7..9e1f2c1c49 100644 --- a/spec/ruby/core/module/const_source_location_spec.rb +++ b/spec/ruby/core/module/const_source_location_spec.rb @@ -6,232 +6,215 @@ describe "Module#const_source_location" do @constants_fixture_path = File.expand_path('../../fixtures/constants.rb', __dir__) end - 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] + 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] - ConstantSpecs::ModuleA::CSL_CONST301 = :const301_2 - ConstantSpecs::ModuleA.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::ParentA::CSL_CONST301 = :const301_3 - ConstantSpecs::ParentA.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::ContainerA::ChildA::CSL_CONST301 = :const301_5 - ConstantSpecs::ContainerA::ChildA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1] - 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 - 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 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 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 "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 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 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] + 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::ClassB::CSL_CONST309 = :const309_2 + }.should complain(/already initialized constant/) + ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 2] + end 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] + 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 - -> { - 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 "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 - describe "with statically assigned constants" do - it "works for the module and class keywords" do - ConstantSpecs.const_source_location(:ModuleB).should == [@constants_fixture_path, ConstantSpecs::ModuleB::LINE] - ConstantSpecs.const_source_location(:ClassA).should == [@constants_fixture_path, ConstantSpecs::ClassA::LINE] - 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 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 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 "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 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 "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 "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 "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] + 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 "searches location path the superclass chain" do - ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST13).should == [@constants_fixture_path, ConstantSpecs::ModuleA::CS_CONST13_LINE] + it "return empty path if constant defined in C code" do + Object.const_source_location(:String).should == [] 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] + 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 "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] + it "returns nil if no constant is defined in the search path" do + ConstantSpecs.const_source_location(:CS_CONSTX).should == nil end - end - - it "return empty path if constant defined in C code" do - Object.const_source_location(:String).should == [] - 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 "returns nil if no constant is defined in the search path" do - ConstantSpecs.const_source_location(:CS_CONSTX).should == 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 "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 "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 "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::LINE] - 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 "raises a NameError if the name does not start with a capital letter" do + -> { ConstantSpecs.const_source_location "name" }.should raise_error(NameError) + end - name.should_receive(:to_str).and_return(123) - -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError) - 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 "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 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 "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 "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 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 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 "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 + name.should_receive(:to_str).and_return(123) + -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError) + 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 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 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 "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 "accepts a toplevel scope qualifier" do - ConstantSpecs.const_source_location("::CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE] - 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 "accepts a scoped constant name" do - ConstantSpecs.const_source_location("ClassA::CS_CONST10").should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_LINE] - 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 "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 "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 "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 "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 NameError if only '::' is passed" do - -> { ConstantSpecs.const_source_location("::") }.should raise_error(NameError) - end + it "accepts a toplevel scope qualifier" do + ConstantSpecs.const_source_location("::CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE] + 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 "accepts a scoped constant name" do + ConstantSpecs.const_source_location("ClassA::CS_CONST10").should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_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 "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 search private constants path" do - ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE] - end + it "raises a NameError if only '::' is passed" do + -> { ConstantSpecs.const_source_location("::") }.should raise_error(NameError) + end - it "works for eval with a given line" do - c = Class.new do - eval('self::C = 1', nil, "foo", 100) + it "raises a NameError if a Symbol has a toplevel scope qualifier" do + -> { ConstantSpecs.const_source_location(:'::CS_CONST1') }.should raise_error(NameError) end - c.const_source_location(:C).should == ["foo", 100] - end - context 'autoload' do - before :all do - ConstantSpecs.autoload :CSL_CONST1, "#{__dir__}/notexisting.rb" - @line = __LINE__ - 1 + 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 the autoload location while not resolved' do - ConstantSpecs.const_source_location('CSL_CONST1').should == [__FILE__, @line] + it "does search private constants path" do + ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_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] + 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 end end end diff --git a/spec/ruby/core/module/define_method_spec.rb b/spec/ruby/core/module/define_method_spec.rb index e04bb87ceb..c65b30de24 100644 --- a/spec/ruby/core/module/define_method_spec.rb +++ b/spec/ruby/core/module/define_method_spec.rb @@ -133,17 +133,6 @@ describe "Module#define_method when name is not a special private name" do klass.should have_public_instance_method(:baz) end end - - it "sets the method owner for a dynamically added method with a different original owner" do - mixin_module = Module.new do - def bar; end - end - - foo = Object.new - foo.singleton_class.define_method(:bar, mixin_module.instance_method(:bar)) - - foo.method(:bar).owner.should == foo.singleton_class - end end describe "passed a block" do @@ -230,55 +219,18 @@ describe "Module#define_method" do o.block_test2.should == o end - it "raises TypeError if name cannot converted to String" do - -> { - Class.new { define_method(1001, -> {}) } - }.should raise_error(TypeError, /is not a symbol nor a string/) - - -> { - Class.new { define_method([], -> {}) } - }.should raise_error(TypeError, /is not a symbol nor a string/) - end - - it "converts non-String name to String with #to_str" do - obj = Object.new - def obj.to_str() "foo" end - - new_class = Class.new { define_method(obj, -> { :called }) } - new_class.new.foo.should == :called - end - - it "raises TypeError when #to_str called on non-String name returns non-String value" do - obj = Object.new - def obj.to_str() [] end - - -> { - Class.new { define_method(obj, -> {}) } - }.should raise_error(TypeError, /can't convert Object to String/) - end - it "raises a TypeError when the given method is no Method/Proc" do -> { Class.new { define_method(:test, "self") } - }.should raise_error(TypeError, "wrong argument type String (expected Proc/Method/UnboundMethod)") + }.should raise_error(TypeError) -> { Class.new { define_method(:test, 1234) } - }.should raise_error(TypeError, "wrong argument type Integer (expected Proc/Method/UnboundMethod)") + }.should raise_error(TypeError) -> { Class.new { define_method(:test, nil) } - }.should raise_error(TypeError, "wrong argument type NilClass (expected Proc/Method/UnboundMethod)") - end - - it "uses provided Method/Proc even if block is specified" do - new_class = Class.new do - define_method(:test, -> { :method_is_called }) do - :block_is_called - end - end - - new_class.new.test.should == :method_is_called + }.should raise_error(TypeError) end it "raises an ArgumentError when no block is given" do @@ -499,33 +451,6 @@ describe "Module#define_method" do Class.new { define_method :bar, m } }.should raise_error(TypeError, /can't bind singleton method to a different class/) end - - it "defines a new method with public visibility when a Method passed and the class/module of the context isn't equal to the receiver of #define_method" do - c = Class.new do - private def foo - "public" - end - end - - object = c.new - object.singleton_class.define_method(:bar, object.method(:foo)) - - object.bar.should == "public" - end - - it "defines the new method according to the scope visibility when a Method passed and the class/module of the context is equal to the receiver of #define_method" do - c = Class.new do - def foo; end - end - - object = c.new - object.singleton_class.class_eval do - private - define_method(:bar, c.new.method(:foo)) - end - - -> { object.bar }.should raise_error(NoMethodError) - end end describe "Module#define_method" do @@ -724,7 +649,7 @@ describe "Module#define_method" do end end -describe "Module#define_method when passed a Method object" do +describe "Method#define_method when passed a Method object" do before :each do @klass = Class.new do def m(a, b, *c) @@ -749,7 +674,7 @@ describe "Module#define_method when passed a Method object" do end end -describe "Module#define_method when passed an UnboundMethod object" do +describe "Method#define_method when passed an UnboundMethod object" do before :each do @klass = Class.new do def m(a, b, *c) @@ -774,7 +699,7 @@ describe "Module#define_method when passed an UnboundMethod object" do end end -describe "Module#define_method when passed a Proc object" do +describe "Method#define_method when passed a Proc object" do describe "and a method is defined inside" do it "defines the nested method in the default definee where the Proc was created" do prc = nil @@ -799,7 +724,7 @@ describe "Module#define_method when passed a Proc object" do end end -describe "Module#define_method when passed a block" do +describe "Method#define_method when passed a block" do describe "behaves exactly like a lambda" do it "for return" do Class.new do diff --git a/spec/ruby/core/module/deprecate_constant_spec.rb b/spec/ruby/core/module/deprecate_constant_spec.rb index aabef934c4..faacbea03e 100644 --- a/spec/ruby/core/module/deprecate_constant_spec.rb +++ b/spec/ruby/core/module/deprecate_constant_spec.rb @@ -31,15 +31,17 @@ describe "Module#deprecate_constant" do -> { @module.const_get :PRIVATE }.should complain(/warning: constant .+::PRIVATE is 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 + 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 end end end diff --git a/spec/ruby/core/module/extend_object_spec.rb b/spec/ruby/core/module/extend_object_spec.rb index 1fd1abc0b5..e66b87efef 100644 --- a/spec/ruby/core/module/extend_object_spec.rb +++ b/spec/ruby/core/module/extend_object_spec.rb @@ -42,6 +42,20 @@ 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/fixtures/classes.rb b/spec/ruby/core/module/fixtures/classes.rb index a434e7b0b8..40777cdbbd 100644 --- a/spec/ruby/core/module/fixtures/classes.rb +++ b/spec/ruby/core/module/fixtures/classes.rb @@ -42,14 +42,6 @@ module ModuleSpecs class LookupChild < Lookup end - module ModuleWithPrepend - prepend LookupMod - end - - class WithPrependedModule - include ModuleWithPrepend - end - class Parent # For private_class_method spec def self.private_method; end @@ -360,10 +352,6 @@ module ModuleSpecs end end - class SubCVars < CVars - @@sub = :sub - end - module MVars @@mvar = :mvar end @@ -388,7 +376,6 @@ module ModuleSpecs # empty modules module M1; end module M2; end - module M3; end module Autoload def self.use_ex1 @@ -596,32 +583,6 @@ module ModuleSpecs private :foo end EmptyFooMethod = m.instance_method(:foo) - - # for undefined_instance_methods spec - module UndefinedInstanceMethods - module Super - def super_included_method; end - end - - class Parent - def undefed_method; end - undef_method :undefed_method - - def parent_method; end - def another_parent_method; end - end - - class Child < Parent - include Super - - undef_method :parent_method - undef_method :another_parent_method - end - - class Grandchild < Child - undef_method :super_included_method - end - end end class Object diff --git a/spec/ruby/core/module/fixtures/module.rb b/spec/ruby/core/module/fixtures/module.rb index 34543ca2b4..9050a272ec 100644 --- a/spec/ruby/core/module/fixtures/module.rb +++ b/spec/ruby/core/module/fixtures/module.rb @@ -1,8 +1,4 @@ module ModuleSpecs module Anonymous - module Child - end - - SameChild = Child end end diff --git a/spec/ruby/core/module/include_spec.rb b/spec/ruby/core/module/include_spec.rb index c073bc31ca..128b9af2bf 100644 --- a/spec/ruby/core/module/include_spec.rb +++ b/spec/ruby/core/module/include_spec.rb @@ -104,9 +104,9 @@ describe "Module#include" do class A; include M; end class B < A; include M; end - all = [A, B, M] + all = [A,B,M] - (B.ancestors.filter { |a| all.include?(a) }).should == [B, A, M] + (B.ancestors & all).should == [B, A, M] end end @@ -532,27 +532,6 @@ 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/included_modules_spec.rb b/spec/ruby/core/module/included_modules_spec.rb index ce94ed1285..40e20953f4 100644 --- a/spec/ruby/core/module/included_modules_spec.rb +++ b/spec/ruby/core/module/included_modules_spec.rb @@ -4,11 +4,9 @@ require_relative 'fixtures/classes' describe "Module#included_modules" do it "returns a list of modules included in self" do ModuleSpecs.included_modules.should == [] - ModuleSpecs::Child.included_modules.should include(ModuleSpecs::Super, ModuleSpecs::Basic, Kernel) ModuleSpecs::Parent.included_modules.should include(Kernel) ModuleSpecs::Basic.included_modules.should == [] ModuleSpecs::Super.included_modules.should include(ModuleSpecs::Basic) - ModuleSpecs::WithPrependedModule.included_modules.should include(ModuleSpecs::ModuleWithPrepend) end end diff --git a/spec/ruby/core/module/instance_method_spec.rb b/spec/ruby/core/module/instance_method_spec.rb index 8d006e647e..b4d6a0d8c8 100644 --- a/spec/ruby/core/module/instance_method_spec.rb +++ b/spec/ruby/core/module/instance_method_spec.rb @@ -45,46 +45,20 @@ describe "Module#instance_method" do @parent_um.inspect.should =~ /\bModuleSpecs::InstanceMeth\b/ @child_um.inspect.should =~ /\bfoo\b/ @child_um.inspect.should =~ /\bModuleSpecs::InstanceMeth\b/ - + @child_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/ @mod_um.inspect.should =~ /\bbar\b/ @mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethMod\b/ - - ruby_version_is ""..."3.2" do - @child_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/ - @mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/ - end + @mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/ end - it "raises a TypeError if the given name is not a String/Symbol" do - -> { Object.instance_method([]) }.should raise_error(TypeError, /is not a symbol nor a string/) - -> { Object.instance_method(0) }.should raise_error(TypeError, /is not a symbol nor a string/) - -> { Object.instance_method(nil) }.should raise_error(TypeError, /is not a symbol nor a string/) - -> { Object.instance_method(mock('x')) }.should raise_error(TypeError, /is not a symbol nor a string/) + it "raises a TypeError if not passed a symbol" do + -> { Object.instance_method([]) }.should raise_error(TypeError) + -> { Object.instance_method(0) }.should raise_error(TypeError) end - it "accepts String name argument" do - method = ModuleSpecs::InstanceMeth.instance_method(:foo) - method.should be_kind_of(UnboundMethod) - end - - it "accepts Symbol name argument" do - method = ModuleSpecs::InstanceMeth.instance_method("foo") - method.should be_kind_of(UnboundMethod) - end - - it "converts non-String name by calling #to_str method" do - obj = Object.new - def obj.to_str() "foo" end - - method = ModuleSpecs::InstanceMeth.instance_method(obj) - method.should be_kind_of(UnboundMethod) - end - - it "raises TypeError when passed non-String name and #to_str returns non-String value" do - obj = Object.new - def obj.to_str() [] end - - -> { ModuleSpecs::InstanceMeth.instance_method(obj) }.should raise_error(TypeError, /can't convert Object to String/) + it "raises a TypeError if the given name is not a string/symbol" do + -> { Object.instance_method(nil) }.should raise_error(TypeError) + -> { Object.instance_method(mock('x')) }.should raise_error(TypeError) end it "raises a NameError if the method has been undefined" do diff --git a/spec/ruby/core/module/method_added_spec.rb b/spec/ruby/core/module/method_added_spec.rb index ec92cddc1e..b983c8da76 100644 --- a/spec/ruby/core/module/method_added_spec.rb +++ b/spec/ruby/core/module/method_added_spec.rb @@ -2,10 +2,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "Module#method_added" do - before :each do - ScratchPad.record [] - end - it "is a private instance method" do Module.should have_private_instance_method(:method_added) end @@ -17,6 +13,8 @@ describe "Module#method_added" do end it "is called when a new instance method is defined in self" do + ScratchPad.record [] + Module.new do def self.method_added(name) ScratchPad << name @@ -34,6 +32,8 @@ describe "Module#method_added" do it "is not called when a singleton method is added" do # obj.singleton_method_added is called instead + ScratchPad.record [] + klass = Class.new def klass.method_added(name) ScratchPad << name @@ -60,71 +60,8 @@ describe "Module#method_added" do m.should_not have_method(:method_to_undef) end - it "is not called when a method changes visibility" do - Module.new do - def public_method - end - - def private_method - end - - def self.method_added(name) - ScratchPad << name - end - - public :public_method - private :public_method - - private :private_method - public :private_method - end - - ScratchPad.recorded.should == [] - end - - it "is called when using #private in a subclass" do - parent = Class.new do - def foo - end - end - - Class.new(parent) do - def self.method_added(name) - ScratchPad << name - end - - # Create an instance as that might initialize some method lookup caches, which is interesting to test - self.new.foo - - private :foo - public :foo - end - - ScratchPad.recorded.should == [:foo] - end - - it "is not called when a method is copied via module_function, rather #singleton_method_added is called" do - Module.new do - def mod_function - end - - def self.method_added(name) - ScratchPad << [:method_added, name] - end - - def self.singleton_method_added(name) - ScratchPad << [:singleton_method_added, name] - end - - ScratchPad.record [] - - module_function :mod_function - end - - ScratchPad.recorded.should == [[:singleton_method_added, :mod_function]] - end - it "is called with a precise caller location with the line of the 'def'" do + ScratchPad.record [] line = nil Module.new do diff --git a/spec/ruby/core/module/module_function_spec.rb b/spec/ruby/core/module/module_function_spec.rb index 1c3ec5471b..0602e95ca9 100644 --- a/spec/ruby/core/module/module_function_spec.rb +++ b/spec/ruby/core/module/module_function_spec.rb @@ -155,62 +155,15 @@ describe "Module#module_function with specific method names" do m.foo.should == ["m", "super_m"] end - - context "methods created with define_method" do - context "passed a block" do - it "creates duplicates of the given instance methods" do - m = Module.new do - define_method :test1 do; end - module_function :test1 - end - - m.respond_to?(:test1).should == true - end - end - - context "passed a method" do - it "creates duplicates of the given instance methods" do - module_with_method = Module.new do - def test1; end - end - - c = Class.new do - extend module_with_method - end - - m = Module.new do - define_method :test2, c.method(:test1) - module_function :test2 - end - - m.respond_to?(:test2).should == true - end - end - - context "passed an unbound method" do - it "creates duplicates of the given instance methods" do - module_with_method = Module.new do - def test1; end - end - - m = Module.new do - define_method :test2, module_with_method.instance_method(:test1) - module_function :test2 - end - - m.respond_to?(:test2).should == true - end - end - end end describe "Module#module_function as a toggle (no arguments) in a Module body" do it "makes any subsequently defined methods module functions with the normal semantics" do - m = Module.new do + m = Module.new { module_function def test1() end def test2() end - end + } m.respond_to?(:test1).should == true m.respond_to?(:test2).should == true @@ -234,13 +187,13 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do it "stops creating module functions if the body encounters another toggle " \ "like public/protected/private without arguments" do - m = Module.new do + m = Module.new { module_function def test1() end def test2() end public def test3() end - end + } m.respond_to?(:test1).should == true m.respond_to?(:test2).should == true @@ -249,14 +202,14 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do it "does not stop creating module functions if the body encounters " \ "public/protected/private WITH arguments" do - m = Module.new do + m = Module.new { def foo() end module_function def test1() end def test2() end public :foo def test3() end - end + } m.respond_to?(:test1).should == true m.respond_to?(:test2).should == true @@ -264,116 +217,69 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do end it "does not affect module_evaled method definitions also if outside the eval itself" do - m = Module.new do + m = Module.new { module_function module_eval { def test1() end } module_eval " def test2() end " - end + } m.respond_to?(:test1).should == false m.respond_to?(:test2).should == false end it "has no effect if inside a module_eval if the definitions are outside of it" do - m = Module.new do + m = Module.new { module_eval { module_function } def test1() end def test2() end - end + } m.respond_to?(:test1).should == false m.respond_to?(:test2).should == false end it "functions normally if both toggle and definitions inside a module_eval" do - m = Module.new do - module_eval do + m = Module.new { + module_eval { module_function def test1() end def test2() end - end - end + } + } m.respond_to?(:test1).should == true m.respond_to?(:test2).should == true end - it "affects eval'ed method definitions also even when outside the eval itself" do - m = Module.new do + it "affects evaled method definitions also even when outside the eval itself" do + m = Module.new { module_function eval "def test1() end" - end + } m.respond_to?(:test1).should == true end it "doesn't affect definitions when inside an eval even if the definitions are outside of it" do - m = Module.new do + m = Module.new { eval "module_function" def test1() end - end + } m.respond_to?(:test1).should == false end it "functions normally if both toggle and definitions inside a eval" do - m = Module.new do + m = Module.new { eval <<-CODE module_function def test1() end def test2() end CODE - end + } m.respond_to?(:test1).should == true m.respond_to?(:test2).should == true end - - context "methods are defined with define_method" do - context "passed a block" do - it "makes any subsequently defined methods module functions with the normal semantics" do - m = Module.new do - module_function - define_method :test1 do; end - end - - m.respond_to?(:test1).should == true - end - end - - context "passed a method" do - it "makes any subsequently defined methods module functions with the normal semantics" do - module_with_method = Module.new do - def test1; end - end - - c = Class.new do - extend module_with_method - end - - m = Module.new do - module_function - define_method :test2, c.method(:test1) - end - - m.respond_to?(:test2).should == true - end - end - - context "passed an unbound method" do - it "makes any subsequently defined methods module functions with the normal semantics" do - module_with_method = Module.new do - def test1; end - end - - m = Module.new do - module_function - define_method :test2, module_with_method.instance_method(:test1) - end - - m.respond_to?(:test2).should == true - end - end - end end diff --git a/spec/ruby/core/module/name_spec.rb b/spec/ruby/core/module/name_spec.rb index 0d1f4e24d5..ca9106a973 100644 --- a/spec/ruby/core/module/name_spec.rb +++ b/spec/ruby/core/module/name_spec.rb @@ -6,10 +6,20 @@ describe "Module#name" do Module.new.name.should be_nil end - it "is not nil when assigned to a constant in an anonymous module" do - m = Module.new - m::N = Module.new - m::N.name.should.end_with? '::N' + ruby_version_is ""..."3.0" do + it "is nil when assigned to a constant in an anonymous module" do + m = Module.new + m::N = Module.new + m::N.name.should be_nil + end + end + + ruby_version_is "3.0" do + it "is not nil when assigned to a constant in an anonymous module" do + m = Module.new + m::N = Module.new + m::N.name.should.end_with? '::N' + end end it "is not nil for a nested module created with the module keyword" do @@ -32,19 +42,6 @@ describe "Module#name" do m::N.name.should == "ModuleSpecs::Anonymous::WasAnnon" end - it "may be the repeated in different module objects" do - m = Module.new - n = Module.new - - suppress_warning do - ModuleSpecs::Anonymous::SameName = m - ModuleSpecs::Anonymous::SameName = n - end - - m.name.should == "ModuleSpecs::Anonymous::SameName" - n.name.should == "ModuleSpecs::Anonymous::SameName" - end - it "is set after it is removed from a constant" do module ModuleSpecs module ModuleToRemove @@ -72,18 +69,12 @@ describe "Module#name" do ModuleSpecs::Anonymous.name.should == "ModuleSpecs::Anonymous" end - it "is set when assigning to a constant (constant path matches outer module name)" do + it "is set when assigning to a constant" do m = Module.new ModuleSpecs::Anonymous::A = m m.name.should == "ModuleSpecs::Anonymous::A" end - it "is set when assigning to a constant (constant path does not match outer module name)" do - m = Module.new - ModuleSpecs::Anonymous::SameChild::A = m - m.name.should == "ModuleSpecs::Anonymous::Child::A" - end - it "is not modified when assigning to a new constant after it has been accessed" do m = Module.new ModuleSpecs::Anonymous::B = m @@ -120,33 +111,34 @@ describe "Module#name" do ModuleSpecs::NameEncoding.new.name.encoding.should == Encoding::UTF_8 end - it "is set when the anonymous outer module name is set (module in one single constant)" do + it "is set when the anonymous outer module name is set" do m = Module.new m::N = Module.new ModuleSpecs::Anonymous::E = m m::N.name.should == "ModuleSpecs::Anonymous::E::N" end - # https://bugs.ruby-lang.org/issues/19681 - it "is set when the anonymous outer module name is set (module in several constants)" do - m = Module.new - m::N = Module.new - m::O = m::N - ModuleSpecs::Anonymous::StoredInMultiplePlaces = m - valid_names = [ - "ModuleSpecs::Anonymous::StoredInMultiplePlaces::N", - "ModuleSpecs::Anonymous::StoredInMultiplePlaces::O" - ] - valid_names.should include(m::N.name) # You get one of the two, but you don't know which one. - 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" - it "returns a frozen String" do - ModuleSpecs.name.should.frozen? + ModuleSpecs.name.should == "ModuleSpecs" + end end - it "always returns the same String for a given Module" do - s1 = ModuleSpecs.name - s2 = ModuleSpecs.name - s1.should equal(s2) + 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 end end diff --git a/spec/ruby/core/module/prepend_features_spec.rb b/spec/ruby/core/module/prepend_features_spec.rb index 09c15c5c15..2d1fa713b7 100644 --- a/spec/ruby/core/module/prepend_features_spec.rb +++ b/spec/ruby/core/module/prepend_features_spec.rb @@ -28,6 +28,20 @@ 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 96598e7209..04cc27d472 100644 --- a/spec/ruby/core/module/prepend_spec.rb +++ b/spec/ruby/core/module/prepend_spec.rb @@ -499,17 +499,34 @@ describe "Module#prepend" do c.dup.new.should be_kind_of(m) end - it "uses only new module when dupping the module" do - m1 = Module.new { def calc(x) x end } - m2 = Module.new { prepend(m1) } - c1 = Class.new { prepend(m2) } - m2dup = m2.dup - m2dup.ancestors.should == [m1,m2dup] - c2 = Class.new { prepend(m2dup) } - c1.ancestors[0,3].should == [m1,m2,c1] - c1.new.should be_kind_of(m1) - c2.ancestors[0,3].should == [m1,m2dup,c2] - c2.new.should be_kind_of(m1) + ruby_version_is '0'...'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) } + c1 = Class.new { prepend(m2) } + m2dup = m2.dup + m2dup.ancestors.should == [m2dup,m1,m2] + c2 = Class.new { prepend(m2dup) } + c1.ancestors[0,3].should == [m1,m2,c1] + c1.new.should be_kind_of(m1) + c2.ancestors[0,4].should == [m2dup,m1,m2,c2] + c2.new.should be_kind_of(m1) + end + end + + ruby_version_is '3.0' do + it "uses only new module when dupping the module" do + m1 = Module.new { def calc(x) x end } + m2 = Module.new { prepend(m1) } + c1 = Class.new { prepend(m2) } + m2dup = m2.dup + m2dup.ancestors.should == [m1,m2dup] + c2 = Class.new { prepend(m2dup) } + c1.ancestors[0,3].should == [m1,m2,c1] + c1.new.should be_kind_of(m1) + c2.ancestors[0,3].should == [m1,m2dup,c2] + c2.new.should be_kind_of(m1) + end end it "depends on prepend_features to add the module" do @@ -594,18 +611,6 @@ describe "Module#prepend" do ScratchPad.recorded.should == [[:prepend_features, c], [:prepended, c]] end - it "prepends a module if it is included in a super class" do - module ModuleSpecs::M3 - module M; end - class A; include M; end - class B < A; prepend M; end - - all = [A, B, M] - - (B.ancestors.filter { |a| all.include?(a) }).should == [M, B, A, M] - end - end - it "detects cyclic prepends" do -> { module ModuleSpecs::P diff --git a/spec/ruby/core/module/private_class_method_spec.rb b/spec/ruby/core/module/private_class_method_spec.rb index f899c71a57..407779cccc 100644 --- a/spec/ruby/core/module/private_class_method_spec.rb +++ b/spec/ruby/core/module/private_class_method_spec.rb @@ -79,13 +79,15 @@ describe "Module#private_class_method" do end.should raise_error(NameError) end - context "when single argument is passed and is an array" do - it "sets the visibility of the given methods to private" do - c = Class.new do - def self.foo() "foo" end - private_class_method [:foo] + ruby_version_is "3.0" do + context "when single argument is passed and is an array" do + it "sets the visibility of the given methods to private" do + c = Class.new do + def self.foo() "foo" end + private_class_method [:foo] + end + -> { c.foo }.should raise_error(NoMethodError) end - -> { c.foo }.should raise_error(NoMethodError) end end end diff --git a/spec/ruby/core/module/public_class_method_spec.rb b/spec/ruby/core/module/public_class_method_spec.rb index 71b20acda5..b5d76e7b7a 100644 --- a/spec/ruby/core/module/public_class_method_spec.rb +++ b/spec/ruby/core/module/public_class_method_spec.rb @@ -78,17 +78,19 @@ describe "Module#public_class_method" do end.should raise_error(NameError) end - context "when single argument is passed and is an array" do - it "makes a class method public" do - c = Class.new do - class << self - private - def foo() "foo" end + ruby_version_is "3.0" do + context "when single argument is passed and is an array" do + it "makes a class method public" do + c = Class.new do + class << self + private + def foo() "foo" end + end + public_class_method [:foo] end - public_class_method [:foo] - end - c.foo.should == "foo" + c.foo.should == "foo" + end end end end diff --git a/spec/ruby/core/module/refine_spec.rb b/spec/ruby/core/module/refine_spec.rb index 11085c325b..f6751a42da 100644 --- a/spec/ruby/core/module/refine_spec.rb +++ b/spec/ruby/core/module/refine_spec.rb @@ -71,7 +71,7 @@ describe "Module#refine" do Module.new do refine("foo") {} end - end.should raise_error(TypeError, "wrong argument type String (expected Class or Module)") + end.should raise_error(TypeError) end it "accepts a module as argument" do @@ -243,30 +243,28 @@ describe "Module#refine" do result.should == "foo from singleton class" 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 + 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 - end + refinement = Module.new do + refine Integer do + include a 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' - end + result.should == 'Rational' end it "looks in later included modules of the refined module first" do @@ -518,55 +516,115 @@ describe "Module#refine" do result.should == "hello from refinement" end - it "is honored by Kernel#method" do - klass = Class.new - refinement = Module.new do - refine klass do - def foo; 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 end - end - result = nil - Module.new do - using refinement - result = klass.new.method(:foo).class + -> { + Module.new do + using refinement + klass.new.method(:foo) + end + }.should raise_error(NameError, /undefined method `foo'/) end - - result.should == Method end - it "is honored by Kernel#public_method" do - klass = Class.new - refinement = Module.new do - refine klass do - def foo; 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 - end - result = nil - Module.new do - using refinement - result = klass.new.public_method(:foo).class + result = nil + Module.new do + using refinement + result = klass.new.method(:foo).class + end + + result.should == Method 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 - result.should == Method + -> { + Module.new do + using refinement + klass.new.public_method(:foo) + end + }.should raise_error(NameError, /undefined method `foo'/) + end end - it "is honored by Kernel#instance_method" do - klass = Class.new - refinement = Module.new do - refine klass do - def foo; 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 + end + + result.should == Method end + end - result = nil - Module.new do - using refinement - result = klass.instance_method(:foo).class + 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'/) 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 == UnboundMethod + result = nil + Module.new do + using refinement + result = klass.instance_method(:foo).class + end + + result.should == UnboundMethod + end end it "is honored by Kernel#respond_to?" do diff --git a/spec/ruby/core/module/refinements_spec.rb b/spec/ruby/core/module/refinements_spec.rb deleted file mode 100644 index 5648fcbd6f..0000000000 --- a/spec/ruby/core/module/refinements_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -require_relative '../../spec_helper' - -describe "Module#refinements" do - ruby_version_is "3.2" do - it "returns refinements defined in a module" do - ScratchPad.record [] - - m = Module.new do - refine String do - ScratchPad << self - end - - refine Array do - ScratchPad << self - end - end - - m.refinements.sort_by(&:object_id).should == ScratchPad.recorded.sort_by(&:object_id) - end - - it "does not return refinements defined in the included module" do - ScratchPad.record [] - - m1 = Module.new do - refine Integer do - nil - end - end - - m2 = Module.new do - include m1 - - refine String do - ScratchPad << self - end - end - - m2.refinements.should == ScratchPad.recorded - end - - it "returns an empty array if no refinements defined in a module" do - Module.new.refinements.should == [] - end - end -end diff --git a/spec/ruby/core/module/ruby2_keywords_spec.rb b/spec/ruby/core/module/ruby2_keywords_spec.rb index a72612a670..34c45cb1bc 100644 --- a/spec/ruby/core/module/ruby2_keywords_spec.rb +++ b/spec/ruby/core/module/ruby2_keywords_spec.rb @@ -1,297 +1,112 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -describe "Module#ruby2_keywords" do - class << self - ruby2_keywords def mark(*args) - args - end - end - - 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 +ruby_version_is "2.7" do + describe "Module#ruby2_keywords" do + it "marks the final hash argument as keyword hash" do + obj = Object.new - 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 + 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 - h = {a: 1} + 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 + obj.singleton_class.class_exec do + ruby2_keywords :foo + end + + -> { obj.foo(1, 2, {a: "a"}) }.should_not complain end end - h = { a: 1 } - args = mark(**h) - marked = args.last - Hash.ruby2_keywords_hash?(marked).should == true + it "returns nil" do + obj = Object.new - 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.singleton_class.class_exec do + def foo(*a) end - 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 + ruby2_keywords(:foo).should == nil end end - 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 + it "raises NameError when passed not existing method name" do obj = Object.new - obj.singleton_class.class_exec do - def splat(*args) - args.last - end - - def splat1(arg, *args) - args.last - end - def proc_call(*args) - -> *a { a.last }.call(*args) + -> { + obj.singleton_class.class_exec do + ruby2_keywords :not_existing 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 + }.should raise_error(NameError, /undefined method `not_existing'/) end - end - 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 + it "acceps String as well" do obj = Object.new - obj.singleton_class.class_exec do - def splat(*args) - args.last - end - def splat1(arg, *args) - args.last - end - - def proc_call(*args) - -> *a { a.last }.call(*args) - end + obj.singleton_class.class_exec do + def foo(*a) a.last end + ruby2_keywords "foo" 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 + last = obj.foo(1, 2, a: "a") + Hash.ruby2_keywords_hash?(last).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 + it "raises TypeError when passed not Symbol or String" do + obj = Object.new - def baz(*a) a.last end - ruby2_keywords :baz - alias_method :bob, :baz + -> { + obj.singleton_class.class_exec do + ruby2_keywords Object.new + end + }.should raise_error(TypeError, /is not a symbol nor a string/) 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 - - 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 - - it "returns nil" do - obj = Object.new - - obj.singleton_class.class_exec do - def foo(*a) end + it "prints warning when a method does not accept argument splat" do + obj = Object.new + def obj.foo(a, b, c) end - ruby2_keywords(:foo).should == nil + -> { + obj.singleton_class.class_exec do + ruby2_keywords :foo + end + }.should complain(/Skipping set of ruby2_keywords flag for/) end - end - - it "raises NameError when passed not existing method name" do - obj = Object.new - -> { - obj.singleton_class.class_exec do - ruby2_keywords :not_existing - end - }.should raise_error(NameError, /undefined method `not_existing'/) - end - - it "accepts String as well" do - obj = Object.new + it "prints warning when a method accepts keywords" do + obj = Object.new + def obj.foo(a:, b:) end - obj.singleton_class.class_exec do - def foo(*a) a.last end - ruby2_keywords "foo" + -> { + obj.singleton_class.class_exec do + ruby2_keywords :foo + end + }.should complain(/Skipping set of ruby2_keywords flag for/) 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 + 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/) + -> { + obj.singleton_class.class_exec do + ruby2_keywords :foo + end + }.should complain(/Skipping set of ruby2_keywords flag for/) + end end end diff --git a/spec/ruby/core/module/set_temporary_name_spec.rb b/spec/ruby/core/module/set_temporary_name_spec.rb deleted file mode 100644 index f5886a3398..0000000000 --- a/spec/ruby/core/module/set_temporary_name_spec.rb +++ /dev/null @@ -1,68 +0,0 @@ -require_relative '../../spec_helper' - -ruby_version_is "3.3" do - describe "Module#set_temporary_name" do - it "can assign a temporary name" do - m = Module.new - m.name.should be_nil - - m.set_temporary_name("fake_name") - m.name.should == "fake_name" - - m.set_temporary_name(nil) - m.name.should be_nil - end - - it "can assign a temporary name which is not a valid constant path" do - m = Module.new - m.set_temporary_name("a::B") - m.name.should == "a::B" - - m.set_temporary_name("Template['foo.rb']") - m.name.should == "Template['foo.rb']" - end - - it "can't assign empty string as name" do - m = Module.new - -> { m.set_temporary_name("") }.should raise_error(ArgumentError, "empty class/module name") - end - - it "can't assign a constant name as a temporary name" do - m = Module.new - -> { m.set_temporary_name("Object") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion") - end - - it "can't assign a constant path as a temporary name" do - m = Module.new - -> { m.set_temporary_name("A::B") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion") - -> { m.set_temporary_name("::A") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion") - -> { m.set_temporary_name("::A::B") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion") - end - - it "can't assign name to permanent module" do - -> { Object.set_temporary_name("fake_name") }.should raise_error(RuntimeError, "can't change permanent name") - end - - it "can assign a temporary name to a nested module" do - m = Module.new - module m::N; end - m::N.name.should =~ /\A#<Module:0x\h+>::N\z/ - - m::N.set_temporary_name("fake_name") - m::N.name.should == "fake_name" - - m::N.set_temporary_name(nil) - m::N.name.should be_nil - end - - it "can update the name when assigned to a constant" do - m = Module.new - m::N = Module.new - m::N.name.should =~ /\A#<Module:0x\h+>::N\z/ - m::N.set_temporary_name(nil) - - m::M = m::N - m::M.name.should =~ /\A#<Module:0x\h+>::M\z/m - end - end -end diff --git a/spec/ruby/core/module/shared/class_eval.rb b/spec/ruby/core/module/shared/class_eval.rb index b1d5cb3814..224078ae54 100644 --- a/spec/ruby/core/module/shared/class_eval.rb +++ b/spec/ruby/core/module/shared/class_eval.rb @@ -52,58 +52,43 @@ describe :module_class_eval, shared: true do ModuleSpecs.send(@method, "[__FILE__, __LINE__]", "test", 102).should == ["test", 102] end - ruby_version_is "3.3" do - it "uses the caller location as default filename" do - ModuleSpecs.send(@method, "[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1] - end - end - it "converts a non-string filename to a string using to_str" do (file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__) ModuleSpecs.send(@method, "1+1", file) - - (file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__) - ModuleSpecs.send(@method, "1+1", file, 15) end it "raises a TypeError when the given filename can't be converted to string using to_str" do (file = mock('123')).should_receive(:to_str).and_return(123) - -> { ModuleSpecs.send(@method, "1+1", file) }.should raise_error(TypeError, /can't convert MockObject to String/) + -> { ModuleSpecs.send(@method, "1+1", file) }.should raise_error(TypeError) end it "converts non string eval-string to string using to_str" do (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1") ModuleSpecs.send(@method, o).should == 2 - - (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1") - ModuleSpecs.send(@method, o, "file.rb").should == 2 - - (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1") - ModuleSpecs.send(@method, o, "file.rb", 15).should == 2 end it "raises a TypeError when the given eval-string can't be converted to string using to_str" do o = mock('x') - -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, "no implicit conversion of MockObject into String") + -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError) (o = mock('123')).should_receive(:to_str).and_return(123) - -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, /can't convert MockObject to String/) + -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError) end it "raises an ArgumentError when no arguments and no block are given" do - -> { ModuleSpecs.send(@method) }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1..3)") + -> { ModuleSpecs.send(@method) }.should raise_error(ArgumentError) end it "raises an ArgumentError when more than 3 arguments are given" do -> { ModuleSpecs.send(@method, "1 + 1", "some file", 0, "bogus") - }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)") + }.should raise_error(ArgumentError) end it "raises an ArgumentError when a block and normal arguments are given" do -> { ModuleSpecs.send(@method, "1 + 1") { 1 + 1 } - }.should raise_error(ArgumentError, "wrong number of arguments (given 1, expected 0)") + }.should raise_error(ArgumentError) end # This case was found because Rubinius was caching the compiled diff --git a/spec/ruby/core/module/shared/set_visibility.rb b/spec/ruby/core/module/shared/set_visibility.rb index a1586dd2bd..9f31e230ca 100644 --- a/spec/ruby/core/module/shared/set_visibility.rb +++ b/spec/ruby/core/module/shared/set_visibility.rb @@ -22,19 +22,21 @@ describe :set_visibility, shared: true do end end - describe "array as a single argument" do - it "sets visibility of given method names" do - visibility = @method - old_visibility = [:protected, :private].find {|vis| vis != visibility } - - mod = Module.new { - send old_visibility - def test1() end - def test2() end - send visibility, [:test1, :test2] - } - mod.should send(:"have_#{visibility}_instance_method", :test1, false) - mod.should send(:"have_#{visibility}_instance_method", :test2, false) + ruby_version_is "3.0" do + describe "array as a single argument" do + it "sets visibility of given method names" do + visibility = @method + old_visibility = [:protected, :private].find {|vis| vis != visibility } + + mod = Module.new { + send old_visibility + def test1() end + def test2() end + send visibility, [:test1, :test2] + } + mod.should send(:"have_#{visibility}_instance_method", :test1, false) + mod.should send(:"have_#{visibility}_instance_method", :test2, false) + end end end diff --git a/spec/ruby/core/module/undefined_instance_methods_spec.rb b/spec/ruby/core/module/undefined_instance_methods_spec.rb deleted file mode 100644 index 3be860d053..0000000000 --- a/spec/ruby/core/module/undefined_instance_methods_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/classes' - -describe "Module#undefined_instance_methods" do - ruby_version_is "3.2" do - it "returns methods undefined in the class" do - methods = ModuleSpecs::UndefinedInstanceMethods::Parent.undefined_instance_methods - methods.should == [:undefed_method] - end - - it "returns inherited methods undefined in the class" do - methods = ModuleSpecs::UndefinedInstanceMethods::Child.undefined_instance_methods - methods.should include(:parent_method, :another_parent_method) - end - - it "returns methods from an included module that are undefined in the class" do - methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods - methods.should include(:super_included_method) - end - - it "does not returns ancestors undefined methods" do - methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods - methods.should_not include(:parent_method, :another_parent_method) - end - end -end diff --git a/spec/ruby/core/module/used_refinements_spec.rb b/spec/ruby/core/module/used_refinements_spec.rb deleted file mode 100644 index c16cab0e3c..0000000000 --- a/spec/ruby/core/module/used_refinements_spec.rb +++ /dev/null @@ -1,87 +0,0 @@ -require_relative '../../spec_helper' - -describe "Module.used_refinements" do - ruby_version_is "3.2" do - it "returns list of all refinements imported in the current scope" do - refinement_int = nil - refinement_str = nil - ScratchPad.record [] - - m1 = Module.new do - refine Integer do - refinement_int = self - end - end - - m2 = Module.new do - refine String do - refinement_str = self - end - end - - Module.new do - using m1 - using m2 - - Module.used_refinements.each { |r| ScratchPad << r } - end - - ScratchPad.recorded.sort_by(&:object_id).should == [refinement_int, refinement_str].sort_by(&:object_id) - end - - it "returns empty array if does not have any refinements imported" do - used_refinements = nil - - Module.new do - used_refinements = Module.used_refinements - end - - used_refinements.should == [] - end - - it "ignores refinements imported in a module that is included into the current one" do - used_refinements = nil - - m1 = Module.new do - refine Integer do - nil - end - end - - m2 = Module.new do - using m1 - end - - Module.new do - include m2 - - used_refinements = Module.used_refinements - end - - used_refinements.should == [] - end - - it "returns refinements even not defined directly in a module refinements are imported from" do - used_refinements = nil - ScratchPad.record [] - - m1 = Module.new do - refine Integer do - ScratchPad << self - end - end - - m2 = Module.new do - include m1 - end - - Module.new do - using m2 - - used_refinements = Module.used_refinements - end - - used_refinements.should == ScratchPad.recorded - end - end -end diff --git a/spec/ruby/core/mutex/lock_spec.rb b/spec/ruby/core/mutex/lock_spec.rb index e9d33f5fd9..7a39817b11 100644 --- a/spec/ruby/core/mutex/lock_spec.rb +++ b/spec/ruby/core/mutex/lock_spec.rb @@ -1,6 +1,10 @@ require_relative '../../spec_helper' describe "Mutex#lock" do + before :each do + ScratchPad.clear + end + it "returns self" do m = Mutex.new m.lock.should == m diff --git a/spec/ruby/core/mutex/owned_spec.rb b/spec/ruby/core/mutex/owned_spec.rb index 7bfc7d8f83..1f843cd576 100644 --- a/spec/ruby/core/mutex/owned_spec.rb +++ b/spec/ruby/core/mutex/owned_spec.rb @@ -41,13 +41,15 @@ describe "Mutex#owned?" do end end - it "is held per Fiber" do - m = Mutex.new - m.lock - - Fiber.new do - m.locked?.should == true - m.owned?.should == false - end.resume + ruby_version_is "3.0" do + it "is held per Fiber" do + m = Mutex.new + m.lock + + Fiber.new do + m.locked?.should == true + m.owned?.should == false + end.resume + end end end diff --git a/spec/ruby/core/nil/match_spec.rb b/spec/ruby/core/nil/match_spec.rb index bc1c591793..2e2b5d1c1b 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 = nil + o = Object.new suppress_warning do (o =~ /Object/).should be_nil diff --git a/spec/ruby/core/nil/singleton_method_spec.rb b/spec/ruby/core/nil/singleton_method_spec.rb deleted file mode 100644 index 8d898b1cc9..0000000000 --- a/spec/ruby/core/nil/singleton_method_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative '../../spec_helper' - -describe "NilClass#singleton_method" do - ruby_version_is '3.3' do - it "raises regardless of whether NilClass defines the method" do - -> { nil.singleton_method(:foo) }.should raise_error(NameError) - begin - def (nil).foo; end - -> { nil.singleton_method(:foo) }.should raise_error(NameError) - ensure - NilClass.send(:remove_method, :foo) - end - end - end -end diff --git a/spec/ruby/core/nil/to_s_spec.rb b/spec/ruby/core/nil/to_s_spec.rb index fa0b929677..283d26477a 100644 --- a/spec/ruby/core/nil/to_s_spec.rb +++ b/spec/ruby/core/nil/to_s_spec.rb @@ -5,11 +5,13 @@ describe "NilClass#to_s" do nil.to_s.should == "" end - it "returns a frozen string" do - nil.to_s.should.frozen? - end + ruby_version_is "2.7" do + 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) + it "always returns the same string" do + nil.to_s.should equal(nil.to_s) + end end end diff --git a/spec/ruby/core/numeric/clone_spec.rb b/spec/ruby/core/numeric/clone_spec.rb index 423cec85dd..c3b06ca0c9 100644 --- a/spec/ruby/core/numeric/clone_spec.rb +++ b/spec/ruby/core/numeric/clone_spec.rb @@ -14,7 +14,7 @@ describe "Numeric#clone" do 1.clone.frozen?.should == true end - it "accepts optional keyword argument :freeze" do + it "accepts optonal keyword argument :freeze" do value = 1 value.clone(freeze: true).should equal(value) end @@ -23,8 +23,10 @@ describe "Numeric#clone" do -> { 1.clone(freeze: false) }.should raise_error(ArgumentError, /can't unfreeze/) end - it "does not change frozen status if passed freeze: nil" do - value = 1 - value.clone(freeze: nil).should equal(value) + ruby_version_is "3.0" do + it "does not change frozen status if passed freeze: nil" do + value = 1 + value.clone(freeze: nil).should equal(value) + end end end diff --git a/spec/ruby/core/numeric/fdiv_spec.rb b/spec/ruby/core/numeric/fdiv_spec.rb index e97fa77f79..907e5d343c 100644 --- a/spec/ruby/core/numeric/fdiv_spec.rb +++ b/spec/ruby/core/numeric/fdiv_spec.rb @@ -1,4 +1,5 @@ require_relative '../../spec_helper' +require_relative 'shared/quo' describe "Numeric#fdiv" do it "coerces self with #to_f" do diff --git a/spec/ruby/core/numeric/magnitude_spec.rb b/spec/ruby/core/numeric/magnitude_spec.rb index 1371dff21f..7a3290b036 100644 --- a/spec/ruby/core/numeric/magnitude_spec.rb +++ b/spec/ruby/core/numeric/magnitude_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative 'shared/abs' describe "Numeric#magnitude" do diff --git a/spec/ruby/core/numeric/quo_spec.rb b/spec/ruby/core/numeric/quo_spec.rb index 6e3ce7a374..b4a23fd476 100644 --- a/spec/ruby/core/numeric/quo_spec.rb +++ b/spec/ruby/core/numeric/quo_spec.rb @@ -1,5 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' +require_relative 'shared/quo' describe "Numeric#quo" do it "returns the result of self divided by the given Integer as a Rational" do @@ -19,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/remainder_spec.rb b/spec/ruby/core/numeric/remainder_spec.rb index 674fa22d8e..1e2f5f3a96 100644 --- a/spec/ruby/core/numeric/remainder_spec.rb +++ b/spec/ruby/core/numeric/remainder_spec.rb @@ -6,9 +6,6 @@ describe "Numeric#remainder" do @obj = NumericSpecs::Subclass.new @result = mock("Numeric#% result") @other = mock("Passed Object") - ruby_version_is "3.3" do - @other.should_receive(:coerce).with(@obj).and_return([@obj, @other]) - end end it "returns the result of calling self#% with other if self is 0" do diff --git a/spec/ruby/core/numeric/shared/quo.rb b/spec/ruby/core/numeric/shared/quo.rb new file mode 100644 index 0000000000..2392636fe7 --- /dev/null +++ b/spec/ruby/core/numeric/shared/quo.rb @@ -0,0 +1,7 @@ +describe :numeric_quo_18, shared: true do + it "returns the result of calling self#/ with other" do + obj = mock_numeric('numeric') + obj.should_receive(:/).with(19).and_return(:result) + obj.send(@method, 19).should == :result + end +end diff --git a/spec/ruby/core/numeric/shared/step.rb b/spec/ruby/core/numeric/shared/step.rb index 977ec6de02..a4fe74f9db 100644 --- a/spec/ruby/core/numeric/shared/step.rb +++ b/spec/ruby/core/numeric/shared/step.rb @@ -5,7 +5,7 @@ require_relative '../fixtures/classes' # To be able to do it, the @step ivar must contain a Proc that transforms # the step call arguments passed as positional arguments to the style of # arguments pretended to test. -describe :numeric_step, shared: true do +describe :numeric_step, :shared => true do before :each do ScratchPad.record [] @prc = -> x { ScratchPad << x } @@ -256,8 +256,15 @@ 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 + it "returns an #{step_enum_class} when step is 0" do + @step.call(1, 2, 0).should be_an_instance_of(step_enum_class) + end + end + it "returns an #{step_enum_class} when not passed a block and self > stop" do @step.call(1, 0, 2).should be_an_instance_of(step_enum_class) end diff --git a/spec/ruby/core/numeric/step_spec.rb b/spec/ruby/core/numeric/step_spec.rb index 1705fb1b4e..03af8b0e4d 100644 --- a/spec/ruby/core/numeric/step_spec.rb +++ b/spec/ruby/core/numeric/step_spec.rb @@ -21,10 +21,33 @@ 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 + it "returns an #{step_enum_class} when step is 0" do + 1.step(5, 0).should be_an_instance_of(step_enum_class) + end + + it "returns an #{step_enum_class} when step is 0.0" do + 1.step(2, 0.0).should be_an_instance_of(step_enum_class) + end + end + describe "returned #{step_enum_class}" do describe "size" do + ruby_version_is ""..."3.0" do + it "is infinity when step is 0" do + enum = 1.step(5, 0) + enum.size.should == Float::INFINITY + end + + it "is infinity when step is 0.0" do + enum = 1.step(2, 0.0) + enum.size.should == Float::INFINITY + end + end + it "defaults to an infinite size" do enum = 1.step enum.size.should == Float::INFINITY @@ -38,9 +61,26 @@ describe "Numeric#step" do end end end + end describe 'with keyword arguments' do + ruby_version_is ""..."3.0" do + it "doesn't raise an error when step is 0" do + -> { 1.step(to: 5, by: 0) { break } }.should_not raise_error + end + + it "doesn't raise an error when step is 0.0" do + -> { 1.step(to: 2, by: 0.0) { break } }.should_not raise_error + end + + it "should loop over self when step is 0 or 0.0" do + 1.step(to: 2, by: 0.0).take(5).should eql [1.0, 1.0, 1.0, 1.0, 1.0] + 1.step(to: 2, by: 0).take(5).should eql [1, 1, 1, 1, 1] + 1.1.step(to: 2, by: 0).take(5).should eql [1.1, 1.1, 1.1, 1.1, 1.1] + end + end + describe "when no block is given" do describe "returned Enumerator" do describe "size" do @@ -48,6 +88,16 @@ describe "Numeric#step" do 1.step(by: 42).size.should == infinity_value end + ruby_version_is ""..."3.0" do + it "should return infinity_value when step is 0" do + 1.step(to: 5, by: 0).size.should == infinity_value + end + + it "should return infinity_value when step is 0.0" do + 1.step(to: 2, by: 0.0).size.should == infinity_value + end + end + it "should return infinity_value when ascending towards a limit of Float::INFINITY" do 1.step(to: Float::INFINITY, by: 42).size.should == infinity_value end @@ -80,12 +130,24 @@ describe "Numeric#step" do end describe 'with mixed arguments' do - it " raises an ArgumentError when step is 0" do - -> { 1.step(5, by: 0) { break } }.should raise_error(ArgumentError) + ruby_version_is ""..."3.0" do + it "doesn't raise an error when step is 0" do + -> { 1.step(5, by: 0) { break } }.should_not raise_error + end + + it "doesn't raise an error when step is 0.0" do + -> { 1.step(2, by: 0.0) { break } }.should_not raise_error + end end - it "raises an ArgumentError when step is 0.0" do - -> { 1.step(2, by: 0.0) { break } }.should raise_error(ArgumentError) + ruby_version_is "3.0" do + it " raises an ArgumentError when step is 0" do + -> { 1.step(5, by: 0) { break } }.should raise_error(ArgumentError) + end + + it "raises an ArgumentError when step is 0.0" do + -> { 1.step(2, by: 0.0) { break } }.should raise_error(ArgumentError) + end end it "raises a ArgumentError when limit and to are defined" do @@ -96,9 +158,26 @@ describe "Numeric#step" do -> { 1.step(5, 1, by: 5) { break } }.should raise_error(ArgumentError) end + ruby_version_is ""..."3.0" do + it "should loop over self when step is 0 or 0.0" do + 1.step(2, by: 0.0).take(5).should eql [1.0, 1.0, 1.0, 1.0, 1.0] + 1.step(2, by: 0).take(5).should eql [1, 1, 1, 1, 1] + 1.1.step(2, by: 0).take(5).should eql [1.1, 1.1, 1.1, 1.1, 1.1] + end + end + describe "when no block is given" do describe "returned Enumerator" do describe "size" do + ruby_version_is ""..."3.0" do + it "should return infinity_value when step is 0" do + 1.step(5, by: 0).size.should == infinity_value + end + + it "should return infinity_value when step is 0.0" do + 1.step(2, by: 0.0).size.should == infinity_value + end + end end end end diff --git a/spec/ruby/core/objectspace/define_finalizer_spec.rb b/spec/ruby/core/objectspace/define_finalizer_spec.rb index 6be83e518e..281785b0a4 100644 --- a/spec/ruby/core/objectspace/define_finalizer_spec.rb +++ b/spec/ruby/core/objectspace/define_finalizer_spec.rb @@ -60,53 +60,55 @@ describe "ObjectSpace.define_finalizer" do ruby_exe(code, :args => "2>&1").should include("finalizer run\n") end - it "warns if the finalizer has the object as the receiver" do - code = <<-RUBY - class CapturesSelf - def initialize - ObjectSpace.define_finalizer(self, proc { - puts "finalizer run" - }) + ruby_version_is "3.0" do + it "warns if the finalizer has the object as the receiver" do + code = <<-RUBY + class CapturesSelf + def initialize + ObjectSpace.define_finalizer(self, proc { + puts "finalizer run" + }) + end end - end - CapturesSelf.new - exit 0 - RUBY + CapturesSelf.new + exit 0 + RUBY - ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n") - end + ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n") + end - it "warns if the finalizer is a method bound to the receiver" do - code = <<-RUBY - class CapturesSelf - def initialize - ObjectSpace.define_finalizer(self, method(:finalize)) - end - def finalize(id) - puts "finalizer run" + it "warns if the finalizer is a method bound to the receiver" do + code = <<-RUBY + class CapturesSelf + def initialize + ObjectSpace.define_finalizer(self, method(:finalize)) + end + def finalize(id) + puts "finalizer run" + end end - end - CapturesSelf.new - exit 0 - RUBY + CapturesSelf.new + exit 0 + RUBY - ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n") - end + ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n") + end - it "warns if the finalizer was a block in the receiver" do - code = <<-RUBY - class CapturesSelf - def initialize - ObjectSpace.define_finalizer(self) do - puts "finalizer run" + it "warns if the finalizer was a block in the receiver" do + code = <<-RUBY + class CapturesSelf + def initialize + ObjectSpace.define_finalizer(self) do + puts "finalizer run" + end end end - end - CapturesSelf.new - exit 0 - RUBY + CapturesSelf.new + exit 0 + RUBY - ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n") + ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n") + end end it "calls a finalizer at exit even if it is self-referencing" do @@ -167,26 +169,4 @@ describe "ObjectSpace.define_finalizer" do ruby_exe(code).lines.sort.should == ["finalized1\n", "finalized2\n"] end - - ruby_version_is "3.1" do - describe "when $VERBOSE is not nil" do - it "warns if an exception is raised in finalizer" do - code = <<-RUBY - ObjectSpace.define_finalizer(Object.new) { raise "finalizing" } - RUBY - - ruby_exe(code, args: "2>&1").should include("warning: Exception in finalizer", "finalizing") - end - end - - describe "when $VERBOSE is nil" do - it "does not warn even if an exception is raised in finalizer" do - code = <<-RUBY - ObjectSpace.define_finalizer(Object.new) { raise "finalizing" } - RUBY - - ruby_exe(code, args: "2>&1", options: "-W0").should == "" - end - end - end end diff --git a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb deleted file mode 100644 index 6e534b8ea8..0000000000 --- a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -require_relative '../../../spec_helper' - -ruby_version_is '3.3' do - describe "ObjectSpace::WeakKeyMap#delete" do - it "removes the entry and returns the deleted value" do - m = ObjectSpace::WeakKeyMap.new - key = Object.new - value = Object.new - m[key] = value - - m.delete(key).should == value - m.key?(key).should == false - end - - it "uses equality semantic" do - m = ObjectSpace::WeakKeyMap.new - key = "foo".upcase - value = Object.new - m[key] = value - - m.delete("foo".upcase).should == value - m.key?(key).should == false - end - - it "calls supplied block if the key is not found" do - key = Object.new - m = ObjectSpace::WeakKeyMap.new - return_value = m.delete(key) do |yielded_key| - yielded_key.should == key - 5 - end - return_value.should == 5 - end - - it "returns nil if the key is not found when no block is given" do - m = ObjectSpace::WeakMap.new - m.delete(Object.new).should == nil - end - end -end diff --git a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb deleted file mode 100644 index 862480cd02..0000000000 --- a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -require_relative '../../../spec_helper' - -ruby_version_is "3.3" do - describe "ObjectSpace::WeakKeyMap#[]" do - it "is faithful to the map's content" do - map = ObjectSpace::WeakKeyMap.new - key1, key2 = %w[a b].map(&:upcase) - ref1, ref2 = %w[x y] - map[key1] = ref1 - map[key1].should == ref1 - map[key1] = ref1 - map[key1].should == ref1 - map[key2] = ref2 - map[key1].should == ref1 - map[key2].should == ref2 - end - - it "matches using equality semantics" do - map = ObjectSpace::WeakKeyMap.new - key1, key2 = %w[a a].map(&:upcase) - ref = "x" - map[key1] = ref - map[key2].should == ref - end - end -end diff --git a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb deleted file mode 100644 index 689509d820..0000000000 --- a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb +++ /dev/null @@ -1,71 +0,0 @@ -require_relative '../../../spec_helper' - -ruby_version_is "3.3" do - describe "ObjectSpace::WeakKeyMap#[]=" do - def should_accept(map, key, value) - (map[key] = value).should == value - map.should.key?(key) - map[key].should == value - end - - def should_not_accept(map, key, value) - -> { map[key] = value }.should raise_error(ArgumentError) - end - - it "is correct" do - map = ObjectSpace::WeakKeyMap.new - key1, key2 = %w[a b].map(&:upcase) - ref1, ref2 = %w[x y] - should_accept(map, key1, ref1) - should_accept(map, key1, ref1) - should_accept(map, key2, ref2) - map[key1].should == ref1 - end - - it "requires the keys to implement #hash" do - map = ObjectSpace::WeakKeyMap.new - -> { map[BasicObject.new] = 1 }.should raise_error(NoMethodError, "undefined method `hash' for an instance of BasicObject") - end - - it "accepts frozen keys or values" do - map = ObjectSpace::WeakKeyMap.new - x = Object.new - 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 - - it "rejects symbols as keys" do - map = ObjectSpace::WeakKeyMap.new - should_not_accept(map, :foo, true) - should_not_accept(map, rand.to_s.to_sym, true) - end - - it "rejects integers as keys" do - map = ObjectSpace::WeakKeyMap.new - should_not_accept(map, 42, true) - should_not_accept(map, 2 ** 68, true) - end - - it "rejects floats as keys" do - map = ObjectSpace::WeakKeyMap.new - should_not_accept(map, 4.2, true) - end - - it "rejects booleans as keys" do - map = ObjectSpace::WeakKeyMap.new - should_not_accept(map, true, true) - should_not_accept(map, false, true) - end - - it "rejects nil as keys" do - map = ObjectSpace::WeakKeyMap.new - should_not_accept(map, nil, true) - end - end -end diff --git a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb deleted file mode 100644 index 3af0186f27..0000000000 --- a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb +++ /dev/null @@ -1,14 +0,0 @@ -require_relative '../../../spec_helper' - -ruby_version_is "3.3" do - describe "ObjectSpace::WeakKeyMap#getkey" do - it "returns the existing equal key" do - map = ObjectSpace::WeakKeyMap.new - key1, key2 = %w[a a].map(&:upcase) - - map[key1] = true - map.getkey(key2).should equal(key1) - map.getkey("X").should == nil - end - end -end diff --git a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb deleted file mode 100644 index 557fbc8733..0000000000 --- a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -require_relative '../../../spec_helper' - -ruby_version_is "3.3" do - describe "ObjectSpace::WeakKeyMap#inspect" do - it "only displays size in output" do - map = ObjectSpace::WeakKeyMap.new - key1, key2, key3 = "foo", "bar", "bar" - map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=0>\z/ - map[key1] = 1 - map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=1>\z/ - map[key2] = 2 - map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/ - map[key3] = 3 - map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/ - end - end -end diff --git a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb deleted file mode 100644 index 2af9c2b8e7..0000000000 --- a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb +++ /dev/null @@ -1,33 +0,0 @@ -require_relative '../../../spec_helper' - -ruby_version_is "3.3" do - describe "ObjectSpace::WeakKeyMap#key?" do - it "recognizes keys in use" do - map = ObjectSpace::WeakKeyMap.new - key1, key2 = %w[a b].map(&:upcase) - ref1, ref2 = %w[x y] - - map[key1] = ref1 - map.key?(key1).should == true - map[key1] = ref1 - map.key?(key1).should == true - map[key2] = ref2 - map.key?(key2).should == true - end - - it "matches using equality semantics" do - map = ObjectSpace::WeakKeyMap.new - key1, key2 = %w[a a].map(&:upcase) - ref = "x" - map[key1] = ref - map.key?(key2).should == true - end - - it "reports true if the pair exists and the value is nil" do - map = ObjectSpace::WeakKeyMap.new - key = Object.new - map[key] = nil - map.key?(key).should == true - end - end -end diff --git a/spec/ruby/core/objectspace/weakmap/delete_spec.rb b/spec/ruby/core/objectspace/weakmap/delete_spec.rb deleted file mode 100644 index 302de264fb..0000000000 --- a/spec/ruby/core/objectspace/weakmap/delete_spec.rb +++ /dev/null @@ -1,30 +0,0 @@ -require_relative '../../../spec_helper' - -ruby_version_is '3.3' do - describe "ObjectSpace::WeakMap#delete" do - it "removes the entry and returns the deleted value" do - m = ObjectSpace::WeakMap.new - key = Object.new - value = Object.new - m[key] = value - - m.delete(key).should == value - m.key?(key).should == false - end - - it "calls supplied block if the key is not found" do - key = Object.new - m = ObjectSpace::WeakMap.new - return_value = m.delete(key) do |yielded_key| - yielded_key.should == key - 5 - end - return_value.should == 5 - end - - it "returns nil if the key is not found when no block is given" do - m = ObjectSpace::WeakMap.new - m.delete(Object.new).should == nil - end - end -end diff --git a/spec/ruby/core/objectspace/weakmap/element_set_spec.rb b/spec/ruby/core/objectspace/weakmap/element_set_spec.rb index 8588877158..2b53650148 100644 --- a/spec/ruby/core/objectspace/weakmap/element_set_spec.rb +++ b/spec/ruby/core/objectspace/weakmap/element_set_spec.rb @@ -17,22 +17,45 @@ describe "ObjectSpace::WeakMap#[]=" do map[key1].should == ref1 end - 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) + 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) - 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) + y = Object.new.freeze + should_accept(map, x, y) + should_accept(map, y, x) + end end end diff --git a/spec/ruby/core/objectspace/weakmap/shared/include.rb b/spec/ruby/core/objectspace/weakmap/shared/include.rb index 1770eeac8b..f9c174b6d1 100644 --- a/spec/ruby/core/objectspace/weakmap/shared/include.rb +++ b/spec/ruby/core/objectspace/weakmap/shared/include.rb @@ -20,11 +20,15 @@ describe :weakmap_include?, shared: true do map.send(@method, key2).should == false 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 + 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 end end diff --git a/spec/ruby/core/proc/block_pass_spec.rb b/spec/ruby/core/proc/block_pass_spec.rb index 411c0bf3db..99255139d4 100644 --- a/spec/ruby/core/proc/block_pass_spec.rb +++ b/spec/ruby/core/proc/block_pass_spec.rb @@ -19,3 +19,25 @@ 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/clone_spec.rb b/spec/ruby/core/proc/clone_spec.rb index 7eca9c561e..a1a1292654 100644 --- a/spec/ruby/core/proc/clone_spec.rb +++ b/spec/ruby/core/proc/clone_spec.rb @@ -3,13 +3,4 @@ require_relative 'shared/dup' describe "Proc#clone" do it_behaves_like :proc_dup, :clone - - ruby_bug "cloning a frozen proc is broken on Ruby 3.3", "3.3"..."3.4" do - it "preserves frozen status" do - proc = Proc.new { } - proc.freeze - proc.frozen?.should == true - proc.clone.frozen?.should == true - end - end end diff --git a/spec/ruby/core/proc/compose_spec.rb b/spec/ruby/core/proc/compose_spec.rb index 9e9b57e06f..803a32af7b 100644 --- a/spec/ruby/core/proc/compose_spec.rb +++ b/spec/ruby/core/proc/compose_spec.rb @@ -37,22 +37,34 @@ describe "Proc#<<" do (f << g).should_not.lambda? end - it "is a lambda when parameter is lambda" do - f = -> x { x * x } - g = proc { |x| x + x } - lambda_proc = -> x { x } - - # lambda << proc - (f << g).is_a?(Proc).should == true - (f << g).should_not.lambda? + ruby_version_is(''...'3.0') do + it "is a Proc when other is lambda" do + f = proc { |x| x * x } + g = -> x { x + x } + + (f << g).is_a?(Proc).should == true + (f << g).should_not.lambda? + end + + it "is a lambda when self is lambda" do + f = -> x { x * x } + g = proc { |x| x + x } + + (f << g).is_a?(Proc).should == true + (f << g).should.lambda? + end + end - # lambda << lambda - (f << lambda_proc).is_a?(Proc).should == true - (f << lambda_proc).should.lambda? + ruby_version_is('3.0') do + it "is a lambda when parameter is lambda" do + f = -> x { x * x } + g = proc { |x| x + x } + lambda_proc = -> x { x } - # proc << lambda - (g << f).is_a?(Proc).should == true - (g << f).should.lambda? + (f << g).is_a?(Proc).should == true + (f << g).should_not.lambda? + (f << lambda_proc).should.lambda? + end end it "may accept multiple arguments" do diff --git a/spec/ruby/core/proc/dup_spec.rb b/spec/ruby/core/proc/dup_spec.rb index dd19b3c1e9..6da2f3080c 100644 --- a/spec/ruby/core/proc/dup_spec.rb +++ b/spec/ruby/core/proc/dup_spec.rb @@ -3,11 +3,4 @@ require_relative 'shared/dup' describe "Proc#dup" do it_behaves_like :proc_dup, :dup - - it "resets frozen status" do - proc = Proc.new { } - proc.freeze - proc.frozen?.should == true - proc.dup.frozen?.should == false - end end diff --git a/spec/ruby/core/proc/eql_spec.rb b/spec/ruby/core/proc/eql_spec.rb index ad8f6749fc..5f38af72d9 100644 --- a/spec/ruby/core/proc/eql_spec.rb +++ b/spec/ruby/core/proc/eql_spec.rb @@ -2,5 +2,11 @@ require_relative '../../spec_helper' require_relative 'shared/equal' describe "Proc#eql?" do - it_behaves_like :proc_equal, :eql? + ruby_version_is "0"..."3.0" do + it_behaves_like :proc_equal_undefined, :eql? + end + + ruby_version_is "3.0" do + it_behaves_like :proc_equal, :eql? + end end diff --git a/spec/ruby/core/proc/equal_value_spec.rb b/spec/ruby/core/proc/equal_value_spec.rb index ec7f274732..4c336331d7 100644 --- a/spec/ruby/core/proc/equal_value_spec.rb +++ b/spec/ruby/core/proc/equal_value_spec.rb @@ -2,5 +2,11 @@ require_relative '../../spec_helper' require_relative 'shared/equal' describe "Proc#==" do - it_behaves_like :proc_equal, :== + ruby_version_is "0"..."3.0" do + it_behaves_like :proc_equal_undefined, :== + end + + ruby_version_is "3.0" do + it_behaves_like :proc_equal, :== + end end diff --git a/spec/ruby/core/proc/lambda_spec.rb b/spec/ruby/core/proc/lambda_spec.rb index 5c3c38fc2a..b2d3f50350 100644 --- a/spec/ruby/core/proc/lambda_spec.rb +++ b/spec/ruby/core/proc/lambda_spec.rb @@ -14,11 +14,9 @@ describe "Proc#lambda?" do Proc.new {}.lambda?.should be_false end - ruby_version_is ""..."3.3" do - it "is preserved when passing a Proc with & to the lambda keyword" do - suppress_warning {lambda(&->{})}.lambda?.should be_true - suppress_warning {lambda(&proc{})}.lambda?.should be_false - end + it "is preserved when passing a Proc with & to the lambda keyword" do + suppress_warning {lambda(&->{})}.lambda?.should be_true + suppress_warning {lambda(&proc{})}.lambda?.should be_false end it "is preserved when passing a Proc with & to the proc keyword" do diff --git a/spec/ruby/core/proc/new_spec.rb b/spec/ruby/core/proc/new_spec.rb index b2b7387756..6d5eb67a4b 100644 --- a/spec/ruby/core/proc/new_spec.rb +++ b/spec/ruby/core/proc/new_spec.rb @@ -94,6 +94,20 @@ 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 @@ -166,13 +180,59 @@ describe "Proc.new without a block" do -> { ProcSpecs.new_proc_subclass_in_method }.should raise_error(ArgumentError) end - it "raises an ArgumentError when passed no block" do - def some_method - Proc.new + 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 - -> { ProcSpecs.new_proc_in_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block') - -> { ProcSpecs.new_proc_subclass_in_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block') - -> { some_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block') + 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 + 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 + + it "can be created if invoked on a subclass from within a method with a block" do + -> { ProcSpecs.new_proc_subclass_in_method { "hello" } }.should complain(/Capturing the given block using Proc.new is deprecated/) + end + + + it "can be create when called with no block" do + def some_method + Proc.new + end + + -> { + some_method { "hello" } + }.should complain(/Capturing the given block using Proc.new is deprecated/) + end + end + + ruby_version_is "3.0" do + it "raises an ArgumentError when passed no block" do + def some_method + Proc.new + end + + -> { ProcSpecs.new_proc_in_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block') + -> { ProcSpecs.new_proc_subclass_in_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block') + -> { some_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block') + end end end diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb index 2a4dcc36b3..5fb5cf418d 100644 --- a/spec/ruby/core/proc/parameters_spec.rb +++ b/spec/ruby/core/proc/parameters_spec.rb @@ -20,21 +20,6 @@ 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 for required argument 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 @@ -91,34 +76,12 @@ describe "Proc#parameters" do proc {|&block| }.parameters.first.last.should == :block end - it "ignores unnamed rest arguments" do + it "ignores unnamed rest args" do -> x {}.parameters.should == [[:req, :x]] end - ruby_version_is '3.2' do - it "adds rest arg with name * for \"star\" argument" do - -> * {}.parameters.should == [[:rest, :*]] - end - - it "adds keyrest arg with ** as a name for \"double star\" argument" do - -> ** {}.parameters.should == [[:keyrest, :**]] - end - end - - ruby_version_is ''...'3.2' do - it "adds nameless rest arg for \"star\" argument" do - -> * {}.parameters.should == [[:rest]] - end - - it "adds nameless keyrest arg for \"double star\" argument" do - -> ** {}.parameters.should == [[:keyrest]] - end - end - - ruby_version_is '3.1' do - it "adds block arg with name & for anonymous block argument" do - eval('-> & {}.parameters').should == [[:block, :&]] - end + it "adds nameless rest arg for \"star\" argument" do + -> x, * {}.parameters.should == [[:req, :x], [:rest]] end it "does not add locals as block options with a block and splat" do @@ -129,30 +92,4 @@ describe "Proc#parameters" do local_is_not_parameter = {} end.parameters.should == [[:rest, :args], [:block, :blk]] end - - it "returns all parameters defined with the name _ as _" do - proc = proc {|_, _, _ = 1, *_, _:, _: 2, **_, &_| } - proc.parameters.should == [ - [:opt, :_], - [:opt, :_], - [:opt, :_], - [:rest, :_], - [:keyreq, :_], - [:key, :_], - [:keyrest, :_], - [:block, :_] - ] - - lambda = -> _, _, _ = 1, *_, _:, _: 2, **_, &_ {} - lambda.parameters.should == [ - [:req, :_], - [:req, :_], - [:opt, :_], - [:rest, :_], - [:keyreq, :_], - [:key, :_], - [:keyrest, :_], - [:block, :_] - ] - end end diff --git a/spec/ruby/core/proc/ruby2_keywords_spec.rb b/spec/ruby/core/proc/ruby2_keywords_spec.rb index ab67302231..4f6bc151b6 100644 --- a/spec/ruby/core/proc/ruby2_keywords_spec.rb +++ b/spec/ruby/core/proc/ruby2_keywords_spec.rb @@ -1,56 +1,64 @@ require_relative '../../spec_helper' -describe "Proc#ruby2_keywords" do - it "marks the final hash argument as keyword hash" do - f = -> *a { a.last } - f.ruby2_keywords +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 - 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 - it "applies to the underlying method and applies across duplication" do - f1 = -> *a { a.last } - f1.ruby2_keywords - f2 = f1.dup + 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 - 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 = -> *a { obj.foo(*a) } - f3 = -> *a { a.last } - f4 = f3.dup - f3.ruby2_keywords + -> { 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 - 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 + it "fixes delegation warnings when calling a proc accepting keywords" do + g = -> *a, **b { } + f = -> *a { g.call(*a) } - it "returns self" do - f = -> *a { } - f.ruby2_keywords.should equal f - 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 - it "prints warning when a proc does not accept argument splat" do - f = -> a, b, c { } + it "returns self" do + f = -> *a { } + f.ruby2_keywords.should equal f + end - -> { - f.ruby2_keywords - }.should complain(/Skipping set of ruby2_keywords flag for/) - end + it "prints warning when a proc does not accept argument splat" do + f = -> a, b, c { } - 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 keywords" do + f = -> a:, b: { } - 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 - -> { - f.ruby2_keywords - }.should complain(/Skipping set of ruby2_keywords flag for/) + 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 end diff --git a/spec/ruby/core/proc/shared/compose.rb b/spec/ruby/core/proc/shared/compose.rb index 3d3f3b310d..e3ae7f76b8 100644 --- a/spec/ruby/core/proc/shared/compose.rb +++ b/spec/ruby/core/proc/shared/compose.rb @@ -1,22 +1,47 @@ describe :proc_compose, shared: true do - it "raises TypeError if passed not callable object" do - lhs = @object.call - not_callable = Object.new + 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) - -> { - lhs.send(@method, not_callable) - }.should raise_error(TypeError, "callable object is expected") + -> { + composed.call('a') + }.should raise_error(NoMethodError, /undefined method `call' for/) + 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 - it "does not try to coerce argument with #to_proc" do - lhs = @object.call + 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 - 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") + -> { + lhs.send(@method, succ) + }.should raise_error(TypeError, "callable object is expected") + end end end diff --git a/spec/ruby/core/proc/shared/dup.rb b/spec/ruby/core/proc/shared/dup.rb index c419a4078a..eda1d6929d 100644 --- a/spec/ruby/core/proc/shared/dup.rb +++ b/spec/ruby/core/proc/shared/dup.rb @@ -7,35 +7,4 @@ describe :proc_dup, shared: true do a.call.should == b.call end - - ruby_version_is "3.2" do - it "returns an instance of subclass" do - cl = Class.new(Proc) - - cl.new{}.send(@method).class.should == cl - end - end - - ruby_version_is "3.4" do - it "copies instance variables" do - proc = -> { "hello" } - proc.instance_variable_set(:@ivar, 1) - cl = proc.send(@method) - cl.instance_variables.should == [:@ivar] - end - - it "copies the finalizer" do - code = <<-RUBY - obj = Proc.new { } - - ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" }) - - obj.clone - - exit 0 - RUBY - - ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"] - end - end end diff --git a/spec/ruby/core/proc/shared/equal.rb b/spec/ruby/core/proc/shared/equal.rb index d0503fb064..0c0020ca7f 100644 --- a/spec/ruby/core/proc/shared/equal.rb +++ b/spec/ruby/core/proc/shared/equal.rb @@ -81,3 +81,20 @@ describe :proc_equal, shared: true do p.send(@method, p2).should be_false end end + +describe :proc_equal_undefined, shared: true do + it "is not defined" do + Proc.should_not have_instance_method(@method, false) + end + + it "returns false if other is a dup of the original" do + p = proc { :foo } + p.send(@method, p.dup).should be_false + + p = Proc.new { :foo } + p.send(@method, p.dup).should be_false + + p = -> { :foo } + p.send(@method, p.dup).should be_false + end +end diff --git a/spec/ruby/core/proc/shared/to_s.rb b/spec/ruby/core/proc/shared/to_s.rb index f1e2f416fc..7f167a3d9d 100644 --- a/spec/ruby/core/proc/shared/to_s.rb +++ b/spec/ruby/core/proc/shared/to_s.rb @@ -1,7 +1,9 @@ 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:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ }>$/ + Proc.new { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{__LINE__ }>$/ end it "has a binary encoding" do @@ -11,7 +13,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:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ } \(lambda\)>$/ + -> { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{__LINE__ } \(lambda\)>$/ end it "has a binary encoding" do @@ -21,7 +23,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:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ }>$/ + proc { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{__LINE__ }>$/ end it "has a binary encoding" do @@ -34,7 +36,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:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ - 3} \(lambda\)>$/ + s.should =~ /^#<Proc:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{__LINE__ - 3} \(lambda\)>$/ else s.should =~ /^#<Proc:([^ ]*?) \(lambda\)>$/ end diff --git a/spec/ruby/core/proc/source_location_spec.rb b/spec/ruby/core/proc/source_location_spec.rb index a8b99287d5..f268499b82 100644 --- a/spec/ruby/core/proc/source_location_spec.rb +++ b/spec/ruby/core/proc/source_location_spec.rb @@ -19,19 +19,19 @@ describe "Proc#source_location" do it "sets the first value to the path of the file in which the proc was defined" do file = @proc.source_location.first file.should be_an_instance_of(String) - file.should == File.realpath('fixtures/source_location.rb', __dir__) + file.should == File.realpath('../fixtures/source_location.rb', __FILE__) file = @proc_new.source_location.first file.should be_an_instance_of(String) - file.should == File.realpath('fixtures/source_location.rb', __dir__) + file.should == File.realpath('../fixtures/source_location.rb', __FILE__) file = @lambda.source_location.first file.should be_an_instance_of(String) - file.should == File.realpath('fixtures/source_location.rb', __dir__) + file.should == File.realpath('../fixtures/source_location.rb', __FILE__) file = @method.source_location.first file.should be_an_instance_of(String) - file.should == File.realpath('fixtures/source_location.rb', __dir__) + file.should == File.realpath('../fixtures/source_location.rb', __FILE__) end it "sets the last value to an Integer representing the line on which the proc was defined" do @@ -83,9 +83,4 @@ describe "Proc#source_location" do proc.source_location.should == nil end - - it "works for eval with a given line" do - proc = eval('-> {}', nil, "foo", 100) - proc.source_location.should == ["foo", 100] - end end diff --git a/spec/ruby/core/process/_fork_spec.rb b/spec/ruby/core/process/_fork_spec.rb deleted file mode 100644 index 6f711ad2dd..0000000000 --- a/spec/ruby/core/process/_fork_spec.rb +++ /dev/null @@ -1,24 +0,0 @@ -require_relative '../../spec_helper' - -ruby_version_is "3.1" do - describe "Process._fork" do - it "for #respond_to? returns the same as Process.respond_to?(:fork)" do - Process.respond_to?(:_fork).should == Process.respond_to?(:fork) - end - - guard_not -> { Process.respond_to?(:fork) } do - it "raises a NotImplementedError when called" do - -> { Process._fork }.should raise_error(NotImplementedError) - end - end - - guard -> { Process.respond_to?(:fork) } do - it "is called by Process#fork" do - Process.should_receive(:_fork).once.and_return(42) - - pid = Process.fork {} - pid.should equal(42) - end - end - end -end diff --git a/spec/ruby/core/process/argv0_spec.rb b/spec/ruby/core/process/argv0_spec.rb deleted file mode 100644 index f5aba719e9..0000000000 --- a/spec/ruby/core/process/argv0_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -require_relative '../../spec_helper' - -describe "Process.argv0" do - it "returns a String" do - Process.argv0.should be_kind_of(String) - end - - it "is the path given as the main script and the same as __FILE__" do - script = "fixtures/argv0.rb" - - Dir.chdir(__dir__) do - ruby_exe(script).should == "#{script}\n#{script}\nOK" - end - end - - ruby_bug "#19597", ""..."3.3" do - it "returns a frozen object" do - Process.argv0.should.frozen? - end - end - - it "returns every time the same object" do - Process.argv0.should.equal?(Process.argv0) - end -end diff --git a/spec/ruby/core/process/clock_gettime_spec.rb b/spec/ruby/core/process/clock_gettime_spec.rb index 6c1a52f21e..59e1406e02 100644 --- a/spec/ruby/core/process/clock_gettime_spec.rb +++ b/spec/ruby/core/process/clock_gettime_spec.rb @@ -52,7 +52,7 @@ describe "Process.clock_gettime" do end # These specs need macOS 10.12+ / darwin 16+ - guard -> { platform_is_not(:darwin) or kernel_version_is '16' } do + guard_not -> { platform_is_not(:darwin) or RUBY_PLATFORM[/darwin\d+/].to_i >= 16 } do platform_is :linux, :openbsd, :darwin do it "CLOCK_PROCESS_CPUTIME_ID" do Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID).should be_an_instance_of(Float) @@ -65,6 +65,20 @@ describe "Process.clock_gettime" do end end + platform_is :freebsd, :openbsd do + it "CLOCK_VIRTUAL" do + Process.clock_gettime(Process::CLOCK_VIRTUAL).should be_an_instance_of(Float) + end + + it "CLOCK_PROF" do + Process.clock_gettime(Process::CLOCK_PROF).should be_an_instance_of(Float) + end + + it "CLOCK_UPTIME" do + Process.clock_gettime(Process::CLOCK_UPTIME).should be_an_instance_of(Float) + end + end + platform_is :linux, :darwin do it "CLOCK_MONOTONIC_RAW" do Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW).should be_an_instance_of(Float) @@ -81,71 +95,42 @@ describe "Process.clock_gettime" do Process.clock_gettime(Process::CLOCK_UPTIME_RAW_APPROX).should be_an_instance_of(Float) end end - end - - platform_is :freebsd do - it "CLOCK_VIRTUAL" do - Process.clock_gettime(Process::CLOCK_VIRTUAL).should be_an_instance_of(Float) - end - - it "CLOCK_PROF" do - Process.clock_gettime(Process::CLOCK_PROF).should be_an_instance_of(Float) - end - end - - platform_is :freebsd, :openbsd do - it "CLOCK_UPTIME" do - Process.clock_gettime(Process::CLOCK_UPTIME).should be_an_instance_of(Float) - end - end - - platform_is :freebsd do - it "CLOCK_REALTIME_FAST and CLOCK_REALTIME_PRECISE" do - Process.clock_gettime(Process::CLOCK_REALTIME_FAST).should be_an_instance_of(Float) - Process.clock_gettime(Process::CLOCK_REALTIME_PRECISE).should be_an_instance_of(Float) - end - it "CLOCK_MONOTONIC_FAST and CLOCK_MONOTONIC_PRECISE" do - Process.clock_gettime(Process::CLOCK_MONOTONIC_FAST).should be_an_instance_of(Float) - Process.clock_gettime(Process::CLOCK_MONOTONIC_PRECISE).should be_an_instance_of(Float) - end - - it "CLOCK_UPTIME_FAST and CLOCK_UPTIME_PRECISE" do - Process.clock_gettime(Process::CLOCK_UPTIME_FAST).should be_an_instance_of(Float) - Process.clock_gettime(Process::CLOCK_UPTIME_PRECISE).should be_an_instance_of(Float) - end + platform_is :freebsd do + it "CLOCK_REALTIME_FAST and CLOCK_REALTIME_PRECISE" do + Process.clock_gettime(Process::CLOCK_REALTIME_FAST).should be_an_instance_of(Float) + Process.clock_gettime(Process::CLOCK_REALTIME_PRECISE).should be_an_instance_of(Float) + end - it "CLOCK_SECOND" do - Process.clock_gettime(Process::CLOCK_SECOND).should be_an_instance_of(Float) - end - end + it "CLOCK_MONOTONIC_FAST and CLOCK_MONOTONIC_PRECISE" do + Process.clock_gettime(Process::CLOCK_MONOTONIC_FAST).should be_an_instance_of(Float) + Process.clock_gettime(Process::CLOCK_MONOTONIC_PRECISE).should be_an_instance_of(Float) + end - guard -> { platform_is :linux and kernel_version_is '2.6.32' } do - it "CLOCK_REALTIME_COARSE" do - Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should be_an_instance_of(Float) - end + it "CLOCK_UPTIME_FAST and CLOCK_UPTIME_PRECISE" do + Process.clock_gettime(Process::CLOCK_UPTIME_FAST).should be_an_instance_of(Float) + Process.clock_gettime(Process::CLOCK_UPTIME_PRECISE).should be_an_instance_of(Float) + end - it "CLOCK_MONOTONIC_COARSE" do - Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should be_an_instance_of(Float) + it "CLOCK_SECOND" do + Process.clock_gettime(Process::CLOCK_SECOND).should be_an_instance_of(Float) + end end - end - guard -> { platform_is :linux and kernel_version_is '2.6.39' } do - it "CLOCK_BOOTTIME" do - skip "No Process::CLOCK_BOOTTIME" unless defined?(Process::CLOCK_BOOTTIME) - Process.clock_gettime(Process::CLOCK_BOOTTIME).should be_an_instance_of(Float) - end - end + platform_is :linux do + it "CLOCK_REALTIME_COARSE and CLOCK_REALTIME_ALARM" do + Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should be_an_instance_of(Float) + Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should be_an_instance_of(Float) + end - guard -> { platform_is "x86_64-linux" and kernel_version_is '3.0' } do - it "CLOCK_REALTIME_ALARM" do - skip "No Process::CLOCK_REALTIME_ALARM" unless defined?(Process::CLOCK_REALTIME_ALARM) - Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should be_an_instance_of(Float) - end + it "CLOCK_MONOTONIC_COARSE" do + Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should be_an_instance_of(Float) + end - it "CLOCK_BOOTTIME_ALARM" do - skip "No Process::CLOCK_BOOTTIME_ALARM" unless defined?(Process::CLOCK_BOOTTIME_ALARM) - Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should be_an_instance_of(Float) + it "CLOCK_BOOTTIME and CLOCK_BOOTTIME_ALARM" do + Process.clock_gettime(Process::CLOCK_BOOTTIME).should be_an_instance_of(Float) + Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should be_an_instance_of(Float) + end end end end diff --git a/spec/ruby/core/process/constants_spec.rb b/spec/ruby/core/process/constants_spec.rb index 616c54b8e1..b61f5ab64e 100644 --- a/spec/ruby/core/process/constants_spec.rb +++ b/spec/ruby/core/process/constants_spec.rb @@ -1,4 +1,3 @@ -require_relative '../../spec_helper' describe "Process::Constants" do platform_is :darwin, :netbsd, :freebsd do @@ -56,18 +55,12 @@ describe "Process::Constants" do end platform_is :netbsd, :freebsd do - it "has the correct constant values on NetBSD and FreeBSD" do + it "Process::RLIMIT_SBSIZE" do Process::RLIMIT_SBSIZE.should == 9 # FIXME: what's it equal? Process::RLIMIT_AS.should == 10 end end - platform_is :freebsd do - it "has the correct constant values on FreeBSD" do - Process::RLIMIT_NPTS.should == 11 - end - end - platform_is :windows do it "does not define RLIMIT constants" do %i[ diff --git a/spec/ruby/core/process/daemon_spec.rb b/spec/ruby/core/process/daemon_spec.rb index 70ffd1b320..20b0d743b9 100644 --- a/spec/ruby/core/process/daemon_spec.rb +++ b/spec/ruby/core/process/daemon_spec.rb @@ -2,6 +2,9 @@ require_relative '../../spec_helper' require_relative 'fixtures/common' platform_is_not :windows do + # macOS 15 is not working this examples + return if /darwin/ =~ RUBY_PLATFORM && /15/ =~ `sw_vers -productVersion` + describe :process_daemon_keep_stdio_open_false, shared: true do it "redirects stdout to /dev/null" do @daemon.invoke("keep_stdio_open_false_stdout", @object).should == "" diff --git a/spec/ruby/core/process/detach_spec.rb b/spec/ruby/core/process/detach_spec.rb index f13bda1f5d..1c27ed9c2c 100644 --- a/spec/ruby/core/process/detach_spec.rb +++ b/spec/ruby/core/process/detach_spec.rb @@ -42,40 +42,5 @@ describe "Process.detach" do thr.pid.should == pid end - - it "tolerates not existing child process pid" do - # Use a value that is close to the INT_MAX (pid usually is signed int). - # It should (at least) be greater than allowed pid limit value that depends on OS. - pid_not_existing = 2.pow(30) - - # Check that there is no a child process with this hardcoded pid. - # Command `kill 0 pid`: - # - returns "1" if a process exists and - # - raises Errno::ESRCH otherwise - -> { Process.kill(0, pid_not_existing) }.should raise_error(Errno::ESRCH) - - thr = Process.detach(pid_not_existing) - thr.join - - thr.should be_kind_of(Thread) - end - - it "calls #to_int to implicitly convert non-Integer pid to Integer" do - pid = MockObject.new('mock-enumerable') - pid.should_receive(:to_int).and_return(100500) - - Process.detach(pid).join - end - - it "raises TypeError when pid argument does not have #to_int method" do - -> { Process.detach(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into Integer") - end - - it "raises TypeError when #to_int returns non-Integer value" do - pid = MockObject.new('mock-enumerable') - pid.should_receive(:to_int).and_return(:symbol) - - -> { Process.detach(pid) }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Symbol)") - end end end diff --git a/spec/ruby/core/process/egid_spec.rb b/spec/ruby/core/process/egid_spec.rb index a67b623d5c..24dda43804 100644 --- a/spec/ruby/core/process/egid_spec.rb +++ b/spec/ruby/core/process/egid_spec.rb @@ -15,44 +15,5 @@ describe "Process.egid" do end describe "Process.egid=" do - - platform_is_not :windows do - it "raises TypeError if not passed an Integer or String" do - -> { Process.egid = Object.new }.should raise_error(TypeError) - end - - it "sets the effective group id to its own gid if given the username corresponding to its own gid" do - raise unless Process.gid == Process.egid - - require "etc" - group = Etc.getgrgid(Process.gid).name - - Process.egid = group - Process.egid.should == Process.gid - end - - as_user do - it "raises Errno::ERPERM if run by a non superuser trying to set the root group id" do - -> { Process.egid = 0 }.should raise_error(Errno::EPERM) - end - - platform_is :linux do - it "raises Errno::ERPERM if run by a non superuser trying to set the group id from group name" do - -> { Process.egid = "root" }.should raise_error(Errno::EPERM) - end - end - end - - as_superuser do - context "when ran by a superuser" do - it "sets the effective group id for the current process if run by a superuser" do - code = <<-RUBY - Process.egid = 1 - puts Process.egid - RUBY - ruby_exe(code).should == "1\n" - end - end - end - end + it "needs to be reviewed for spec completeness" end diff --git a/spec/ruby/core/process/euid_spec.rb b/spec/ruby/core/process/euid_spec.rb index c1ec4171d0..a2f1bbf42e 100644 --- a/spec/ruby/core/process/euid_spec.rb +++ b/spec/ruby/core/process/euid_spec.rb @@ -21,19 +21,9 @@ describe "Process.euid=" do -> { Process.euid = Object.new }.should raise_error(TypeError) end - it "sets the effective user id to its own uid if given the username corresponding to its own uid" do - raise unless Process.uid == Process.euid - - require "etc" - user = Etc.getpwuid(Process.uid).name - - Process.euid = user - Process.euid.should == Process.uid - end - as_user do it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id" do - -> { Process.euid = 0 }.should raise_error(Errno::EPERM) + -> { (Process.euid = 0)}.should raise_error(Errno::EPERM) end it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id from username" do diff --git a/spec/ruby/core/process/exec_spec.rb b/spec/ruby/core/process/exec_spec.rb index 0f371b39c8..deb8913b6b 100644 --- a/spec/ruby/core/process/exec_spec.rb +++ b/spec/ruby/core/process/exec_spec.rb @@ -30,20 +30,20 @@ describe "Process.exec" do end it "raises Errno::EACCES when passed a directory" do - -> { Process.exec __dir__ }.should raise_error(Errno::EACCES) + -> { Process.exec File.dirname(__FILE__) }.should raise_error(Errno::EACCES) end it "runs the specified command, replacing current process" do - ruby_exe('Process.exec "echo hello"; puts "fail"').should == "hello\n" + ruby_exe('Process.exec "echo hello"; puts "fail"', escape: true).should == "hello\n" end it "sets the current directory when given the :chdir option" do tmpdir = tmp("")[0..-2] platform_is_not :windows do - ruby_exe("Process.exec(\"pwd\", chdir: #{tmpdir.inspect})").should == "#{tmpdir}\n" + ruby_exe("Process.exec(\"pwd\", chdir: #{tmpdir.inspect})", escape: true).should == "#{tmpdir}\n" end platform_is :windows do - ruby_exe("Process.exec(\"cd\", chdir: #{tmpdir.inspect})").tr('\\', '/').should == "#{tmpdir}\n" + ruby_exe("Process.exec(\"cd\", chdir: #{tmpdir.inspect})", escape: true).tr('\\', '/').should == "#{tmpdir}\n" end end @@ -73,13 +73,13 @@ describe "Process.exec" do platform_is_not :windows do it "subjects the specified command to shell expansion" do result = Dir.chdir(@dir) do - ruby_exe('Process.exec "echo *"') + ruby_exe('Process.exec "echo *"', escape: true) end result.chomp.should == @name end it "creates an argument array with shell parsing semantics for whitespace" do - ruby_exe('Process.exec "echo a b c d"').should == "a b c d\n" + ruby_exe('Process.exec "echo a b c d"', escape: true).should == "a b c d\n" end end @@ -87,13 +87,13 @@ describe "Process.exec" do # There is no shell expansion on Windows it "does not subject the specified command to shell expansion on Windows" do result = Dir.chdir(@dir) do - ruby_exe('Process.exec "echo *"') + ruby_exe('Process.exec "echo *"', escape: true) end result.should == "*\n" end it "does not create an argument array with shell parsing semantics for whitespace on Windows" do - ruby_exe('Process.exec "echo a b c d"').should == "a b c d\n" + ruby_exe('Process.exec "echo a b c d"', escape: true).should == "a b c d\n" end end @@ -105,7 +105,7 @@ describe "Process.exec" do platform_is :windows do cmd = '"cmd.exe", "/C", "echo", "*"' end - ruby_exe("Process.exec #{cmd}").should == "*\n" + ruby_exe("Process.exec #{cmd}", escape: true).should == "*\n" end end @@ -124,29 +124,29 @@ describe "Process.exec" do end it "sets environment variables in the child environment" do - ruby_exe('Process.exec({"FOO" => "BAR"}, "echo ' + var + '")').should == "BAR\n" + ruby_exe('Process.exec({"FOO" => "BAR"}, "echo ' + var + '")', escape: true).should == "BAR\n" end it "unsets environment variables whose value is nil" do platform_is_not :windows do - ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")').should == "\n" + ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")', escape: true).should == "\n" end platform_is :windows do # On Windows, echo-ing a non-existent env var is treated as echo-ing any other string of text - ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")').should == var + "\n" + ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")', escape: true).should == var + "\n" end end it "coerces environment argument using to_hash" do - ruby_exe('o = Object.new; def o.to_hash; {"FOO" => "BAR"}; end; Process.exec(o, "echo ' + var + '")').should == "BAR\n" + ruby_exe('o = Object.new; def o.to_hash; {"FOO" => "BAR"}; end; Process.exec(o, "echo ' + var + '")', escape: true).should == "BAR\n" end it "unsets other environment variables when given a true :unsetenv_others option" do platform_is_not :windows do - ruby_exe('Process.exec("echo ' + var + '", unsetenv_others: true)').should == "\n" + ruby_exe('Process.exec("echo ' + var + '", unsetenv_others: true)', escape: true).should == "\n" end platform_is :windows do - ruby_exe('Process.exec("' + ENV['COMSPEC'].gsub('\\', '\\\\\\') + ' /C echo ' + var + '", unsetenv_others: true)').should == var + "\n" + ruby_exe('Process.exec("' + ENV['COMSPEC'].gsub('\\', '\\\\\\') + ' /C echo ' + var + '", unsetenv_others: true)', escape: true).should == var + "\n" end end end @@ -154,19 +154,19 @@ describe "Process.exec" do describe "with a command array" do it "uses the first element as the command name and the second as the argv[0] value" do platform_is_not :windows do - ruby_exe('Process.exec(["/bin/sh", "argv_zero"], "-c", "echo $0")').should == "argv_zero\n" + ruby_exe('Process.exec(["/bin/sh", "argv_zero"], "-c", "echo $0")', escape: true).should == "argv_zero\n" end platform_is :windows do - ruby_exe('Process.exec(["cmd.exe", "/C"], "/C", "echo", "argv_zero")').should == "argv_zero\n" + ruby_exe('Process.exec(["cmd.exe", "/C"], "/C", "echo", "argv_zero")', escape: true).should == "argv_zero\n" end end it "coerces the argument using to_ary" do platform_is_not :windows do - ruby_exe('o = Object.new; def o.to_ary; ["/bin/sh", "argv_zero"]; end; Process.exec(o, "-c", "echo $0")').should == "argv_zero\n" + ruby_exe('o = Object.new; def o.to_ary; ["/bin/sh", "argv_zero"]; end; Process.exec(o, "-c", "echo $0")', escape: true).should == "argv_zero\n" end platform_is :windows do - ruby_exe('o = Object.new; def o.to_ary; ["cmd.exe", "/C"]; end; Process.exec(o, "/C", "echo", "argv_zero")').should == "argv_zero\n" + ruby_exe('o = Object.new; def o.to_ary; ["cmd.exe", "/C"]; end; Process.exec(o, "/C", "echo", "argv_zero")', escape: true).should == "argv_zero\n" end end @@ -200,7 +200,7 @@ describe "Process.exec" do end EOC - ruby_exe(cmd) + ruby_exe(cmd, escape: true) child_fd = IO.read(@child_fd_file).to_i child_fd.to_i.should > STDERR.fileno @@ -216,7 +216,7 @@ describe "Process.exec" do Process.exec("#{ruby_cmd(map_fd_fixture)} \#{f.fileno}", f.fileno => f.fileno) EOC - output = ruby_exe(cmd) + output = ruby_exe(cmd, escape: true) child_fd, close_on_exec = output.split child_fd.to_i.should > STDERR.fileno @@ -232,7 +232,7 @@ describe "Process.exec" do puts(f.close_on_exec?) EOC - output = ruby_exe(cmd) + output = ruby_exe(cmd, escape: true) output.split.should == ['true', 'false'] end end diff --git a/spec/ruby/core/process/exit_spec.rb b/spec/ruby/core/process/exit_spec.rb index 4f7dc94407..70d79d789d 100644 --- a/spec/ruby/core/process/exit_spec.rb +++ b/spec/ruby/core/process/exit_spec.rb @@ -6,5 +6,5 @@ describe "Process.exit" do end describe "Process.exit!" do - it_behaves_like :process_exit!, :exit!, "Process" + it_behaves_like :process_exit!, :exit!, Process end diff --git a/spec/ruby/core/process/fixtures/argv0.rb b/spec/ruby/core/process/fixtures/argv0.rb deleted file mode 100644 index 847a3e903e..0000000000 --- a/spec/ruby/core/process/fixtures/argv0.rb +++ /dev/null @@ -1,6 +0,0 @@ -puts Process.argv0 -puts __FILE__ - -if Process.argv0 == __FILE__ - print "OK" -end diff --git a/spec/ruby/core/process/spawn_spec.rb b/spec/ruby/core/process/spawn_spec.rb index 283a7f033d..6be3f41a87 100644 --- a/spec/ruby/core/process/spawn_spec.rb +++ b/spec/ruby/core/process/spawn_spec.rb @@ -349,7 +349,7 @@ describe "Process.spawn" do pgid = Process.getpgid(Process.pid) # The process group is not available on all platforms. # See "man proc" - /proc/[pid]/stat - (5) pgrp - # In Travis aarch64 environment, the value is 0. + # In Travis arm64 environment, the value is 0. # # $ cat /proc/[pid]/stat # 19179 (ruby) S 19160 0 0 ... @@ -477,16 +477,6 @@ describe "Process.spawn" do # redirection - it 'redirects to the wrapped IO using wrapped_io.to_io if out: wrapped_io' do - File.open(@name, 'w') do |file| - -> do - wrapped_io = mock('wrapped IO') - wrapped_io.should_receive(:to_io).and_return(file) - Process.wait Process.spawn('echo Hello World', out: wrapped_io) - end.should output_to_fd("Hello World\n", file) - end - end - it "redirects STDOUT to the given file descriptor if out: Integer" do File.open(@name, 'w') do |file| -> do @@ -577,24 +567,6 @@ describe "Process.spawn" do end end - platform_is_not :windows do - it "redirects non-default file descriptor to itself" do - File.open(@name, 'w') do |file| - -> do - Process.wait Process.spawn( - ruby_cmd("f = IO.new(#{file.fileno}, 'w'); f.print(:bang); f.flush"), file.fileno => file.fileno) - end.should output_to_fd("bang", file) - end - end - end - - it "redirects default file descriptor to itself" do - -> do - Process.wait Process.spawn( - ruby_cmd("f = IO.new(#{STDOUT.fileno}, 'w'); f.print(:bang); f.flush"), STDOUT.fileno => STDOUT.fileno) - end.should output_to_fd("bang", STDOUT) - end - # :close_others platform_is_not :windows do @@ -714,7 +686,7 @@ describe "Process.spawn" do end it "raises an Errno::EACCES or Errno::EISDIR when passed a directory" do - -> { Process.spawn __dir__ }.should raise_error(SystemCallError) { |e| + -> { Process.spawn File.dirname(__FILE__) }.should raise_error(SystemCallError) { |e| [Errno::EACCES, Errno::EISDIR].should include(e.class) } end diff --git a/spec/ruby/core/process/status/equal_value_spec.rb b/spec/ruby/core/process/status/equal_value_spec.rb index d8a2be26b8..d85bb22214 100644 --- a/spec/ruby/core/process/status/equal_value_spec.rb +++ b/spec/ruby/core/process/status/equal_value_spec.rb @@ -8,7 +8,7 @@ describe "Process::Status#==" do end it "returns true when compared to the integer status of a terminated child" do - ruby_exe("Process.kill(:KILL, $$); exit(29)", exit_status: platform_is(:windows) ? 0 : :SIGKILL) + ruby_exe("Process.kill(:KILL, $$); exit(29)", exit_status: platform_is(:windows) ? 0 : nil) $?.to_i.should == $? $?.should == $?.to_i end diff --git a/spec/ruby/core/process/status/exited_spec.rb b/spec/ruby/core/process/status/exited_spec.rb index a61292b146..059cd5b1aa 100644 --- a/spec/ruby/core/process/status/exited_spec.rb +++ b/spec/ruby/core/process/status/exited_spec.rb @@ -14,7 +14,7 @@ describe "Process::Status#exited?" do describe "for a terminated child" do before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL) + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) end platform_is_not :windows do diff --git a/spec/ruby/core/process/status/exitstatus_spec.rb b/spec/ruby/core/process/status/exitstatus_spec.rb index 5c86c2b3c8..3087bd619e 100644 --- a/spec/ruby/core/process/status/exitstatus_spec.rb +++ b/spec/ruby/core/process/status/exitstatus_spec.rb @@ -11,7 +11,7 @@ describe "Process::Status#exitstatus" do describe "for a child that raised SignalException" do before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL) + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) end platform_is_not :windows do diff --git a/spec/ruby/core/process/status/signaled_spec.rb b/spec/ruby/core/process/status/signaled_spec.rb index c0de7b8006..389092a533 100644 --- a/spec/ruby/core/process/status/signaled_spec.rb +++ b/spec/ruby/core/process/status/signaled_spec.rb @@ -13,7 +13,7 @@ describe "Process::Status#signaled?" do describe "for a terminated child" do before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL) + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) end platform_is_not :windows do diff --git a/spec/ruby/core/process/status/success_spec.rb b/spec/ruby/core/process/status/success_spec.rb index 3589cc611f..c531121f08 100644 --- a/spec/ruby/core/process/status/success_spec.rb +++ b/spec/ruby/core/process/status/success_spec.rb @@ -23,7 +23,7 @@ describe "Process::Status#success?" do describe "for a child that was terminated" do before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL) + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) end platform_is_not :windows do diff --git a/spec/ruby/core/process/status/termsig_spec.rb b/spec/ruby/core/process/status/termsig_spec.rb index 5d286950f8..1c87a6f455 100644 --- a/spec/ruby/core/process/status/termsig_spec.rb +++ b/spec/ruby/core/process/status/termsig_spec.rb @@ -13,7 +13,7 @@ describe "Process::Status#termsig" do describe "for a child that raised SignalException" do before :each do - ruby_exe("raise SignalException, 'SIGTERM'", exit_status: :SIGTERM) + ruby_exe("raise SignalException, 'SIGTERM'", exit_status: nil) end platform_is_not :windows do @@ -25,7 +25,7 @@ describe "Process::Status#termsig" do describe "for a child that was sent a signal" do before :each do - ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL) + ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil) end platform_is_not :windows do diff --git a/spec/ruby/core/process/status/to_i_spec.rb b/spec/ruby/core/process/status/to_i_spec.rb index 39f8e2d84c..7cde9b915b 100644 --- a/spec/ruby/core/process/status/to_i_spec.rb +++ b/spec/ruby/core/process/status/to_i_spec.rb @@ -7,7 +7,7 @@ describe "Process::Status#to_i" do end it "returns an integer when the child is signaled" do - ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : :SIGTERM) + ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : nil) $?.to_i.should be_an_instance_of(Integer) end end diff --git a/spec/ruby/core/process/status/wait_spec.rb b/spec/ruby/core/process/status/wait_spec.rb index 57d56209a9..b9d80e31f4 100644 --- a/spec/ruby/core/process/status/wait_spec.rb +++ b/spec/ruby/core/process/status/wait_spec.rb @@ -1,100 +1,102 @@ require_relative '../../../spec_helper' require_relative '../fixtures/common' -describe "Process::Status.wait" do - ProcessSpecs.use_system_ruby(self) - - before :all do - begin - leaked = Process.waitall - # Ruby-space should not see PIDs used by rjit - raise "subprocesses leaked before wait specs: #{leaked}" unless leaked.empty? - rescue NotImplementedError +ruby_version_is "3.0" do + describe "Process::Status.wait" do + ProcessSpecs.use_system_ruby(self) + + before :all do + begin + leaked = Process.waitall + # Ruby-space should not see PIDs used by mjit + raise "subprocesses leaked before wait specs: #{leaked}" unless leaked.empty? + rescue NotImplementedError + end end - end - - it "returns a status with pid -1 if there are no child processes" do - Process::Status.wait.pid.should == -1 - end - platform_is_not :windows do - it "returns a status with its child pid" do - pid = Process.spawn(ruby_cmd('exit')) - status = Process::Status.wait - status.should be_an_instance_of(Process::Status) - status.pid.should == pid + it "returns a status with pid -1 if there are no child processes" do + Process::Status.wait.pid.should == -1 end - it "should not set $? to the Process::Status" do - pid = Process.spawn(ruby_cmd('exit')) - status = Process::Status.wait - $?.should_not equal(status) - end + platform_is_not :windows do + it "returns a status with its child pid" do + pid = Process.spawn(ruby_cmd('exit')) + status = Process::Status.wait + status.should be_an_instance_of(Process::Status) + status.pid.should == pid + end - it "should not change the value of $?" do - pid = Process.spawn(ruby_cmd('exit')) - Process.wait - status = $? - Process::Status.wait - status.should equal($?) - end + it "should not set $? to the Process::Status" do + pid = Process.spawn(ruby_cmd('exit')) + status = Process::Status.wait + $?.should_not equal(status) + end - it "waits for any child process if no pid is given" do - pid = Process.spawn(ruby_cmd('exit')) - Process::Status.wait.pid.should == pid - -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH) - end + it "should not change the value of $?" do + pid = Process.spawn(ruby_cmd('exit')) + Process.wait + status = $? + Process::Status.wait + status.should equal($?) + end - it "waits for a specific child if a pid is given" do - pid1 = Process.spawn(ruby_cmd('exit')) - pid2 = Process.spawn(ruby_cmd('exit')) - Process::Status.wait(pid2).pid.should == pid2 - Process::Status.wait(pid1).pid.should == pid1 - -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH) - -> { Process.kill(0, pid2) }.should raise_error(Errno::ESRCH) - end + it "waits for any child process if no pid is given" do + pid = Process.spawn(ruby_cmd('exit')) + Process::Status.wait.pid.should == pid + -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH) + end - it "coerces the pid to an Integer" do - pid1 = Process.spawn(ruby_cmd('exit')) - Process::Status.wait(mock_int(pid1)).pid.should == pid1 - -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH) - end + it "waits for a specific child if a pid is given" do + pid1 = Process.spawn(ruby_cmd('exit')) + pid2 = Process.spawn(ruby_cmd('exit')) + Process::Status.wait(pid2).pid.should == pid2 + Process::Status.wait(pid1).pid.should == pid1 + -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH) + -> { Process.kill(0, pid2) }.should raise_error(Errno::ESRCH) + end - # This spec is probably system-dependent. - it "waits for a child whose process group ID is that of the calling process" do - pid1 = Process.spawn(ruby_cmd('exit'), pgroup: true) - pid2 = Process.spawn(ruby_cmd('exit')) + it "coerces the pid to an Integer" do + pid1 = Process.spawn(ruby_cmd('exit')) + Process::Status.wait(mock_int(pid1)).pid.should == pid1 + -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH) + end - Process::Status.wait(0).pid.should == pid2 - Process::Status.wait.pid.should == pid1 - end + # This spec is probably system-dependent. + it "waits for a child whose process group ID is that of the calling process" do + pid1 = Process.spawn(ruby_cmd('exit'), pgroup: true) + pid2 = Process.spawn(ruby_cmd('exit')) - # This spec is probably system-dependent. - it "doesn't block if no child is available when WNOHANG is used" do - read, write = IO.pipe - pid = Process.fork do - read.close - Signal.trap("TERM") { Process.exit! } - write << 1 - write.close - sleep + Process::Status.wait(0).pid.should == pid2 + Process::Status.wait.pid.should == pid1 end - Process::Status.wait(pid, Process::WNOHANG).should be_nil + # This spec is probably system-dependent. + it "doesn't block if no child is available when WNOHANG is used" do + read, write = IO.pipe + pid = Process.fork do + read.close + Signal.trap("TERM") { Process.exit! } + write << 1 + write.close + sleep + end - # wait for the child to setup its TERM handler - write.close - read.read(1) - read.close + Process::Status.wait(pid, Process::WNOHANG).should be_nil - Process.kill("TERM", pid) - Process::Status.wait.pid.should == pid - end + # wait for the child to setup its TERM handler + write.close + read.read(1) + read.close - it "always accepts flags=0" do - pid = Process.spawn(ruby_cmd('exit')) - Process::Status.wait(-1, 0).pid.should == pid - -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH) + Process.kill("TERM", pid) + Process::Status.wait.pid.should == pid + end + + it "always accepts flags=0" do + pid = Process.spawn(ruby_cmd('exit')) + Process::Status.wait(-1, 0).pid.should == pid + -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH) + end end end end diff --git a/spec/ruby/core/process/times_spec.rb b/spec/ruby/core/process/times_spec.rb index d3bff2cda9..b47189a7e7 100644 --- a/spec/ruby/core/process/times_spec.rb +++ b/spec/ruby/core/process/times_spec.rb @@ -5,15 +5,31 @@ describe "Process.times" do Process.times.should be_kind_of(Process::Tms) end - # TODO: Intel C Compiler does not work this example - # http://rubyci.s3.amazonaws.com/icc-x64/ruby-master/log/20221013T030005Z.fail.html.gz - unless RbConfig::CONFIG['CC']&.include?("icx") - it "returns current cpu times" do - t = Process.times - user = t.utime + it "returns current cpu times" do + t = Process.times + user = t.utime - 1 until Process.times.utime > user - Process.times.utime.should > user + 1 until Process.times.utime > user + Process.times.utime.should > user + end + + platform_is_not :windows do + it "uses getrusage when available to improve precision beyond milliseconds" do + max = 10_000 + has_getrusage = max.times.find do + time = Process.clock_gettime(:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) + ('%.6f' % time).end_with?('000') + end + unless has_getrusage + skip "getrusage is not supported on this environment" + end + + found = (max * 100).times.find do + time = Process.times.utime + ('%.6f' % time).end_with?('000') + end + + found.should_not == nil end end end diff --git a/spec/ruby/core/process/wait2_spec.rb b/spec/ruby/core/process/wait2_spec.rb index 8ba429dc96..6eb7fc6d06 100644 --- a/spec/ruby/core/process/wait2_spec.rb +++ b/spec/ruby/core/process/wait2_spec.rb @@ -4,14 +4,14 @@ describe "Process.wait2" do before :all do # HACK: this kludge is temporarily necessary because some # misbehaving spec somewhere else does not clear processes - # Note: background processes are unavoidable with RJIT, + # Note: background processes are unavoidable with MJIT, # but we shouldn't reap them from Ruby-space begin Process.wait(-1, Process::WNOHANG) $stderr.puts "Leaked process before wait2 specs! Waiting for it" leaked = Process.waitall $stderr.puts "leaked before wait2 specs: #{leaked}" unless leaked.empty? - # Ruby-space should not see PIDs used by rjit + # Ruby-space should not see PIDs used by mjit leaked.should be_empty rescue Errno::ECHILD # No child processes rescue NotImplementedError @@ -33,13 +33,4 @@ 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/process/wait_spec.rb b/spec/ruby/core/process/wait_spec.rb index 385acc9928..44c95d6304 100644 --- a/spec/ruby/core/process/wait_spec.rb +++ b/spec/ruby/core/process/wait_spec.rb @@ -7,7 +7,7 @@ describe "Process.wait" do before :all do begin leaked = Process.waitall - # Ruby-space should not see PIDs used by rjit + # Ruby-space should not see PIDs used by mjit raise "subprocesses leaked before wait specs: #{leaked}" unless leaked.empty? rescue NotImplementedError end diff --git a/spec/ruby/core/process/warmup_spec.rb b/spec/ruby/core/process/warmup_spec.rb deleted file mode 100644 index b562d52d22..0000000000 --- a/spec/ruby/core/process/warmup_spec.rb +++ /dev/null @@ -1,11 +0,0 @@ -require_relative '../../spec_helper' - -describe "Process.warmup" do - ruby_version_is "3.3" do - # The behavior is entirely implementation specific. - # Other implementations are free to just make it a noop - it "is implemented" do - Process.warmup.should == true - end - end -end diff --git a/spec/ruby/core/queue/deq_spec.rb b/spec/ruby/core/queue/deq_spec.rb index f84d4220ea..9510978eac 100644 --- a/spec/ruby/core/queue/deq_spec.rb +++ b/spec/ruby/core/queue/deq_spec.rb @@ -1,13 +1,6 @@ require_relative '../../spec_helper' require_relative '../../shared/queue/deque' -require_relative '../../shared/types/rb_num2dbl_fails' describe "Queue#deq" do it_behaves_like :queue_deq, :deq, -> { Queue.new } end - -describe "Queue operations with timeout" do - ruby_version_is "3.2" do - it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.deq(timeout: v) } - end -end diff --git a/spec/ruby/core/queue/initialize_spec.rb b/spec/ruby/core/queue/initialize_spec.rb index c6c1ae63c5..83c7e595fe 100644 --- a/spec/ruby/core/queue/initialize_spec.rb +++ b/spec/ruby/core/queue/initialize_spec.rb @@ -7,10 +7,6 @@ describe "Queue#initialize" do q.should.empty? end - it "is a private method" do - Queue.private_instance_methods.include?(:initialize).should == true - end - ruby_version_is '3.1' do it "adds all elements of the passed Enumerable to self" do q = Queue.new([1, 2, 3]) @@ -22,41 +18,21 @@ describe "Queue#initialize" do q.should.empty? end - describe "converts the given argument to an Array using #to_a" do - it "uses #to_a on the provided Enumerable" do - enumerable = MockObject.new('mock-enumerable') - enumerable.should_receive(:to_a).and_return([1, 2, 3]) - q = Queue.new(enumerable) - q.size.should == 3 - q.should_not.empty? - q.pop.should == 1 - q.pop.should == 2 - q.pop.should == 3 - q.should.empty? - end - - it "raises a TypeError if the given argument can't be converted to an Array" do - -> { Queue.new(42) }.should raise_error(TypeError) - -> { Queue.new(:abc) }.should raise_error(TypeError) - end - - it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do - enumerable = MockObject.new('mock-enumerable') - enumerable.should_receive(:to_a).and_raise(NoMethodError) - -> { Queue.new(enumerable) }.should raise_error(NoMethodError) - end - end - - it "raises TypeError if the provided Enumerable does not respond to #to_a" do + it "uses #to_a on the provided Enumerable" do enumerable = MockObject.new('mock-enumerable') - -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject into Array") + enumerable.should_receive(:to_a).and_return([1, 2, 3]) + q = Queue.new(enumerable) + q.size.should == 3 + q.should_not.empty? + q.pop.should == 1 + q.pop.should == 2 + q.pop.should == 3 + q.should.empty? end - it "raises TypeError if #to_a does not return Array" do + it "raises if the provided Enumerable does not respond to #to_a" do enumerable = MockObject.new('mock-enumerable') - enumerable.should_receive(:to_a).and_return("string") - - -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_a gives String)") + -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject into Array") end end end diff --git a/spec/ruby/core/queue/pop_spec.rb b/spec/ruby/core/queue/pop_spec.rb index d344740834..1ce9231685 100644 --- a/spec/ruby/core/queue/pop_spec.rb +++ b/spec/ruby/core/queue/pop_spec.rb @@ -1,13 +1,6 @@ require_relative '../../spec_helper' require_relative '../../shared/queue/deque' -require_relative '../../shared/types/rb_num2dbl_fails' describe "Queue#pop" do it_behaves_like :queue_deq, :pop, -> { Queue.new } end - -describe "Queue operations with timeout" do - ruby_version_is "3.2" do - it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.pop(timeout: v) } - end -end diff --git a/spec/ruby/core/queue/shift_spec.rb b/spec/ruby/core/queue/shift_spec.rb index 64165e0b61..f84058e1df 100644 --- a/spec/ruby/core/queue/shift_spec.rb +++ b/spec/ruby/core/queue/shift_spec.rb @@ -1,13 +1,6 @@ require_relative '../../spec_helper' require_relative '../../shared/queue/deque' -require_relative '../../shared/types/rb_num2dbl_fails' describe "Queue#shift" do it_behaves_like :queue_deq, :shift, -> { Queue.new } end - -describe "Queue operations with timeout" do - ruby_version_is "3.2" do - it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.shift(timeout: v) } - end -end diff --git a/spec/ruby/core/random/bytes_spec.rb b/spec/ruby/core/random/bytes_spec.rb index b42dc61234..06e84d03bd 100644 --- a/spec/ruby/core/random/bytes_spec.rb +++ b/spec/ruby/core/random/bytes_spec.rb @@ -9,6 +9,7 @@ describe "Random#bytes" do Random.new(33).bytes(2).should == Random.new(33).bytes(2) end + # Should double check this is official spec it "returns the same numeric output for a given seed across all implementations and platforms" do rnd = Random.new(33) rnd.bytes(2).should == "\x14\\" @@ -17,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(2 ** (63 * 4)) + rnd = Random.new(bignum_value ** 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 01d7430df8..db444d203d 100644 --- a/spec/ruby/core/random/default_spec.rb +++ b/spec/ruby/core/random/default_spec.rb @@ -1,19 +1,21 @@ require_relative '../../spec_helper' describe "Random::DEFAULT" do - ruby_version_is ''...'3.2' do - it "returns a random number generator" do - suppress_warning do - Random::DEFAULT.should respond_to(:rand) - end + it "returns a random number generator" do + suppress_warning do + Random::DEFAULT.should respond_to(:rand) 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.0' do + it "returns a Random instance" do + suppress_warning do + Random::DEFAULT.should be_an_instance_of(Random) + end end + end + ruby_version_is '3.0' do it "refers to the Random class" do suppress_warning do Random::DEFAULT.should.equal?(Random) @@ -27,9 +29,9 @@ describe "Random::DEFAULT" do end end - ruby_version_is '3.2' do - it "is no longer defined" do - Random.should_not.const_defined?(:DEFAULT) - 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 end end diff --git a/spec/ruby/core/random/new_spec.rb b/spec/ruby/core/random/new_spec.rb index 90e2a9d6f2..4280b5b9c3 100644 --- a/spec/ruby/core/random/new_spec.rb +++ b/spec/ruby/core/random/new_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" describe "Random.new" do it "returns a new instance of Random" do Random.new.should be_an_instance_of(Random) diff --git a/spec/ruby/core/random/rand_spec.rb b/spec/ruby/core/random/rand_spec.rb index 9244177ab5..6ea7eece5f 100644 --- a/spec/ruby/core/random/rand_spec.rb +++ b/spec/ruby/core/random/rand_spec.rb @@ -205,11 +205,6 @@ 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 new file mode 100644 index 0000000000..0e40ed0796 --- /dev/null +++ b/spec/ruby/core/random/raw_seed_spec.rb @@ -0,0 +1,6 @@ +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 new file mode 100644 index 0000000000..159716075c --- /dev/null +++ b/spec/ruby/core/random/shared/urandom.rb @@ -0,0 +1,23 @@ +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 deleted file mode 100644 index 6f180e54ac..0000000000 --- a/spec/ruby/core/random/urandom_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -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 9c93671d85..438c7ce314 100644 --- a/spec/ruby/core/range/bsearch_spec.rb +++ b/spec/ruby/core/range/bsearch_spec.rb @@ -330,106 +330,108 @@ describe "Range#bsearch" do 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) + 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 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 - 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 + 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 end end end diff --git a/spec/ruby/core/range/case_compare_spec.rb b/spec/ruby/core/range/case_compare_spec.rb index 65878aaabe..e795026230 100644 --- a/spec/ruby/core/range/case_compare_spec.rb +++ b/spec/ruby/core/range/case_compare_spec.rb @@ -8,12 +8,8 @@ describe "Range#===" do (range === RangeSpecs::WithoutSucc.new(2)).should == true end - it_behaves_like :range_cover_and_include, :=== - it_behaves_like :range_cover, :=== - - ruby_bug "#19533", "3.2"..."3.3" do - it "returns true on any value if begin and end are both nil" do - (nil..nil).should === 1 - end + ruby_version_is "2.7" do + it_behaves_like :range_cover_and_include, :=== + it_behaves_like :range_cover, :=== end end diff --git a/spec/ruby/core/range/clone_spec.rb b/spec/ruby/core/range/clone_spec.rb deleted file mode 100644 index cf6ce74da0..0000000000 --- a/spec/ruby/core/range/clone_spec.rb +++ /dev/null @@ -1,26 +0,0 @@ -require_relative '../../spec_helper' - -describe "Range#clone" do - it "duplicates the range" do - original = (1..3) - copy = original.clone - copy.begin.should == 1 - copy.end.should == 3 - copy.should_not.exclude_end? - copy.should_not.equal? original - - original = ("a"..."z") - copy = original.clone - copy.begin.should == "a" - copy.end.should == "z" - copy.should.exclude_end? - copy.should_not.equal? original - end - - it "maintains the frozen state" do - (1..2).clone.frozen?.should == (1..2).frozen? - (1..).clone.frozen?.should == (1..).frozen? - Range.new(1, 2).clone.frozen?.should == Range.new(1, 2).frozen? - Class.new(Range).new(1, 2).clone.frozen?.should == Class.new(Range).new(1, 2).frozen? - end -end diff --git a/spec/ruby/core/range/count_spec.rb b/spec/ruby/core/range/count_spec.rb index 24d4a9caf3..f6f60fa054 100644 --- a/spec/ruby/core/range/count_spec.rb +++ b/spec/ruby/core/range/count_spec.rb @@ -1,12 +1,14 @@ require_relative '../../spec_helper' describe "Range#count" 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 - (...'a').count.should == inf - (...nil).count.should == inf - (..10.0).count.should == inf + 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 end end diff --git a/spec/ruby/core/range/cover_spec.rb b/spec/ruby/core/range/cover_spec.rb index eb7cddc967..fa881607e9 100644 --- a/spec/ruby/core/range/cover_spec.rb +++ b/spec/ruby/core/range/cover_spec.rb @@ -7,8 +7,4 @@ describe "Range#cover?" do it_behaves_like :range_cover_and_include, :cover? it_behaves_like :range_cover, :cover? it_behaves_like :range_cover_subrange, :cover? - - it "covers U+9995 in the range U+0999..U+9999" do - ("\u{999}".."\u{9999}").cover?("\u{9995}").should be_true - end end diff --git a/spec/ruby/core/range/dup_spec.rb b/spec/ruby/core/range/dup_spec.rb index fab3c3f1b2..6c9d0c954a 100644 --- a/spec/ruby/core/range/dup_spec.rb +++ b/spec/ruby/core/range/dup_spec.rb @@ -2,22 +2,14 @@ require_relative '../../spec_helper' describe "Range#dup" do it "duplicates the range" do - original = (1..3) - copy = original.dup + copy = (1..3).dup copy.begin.should == 1 copy.end.should == 3 copy.should_not.exclude_end? - copy.should_not.equal?(original) copy = ("a"..."z").dup copy.begin.should == "a" 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 ecae17c881..6b33f57737 100644 --- a/spec/ruby/core/range/each_spec.rb +++ b/spec/ruby/core/range/each_spec.rb @@ -58,8 +58,10 @@ describe "Range#each" do a.should == ["A", "B", "C", "D"] end - it "raises a TypeError beginless ranges" do - -> { (..2).each { |x| x } }.should raise_error(TypeError) + ruby_version_is "2.7" do + it "raises a TypeError beginless ranges" do + -> { eval("(..2)").each { |x| x } }.should raise_error(TypeError) + end 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 83dcf5cec8..0aaebfb59a 100644 --- a/spec/ruby/core/range/equal_value_spec.rb +++ b/spec/ruby/core/range/equal_value_spec.rb @@ -12,7 +12,9 @@ describe "Range#==" do eval("(1.0..)").should == eval("(1.0..)") end - it "returns true if the endpoints are == for beginless ranges" do - (...10).should == (...10) + ruby_version_is "2.7" do + it "returns true if the endpoints are == for beginless ranges" do + eval("(...10)").should == eval("(...10)") + end end end diff --git a/spec/ruby/core/range/first_spec.rb b/spec/ruby/core/range/first_spec.rb index 2af935f439..c5c90800ac 100644 --- a/spec/ruby/core/range/first_spec.rb +++ b/spec/ruby/core/range/first_spec.rb @@ -47,7 +47,9 @@ describe "Range#first" do -> { (2..3).first("1") }.should raise_error(TypeError) end - it "raises a RangeError when called on an beginless range" do - -> { (..1).first }.should raise_error(RangeError) + 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 end end diff --git a/spec/ruby/core/range/frozen_spec.rb b/spec/ruby/core/range/frozen_spec.rb deleted file mode 100644 index 8dab5e5339..0000000000 --- a/spec/ruby/core/range/frozen_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -require_relative '../../spec_helper' - -# There is no Range#frozen? method but this feels like the best place for these specs -describe "Range#frozen?" 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 diff --git a/spec/ruby/core/range/include_spec.rb b/spec/ruby/core/range/include_spec.rb index 277de205d1..b2c7a54545 100644 --- a/spec/ruby/core/range/include_spec.rb +++ b/spec/ruby/core/range/include_spec.rb @@ -7,8 +7,4 @@ require_relative 'shared/cover' describe "Range#include?" do it_behaves_like :range_cover_and_include, :include? it_behaves_like :range_include, :include? - - it "does not include U+9995 in the range U+0999..U+9999" do - ("\u{999}".."\u{9999}").include?("\u{9995}").should be_false - end end diff --git a/spec/ruby/core/range/initialize_spec.rb b/spec/ruby/core/range/initialize_spec.rb index c653caf0c6..8a6ca65daa 100644 --- a/spec/ruby/core/range/initialize_spec.rb +++ b/spec/ruby/core/range/initialize_spec.rb @@ -27,9 +27,18 @@ describe "Range#initialize" do -> { @range.send(:initialize, 1, 3, 5, 7, 9) }.should raise_error(ArgumentError) end - it "raises a FrozenError if called on an already initialized Range" do - -> { (0..1).send(:initialize, 1, 3) }.should raise_error(FrozenError) - -> { (0..1).send(:initialize, 1, 3, true) }.should raise_error(FrozenError) + ruby_version_is ""..."3.0" do + it "raises a NameError if called on an already initialized Range" do + -> { (0..1).send(:initialize, 1, 3) }.should raise_error(NameError) + -> { (0..1).send(:initialize, 1, 3, true) }.should raise_error(NameError) + end + end + + ruby_version_is "3.0" do + it "raises a FrozenError if called on an already initialized Range" do + -> { (0..1).send(:initialize, 1, 3) }.should raise_error(FrozenError) + -> { (0..1).send(:initialize, 1, 3, true) }.should raise_error(FrozenError) + end end it "raises an ArgumentError if arguments don't respond to <=>" do diff --git a/spec/ruby/core/range/inspect_spec.rb b/spec/ruby/core/range/inspect_spec.rb index 072de123b7..f49882e6ce 100644 --- a/spec/ruby/core/range/inspect_spec.rb +++ b/spec/ruby/core/range/inspect_spec.rb @@ -17,13 +17,29 @@ describe "Range#inspect" do eval("(0.1...)").inspect.should == "0.1..." end - it "works for beginless ranges" do - (..1).inspect.should == "..1" - (...0.1).inspect.should == "...0.1" + 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 end - it "works for nil ... nil ranges" do - (..nil).inspect.should == "nil..nil" - eval("(nil...)").inspect.should == "nil...nil" + 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 end end diff --git a/spec/ruby/core/range/max_spec.rb b/spec/ruby/core/range/max_spec.rb index a3bbc31e7d..a970144d66 100644 --- a/spec/ruby/core/range/max_spec.rb +++ b/spec/ruby/core/range/max_spec.rb @@ -50,15 +50,17 @@ describe "Range#max" do -> { eval("(1..)").max }.should raise_error(RangeError) end - it "returns the end point for beginless ranges" do - (..1).max.should == 1 - (..1.0).max.should == 1.0 - end + 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 + end - it "raises for an exclusive beginless range" do - -> { - (...1).max - }.should raise_error(TypeError, 'cannot exclude end value with non Integer begin value') + it "raises for an exclusive beginless range" do + -> { + eval("(...1)").max + }.should raise_error(TypeError, 'cannot exclude end value with non Integer begin value') + end end end @@ -95,7 +97,9 @@ describe "Range#max given a block" do (5...5).max {|x,y| x <=> y}.should be_nil end - it "raises RangeError when called with custom comparison method on an beginless range" do - -> { (..1).max {|a, b| a} }.should raise_error(RangeError) + 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 end end diff --git a/spec/ruby/core/range/min_spec.rb b/spec/ruby/core/range/min_spec.rb index 89310ee589..6e56cc733b 100644 --- a/spec/ruby/core/range/min_spec.rb +++ b/spec/ruby/core/range/min_spec.rb @@ -44,8 +44,10 @@ describe "Range#min" do eval("(1.0...)").min.should == 1.0 end - it "raises RangeError when called on an beginless range" do - -> { (..1).min }.should raise_error(RangeError) + ruby_version_is "2.7" do + it "raises RangeError when called on an beginless range" do + -> { eval("(..1)").min }.should raise_error(RangeError) + end end end diff --git a/spec/ruby/core/range/minmax_spec.rb b/spec/ruby/core/range/minmax_spec.rb index 6651ae3726..1db9bfce38 100644 --- a/spec/ruby/core/range/minmax_spec.rb +++ b/spec/ruby/core/range/minmax_spec.rb @@ -1,5 +1,6 @@ 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') @@ -12,26 +13,37 @@ describe 'Range#minmax' do end describe 'on an inclusive range' do - it 'should raise RangeError on an endless range without iterating the range' do - @x.should_not_receive(:succ) - - range = (@x..) + 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(RangeError, 'cannot get the maximum of endless range') + -> { range.minmax }.should raise_error(NoMethodError, /^undefined method `succ' for/) + 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 - } + ruby_version_is '2.7' do + it 'should raise RangeError on an endless range without iterating the range' do + @x.should_not_receive(:succ) + + range = (@x..) + + -> { 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 end it 'should return beginning of range if beginning and end are equal without iterating the range' do @@ -46,22 +58,34 @@ describe 'Range#minmax' do (@y..@x).minmax.should == [nil, nil] end - it 'should return the minimum and maximum values for a non-numeric range without iterating the range' do - @x.should_not_receive(:succ) + 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) - (@x..@y).minmax.should == [@x, @y] + (@x..@y).minmax.should == [@x, @y] + end end it 'should return the minimum and maximum values for a numeric range' do (1..3).minmax.should == [1, 3] end - 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 + 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 - (1..range_end).minmax.should == [1, range_end] + (1..range_end).minmax.should == [1, range_end] + end end it 'should return the minimum and maximum values according to the provided block by iterating the range' do @@ -72,53 +96,69 @@ describe 'Range#minmax' do end describe 'on an exclusive range' do - it 'should raise RangeError on an endless range' do - @x.should_not_receive(:succ) - range = (@x...) + 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...) - -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range') + -> { range.minmax }.should raise_error(NoMethodError, /^undefined method `succ' for/) + end end - it 'should raise RangeError on a beginless range' do - range = (...@x) + ruby_version_is '2.7' do + it 'should raise RangeError on an endless range' do + @x.should_not_receive(:succ) + range = (@x...) - -> { 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 endless range') + end - it 'should return nil pair if beginning and end are equal without iterating the range' do - @x.should_not_receive(:succ) + it 'should raise RangeError on a beginless range' do + range = Range.new(nil, @x, true) - (@x...@x).minmax.should == [nil, nil] + -> { 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 end - it 'should return nil pair if beginning is greater than end without iterating the range' do - @y.should_not_receive(:succ) + ruby_bug "#17014", "2.7.0"..."3.0" do + it 'should return nil pair if beginning and end are equal without iterating the range' do + @x.should_not_receive(:succ) - (@y...@x).minmax.should == [nil, nil] - end + (@x...@x).minmax.should == [nil, nil] + end - 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) + it 'should return nil pair if beginning is greater than end without iterating the range' do + @y.should_not_receive(:succ) + + (@y...@x).minmax.should == [nil, nil] + end - (@x...@y).minmax.should == [@x, @x] + 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, @x] + end end it 'should return the minimum and maximum values for a numeric range' do (1...3).minmax.should == [1, 2] end - 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 + 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 - (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') + 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 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 3cab887799..a4de4963e7 100644 --- a/spec/ruby/core/range/new_spec.rb +++ b/spec/ruby/core/range/new_spec.rb @@ -42,16 +42,24 @@ describe "Range.new" do end describe "beginless/endless range" do - it "allows beginless left boundary" do - range = Range.new(nil, 1) - range.begin.should == nil + 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 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) + ruby_version_is "2.7" do + it "allows beginless left boundary" do + range = Range.new(nil, 1) + range.begin.should == nil + end - range_exclude.should_not == range_include + 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 end it "allows endless right boundary" do @@ -65,13 +73,5 @@ describe "Range.new" do range_exclude.should_not == range_include end - - it "creates a frozen range if the class is Range.class" do - Range.new(1, 2).should.frozen? - end - - it "does not create a frozen range if the class is not Range.class" do - Class.new(Range).new(1, 2).should_not.frozen? - end end end diff --git a/spec/ruby/core/range/shared/cover.rb b/spec/ruby/core/range/shared/cover.rb index 0b41a26455..f3c7d22668 100644 --- a/spec/ruby/core/range/shared/cover.rb +++ b/spec/ruby/core/range/shared/cover.rb @@ -151,43 +151,45 @@ describe :range_cover_subrange, shared: true do end end - 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 + 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 - (..7.9).send(@method, (2.5..6.5)).should be_true - (..7.9).send(@method, (2.5..8.5)).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 - (..'i').send(@method, ('d'..'f')).should be_true - (..'i').send(@method, ('d'..'z')).should be_false - end + eval("(..'i')").send(@method, ('d'..'f')).should be_true + eval("(..'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 - (..10).send(@method, (...10)).should be_true - (0..10).send(@method, (...10)).should be_false + it "accepts beginless range argument" do + eval("(..10)").send(@method, eval("(...10)")).should be_true + (0..10).send(@method, eval("(...10)")).should be_false - (1.1..7.9).send(@method, (...10.5)).should be_false + (1.1..7.9).send(@method, eval("(...10.5)")).should be_false - ('c'..'i').send(@method, (..'i')).should be_false - end + ('c'..'i').send(@method, eval("(..'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 + ('c'..'i').send(@method, eval("('a'..)")).should be_false + end 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 f36a2cef8b..e978e39af5 100644 --- a/spec/ruby/core/range/shared/cover_and_include.rb +++ b/spec/ruby/core/range/shared/cover_and_include.rb @@ -24,9 +24,11 @@ describe :range_cover_and_include, shared: true do eval("(0.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 + 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 end it "compares values using <=>" do @@ -57,6 +59,7 @@ describe :range_cover_and_include, shared: true do it "returns true if argument is less than the last value of the range and greater than the first value" do (20..30).send(@method, 28).should be_true ('e'..'h').send(@method, 'g').should be_true + ("\u{999}".."\u{9999}").send @method, "\u{9995}" end it "returns true if argument is sole element in the range" do diff --git a/spec/ruby/core/range/size_spec.rb b/spec/ruby/core/range/size_spec.rb index 81ea5a3846..0019c5ff00 100644 --- a/spec/ruby/core/range/size_spec.rb +++ b/spec/ruby/core/range/size_spec.rb @@ -34,27 +34,12 @@ describe "Range#size" do eval("([]...)").size.should == nil end - ruby_version_is ""..."3.2" do + ruby_version_is "2.7" do 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 - end - - ruby_version_is "3.2" do - it 'returns Float::INFINITY for all beginless ranges if the end is numeric' do - (..1).size.should == Float::INFINITY - (...0.5).size.should == Float::INFINITY - end - - it 'returns nil for all beginless ranges if the end is not numeric' do - (...'o').size.should == nil - end - - it 'returns nil if the start and the end is both nil' do - (nil..nil).size.should == nil + 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 end diff --git a/spec/ruby/core/range/step_spec.rb b/spec/ruby/core/range/step_spec.rb index 64ea3de4ed..4c69073854 100644 --- a/spec/ruby/core/range/step_spec.rb +++ b/spec/ruby/core/range/step_spec.rb @@ -377,21 +377,48 @@ describe "Range#step" do end describe "when no block is given" do - it "raises an ArgumentError if step is 0" do - -> { (-1..1).step(0) }.should raise_error(ArgumentError) + ruby_version_is "3.0" do + it "raises an ArgumentError if step is 0" do + -> { (-1..1).step(0) }.should raise_error(ArgumentError) + end end describe "returned Enumerator" do describe "size" do - it "raises a TypeError if step does not respond to #to_int" do - obj = mock("Range#step non-integer") - -> { (1..2).step(obj) }.should raise_error(TypeError) + ruby_version_is ""..."3.0" do + it "raises a TypeError if step does not respond to #to_int" do + obj = mock("Range#step non-integer") + enum = (1..2).step(obj) + -> { enum.size }.should raise_error(TypeError) + end + + it "raises a TypeError if #to_int does not return an Integer" do + obj = mock("Range#step non-integer") + obj.should_receive(:to_int).and_return("1") + enum = (1..2).step(obj) + + -> { enum.size }.should raise_error(TypeError) + end end - it "raises a TypeError if #to_int does not return an Integer" do - obj = mock("Range#step non-integer") - obj.should_receive(:to_int).and_return("1") - -> { (1..2).step(obj) }.should raise_error(TypeError) + ruby_version_is "3.0" do + it "raises a TypeError if step does not respond to #to_int" do + obj = mock("Range#step non-integer") + -> { (1..2).step(obj) }.should raise_error(TypeError) + end + + it "raises a TypeError if #to_int does not return an Integer" do + obj = mock("Range#step non-integer") + obj.should_receive(:to_int).and_return("1") + -> { (1..2).step(obj) }.should raise_error(TypeError) + end + end + + ruby_version_is ""..."3.0" do + it "returns Float::INFINITY for zero step" do + (-1..1).step(0).size.should == Float::INFINITY + (-1..1).step(0.0).size.should == Float::INFINITY + end end it "returns the ceil of range size divided by the number of steps" do @@ -447,45 +474,42 @@ describe "Range#step" do end end - # We use .take below to ensure the enumerator works - # because that's an Enumerable method and so it uses the Enumerator behavior - # not just a method overridden in Enumerator::ArithmeticSequence. describe "type" do context "when both begin and end are numerics" do it "returns an instance of Enumerator::ArithmeticSequence" do (1..10).step.class.should == Enumerator::ArithmeticSequence - (1..10).step(3).take(4).should == [1, 4, 7, 10] end 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 + 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 end end context "when range is endless" do it "returns an instance of Enumerator::ArithmeticSequence when begin is numeric" do (1..).step.class.should == Enumerator::ArithmeticSequence - (1..).step(2).take(3).should == [1, 3, 5] end it "returns an instance of Enumerator when begin is not numeric" do ("a"..).step.class.should == Enumerator - ("a"..).step(2).take(3).should == %w[a c e] end end - context "when range is beginless and endless" do - it "returns an instance of Enumerator" do - Range.new(nil, nil).step.class.should == Enumerator + 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 end end context "when begin and end are not numerics" do it "returns an instance of Enumerator" do ("a".."z").step.class.should == Enumerator - ("a".."z").step(3).take(4).should == %w[a d g j] end end end diff --git a/spec/ruby/core/range/to_a_spec.rb b/spec/ruby/core/range/to_a_spec.rb index b1d3de32db..52ebc02941 100644 --- a/spec/ruby/core/range/to_a_spec.rb +++ b/spec/ruby/core/range/to_a_spec.rb @@ -33,7 +33,9 @@ describe "Range#to_a" do -> { eval("(1..)").to_a }.should raise_error(RangeError) end - it "throws an exception for beginless ranges" do - -> { (..1).to_a }.should raise_error(TypeError) + ruby_version_is "2.7" do + it "throws an exception for beginless ranges" do + -> { eval("(..1)").to_a }.should raise_error(TypeError) + end end end diff --git a/spec/ruby/core/range/to_s_spec.rb b/spec/ruby/core/range/to_s_spec.rb index 460c330912..581c2e7d90 100644 --- a/spec/ruby/core/range/to_s_spec.rb +++ b/spec/ruby/core/range/to_s_spec.rb @@ -16,8 +16,24 @@ describe "Range#to_s" do eval("(1.0...)").to_s.should == "1.0..." end - it "can show beginless ranges" do - (..1).to_s.should == "..1" - (...1.0).to_s.should == "...1.0" + 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 end end diff --git a/spec/ruby/core/rational/abs_spec.rb b/spec/ruby/core/rational/abs_spec.rb index 7272ad2422..aed7713058 100644 --- a/spec/ruby/core/rational/abs_spec.rb +++ b/spec/ruby/core/rational/abs_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/abs' describe "Rational#abs" do diff --git a/spec/ruby/core/rational/ceil_spec.rb b/spec/ruby/core/rational/ceil_spec.rb index e736351604..5b0ca4a9d6 100644 --- a/spec/ruby/core/rational/ceil_spec.rb +++ b/spec/ruby/core/rational/ceil_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/ceil' describe "Rational#ceil" do diff --git a/spec/ruby/core/rational/coerce_spec.rb b/spec/ruby/core/rational/coerce_spec.rb index 9c0f05829b..3f78f0bcd6 100644 --- a/spec/ruby/core/rational/coerce_spec.rb +++ b/spec/ruby/core/rational/coerce_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/coerce' describe "Rational#coerce" do diff --git a/spec/ruby/core/rational/comparison_spec.rb b/spec/ruby/core/rational/comparison_spec.rb index 877069fb8f..9d8e7fd7ee 100644 --- a/spec/ruby/core/rational/comparison_spec.rb +++ b/spec/ruby/core/rational/comparison_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/comparison' describe "Rational#<=> when passed a Rational object" do diff --git a/spec/ruby/core/rational/denominator_spec.rb b/spec/ruby/core/rational/denominator_spec.rb index c2f49b4190..6214b40587 100644 --- a/spec/ruby/core/rational/denominator_spec.rb +++ b/spec/ruby/core/rational/denominator_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/denominator' describe "Rational#denominator" do diff --git a/spec/ruby/core/rational/div_spec.rb b/spec/ruby/core/rational/div_spec.rb index bee7d01a67..1cd8606b90 100644 --- a/spec/ruby/core/rational/div_spec.rb +++ b/spec/ruby/core/rational/div_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/div' describe "Rational#div" do diff --git a/spec/ruby/core/rational/divide_spec.rb b/spec/ruby/core/rational/divide_spec.rb index 14e8c4c195..d8e3a44dc2 100644 --- a/spec/ruby/core/rational/divide_spec.rb +++ b/spec/ruby/core/rational/divide_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/divide' require_relative '../../shared/rational/arithmetic_exception_in_coerce' diff --git a/spec/ruby/core/rational/divmod_spec.rb b/spec/ruby/core/rational/divmod_spec.rb index 7ffdde74f4..6be1f8bd73 100644 --- a/spec/ruby/core/rational/divmod_spec.rb +++ b/spec/ruby/core/rational/divmod_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/divmod' describe "Rational#divmod when passed a Rational" do diff --git a/spec/ruby/core/rational/equal_value_spec.rb b/spec/ruby/core/rational/equal_value_spec.rb index c6f7f4c6a2..8e7acb1354 100644 --- a/spec/ruby/core/rational/equal_value_spec.rb +++ b/spec/ruby/core/rational/equal_value_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/equal_value' describe "Rational#==" do diff --git a/spec/ruby/core/rational/exponent_spec.rb b/spec/ruby/core/rational/exponent_spec.rb index 7e35b4ebc1..622cf22782 100644 --- a/spec/ruby/core/rational/exponent_spec.rb +++ b/spec/ruby/core/rational/exponent_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/exponent' describe "Rational#**" do diff --git a/spec/ruby/core/rational/fdiv_spec.rb b/spec/ruby/core/rational/fdiv_spec.rb index b75f39abd5..bfb321abaa 100644 --- a/spec/ruby/core/rational/fdiv_spec.rb +++ b/spec/ruby/core/rational/fdiv_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/fdiv' describe "Rational#fdiv" do diff --git a/spec/ruby/core/rational/floor_spec.rb b/spec/ruby/core/rational/floor_spec.rb index 70db0499d0..752a2d8815 100644 --- a/spec/ruby/core/rational/floor_spec.rb +++ b/spec/ruby/core/rational/floor_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/floor' describe "Rational#floor" do diff --git a/spec/ruby/core/rational/hash_spec.rb b/spec/ruby/core/rational/hash_spec.rb index 7e8d30049b..84cd31518a 100644 --- a/spec/ruby/core/rational/hash_spec.rb +++ b/spec/ruby/core/rational/hash_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/hash' describe "Rational#hash" do diff --git a/spec/ruby/core/rational/inspect_spec.rb b/spec/ruby/core/rational/inspect_spec.rb index 2cbf6cadc1..ef337ef0ce 100644 --- a/spec/ruby/core/rational/inspect_spec.rb +++ b/spec/ruby/core/rational/inspect_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/inspect' describe "Rational#inspect" do diff --git a/spec/ruby/core/rational/integer_spec.rb b/spec/ruby/core/rational/integer_spec.rb index be7476a9dd..0f9a3bdead 100644 --- a/spec/ruby/core/rational/integer_spec.rb +++ b/spec/ruby/core/rational/integer_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" describe "Rational#integer?" do # Guard against the Mathn library guard -> { !defined?(Math.rsqrt) } do diff --git a/spec/ruby/core/rational/magnitude_spec.rb b/spec/ruby/core/rational/magnitude_spec.rb index 27d9af6a81..878fc8f879 100644 --- a/spec/ruby/core/rational/magnitude_spec.rb +++ b/spec/ruby/core/rational/magnitude_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/abs' describe "Rational#abs" do diff --git a/spec/ruby/core/rational/minus_spec.rb b/spec/ruby/core/rational/minus_spec.rb index a61b62ebe6..9e0f81556b 100644 --- a/spec/ruby/core/rational/minus_spec.rb +++ b/spec/ruby/core/rational/minus_spec.rb @@ -1,51 +1,7 @@ -require_relative '../../spec_helper' +require_relative '../../shared/rational/minus' 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/rational/modulo_spec.rb b/spec/ruby/core/rational/modulo_spec.rb index 7a60c176ac..c43f7788e3 100644 --- a/spec/ruby/core/rational/modulo_spec.rb +++ b/spec/ruby/core/rational/modulo_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/modulo' describe "Rational#%" do diff --git a/spec/ruby/core/rational/multiply_spec.rb b/spec/ruby/core/rational/multiply_spec.rb index 7413376bb1..ea644074e9 100644 --- a/spec/ruby/core/rational/multiply_spec.rb +++ b/spec/ruby/core/rational/multiply_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/multiply' require_relative '../../shared/rational/arithmetic_exception_in_coerce' diff --git a/spec/ruby/core/rational/numerator_spec.rb b/spec/ruby/core/rational/numerator_spec.rb index 6f9a9c0e3b..85b2ed9e86 100644 --- a/spec/ruby/core/rational/numerator_spec.rb +++ b/spec/ruby/core/rational/numerator_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/numerator' describe "Rational#numerator" do diff --git a/spec/ruby/core/rational/plus_spec.rb b/spec/ruby/core/rational/plus_spec.rb index 67c0ff63d2..e7ef3a8f92 100644 --- a/spec/ruby/core/rational/plus_spec.rb +++ b/spec/ruby/core/rational/plus_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/plus' require_relative '../../shared/rational/arithmetic_exception_in_coerce' diff --git a/spec/ruby/core/rational/quo_spec.rb b/spec/ruby/core/rational/quo_spec.rb index 181f091f7c..119aca1955 100644 --- a/spec/ruby/core/rational/quo_spec.rb +++ b/spec/ruby/core/rational/quo_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/divide' describe "Rational#quo" do diff --git a/spec/ruby/core/rational/remainder_spec.rb b/spec/ruby/core/rational/remainder_spec.rb index 1c0035e5f4..0f9442f6f5 100644 --- a/spec/ruby/core/rational/remainder_spec.rb +++ b/spec/ruby/core/rational/remainder_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/remainder' describe "Rational#remainder" do diff --git a/spec/ruby/core/rational/to_f_spec.rb b/spec/ruby/core/rational/to_f_spec.rb index a9cd1be3b5..15bf1e88dc 100644 --- a/spec/ruby/core/rational/to_f_spec.rb +++ b/spec/ruby/core/rational/to_f_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/to_f' describe "Rational#to_f" do diff --git a/spec/ruby/core/rational/to_i_spec.rb b/spec/ruby/core/rational/to_i_spec.rb index 22cf02b4da..3deb3664e1 100644 --- a/spec/ruby/core/rational/to_i_spec.rb +++ b/spec/ruby/core/rational/to_i_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/to_i' describe "Rational#to_i" do diff --git a/spec/ruby/core/rational/to_r_spec.rb b/spec/ruby/core/rational/to_r_spec.rb index 03f204daf1..cc704c965e 100644 --- a/spec/ruby/core/rational/to_r_spec.rb +++ b/spec/ruby/core/rational/to_r_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/to_r' describe "Rational#to_r" do diff --git a/spec/ruby/core/rational/to_s_spec.rb b/spec/ruby/core/rational/to_s_spec.rb index 5d90c7d80b..c5c419787c 100644 --- a/spec/ruby/core/rational/to_s_spec.rb +++ b/spec/ruby/core/rational/to_s_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/to_s' describe "Rational#to_s" do diff --git a/spec/ruby/core/rational/truncate_spec.rb b/spec/ruby/core/rational/truncate_spec.rb index 47a7cdf17c..4e72339752 100644 --- a/spec/ruby/core/rational/truncate_spec.rb +++ b/spec/ruby/core/rational/truncate_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative '../../shared/rational/truncate' describe "Rational#truncate" do diff --git a/spec/ruby/core/rational/zero_spec.rb b/spec/ruby/core/rational/zero_spec.rb index af7fb391ac..e6dd751922 100644 --- a/spec/ruby/core/rational/zero_spec.rb +++ b/spec/ruby/core/rational/zero_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" describe "Rational#zero?" do it "returns true if the numerator is 0" do Rational(0,26).zero?.should be_true diff --git a/spec/ruby/core/refinement/append_features_spec.rb b/spec/ruby/core/refinement/append_features_spec.rb deleted file mode 100644 index fb84f245bd..0000000000 --- a/spec/ruby/core/refinement/append_features_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -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 deleted file mode 100644 index 6c2a0af4f3..0000000000 --- a/spec/ruby/core/refinement/extend_object_spec.rb +++ /dev/null @@ -1,23 +0,0 @@ -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 } - -> { - c.extend(self) - }.should raise_error(TypeError) - called.should == false - end - end - end - end -end diff --git a/spec/ruby/core/refinement/fixtures/classes.rb b/spec/ruby/core/refinement/fixtures/classes.rb deleted file mode 100644 index 94324db47c..0000000000 --- a/spec/ruby/core/refinement/fixtures/classes.rb +++ /dev/null @@ -1,10 +0,0 @@ -module RefinementSpec - - module ModuleWithAncestors - include Module.new do - def indent(level) - " " * level + self - end - end - end -end diff --git a/spec/ruby/core/refinement/import_methods_spec.rb b/spec/ruby/core/refinement/import_methods_spec.rb deleted file mode 100644 index 05973b2380..0000000000 --- a/spec/ruby/core/refinement/import_methods_spec.rb +++ /dev/null @@ -1,269 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/classes' - -describe "Refinement#import_methods" do - ruby_version_is "3.1" do - context "when methods are defined in Ruby code" do - it "imports methods" do - str_utils = Module.new do - def indent(level) - " " * level + self - end - end - - Module.new do - refine String do - import_methods str_utils - "foo".indent(3).should == " foo" - end - end - end - - it "throws an exception when argument is not a module" do - Module.new do - refine String do - -> { - import_methods Integer - }.should raise_error(TypeError, "wrong argument type Class (expected Module)") - end - end - end - - it "imports methods from multiple modules" do - str_utils = Module.new do - def indent(level) - " " * level + self - end - end - - str_utils_fancy = Module.new do - def indent_star(level) - "*" * level + self - end - end - - Module.new do - refine String do - import_methods str_utils, str_utils_fancy - "foo".indent(3).should == " foo" - "foo".indent_star(3).should == "***foo" - end - end - end - - it "imports a method defined in the last module if method with same name is defined in multiple modules" do - str_utils = Module.new do - def indent(level) - " " * level + self - end - end - - str_utils_fancy = Module.new do - def indent(level) - "*" * level + self - end - end - - Module.new do - refine String do - import_methods str_utils, str_utils_fancy - "foo".indent(3).should == "***foo" - end - end - end - - it "still imports methods of modules listed before a module that contains method not defined in Ruby" do - str_utils = Module.new do - def indent(level) - " " * level + self - end - end - - string_refined = Module.new do - refine String do - -> { - import_methods str_utils, Kernel - }.should raise_error(ArgumentError) - end - end - - Module.new do - using string_refined - "foo".indent(3).should == " foo" - end - end - end - - it "warns if a module includes/prepends some other module" do - module1 = Module.new do - end - - module2 = Module.new do - include module1 - end - - Module.new do - refine String do - -> { - import_methods module2 - }.should complain(/warning: #<Module:\w*> has ancestors, but Refinement#import_methods doesn't import their methods/) - end - end - - Module.new do - refine String do - -> { - import_methods RefinementSpec::ModuleWithAncestors - }.should complain(/warning: RefinementSpec::ModuleWithAncestors has ancestors, but Refinement#import_methods doesn't import their methods/) - end - end - end - - it "doesn't import methods from included/prepended modules" do - Module.new do - refine String do - suppress_warning { import_methods RefinementSpec::ModuleWithAncestors } - end - - using self - -> { - "foo".indent(3) - }.should raise_error(NoMethodError, /undefined method `indent' for ("foo":String|an instance of String)/) - end - end - - it "doesn't import any methods if one of the arguments is not a module" do - str_utils = Module.new do - def indent(level) - " " * level + self - end - end - - string_refined = Module.new do - refine String do - -> { - import_methods str_utils, Integer - }.should raise_error(TypeError) - end - end - - Module.new do - using string_refined - -> { - "foo".indent(3) - }.should raise_error(NoMethodError) - end - end - - it "imports methods from multiple modules so that methods see other's module's methods" do - str_utils = Module.new do - def indent(level) - " " * level + self - end - end - - str_utils_normal = Module.new do - def indent_normal(level) - self.indent(level) - end - end - - Module.new do - refine String do - import_methods str_utils, str_utils_normal - end - - using self - "foo".indent_normal(3).should == " foo" - end - end - - it "imports methods from module so that methods can see each other" do - str_utils = Module.new do - def indent(level) - " " * level + self - end - - def indent_with_dot(level) - self.indent(level) + "." - end - end - - Module.new do - refine String do - import_methods str_utils - end - - using self - "foo".indent_with_dot(3).should == " foo." - end - end - - it "doesn't import module's class methods" do - str_utils = Module.new do - def self.indent(level) - " " * level + self - end - end - - Module.new do - refine String do - import_methods str_utils - end - - using self - -> { - String.indent(3) - }.should raise_error(NoMethodError, /undefined method `indent' for (String:Class|class String)/) - end - end - - it "imports module methods with super" do - class_to_refine = Class.new do - def foo(number) - 2 * number - end - end - - extension = Module.new do - def foo(number) - super * 2 - end - end - - refinement = Module.new do - refine class_to_refine do - import_methods extension - end - end - - Module.new do - using refinement - class_to_refine.new.foo(2).should == 8 - end - end - - context "when methods are not defined in Ruby code" do - it "raises ArgumentError" do - Module.new do - refine String do - -> { - import_methods Kernel - }.should raise_error(ArgumentError) - end - end - end - - it "raises ArgumentError when importing methods from C extension" do - require 'zlib' - Module.new do - refine String do - -> { - import_methods Zlib - }.should raise_error(ArgumentError, /Can't import method which is not defined with Ruby code: Zlib#*/) - end - end - end - end - end -end diff --git a/spec/ruby/core/refinement/include_spec.rb b/spec/ruby/core/refinement/include_spec.rb deleted file mode 100644 index 25a53f0ec7..0000000000 --- a/spec/ruby/core/refinement/include_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -require_relative '../../spec_helper' - -describe "Refinement#include" do - ruby_version_is "3.1"..."3.2" do - it "warns about deprecation" do - Module.new do - refine String do - -> { - include Module.new - }.should complain(/warning: Refinement#include is deprecated and will be removed in Ruby 3.2/) - end - end - end - end - - ruby_version_is "3.2" do - it "raises a TypeError" do - Module.new do - refine String do - -> { - include Module.new - }.should raise_error(TypeError, "Refinement#include has been removed") - 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 deleted file mode 100644 index 9fdea199a2..0000000000 --- a/spec/ruby/core/refinement/prepend_features_spec.rb +++ /dev/null @@ -1,21 +0,0 @@ -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/refinement/prepend_spec.rb b/spec/ruby/core/refinement/prepend_spec.rb deleted file mode 100644 index 27b70d392a..0000000000 --- a/spec/ruby/core/refinement/prepend_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -require_relative '../../spec_helper' - -describe "Refinement#prepend" do - ruby_version_is "3.1"..."3.2" do - it "warns about deprecation" do - Module.new do - refine String do - -> { - prepend Module.new - }.should complain(/warning: Refinement#prepend is deprecated and will be removed in Ruby 3.2/) - end - end - end - end - - ruby_version_is "3.2" do - it "raises a TypeError" do - Module.new do - refine String do - -> { - prepend Module.new - }.should raise_error(TypeError, "Refinement#prepend has been removed") - end - end - end - end -end diff --git a/spec/ruby/core/refinement/refined_class_spec.rb b/spec/ruby/core/refinement/refined_class_spec.rb deleted file mode 100644 index 00b65d0895..0000000000 --- a/spec/ruby/core/refinement/refined_class_spec.rb +++ /dev/null @@ -1,17 +0,0 @@ -require_relative '../../spec_helper' - -describe "Refinement#refined_class" do - ruby_version_is "3.2"..."3.3" do - it "returns the class refined by the receiver" do - refinement_int = nil - - Module.new do - refine Integer do - refinement_int = self - end - end - - refinement_int.refined_class.should == Integer - end - end -end diff --git a/spec/ruby/core/regexp/compile_spec.rb b/spec/ruby/core/regexp/compile_spec.rb index c41399cfbb..329cb4f753 100644 --- a/spec/ruby/core/regexp/compile_spec.rb +++ b/spec/ruby/core/regexp/compile_spec.rb @@ -13,7 +13,3 @@ end describe "Regexp.compile given a Regexp" do it_behaves_like :regexp_new_regexp, :compile end - -describe "Regexp.new given a non-String/Regexp" do - it_behaves_like :regexp_new_non_string_or_regexp, :compile -end diff --git a/spec/ruby/core/regexp/initialize_spec.rb b/spec/ruby/core/regexp/initialize_spec.rb index dd57292242..772a233e82 100644 --- a/spec/ruby/core/regexp/initialize_spec.rb +++ b/spec/ruby/core/regexp/initialize_spec.rb @@ -2,11 +2,19 @@ require_relative '../../spec_helper' describe "Regexp#initialize" do it "is a private method" do - Regexp.should have_private_instance_method(:initialize) + Regexp.should have_private_method(:initialize) end - it "raises a FrozenError on a Regexp literal" do - -> { //.send(:initialize, "") }.should raise_error(FrozenError) + ruby_version_is ""..."3.0" do + it "raises a SecurityError on a Regexp literal" do + -> { //.send(:initialize, "") }.should raise_error(SecurityError) + end + end + + ruby_version_is "3.0" do + it "raises a FrozenError on a Regexp literal" do + -> { //.send(:initialize, "") }.should raise_error(FrozenError) + end end it "raises a TypeError on an initialized non-literal Regexp" do diff --git a/spec/ruby/core/regexp/linear_time_spec.rb b/spec/ruby/core/regexp/linear_time_spec.rb deleted file mode 100644 index 4dc436264f..0000000000 --- a/spec/ruby/core/regexp/linear_time_spec.rb +++ /dev/null @@ -1,25 +0,0 @@ -require_relative '../../spec_helper' - -ruby_version_is "3.2" do - describe "Regexp.linear_time?" do - it "returns true if matching can be done in linear time" do - Regexp.linear_time?(/a/).should == true - Regexp.linear_time?('a').should == true - end - - it "return false if matching can't be done in linear time" do - Regexp.linear_time?(/(a)\1/).should == false - Regexp.linear_time?("(a)\\1").should == false - end - - it "accepts flags for string argument" do - Regexp.linear_time?('a', Regexp::IGNORECASE).should == true - end - - it "warns about flags being ignored for regexp arguments" do - -> { - Regexp.linear_time?(/a/, Regexp::IGNORECASE) - }.should complain(/warning: flags ignored/) - end - end -end diff --git a/spec/ruby/core/regexp/new_spec.rb b/spec/ruby/core/regexp/new_spec.rb index 65f612df55..ce662b7a4f 100644 --- a/spec/ruby/core/regexp/new_spec.rb +++ b/spec/ruby/core/regexp/new_spec.rb @@ -11,9 +11,17 @@ end describe "Regexp.new given a Regexp" do it_behaves_like :regexp_new_regexp, :new - it_behaves_like :regexp_new_string_binary, :new + it_behaves_like :regexp_new_string_binary, :compile end -describe "Regexp.new given a non-String/Regexp" do - it_behaves_like :regexp_new_non_string_or_regexp, :new +describe "Regexp.new given an Integer" do + it "raises a TypeError" do + -> { Regexp.new(1) }.should raise_error(TypeError) + end +end + +describe "Regexp.new given a Float" do + it "raises a TypeError" do + -> { Regexp.new(1.0) }.should raise_error(TypeError) + end end diff --git a/spec/ruby/core/regexp/shared/new.rb b/spec/ruby/core/regexp/shared/new.rb index 773882e495..9cbf89cd8b 100644 --- a/spec/ruby/core/regexp/shared/new.rb +++ b/spec/ruby/core/regexp/shared/new.rb @@ -24,32 +24,6 @@ describe :regexp_new, shared: true do end end -describe :regexp_new_non_string_or_regexp, shared: true do - it "calls #to_str method for non-String/Regexp argument" do - obj = Object.new - def obj.to_str() "a" end - - Regexp.send(@method, obj).should == /a/ - end - - it "raises TypeError if there is no #to_str method for non-String/Regexp argument" do - obj = Object.new - -> { Regexp.send(@method, obj) }.should raise_error(TypeError, "no implicit conversion of Object into String") - - -> { Regexp.send(@method, 1) }.should raise_error(TypeError, "no implicit conversion of Integer into String") - -> { Regexp.send(@method, 1.0) }.should raise_error(TypeError, "no implicit conversion of Float into String") - -> { Regexp.send(@method, :symbol) }.should raise_error(TypeError, "no implicit conversion of Symbol into String") - -> { Regexp.send(@method, []) }.should raise_error(TypeError, "no implicit conversion of Array into String") - end - - it "raises TypeError if #to_str returns non-String value" do - obj = Object.new - def obj.to_str() [] end - - -> { Regexp.send(@method, obj) }.should raise_error(TypeError, /can't convert Object to String/) - end -end - describe :regexp_new_string, shared: true do it "uses the String argument as an unescaped literal to construct a Regexp object" do Regexp.send(@method, "^hi{2,3}fo.o$").should == /^hi{2,3}fo.o$/ @@ -84,15 +58,6 @@ describe :regexp_new_string, shared: true do end end - it "sets options from second argument if it is true" do - r = Regexp.send(@method, 'Hi', true) - (r.options & Regexp::IGNORECASE).should_not == 0 - (r.options & Regexp::MULTILINE).should == 0 - not_supported_on :opal do - (r.options & Regexp::EXTENDED).should == 0 - end - end - it "sets options from second argument if it is one of the Integer option constants" do r = Regexp.send(@method, 'Hi', Regexp::IGNORECASE) (r.options & Regexp::IGNORECASE).should_not == 0 @@ -123,124 +88,57 @@ describe :regexp_new_string, shared: true do (r.options & Regexp::EXTENDED).should_not == 0 end - it "does not try to convert the second argument to Integer with #to_int method call" do - ScratchPad.clear - obj = Object.new - def obj.to_int() ScratchPad.record(:called) end - - Regexp.send(@method, "Hi", obj) - - ScratchPad.recorded.should == nil - end - - ruby_version_is ""..."3.2" do - it "treats any non-Integer, non-nil, non-false second argument as IGNORECASE" do - r = Regexp.send(@method, 'Hi', Object.new) - (r.options & Regexp::IGNORECASE).should_not == 0 - (r.options & Regexp::MULTILINE).should == 0 - not_supported_on :opal do - (r.options & Regexp::EXTENDED).should == 0 - end + it "treats any non-Integer, non-nil, non-false second argument as IGNORECASE" do + r = Regexp.send(@method, 'Hi', Object.new) + (r.options & Regexp::IGNORECASE).should_not == 0 + (r.options & Regexp::MULTILINE).should == 0 + not_supported_on :opal do + (r.options & Regexp::EXTENDED).should == 0 end end - ruby_version_is "3.2" do - it "warns any non-Integer, non-nil, non-false second argument" do - r = nil - -> { - r = Regexp.send(@method, 'Hi', Object.new) - }.should complain(/expected true or false as ignorecase/, {verbose: true}) - (r.options & Regexp::IGNORECASE).should_not == 0 - (r.options & Regexp::MULTILINE).should == 0 - not_supported_on :opal do - (r.options & Regexp::EXTENDED).should == 0 - end - end - - it "accepts a String of supported flags as the second argument" do - r = Regexp.send(@method, 'Hi', 'i') - (r.options & Regexp::IGNORECASE).should_not == 0 - (r.options & Regexp::MULTILINE).should == 0 - not_supported_on :opal do - (r.options & Regexp::EXTENDED).should == 0 - end - - r = Regexp.send(@method, 'Hi', 'imx') - (r.options & Regexp::IGNORECASE).should_not == 0 - (r.options & Regexp::MULTILINE).should_not == 0 - not_supported_on :opal do - (r.options & Regexp::EXTENDED).should_not == 0 - end - - r = Regexp.send(@method, 'Hi', 'mimi') - (r.options & Regexp::IGNORECASE).should_not == 0 - (r.options & Regexp::MULTILINE).should_not == 0 - not_supported_on :opal do - (r.options & Regexp::EXTENDED).should == 0 - end - - r = Regexp.send(@method, 'Hi', '') - (r.options & Regexp::IGNORECASE).should == 0 - (r.options & Regexp::MULTILINE).should == 0 - not_supported_on :opal do - (r.options & Regexp::EXTENDED).should == 0 - end - end - - it "raises an Argument error if the second argument contains unsupported chars" do - -> { Regexp.send(@method, 'Hi', 'e') }.should raise_error(ArgumentError) - -> { Regexp.send(@method, 'Hi', 'n') }.should raise_error(ArgumentError) - -> { Regexp.send(@method, 'Hi', 's') }.should raise_error(ArgumentError) - -> { Regexp.send(@method, 'Hi', 'u') }.should raise_error(ArgumentError) - -> { Regexp.send(@method, 'Hi', 'j') }.should raise_error(ArgumentError) - -> { Regexp.send(@method, 'Hi', 'mjx') }.should raise_error(ArgumentError) - end + it "ignores the third argument if it is 'e' or 'euc' (case-insensitive)" do + -> { + Regexp.send(@method, 'Hi', nil, 'e').encoding.should == Encoding::US_ASCII + Regexp.send(@method, 'Hi', nil, 'euc').encoding.should == Encoding::US_ASCII + Regexp.send(@method, 'Hi', nil, 'E').encoding.should == Encoding::US_ASCII + Regexp.send(@method, 'Hi', nil, 'EUC').encoding.should == Encoding::US_ASCII + }.should complain(/encoding option is ignored/) end - ruby_version_is ""..."3.2" do - it "ignores the third argument if it is 'e' or 'euc' (case-insensitive)" do - -> { - Regexp.send(@method, 'Hi', nil, 'e').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'euc').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'E').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'EUC').encoding.should == Encoding::US_ASCII - }.should complain(/encoding option is ignored/) - end - - it "ignores the third argument if it is 's' or 'sjis' (case-insensitive)" do - -> { - Regexp.send(@method, 'Hi', nil, 's').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'sjis').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'S').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'SJIS').encoding.should == Encoding::US_ASCII - }.should complain(/encoding option is ignored/) - end + it "ignores the third argument if it is 's' or 'sjis' (case-insensitive)" do + -> { + Regexp.send(@method, 'Hi', nil, 's').encoding.should == Encoding::US_ASCII + Regexp.send(@method, 'Hi', nil, 'sjis').encoding.should == Encoding::US_ASCII + Regexp.send(@method, 'Hi', nil, 'S').encoding.should == Encoding::US_ASCII + Regexp.send(@method, 'Hi', nil, 'SJIS').encoding.should == Encoding::US_ASCII + }.should complain(/encoding option is ignored/) + end - it "ignores the third argument if it is 'u' or 'utf8' (case-insensitive)" do - -> { - Regexp.send(@method, 'Hi', nil, 'u').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'utf8').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'U').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'UTF8').encoding.should == Encoding::US_ASCII - }.should complain(/encoding option is ignored/) - end + it "ignores the third argument if it is 'u' or 'utf8' (case-insensitive)" do + -> { + Regexp.send(@method, 'Hi', nil, 'u').encoding.should == Encoding::US_ASCII + Regexp.send(@method, 'Hi', nil, 'utf8').encoding.should == Encoding::US_ASCII + Regexp.send(@method, 'Hi', nil, 'U').encoding.should == Encoding::US_ASCII + Regexp.send(@method, 'Hi', nil, 'UTF8').encoding.should == Encoding::US_ASCII + }.should complain(/encoding option is ignored/) + end - it "uses US_ASCII encoding if third argument is 'n' or 'none' (case insensitive) and only ascii characters" do - Regexp.send(@method, 'Hi', nil, 'n').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'none').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'N').encoding.should == Encoding::US_ASCII - Regexp.send(@method, 'Hi', nil, 'NONE').encoding.should == Encoding::US_ASCII - end + it "uses US_ASCII encoding if third argument is 'n' or 'none' (case insensitive) and only ascii characters" do + Regexp.send(@method, 'Hi', nil, 'n').encoding.should == Encoding::US_ASCII + Regexp.send(@method, 'Hi', nil, 'none').encoding.should == Encoding::US_ASCII + Regexp.send(@method, 'Hi', nil, 'N').encoding.should == Encoding::US_ASCII + Regexp.send(@method, 'Hi', nil, 'NONE').encoding.should == Encoding::US_ASCII + end - it "uses ASCII_8BIT encoding if third argument is 'n' or 'none' (case insensitive) and non-ascii characters" do - a = "(?:[\x8E\xA1-\xFE])" - str = "\A(?:#{a}|x*)\z" + it "uses ASCII_8BIT encoding if third argument is 'n' or 'none' (case insensitive) and non-ascii characters" do + a = "(?:[\x8E\xA1-\xFE])" + str = "\A(?:#{a}|x*)\z" - Regexp.send(@method, str, nil, 'N').encoding.should == Encoding::BINARY - Regexp.send(@method, str, nil, 'n').encoding.should == Encoding::BINARY - Regexp.send(@method, str, nil, 'none').encoding.should == Encoding::BINARY - Regexp.send(@method, str, nil, 'NONE').encoding.should == Encoding::BINARY - end + Regexp.send(@method, str, nil, 'N').encoding.should == Encoding::BINARY + Regexp.send(@method, str, nil, 'n').encoding.should == Encoding::BINARY + Regexp.send(@method, str, nil, 'none').encoding.should == Encoding::BINARY + Regexp.send(@method, str, nil, 'NONE').encoding.should == Encoding::BINARY end describe "with escaped characters" do @@ -432,10 +330,6 @@ describe :regexp_new_string, shared: true do Regexp.send(@method, "\056\x42\u3042\x52\076").should == /#{"\x2e\x42\u3042\x52\x3e"}/ end - it "accepts a multiple byte character which need not be escaped" do - Regexp.send(@method, "\").should == /#{""}/ - end - it "raises a RegexpError if less than four digits are given for \\uHHHH" do -> { Regexp.send(@method, "\\" + "u304") }.should raise_error(RegexpError) end @@ -604,10 +498,8 @@ describe :regexp_new_regexp, shared: true do Regexp.send(@method, /Hi/n).encoding.should == Encoding::US_ASCII end - ruby_version_is ''...'3.2' do - it "sets the encoding to source String's encoding if the Regexp literal has the 'n' option and the source String is not ASCII only" do - Regexp.send(@method, Regexp.new("\\xff", nil, 'n')).encoding.should == Encoding::BINARY - end + it "sets the encoding to source String's encoding if the Regexp literal has the 'n' option and the source String is not ASCII only" do + Regexp.send(@method, Regexp.new("\\xff", nil, 'n')).encoding.should == Encoding::BINARY end end end diff --git a/spec/ruby/core/regexp/shared/quote.rb b/spec/ruby/core/regexp/shared/quote.rb index 9533102766..a55adb5bf2 100644 --- a/spec/ruby/core/regexp/shared/quote.rb +++ b/spec/ruby/core/regexp/shared/quote.rb @@ -12,16 +12,6 @@ describe :regexp_quote, shared: true do Regexp.send(@method, :symbol).should == 'symbol' end - it "works with substrings" do - str = ".+[]()"[1...-1] - Regexp.send(@method, str).should == '\+\[\]\(' - end - - it "works for broken strings" do - Regexp.send(@method, "a.\x85b.".force_encoding("US-ASCII")).should =="a\\.\x85b\\.".force_encoding("US-ASCII") - Regexp.send(@method, "a.\x80".force_encoding("UTF-8")).should == "a\\.\x80".force_encoding("UTF-8") - end - it "sets the encoding of the result to US-ASCII if there are only US-ASCII characters present in the input String" do str = "abc".force_encoding("euc-jp") Regexp.send(@method, str).encoding.should == Encoding::US_ASCII diff --git a/spec/ruby/core/regexp/source_spec.rb b/spec/ruby/core/regexp/source_spec.rb index 5f253da9ea..709fee49b3 100644 --- a/spec/ruby/core/regexp/source_spec.rb +++ b/spec/ruby/core/regexp/source_spec.rb @@ -9,26 +9,8 @@ describe "Regexp#source" do /x(.)xz/.source.should == "x(.)xz" end - it "keeps escape sequences as is" do - /\x20\+/.source.should == '\x20\+' - end - - describe "escaping" do - it "keeps escaping of metacharacter" do - /\$/.source.should == "\\$" - end - - it "keeps escaping of metacharacter used as a terminator" do - %r+\++.source.should == "\\+" - end - - it "removes escaping of non-metacharacter used as a terminator" do - %r@\@@.source.should == "@" - end - - it "keeps escaping of non-metacharacter not used as a terminator" do - /\@/.source.should == "\\@" - end + it "will remove escape characters" do + /foo\/bar/.source.should == "foo/bar" end not_supported_on :opal do diff --git a/spec/ruby/core/regexp/timeout_spec.rb b/spec/ruby/core/regexp/timeout_spec.rb deleted file mode 100644 index 6fce261814..0000000000 --- a/spec/ruby/core/regexp/timeout_spec.rb +++ /dev/null @@ -1,35 +0,0 @@ -require_relative '../../spec_helper' - -ruby_version_is "3.2" do - describe "Regexp.timeout" do - after :each do - Regexp.timeout = nil - end - - it "returns global timeout" do - Regexp.timeout = 3 - Regexp.timeout.should == 3 - end - - it "raises Regexp::TimeoutError after global timeout elapsed" do - Regexp.timeout = 0.001 - Regexp.timeout.should == 0.001 - - -> { - # A typical ReDoS case - /^(a*)*$/ =~ "a" * 1000000 + "x" - }.should raise_error(Regexp::TimeoutError, "regexp match timeout") - end - - it "raises Regexp::TimeoutError after timeout keyword value elapsed" do - Regexp.timeout = 3 # This should be ignored - Regexp.timeout.should == 3 - - re = Regexp.new("^a*b?a*$", timeout: 0.001) - - -> { - re =~ "a" * 1000000 + "x" - }.should raise_error(Regexp::TimeoutError, "regexp match timeout") - end - end -end diff --git a/spec/ruby/core/regexp/try_convert_spec.rb b/spec/ruby/core/regexp/try_convert_spec.rb index e775dbe971..be567e2130 100644 --- a/spec/ruby/core/regexp/try_convert_spec.rb +++ b/spec/ruby/core/regexp/try_convert_spec.rb @@ -18,10 +18,4 @@ describe "Regexp.try_convert" do rex.should_receive(:to_regexp).and_return(/(p(a)t[e]rn)/) Regexp.try_convert(rex).should == /(p(a)t[e]rn)/ end - - it "raises a TypeError if the object does not return an Regexp from #to_regexp" do - obj = mock("regexp") - obj.should_receive(:to_regexp).and_return("string") - -> { Regexp.try_convert(obj) }.should raise_error(TypeError, "can't convert MockObject to Regexp (MockObject#to_regexp gives String)") - end end diff --git a/spec/ruby/core/regexp/union_spec.rb b/spec/ruby/core/regexp/union_spec.rb index ea5a5053f7..8076836471 100644 --- a/spec/ruby/core/regexp/union_spec.rb +++ b/spec/ruby/core/regexp/union_spec.rb @@ -43,27 +43,6 @@ describe "Regexp.union" do Regexp.union("\u00A9".encode("ISO-8859-1"), "a".encode("UTF-8")).encoding.should == Encoding::ISO_8859_1 end - it "returns ASCII-8BIT if the regexp encodings are ASCII-8BIT and at least one has non-ASCII characters" do - us_ascii_implicit, us_ascii_explicit, binary = /abc/, /[\x00-\x7f]/n, /[\x80-\xBF]/n - us_ascii_implicit.encoding.should == Encoding::US_ASCII - us_ascii_explicit.encoding.should == Encoding::US_ASCII - binary.encoding.should == Encoding::BINARY - - Regexp.union(us_ascii_implicit, us_ascii_explicit, binary).encoding.should == Encoding::BINARY - Regexp.union(us_ascii_implicit, binary, us_ascii_explicit).encoding.should == Encoding::BINARY - Regexp.union(us_ascii_explicit, us_ascii_implicit, binary).encoding.should == Encoding::BINARY - Regexp.union(us_ascii_explicit, binary, us_ascii_implicit).encoding.should == Encoding::BINARY - Regexp.union(binary, us_ascii_implicit, us_ascii_explicit).encoding.should == Encoding::BINARY - Regexp.union(binary, us_ascii_explicit, us_ascii_implicit).encoding.should == Encoding::BINARY - end - - it "return US-ASCII if all patterns are ASCII-only" do - Regexp.union(/abc/e, /def/e).encoding.should == Encoding::US_ASCII - Regexp.union(/abc/n, /def/n).encoding.should == Encoding::US_ASCII - Regexp.union(/abc/s, /def/s).encoding.should == Encoding::US_ASCII - Regexp.union(/abc/u, /def/u).encoding.should == Encoding::US_ASCII - end - it "returns a Regexp with UTF-8 if one part is UTF-8" do Regexp.union(/probl[éeè]me/i, /help/i).encoding.should == Encoding::UTF_8 end @@ -75,83 +54,83 @@ describe "Regexp.union" do it "raises ArgumentError if the arguments include conflicting ASCII-incompatible Strings" do -> { Regexp.union("a".encode("UTF-16LE"), "b".encode("UTF-16BE")) - }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and UTF-16BE') + }.should raise_error(ArgumentError) end it "raises ArgumentError if the arguments include conflicting ASCII-incompatible Regexps" do -> { Regexp.union(Regexp.new("a".encode("UTF-16LE")), Regexp.new("b".encode("UTF-16BE"))) - }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and UTF-16BE') + }.should raise_error(ArgumentError) end it "raises ArgumentError if the arguments include conflicting fixed encoding Regexps" do -> { Regexp.union(Regexp.new("a".encode("UTF-8"), Regexp::FIXEDENCODING), Regexp.new("b".encode("US-ASCII"), Regexp::FIXEDENCODING)) - }.should raise_error(ArgumentError, 'incompatible encodings: UTF-8 and US-ASCII') + }.should raise_error(ArgumentError) end it "raises ArgumentError if the arguments include a fixed encoding Regexp and a String containing non-ASCII-compatible characters in a different encoding" do -> { Regexp.union(Regexp.new("a".encode("UTF-8"), Regexp::FIXEDENCODING), "\u00A9".encode("ISO-8859-1")) - }.should raise_error(ArgumentError, 'incompatible encodings: UTF-8 and ISO-8859-1') + }.should raise_error(ArgumentError) end it "raises ArgumentError if the arguments include a String containing non-ASCII-compatible characters and a fixed encoding Regexp in a different encoding" do -> { Regexp.union("\u00A9".encode("ISO-8859-1"), Regexp.new("a".encode("UTF-8"), Regexp::FIXEDENCODING)) - }.should raise_error(ArgumentError, 'incompatible encodings: ISO-8859-1 and UTF-8') + }.should raise_error(ArgumentError) end it "raises ArgumentError if the arguments include an ASCII-incompatible String and an ASCII-only String" do -> { Regexp.union("a".encode("UTF-16LE"), "b".encode("UTF-8")) - }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/) + }.should raise_error(ArgumentError) end it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and an ASCII-only String" do -> { Regexp.union(Regexp.new("a".encode("UTF-16LE")), "b".encode("UTF-8")) - }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/) + }.should raise_error(ArgumentError) end it "raises ArgumentError if the arguments include an ASCII-incompatible String and an ASCII-only Regexp" do -> { Regexp.union("a".encode("UTF-16LE"), Regexp.new("b".encode("UTF-8"))) - }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/) + }.should raise_error(ArgumentError) end it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and an ASCII-only Regexp" do -> { Regexp.union(Regexp.new("a".encode("UTF-16LE")), Regexp.new("b".encode("UTF-8"))) - }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/) + }.should raise_error(ArgumentError) end it "raises ArgumentError if the arguments include an ASCII-incompatible String and a String containing non-ASCII-compatible characters in a different encoding" do -> { Regexp.union("a".encode("UTF-16LE"), "\u00A9".encode("ISO-8859-1")) - }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1') + }.should raise_error(ArgumentError) end it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and a String containing non-ASCII-compatible characters in a different encoding" do -> { Regexp.union(Regexp.new("a".encode("UTF-16LE")), "\u00A9".encode("ISO-8859-1")) - }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1') + }.should raise_error(ArgumentError) end it "raises ArgumentError if the arguments include an ASCII-incompatible String and a Regexp containing non-ASCII-compatible characters in a different encoding" do -> { Regexp.union("a".encode("UTF-16LE"), Regexp.new("\u00A9".encode("ISO-8859-1"))) - }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1') + }.should raise_error(ArgumentError) end it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and a Regexp containing non-ASCII-compatible characters in a different encoding" do -> { Regexp.union(Regexp.new("a".encode("UTF-16LE")), Regexp.new("\u00A9".encode("ISO-8859-1"))) - }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1') + }.should raise_error(ArgumentError) end it "uses to_str to convert arguments (if not Regexp)" do @@ -175,8 +154,6 @@ describe "Regexp.union" do not_supported_on :opal do Regexp.union([/dogs/, /cats/i]).should == /(?-mix:dogs)|(?i-mx:cats)/ end - -> { - Regexp.union(["skiing", "sledding"], [/dogs/, /cats/i]) - }.should raise_error(TypeError, 'no implicit conversion of Array into String') + ->{Regexp.union(["skiing", "sledding"], [/dogs/, /cats/i])}.should raise_error(TypeError) end end diff --git a/spec/ruby/core/signal/signame_spec.rb b/spec/ruby/core/signal/signame_spec.rb index adfe895d97..b66de9fc85 100644 --- a/spec/ruby/core/signal/signame_spec.rb +++ b/spec/ruby/core/signal/signame_spec.rb @@ -9,22 +9,10 @@ describe "Signal.signame" do Signal.signame(-1).should == nil end - it "calls #to_int on an object to convert to an Integer" do - obj = mock('signal') - obj.should_receive(:to_int).and_return(0) - Signal.signame(obj).should == "EXIT" - end - it "raises a TypeError when the passed argument can't be coerced to Integer" do -> { Signal.signame("hello") }.should raise_error(TypeError) end - it "raises a TypeError when the passed argument responds to #to_int but does not return an Integer" do - obj = mock('signal') - obj.should_receive(:to_int).and_return('not an int') - -> { Signal.signame(obj) }.should raise_error(TypeError) - end - platform_is_not :windows do it "the original should take precedence over alias when looked up by number" do Signal.signame(Signal.list["ABRT"]).should == "ABRT" diff --git a/spec/ruby/core/signal/trap_spec.rb b/spec/ruby/core/signal/trap_spec.rb index b3186cda92..3c78922694 100644 --- a/spec/ruby/core/signal/trap_spec.rb +++ b/spec/ruby/core/signal/trap_spec.rb @@ -221,37 +221,6 @@ describe "Signal.trap" do Signal.trap(:HUP, @saved_trap).should equal(@proc) end - it "calls #to_str on an object to convert to a String" do - obj = mock("signal") - obj.should_receive(:to_str).exactly(2).times.and_return("HUP") - Signal.trap obj, @proc - Signal.trap(obj, @saved_trap).should equal(@proc) - end - - it "accepts Integer values" do - hup = Signal.list["HUP"] - Signal.trap hup, @proc - Signal.trap(hup, @saved_trap).should equal(@proc) - end - - it "does not call #to_int on an object to convert to an Integer" do - obj = mock("signal") - obj.should_not_receive(:to_int) - -> { Signal.trap obj, @proc }.should raise_error(ArgumentError, /bad signal type/) - end - - it "raises ArgumentError when passed unknown signal" do - -> { Signal.trap(300) { } }.should raise_error(ArgumentError, "invalid signal number (300)") - -> { Signal.trap("USR10") { } }.should raise_error(ArgumentError, "unsupported signal `SIGUSR10'") - -> { Signal.trap("SIGUSR10") { } }.should raise_error(ArgumentError, "unsupported signal `SIGUSR10'") - end - - it "raises ArgumentError when passed signal is not Integer, String or Symbol" do - -> { Signal.trap(nil) { } }.should raise_error(ArgumentError, "bad signal type NilClass") - -> { Signal.trap(100.0) { } }.should raise_error(ArgumentError, "bad signal type Float") - -> { Signal.trap(Rational(100)) { } }.should raise_error(ArgumentError, "bad signal type Rational") - end - # See man 2 signal %w[KILL STOP].each do |signal| it "raises ArgumentError or Errno::EINVAL for SIG#{signal}" do @@ -285,10 +254,12 @@ describe "Signal.trap" do r.close loop { w.write("a"*1024) } RUBY - out = ruby_exe(code, exit_status: :SIGPIPE) + out = ruby_exe(code, exit_status: nil) status = $? out.should == "nil\n" status.should.signaled? + status.termsig.should be_kind_of(Integer) + Signal.signame(status.termsig).should == "PIPE" end end diff --git a/spec/ruby/core/sizedqueue/append_spec.rb b/spec/ruby/core/sizedqueue/append_spec.rb index 6fffe2f272..ca79068930 100644 --- a/spec/ruby/core/sizedqueue/append_spec.rb +++ b/spec/ruby/core/sizedqueue/append_spec.rb @@ -1,7 +1,6 @@ require_relative '../../spec_helper' require_relative '../../shared/queue/enque' require_relative '../../shared/sizedqueue/enque' -require_relative '../../shared/types/rb_num2dbl_fails' describe "SizedQueue#<<" do it_behaves_like :queue_enq, :<<, -> { SizedQueue.new(10) } @@ -10,9 +9,3 @@ end describe "SizedQueue#<<" do it_behaves_like :sizedqueue_enq, :<<, -> n { SizedQueue.new(n) } end - -describe "SizedQueue operations with timeout" do - ruby_version_is "3.2" do - it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.send(:<<, 1, timeout: v) } - end -end diff --git a/spec/ruby/core/sizedqueue/deq_spec.rb b/spec/ruby/core/sizedqueue/deq_spec.rb index 985d654bb3..5e1bd9f746 100644 --- a/spec/ruby/core/sizedqueue/deq_spec.rb +++ b/spec/ruby/core/sizedqueue/deq_spec.rb @@ -1,13 +1,6 @@ require_relative '../../spec_helper' require_relative '../../shared/queue/deque' -require_relative '../../shared/types/rb_num2dbl_fails' describe "SizedQueue#deq" do it_behaves_like :queue_deq, :deq, -> { SizedQueue.new(10) } end - -describe "SizedQueue operations with timeout" do - ruby_version_is "3.2" do - it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.deq(timeout: v) } - end -end diff --git a/spec/ruby/core/sizedqueue/enq_spec.rb b/spec/ruby/core/sizedqueue/enq_spec.rb index 619373e46b..3821afac95 100644 --- a/spec/ruby/core/sizedqueue/enq_spec.rb +++ b/spec/ruby/core/sizedqueue/enq_spec.rb @@ -1,7 +1,6 @@ require_relative '../../spec_helper' require_relative '../../shared/queue/enque' require_relative '../../shared/sizedqueue/enque' -require_relative '../../shared/types/rb_num2dbl_fails' describe "SizedQueue#enq" do it_behaves_like :queue_enq, :enq, -> { SizedQueue.new(10) } @@ -10,9 +9,3 @@ end describe "SizedQueue#enq" do it_behaves_like :sizedqueue_enq, :enq, -> n { SizedQueue.new(n) } end - -describe "SizedQueue operations with timeout" do - ruby_version_is "3.2" do - it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.enq(1, timeout: v) } - end -end diff --git a/spec/ruby/core/sizedqueue/pop_spec.rb b/spec/ruby/core/sizedqueue/pop_spec.rb index 5e7cfea8fb..a0cf6f509c 100644 --- a/spec/ruby/core/sizedqueue/pop_spec.rb +++ b/spec/ruby/core/sizedqueue/pop_spec.rb @@ -1,13 +1,6 @@ require_relative '../../spec_helper' require_relative '../../shared/queue/deque' -require_relative '../../shared/types/rb_num2dbl_fails' describe "SizedQueue#pop" do it_behaves_like :queue_deq, :pop, -> { SizedQueue.new(10) } end - -describe "SizedQueue operations with timeout" do - ruby_version_is "3.2" do - it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.pop(timeout: v) } - end -end diff --git a/spec/ruby/core/sizedqueue/push_spec.rb b/spec/ruby/core/sizedqueue/push_spec.rb index ce61e89b53..bba9be9e3f 100644 --- a/spec/ruby/core/sizedqueue/push_spec.rb +++ b/spec/ruby/core/sizedqueue/push_spec.rb @@ -1,7 +1,6 @@ require_relative '../../spec_helper' require_relative '../../shared/queue/enque' require_relative '../../shared/sizedqueue/enque' -require_relative '../../shared/types/rb_num2dbl_fails' describe "SizedQueue#push" do it_behaves_like :queue_enq, :push, -> { SizedQueue.new(10) } @@ -10,9 +9,3 @@ end describe "SizedQueue#push" do it_behaves_like :sizedqueue_enq, :push, -> n { SizedQueue.new(n) } end - -describe "SizedQueue operations with timeout" do - ruby_version_is "3.2" do - it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.push(1, timeout: v) } - end -end diff --git a/spec/ruby/core/sizedqueue/shift_spec.rb b/spec/ruby/core/sizedqueue/shift_spec.rb index 3220801f3a..5138e68258 100644 --- a/spec/ruby/core/sizedqueue/shift_spec.rb +++ b/spec/ruby/core/sizedqueue/shift_spec.rb @@ -1,13 +1,6 @@ require_relative '../../spec_helper' require_relative '../../shared/queue/deque' -require_relative '../../shared/types/rb_num2dbl_fails' describe "SizedQueue#shift" do it_behaves_like :queue_deq, :shift, -> { SizedQueue.new(10) } end - -describe "SizedQueue operations with timeout" do - ruby_version_is "3.2" do - it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.shift(timeout: v) } - end -end diff --git a/spec/ruby/core/string/allocate_spec.rb b/spec/ruby/core/string/allocate_spec.rb index 30d5f60594..5b36b4fd05 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.allocate.encoding.should == Encoding::BINARY + String.new.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 8497ce8262..1e1667f617 100644 --- a/spec/ruby/core/string/append_spec.rb +++ b/spec/ruby/core/string/append_spec.rb @@ -5,10 +5,4 @@ require_relative 'shared/concat' describe "String#<<" do it_behaves_like :string_concat, :<< it_behaves_like :string_concat_encoding, :<< - it_behaves_like :string_concat_type_coercion, :<< - - 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 37c7994700..b2e3d326ba 100644 --- a/spec/ruby/core/string/b_spec.rb +++ b/spec/ruby/core/string/b_spec.rb @@ -12,4 +12,13 @@ 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/byteindex_spec.rb b/spec/ruby/core/string/byteindex_spec.rb deleted file mode 100644 index 7be0c7ec1e..0000000000 --- a/spec/ruby/core/string/byteindex_spec.rb +++ /dev/null @@ -1,304 +0,0 @@ -# -*- encoding: utf-8 -*- -require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/byte_index_common.rb' - -describe "String#byteindex" do - ruby_version_is "3.2" do - it "calls #to_str to convert the first argument" do - char = mock("string index char") - char.should_receive(:to_str).and_return("b") - "abc".byteindex(char).should == 1 - end - - it "calls #to_int to convert the second argument" do - offset = mock("string index offset") - offset.should_receive(:to_int).and_return(1) - "abc".byteindex("c", offset).should == 2 - end - - it "does not raise IndexError when byte offset is correct or on string boundary" do - "わ".byteindex("").should == 0 - "わ".byteindex("", 0).should == 0 - "わ".byteindex("", 3).should == 3 - end - - it_behaves_like :byte_index_common, :byteindex - end -end - -describe "String#byteindex with String" do - ruby_version_is "3.2" do - it "behaves the same as String#byteindex(char) for one-character strings" do - "blablabla hello cruel world...!".split("").uniq.each do |str| - chr = str[0] - str.byteindex(str).should == str.byteindex(chr) - - 0.upto(str.size + 1) do |start| - str.byteindex(str, start).should == str.byteindex(chr, start) - end - - (-str.size - 1).upto(-1) do |start| - str.byteindex(str, start).should == str.byteindex(chr, start) - end - end - end - - it "returns the byteindex of the first occurrence of the given substring" do - "blablabla".byteindex("").should == 0 - "blablabla".byteindex("b").should == 0 - "blablabla".byteindex("bla").should == 0 - "blablabla".byteindex("blabla").should == 0 - "blablabla".byteindex("blablabla").should == 0 - - "blablabla".byteindex("l").should == 1 - "blablabla".byteindex("la").should == 1 - "blablabla".byteindex("labla").should == 1 - "blablabla".byteindex("lablabla").should == 1 - - "blablabla".byteindex("a").should == 2 - "blablabla".byteindex("abla").should == 2 - "blablabla".byteindex("ablabla").should == 2 - end - - it "treats the offset as a byteindex" do - "aaaaa".byteindex("a", 0).should == 0 - "aaaaa".byteindex("a", 2).should == 2 - "aaaaa".byteindex("a", 4).should == 4 - end - - it "ignores string subclasses" do - "blablabla".byteindex(StringSpecs::MyString.new("bla")).should == 0 - StringSpecs::MyString.new("blablabla").byteindex("bla").should == 0 - StringSpecs::MyString.new("blablabla").byteindex(StringSpecs::MyString.new("bla")).should == 0 - end - - it "starts the search at the given offset" do - "blablabla".byteindex("bl", 0).should == 0 - "blablabla".byteindex("bl", 1).should == 3 - "blablabla".byteindex("bl", 2).should == 3 - "blablabla".byteindex("bl", 3).should == 3 - - "blablabla".byteindex("bla", 0).should == 0 - "blablabla".byteindex("bla", 1).should == 3 - "blablabla".byteindex("bla", 2).should == 3 - "blablabla".byteindex("bla", 3).should == 3 - - "blablabla".byteindex("blab", 0).should == 0 - "blablabla".byteindex("blab", 1).should == 3 - "blablabla".byteindex("blab", 2).should == 3 - "blablabla".byteindex("blab", 3).should == 3 - - "blablabla".byteindex("la", 1).should == 1 - "blablabla".byteindex("la", 2).should == 4 - "blablabla".byteindex("la", 3).should == 4 - "blablabla".byteindex("la", 4).should == 4 - - "blablabla".byteindex("lab", 1).should == 1 - "blablabla".byteindex("lab", 2).should == 4 - "blablabla".byteindex("lab", 3).should == 4 - "blablabla".byteindex("lab", 4).should == 4 - - "blablabla".byteindex("ab", 2).should == 2 - "blablabla".byteindex("ab", 3).should == 5 - "blablabla".byteindex("ab", 4).should == 5 - "blablabla".byteindex("ab", 5).should == 5 - - "blablabla".byteindex("", 0).should == 0 - "blablabla".byteindex("", 1).should == 1 - "blablabla".byteindex("", 2).should == 2 - "blablabla".byteindex("", 7).should == 7 - "blablabla".byteindex("", 8).should == 8 - "blablabla".byteindex("", 9).should == 9 - end - - it "starts the search at offset + self.length if offset is negative" do - str = "blablabla" - - ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle| - (-str.length .. -1).each do |offset| - str.byteindex(needle, offset).should == - str.byteindex(needle, offset + str.length) - end - end - end - - it "returns nil if the substring isn't found" do - "blablabla".byteindex("B").should == nil - "blablabla".byteindex("z").should == nil - "blablabla".byteindex("BLA").should == nil - "blablabla".byteindex("blablablabla").should == nil - "blablabla".byteindex("", 10).should == nil - - "hello".byteindex("he", 1).should == nil - "hello".byteindex("he", 2).should == nil - "I’ve got a multibyte character.\n".byteindex("\n\n").should == nil - end - - it "returns the character byteindex of a multibyte character" do - "ありがとう".byteindex("が").should == 6 - end - - it "returns the character byteindex after offset" do - "われわれ".byteindex("わ", 3).should == 6 - "ありがとうありがとう".byteindex("が", 9).should == 21 - end - - it "returns the character byteindex after a partial first match" do - "</</h".byteindex("</h").should == 2 - end - - it "raises an Encoding::CompatibilityError if the encodings are incompatible" do - char = "れ".encode Encoding::EUC_JP - -> do - "あれ".byteindex(char) - end.should raise_error(Encoding::CompatibilityError) - end - - it "handles a substring in a superset encoding" do - 'abc'.force_encoding(Encoding::US_ASCII).byteindex('é').should == nil - end - - it "handles a substring in a subset encoding" do - 'été'.byteindex('t'.force_encoding(Encoding::US_ASCII)).should == 2 - end - end -end - -describe "String#byteindex with Regexp" do - ruby_version_is "3.2" do - it "behaves the same as String#byteindex(string) for escaped string regexps" do - ["blablabla", "hello cruel world...!"].each do |str| - ["", "b", "bla", "lab", "o c", "d."].each do |needle| - regexp = Regexp.new(Regexp.escape(needle)) - str.byteindex(regexp).should == str.byteindex(needle) - - 0.upto(str.size + 1) do |start| - str.byteindex(regexp, start).should == str.byteindex(needle, start) - end - - (-str.size - 1).upto(-1) do |start| - str.byteindex(regexp, start).should == str.byteindex(needle, start) - end - end - end - end - - it "returns the byteindex of the first match of regexp" do - "blablabla".byteindex(/bla/).should == 0 - "blablabla".byteindex(/BLA/i).should == 0 - - "blablabla".byteindex(/.{0}/).should == 0 - "blablabla".byteindex(/.{6}/).should == 0 - "blablabla".byteindex(/.{9}/).should == 0 - - "blablabla".byteindex(/.*/).should == 0 - "blablabla".byteindex(/.+/).should == 0 - - "blablabla".byteindex(/lab|b/).should == 0 - - not_supported_on :opal do - "blablabla".byteindex(/\A/).should == 0 - "blablabla".byteindex(/\Z/).should == 9 - "blablabla".byteindex(/\z/).should == 9 - "blablabla\n".byteindex(/\Z/).should == 9 - "blablabla\n".byteindex(/\z/).should == 10 - end - - "blablabla".byteindex(/^/).should == 0 - "\nblablabla".byteindex(/^/).should == 0 - "b\nablabla".byteindex(/$/).should == 1 - "bl\nablabla".byteindex(/$/).should == 2 - - "blablabla".byteindex(/.l./).should == 0 - end - - it "starts the search at the given offset" do - "blablabla".byteindex(/.{0}/, 5).should == 5 - "blablabla".byteindex(/.{1}/, 5).should == 5 - "blablabla".byteindex(/.{2}/, 5).should == 5 - "blablabla".byteindex(/.{3}/, 5).should == 5 - "blablabla".byteindex(/.{4}/, 5).should == 5 - - "blablabla".byteindex(/.{0}/, 3).should == 3 - "blablabla".byteindex(/.{1}/, 3).should == 3 - "blablabla".byteindex(/.{2}/, 3).should == 3 - "blablabla".byteindex(/.{5}/, 3).should == 3 - "blablabla".byteindex(/.{6}/, 3).should == 3 - - "blablabla".byteindex(/.l./, 0).should == 0 - "blablabla".byteindex(/.l./, 1).should == 3 - "blablabla".byteindex(/.l./, 2).should == 3 - "blablabla".byteindex(/.l./, 3).should == 3 - - "xblaxbla".byteindex(/x./, 0).should == 0 - "xblaxbla".byteindex(/x./, 1).should == 4 - "xblaxbla".byteindex(/x./, 2).should == 4 - - not_supported_on :opal do - "blablabla\n".byteindex(/\Z/, 9).should == 9 - end - end - - it "starts the search at offset + self.length if offset is negative" do - str = "blablabla" - - ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle| - (-str.length .. -1).each do |offset| - str.byteindex(needle, offset).should == - str.byteindex(needle, offset + str.length) - end - end - end - - it "returns nil if the substring isn't found" do - "blablabla".byteindex(/BLA/).should == nil - - "blablabla".byteindex(/.{10}/).should == nil - "blaxbla".byteindex(/.x/, 3).should == nil - "blaxbla".byteindex(/..x/, 2).should == nil - end - - it "returns nil if the Regexp matches the empty string and the offset is out of range" do - "ruby".byteindex(//, 12).should be_nil - end - - it "supports \\G which matches at the given start offset" do - "helloYOU.".byteindex(/\GYOU/, 5).should == 5 - "helloYOU.".byteindex(/\GYOU/).should == nil - - re = /\G.+YOU/ - # The # marks where \G will match. - [ - ["#hi!YOUall.", 0], - ["h#i!YOUall.", 1], - ["hi#!YOUall.", 2], - ["hi!#YOUall.", nil] - ].each do |spec| - - start = spec[0].byteindex("#") - str = spec[0].delete("#") - - str.byteindex(re, start).should == spec[1] - end - end - - it "converts start_offset to an integer via to_int" do - obj = mock('1') - obj.should_receive(:to_int).and_return(1) - "RWOARW".byteindex(/R./, obj).should == 4 - end - - it "returns the character byteindex of a multibyte character" do - "ありがとう".byteindex(/が/).should == 6 - end - - it "returns the character byteindex after offset" do - "われわれ".byteindex(/わ/, 3).should == 6 - end - - it "treats the offset as a byteindex" do - "われわわれ".byteindex(/わ/, 6).should == 6 - end - end -end diff --git a/spec/ruby/core/string/byterindex_spec.rb b/spec/ruby/core/string/byterindex_spec.rb deleted file mode 100644 index 717708c97d..0000000000 --- a/spec/ruby/core/string/byterindex_spec.rb +++ /dev/null @@ -1,359 +0,0 @@ -# -*- encoding: utf-8 -*- -require_relative '../../spec_helper' -require_relative 'fixtures/classes' -require_relative 'shared/byte_index_common.rb' - -describe "String#byterindex with object" do - ruby_version_is "3.2" do - it "tries to convert obj to a string via to_str" do - obj = mock('lo') - def obj.to_str() "lo" end - "hello".byterindex(obj).should == "hello".byterindex("lo") - - obj = mock('o') - def obj.respond_to?(arg, *) true end - def obj.method_missing(*args) "o" end - "hello".byterindex(obj).should == "hello".byterindex("o") - end - - it "calls #to_int to convert the second argument" do - offset = mock("string index offset") - offset.should_receive(:to_int).and_return(3) - "abc".byterindex("c", offset).should == 2 - end - - it "does not raise IndexError when byte offset is correct or on string boundary" do - "わ".byterindex("", 0).should == 0 - "わ".byterindex("", 3).should == 3 - "わ".byterindex("").should == 3 - end - - it_behaves_like :byte_index_common, :byterindex - end -end - -describe "String#byterindex with String" do - ruby_version_is "3.2" do - it "behaves the same as String#byterindex(char) for one-character strings" do - "blablabla hello cruel world...!".split("").uniq.each do |str| - chr = str[0] - str.byterindex(str).should == str.byterindex(chr) - - 0.upto(str.size + 1) do |start| - str.byterindex(str, start).should == str.byterindex(chr, start) - end - - (-str.size - 1).upto(-1) do |start| - str.byterindex(str, start).should == str.byterindex(chr, start) - end - end - end - - it "behaves the same as String#byterindex(?char) for one-character strings" do - "blablabla hello cruel world...!".split("").uniq.each do |str| - chr = str[0] =~ / / ? str[0] : eval("?#{str[0]}") - str.byterindex(str).should == str.byterindex(chr) - - 0.upto(str.size + 1) do |start| - str.byterindex(str, start).should == str.byterindex(chr, start) - end - - (-str.size - 1).upto(-1) do |start| - str.byterindex(str, start).should == str.byterindex(chr, start) - end - end - end - - it "returns the index of the last occurrence of the given substring" do - "blablabla".byterindex("").should == 9 - "blablabla".byterindex("a").should == 8 - "blablabla".byterindex("la").should == 7 - "blablabla".byterindex("bla").should == 6 - "blablabla".byterindex("abla").should == 5 - "blablabla".byterindex("labla").should == 4 - "blablabla".byterindex("blabla").should == 3 - "blablabla".byterindex("ablabla").should == 2 - "blablabla".byterindex("lablabla").should == 1 - "blablabla".byterindex("blablabla").should == 0 - - "blablabla".byterindex("l").should == 7 - "blablabla".byterindex("bl").should == 6 - "blablabla".byterindex("abl").should == 5 - "blablabla".byterindex("labl").should == 4 - "blablabla".byterindex("blabl").should == 3 - "blablabla".byterindex("ablabl").should == 2 - "blablabla".byterindex("lablabl").should == 1 - "blablabla".byterindex("blablabl").should == 0 - - "blablabla".byterindex("b").should == 6 - "blablabla".byterindex("ab").should == 5 - "blablabla".byterindex("lab").should == 4 - "blablabla".byterindex("blab").should == 3 - "blablabla".byterindex("ablab").should == 2 - "blablabla".byterindex("lablab").should == 1 - "blablabla".byterindex("blablab").should == 0 - end - - it "ignores string subclasses" do - "blablabla".byterindex(StringSpecs::MyString.new("bla")).should == 6 - StringSpecs::MyString.new("blablabla").byterindex("bla").should == 6 - StringSpecs::MyString.new("blablabla").byterindex(StringSpecs::MyString.new("bla")).should == 6 - end - - it "starts the search at the given offset" do - "blablabla".byterindex("bl", 0).should == 0 - "blablabla".byterindex("bl", 1).should == 0 - "blablabla".byterindex("bl", 2).should == 0 - "blablabla".byterindex("bl", 3).should == 3 - - "blablabla".byterindex("bla", 0).should == 0 - "blablabla".byterindex("bla", 1).should == 0 - "blablabla".byterindex("bla", 2).should == 0 - "blablabla".byterindex("bla", 3).should == 3 - - "blablabla".byterindex("blab", 0).should == 0 - "blablabla".byterindex("blab", 1).should == 0 - "blablabla".byterindex("blab", 2).should == 0 - "blablabla".byterindex("blab", 3).should == 3 - "blablabla".byterindex("blab", 6).should == 3 - "blablablax".byterindex("blab", 6).should == 3 - - "blablabla".byterindex("la", 1).should == 1 - "blablabla".byterindex("la", 2).should == 1 - "blablabla".byterindex("la", 3).should == 1 - "blablabla".byterindex("la", 4).should == 4 - - "blablabla".byterindex("lab", 1).should == 1 - "blablabla".byterindex("lab", 2).should == 1 - "blablabla".byterindex("lab", 3).should == 1 - "blablabla".byterindex("lab", 4).should == 4 - - "blablabla".byterindex("ab", 2).should == 2 - "blablabla".byterindex("ab", 3).should == 2 - "blablabla".byterindex("ab", 4).should == 2 - "blablabla".byterindex("ab", 5).should == 5 - - "blablabla".byterindex("", 0).should == 0 - "blablabla".byterindex("", 1).should == 1 - "blablabla".byterindex("", 2).should == 2 - "blablabla".byterindex("", 7).should == 7 - "blablabla".byterindex("", 8).should == 8 - "blablabla".byterindex("", 9).should == 9 - "blablabla".byterindex("", 10).should == 9 - end - - it "starts the search at offset + self.length if offset is negative" do - str = "blablabla" - - ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle| - (-str.length .. -1).each do |offset| - str.byterindex(needle, offset).should == - str.byterindex(needle, offset + str.length) - end - end - end - - it "returns nil if the substring isn't found" do - "blablabla".byterindex("B").should == nil - "blablabla".byterindex("z").should == nil - "blablabla".byterindex("BLA").should == nil - "blablabla".byterindex("blablablabla").should == nil - - "hello".byterindex("lo", 0).should == nil - "hello".byterindex("lo", 1).should == nil - "hello".byterindex("lo", 2).should == nil - - "hello".byterindex("llo", 0).should == nil - "hello".byterindex("llo", 1).should == nil - - "hello".byterindex("el", 0).should == nil - "hello".byterindex("ello", 0).should == nil - - "hello".byterindex("", -6).should == nil - "hello".byterindex("", -7).should == nil - - "hello".byterindex("h", -6).should == nil - end - - it "tries to convert start_offset to an integer via to_int" do - obj = mock('5') - def obj.to_int() 5 end - "str".byterindex("st", obj).should == 0 - - obj = mock('5') - def obj.respond_to?(arg, *) true end - def obj.method_missing(*args) 5 end - "str".byterindex("st", obj).should == 0 - end - - it "raises a TypeError when given offset is nil" do - -> { "str".byterindex("st", nil) }.should raise_error(TypeError) - end - - it "handles a substring in a superset encoding" do - 'abc'.force_encoding(Encoding::US_ASCII).byterindex('é').should == nil - end - - it "handles a substring in a subset encoding" do - 'été'.byterindex('t'.force_encoding(Encoding::US_ASCII)).should == 2 - end - end -end - -describe "String#byterindex with Regexp" do - ruby_version_is "3.2" do - it "behaves the same as String#byterindex(string) for escaped string regexps" do - ["blablabla", "hello cruel world...!"].each do |str| - ["", "b", "bla", "lab", "o c", "d."].each do |needle| - regexp = Regexp.new(Regexp.escape(needle)) - str.byterindex(regexp).should == str.byterindex(needle) - - 0.upto(str.size + 1) do |start| - str.byterindex(regexp, start).should == str.byterindex(needle, start) - end - - (-str.size - 1).upto(-1) do |start| - str.byterindex(regexp, start).should == str.byterindex(needle, start) - end - end - end - end - - it "returns the index of the first match from the end of string of regexp" do - "blablabla".byterindex(/bla/).should == 6 - "blablabla".byterindex(/BLA/i).should == 6 - - "blablabla".byterindex(/.{0}/).should == 9 - "blablabla".byterindex(/.{1}/).should == 8 - "blablabla".byterindex(/.{2}/).should == 7 - "blablabla".byterindex(/.{6}/).should == 3 - "blablabla".byterindex(/.{9}/).should == 0 - - "blablabla".byterindex(/.*/).should == 9 - "blablabla".byterindex(/.+/).should == 8 - - "blablabla".byterindex(/bla|a/).should == 8 - - not_supported_on :opal do - "blablabla".byterindex(/\A/).should == 0 - "blablabla".byterindex(/\Z/).should == 9 - "blablabla".byterindex(/\z/).should == 9 - "blablabla\n".byterindex(/\Z/).should == 10 - "blablabla\n".byterindex(/\z/).should == 10 - end - - "blablabla".byterindex(/^/).should == 0 - not_supported_on :opal do - "\nblablabla".byterindex(/^/).should == 1 - "b\nlablabla".byterindex(/^/).should == 2 - end - "blablabla".byterindex(/$/).should == 9 - - "blablabla".byterindex(/.l./).should == 6 - end - - it "starts the search at the given offset" do - "blablabla".byterindex(/.{0}/, 5).should == 5 - "blablabla".byterindex(/.{1}/, 5).should == 5 - "blablabla".byterindex(/.{2}/, 5).should == 5 - "blablabla".byterindex(/.{3}/, 5).should == 5 - "blablabla".byterindex(/.{4}/, 5).should == 5 - - "blablabla".byterindex(/.{0}/, 3).should == 3 - "blablabla".byterindex(/.{1}/, 3).should == 3 - "blablabla".byterindex(/.{2}/, 3).should == 3 - "blablabla".byterindex(/.{5}/, 3).should == 3 - "blablabla".byterindex(/.{6}/, 3).should == 3 - - "blablabla".byterindex(/.l./, 0).should == 0 - "blablabla".byterindex(/.l./, 1).should == 0 - "blablabla".byterindex(/.l./, 2).should == 0 - "blablabla".byterindex(/.l./, 3).should == 3 - - "blablablax".byterindex(/.x/, 10).should == 8 - "blablablax".byterindex(/.x/, 9).should == 8 - "blablablax".byterindex(/.x/, 8).should == 8 - - "blablablax".byterindex(/..x/, 10).should == 7 - "blablablax".byterindex(/..x/, 9).should == 7 - "blablablax".byterindex(/..x/, 8).should == 7 - "blablablax".byterindex(/..x/, 7).should == 7 - - not_supported_on :opal do - "blablabla\n".byterindex(/\Z/, 9).should == 9 - end - end - - it "starts the search at offset + self.length if offset is negative" do - str = "blablabla" - - ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle| - (-str.length .. -1).each do |offset| - str.byterindex(needle, offset).should == - str.byterindex(needle, offset + str.length) - end - end - end - - it "returns nil if the substring isn't found" do - "blablabla".byterindex(/BLA/).should == nil - "blablabla".byterindex(/.{10}/).should == nil - "blablablax".byterindex(/.x/, 7).should == nil - "blablablax".byterindex(/..x/, 6).should == nil - - not_supported_on :opal do - "blablabla".byterindex(/\Z/, 5).should == nil - "blablabla".byterindex(/\z/, 5).should == nil - "blablabla\n".byterindex(/\z/, 9).should == nil - end - end - - not_supported_on :opal do - it "supports \\G which matches at the given start offset" do - "helloYOU.".byterindex(/YOU\G/, 8).should == 5 - "helloYOU.".byterindex(/YOU\G/).should == nil - - idx = "helloYOUall!".index("YOU") - re = /YOU.+\G.+/ - # The # marks where \G will match. - [ - ["helloYOU#all.", nil], - ["helloYOUa#ll.", idx], - ["helloYOUal#l.", idx], - ["helloYOUall#.", idx], - ["helloYOUall.#", nil] - ].each do |i| - start = i[0].index("#") - str = i[0].delete("#") - - str.byterindex(re, start).should == i[1] - end - end - end - - it "tries to convert start_offset to an integer" do - obj = mock('5') - def obj.to_int() 5 end - "str".byterindex(/../, obj).should == 1 - - obj = mock('5') - def obj.respond_to?(arg, *) true end - def obj.method_missing(*args); 5; end - "str".byterindex(/../, obj).should == 1 - end - - it "raises a TypeError when given offset is nil" do - -> { "str".byterindex(/../, nil) }.should raise_error(TypeError) - end - - it "returns the reverse byte index of a multibyte character" do - "ありがりがとう".byterindex("が").should == 12 - "ありがりがとう".byterindex(/が/).should == 12 - end - - it "returns the character index before the finish" do - "ありがりがとう".byterindex("が", 9).should == 6 - "ありがりがとう".byterindex(/が/, 9).should == 6 - end - end -end diff --git a/spec/ruby/core/string/bytesize_spec.rb b/spec/ruby/core/string/bytesize_spec.rb index a31f3ae671..b8b07cfbec 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/byteslice_spec.rb b/spec/ruby/core/string/byteslice_spec.rb index 312229523d..a49da040eb 100644 --- a/spec/ruby/core/string/byteslice_spec.rb +++ b/spec/ruby/core/string/byteslice_spec.rb @@ -24,10 +24,4 @@ describe "String#byteslice on on non ASCII strings" do "\u3042".byteslice(1..2).should == "\x81\x82".force_encoding("UTF-8") "\u3042".byteslice(-1).should == "\x82".force_encoding("UTF-8") end - - it "returns a String in the same encoding as self" do - "ruby".encode("UTF-8").slice(0).encoding.should == Encoding::UTF_8 - "ruby".encode("US-ASCII").slice(0).encoding.should == Encoding::US_ASCII - "ruby".encode("Windows-1251").slice(0).encoding.should == Encoding::Windows_1251 - end end diff --git a/spec/ruby/core/string/bytesplice_spec.rb b/spec/ruby/core/string/bytesplice_spec.rb deleted file mode 100644 index f13024a79b..0000000000 --- a/spec/ruby/core/string/bytesplice_spec.rb +++ /dev/null @@ -1,133 +0,0 @@ -# -*- encoding: utf-8 -*- -require_relative '../../spec_helper' - -describe "String#bytesplice" do - ruby_version_is "3.2" do - it "raises IndexError when index is less than -bytesize" do - -> { "hello".bytesplice(-6, 0, "xxx") }.should raise_error(IndexError, "index -6 out of string") - end - - it "raises IndexError when index is greater than bytesize" do - -> { "hello".bytesplice(6, 0, "xxx") }.should raise_error(IndexError, "index 6 out of string") - end - - it "raises IndexError for negative length" do - -> { "abc".bytesplice(0, -2, "") }.should raise_error(IndexError, "negative length -2") - end - - it "replaces with integer indices" do - "hello".bytesplice(-5, 0, "xxx").should == "xxxhello" - "hello".bytesplice(0, 0, "xxx").should == "xxxhello" - "hello".bytesplice(0, 1, "xxx").should == "xxxello" - "hello".bytesplice(0, 5, "xxx").should == "xxx" - "hello".bytesplice(0, 6, "xxx").should == "xxx" - end - - it "raises RangeError when range left boundary is less than -bytesize" do - -> { "hello".bytesplice(-6...-6, "xxx") }.should raise_error(RangeError, "-6...-6 out of range") - end - - it "replaces with ranges" do - "hello".bytesplice(-5...-5, "xxx").should == "xxxhello" - "hello".bytesplice(0...0, "xxx").should == "xxxhello" - "hello".bytesplice(0..0, "xxx").should == "xxxello" - "hello".bytesplice(0...1, "xxx").should == "xxxello" - "hello".bytesplice(0..1, "xxx").should == "xxxllo" - "hello".bytesplice(0..-1, "xxx").should == "xxx" - "hello".bytesplice(0...5, "xxx").should == "xxx" - "hello".bytesplice(0...6, "xxx").should == "xxx" - end - - it "raises TypeError when integer index is provided without length argument" do - -> { "hello".bytesplice(0, "xxx") }.should raise_error(TypeError, "wrong argument type Integer (expected Range)") - end - - it "replaces on an empty string" do - "".bytesplice(0, 0, "").should == "" - "".bytesplice(0, 0, "xxx").should == "xxx" - end - - it "mutates self" do - s = "hello" - s.bytesplice(2, 1, "xxx").should.equal?(s) - end - - it "raises when string is frozen" do - s = "hello".freeze - -> { s.bytesplice(2, 1, "xxx") }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"") - end - end -end - -describe "String#bytesplice with multibyte characters" do - ruby_version_is "3.2" do - it "raises IndexError when index is out of byte size boundary" do - -> { "こんにちは".bytesplice(-16, 0, "xxx") }.should raise_error(IndexError, "index -16 out of string") - end - - it "raises IndexError when index is not on a codepoint boundary" do - -> { "こんにちは".bytesplice(1, 0, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary") - end - - it "raises IndexError when length is not matching the codepoint boundary" do - -> { "こんにちは".bytesplice(0, 1, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary") - -> { "こんにちは".bytesplice(0, 2, "xxx") }.should raise_error(IndexError, "offset 2 does not land on character boundary") - end - - it "replaces with integer indices" do - "こんにちは".bytesplice(-15, 0, "xxx").should == "xxxこんにちは" - "こんにちは".bytesplice(0, 0, "xxx").should == "xxxこんにちは" - "こんにちは".bytesplice(0, 3, "xxx").should == "xxxんにちは" - "こんにちは".bytesplice(3, 3, "はは").should == "こははにちは" - "こんにちは".bytesplice(15, 0, "xxx").should == "こんにちはxxx" - end - - it "replaces with range" do - "こんにちは".bytesplice(-15...-16, "xxx").should == "xxxこんにちは" - "こんにちは".bytesplice(0...0, "xxx").should == "xxxこんにちは" - "こんにちは".bytesplice(0..2, "xxx").should == "xxxんにちは" - "こんにちは".bytesplice(0...3, "xxx").should == "xxxんにちは" - "こんにちは".bytesplice(0..5, "xxx").should == "xxxにちは" - "こんにちは".bytesplice(0..-1, "xxx").should == "xxx" - "こんにちは".bytesplice(0...15, "xxx").should == "xxx" - "こんにちは".bytesplice(0...18, "xxx").should == "xxx" - end - - it "treats negative length for range as 0" do - "こんにちは".bytesplice(0...-100, "xxx").should == "xxxこんにちは" - "こんにちは".bytesplice(3...-100, "xxx").should == "こxxxんにちは" - "こんにちは".bytesplice(-15...-100, "xxx").should == "xxxこんにちは" - end - - it "raises when ranges not match codepoint boundaries" do - -> { "こんにちは".bytesplice(0..0, "x") }.should raise_error(IndexError, "offset 1 does not land on character boundary") - -> { "こんにちは".bytesplice(0..1, "x") }.should raise_error(IndexError, "offset 2 does not land on character boundary") - # Begin is incorrect - -> { "こんにちは".bytesplice(-4..-1, "x") }.should raise_error(IndexError, "offset 11 does not land on character boundary") - -> { "こんにちは".bytesplice(-5..-1, "x") }.should raise_error(IndexError, "offset 10 does not land on character boundary") - # End is incorrect - -> { "こんにちは".bytesplice(-3..-2, "x") }.should raise_error(IndexError, "offset 14 does not land on character boundary") - -> { "こんにちは".bytesplice(-3..-3, "x") }.should raise_error(IndexError, "offset 13 does not land on character boundary") - end - - it "deals with a different encoded argument" do - s = "こんにちは" - s.encoding.should == Encoding::UTF_8 - sub = "xxxxxx" - sub.force_encoding(Encoding::US_ASCII) - - result = s.bytesplice(0, 3, sub) - result.should == "xxxxxxんにちは" - result.encoding.should == Encoding::UTF_8 - - s = "xxxxxx" - s.force_encoding(Encoding::US_ASCII) - sub = "こんにちは" - sub.encoding.should == Encoding::UTF_8 - - result = s.bytesplice(0, 3, sub) - result.should == "こんにちはxxx" - result.encoding.should == Encoding::UTF_8 - end - end -end diff --git a/spec/ruby/core/string/capitalize_spec.rb b/spec/ruby/core/string/capitalize_spec.rb index b79e9cfdbd..21df18a5ae 100644 --- a/spec/ruby/core/string/capitalize_spec.rb +++ b/spec/ruby/core/string/capitalize_spec.rb @@ -10,7 +10,13 @@ describe "String#capitalize" do "hello".capitalize.should == "Hello" "HELLO".capitalize.should == "Hello" "123ABC".capitalize.should == "123abc" - "abcdef"[1...-1].capitalize.should == "Bcde" + 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 @@ -36,10 +42,6 @@ describe "String#capitalize" do it "does not capitalize non-ASCII characters" do "ßet".capitalize(:ascii).should == "ßet" end - - it "handles non-ASCII substrings properly" do - "garçon"[1...-1].capitalize(:ascii).should == "Arço" - end end describe "full Unicode case mapping adapted for Turkic languages" do @@ -78,13 +80,18 @@ describe "String#capitalize" do -> { "abc".capitalize(:invalid_option) }.should raise_error(ArgumentError) end - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(String) - StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(StringSpecs::MyString) + end end - it "returns a String in the same encoding as self" do - "h".encode("US-ASCII").capitalize.encoding.should == Encoding::US_ASCII + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(String) + StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/casecmp_spec.rb b/spec/ruby/core/string/casecmp_spec.rb index 81ebea557c..986fbc8718 100644 --- a/spec/ruby/core/string/casecmp_spec.rb +++ b/spec/ruby/core/string/casecmp_spec.rb @@ -117,11 +117,6 @@ describe "String#casecmp independent of case" do "B".casecmp(a).should == 1 end end - - it "returns 0 for empty strings in different encodings" do - ''.b.casecmp('').should == 0 - ''.b.casecmp(''.encode("UTF-32LE")).should == 0 - end end describe 'String#casecmp? independent of case' do @@ -196,9 +191,4 @@ describe 'String#casecmp? independent of case' do it "returns nil if other can't be converted to a string" do "abc".casecmp?(mock('abc')).should be_nil end - - it "returns true for empty strings in different encodings" do - ''.b.should.casecmp?('') - ''.b.should.casecmp?(''.encode("UTF-32LE")) - end end diff --git a/spec/ruby/core/string/center_spec.rb b/spec/ruby/core/string/center_spec.rb index a59dd2a91b..b66015172c 100644 --- a/spec/ruby/core/string/center_spec.rb +++ b/spec/ruby/core/string/center_spec.rb @@ -47,6 +47,16 @@ 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 == "^_^" @@ -81,13 +91,34 @@ describe "String#center with length, padding" do -> { "hello".center(0, "") }.should raise_error(ArgumentError) end - it "returns String instances when called on subclasses" do - StringSpecs::MyString.new("").center(10).should be_an_instance_of(String) - StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(String) - StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on subclasses" do + StringSpecs::MyString.new("").center(10).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString) + + "".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + "foo".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + end + end - "".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) - "foo".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + ruby_version_is '3.0' do + it "returns String instances when called on subclasses" do + StringSpecs::MyString.new("").center(10).should be_an_instance_of(String) + StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(String) + StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + + "".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + "foo".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + 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 diff --git a/spec/ruby/core/string/chars_spec.rb b/spec/ruby/core/string/chars_spec.rb index ee85430574..e4f26bc0cc 100644 --- a/spec/ruby/core/string/chars_spec.rb +++ b/spec/ruby/core/string/chars_spec.rb @@ -1,5 +1,5 @@ -require_relative "../../spec_helper" require_relative 'shared/chars' +require_relative 'shared/each_char_without_block' describe "String#chars" do it_behaves_like :string_chars, :chars @@ -7,10 +7,4 @@ describe "String#chars" do it "returns an array when no block given" do "hello".chars.should == ['h', 'e', 'l', 'l', 'o'] end - - it "returns Strings in the same encoding as self" do - "hello".encode("US-ASCII").chars.each do |c| - c.encoding.should == Encoding::US_ASCII - end - end end diff --git a/spec/ruby/core/string/chomp_spec.rb b/spec/ruby/core/string/chomp_spec.rb index ec0490220b..3d6207f876 100644 --- a/spec/ruby/core/string/chomp_spec.rb +++ b/spec/ruby/core/string/chomp_spec.rb @@ -40,13 +40,24 @@ describe "String#chomp" do "".chomp.should == "" end - it "returns a String in the same encoding as self" do - "abc\n\n".encode("US-ASCII").chomp.encoding.should == Encoding::US_ASCII + 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 String instances when called on a subclass" do - str = StringSpecs::MyString.new("hello\n").chomp - str.should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + 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) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + str = StringSpecs::MyString.new("hello\n").chomp + str.should be_an_instance_of(String) + end end it "removes trailing characters that match $/ when it has been assigned a value" do @@ -69,6 +80,12 @@ 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 @@ -95,6 +112,12 @@ 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 @@ -117,6 +140,12 @@ 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 @@ -149,6 +178,16 @@ 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 @@ -193,6 +232,12 @@ 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) @@ -235,6 +280,12 @@ 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 @@ -253,6 +304,12 @@ 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 @@ -284,6 +341,16 @@ 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 75f25b39cd..9b4e7363c6 100644 --- a/spec/ruby/core/string/chop_spec.rb +++ b/spec/ruby/core/string/chop_spec.rb @@ -49,12 +49,28 @@ describe "String#chop" do s.chop.should_not equal(s) end - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(String) + 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) + end end - it "returns a String in the same encoding as self" do - "abc\n\n".encode("US-ASCII").chop.encoding.should == Encoding::US_ASCII + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/clone_spec.rb b/spec/ruby/core/string/clone_spec.rb index a2ba2f9877..f8d40423f0 100644 --- a/spec/ruby/core/string/clone_spec.rb +++ b/spec/ruby/core/string/clone_spec.rb @@ -54,8 +54,4 @@ describe "String#clone" do orig.should == "xtring" clone.should == "string" end - - it "returns a String in the same encoding as self" do - "a".encode("US-ASCII").clone.encoding.should == Encoding::US_ASCII - end end diff --git a/spec/ruby/core/string/comparison_spec.rb b/spec/ruby/core/string/comparison_spec.rb index 91cfdca25a..01199274b6 100644 --- a/spec/ruby/core/string/comparison_spec.rb +++ b/spec/ruby/core/string/comparison_spec.rb @@ -75,10 +75,6 @@ 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/concat_spec.rb b/spec/ruby/core/string/concat_spec.rb index 6f487eaa3a..5f6daadad7 100644 --- a/spec/ruby/core/string/concat_spec.rb +++ b/spec/ruby/core/string/concat_spec.rb @@ -5,7 +5,6 @@ require_relative 'shared/concat' describe "String#concat" do it_behaves_like :string_concat, :concat it_behaves_like :string_concat_encoding, :concat - it_behaves_like :string_concat_type_coercion, :concat it "takes multiple arguments" do str = "hello " diff --git a/spec/ruby/core/string/crypt_spec.rb b/spec/ruby/core/string/crypt_spec.rb index 06f84c70a4..b947702492 100644 --- a/spec/ruby/core/string/crypt_spec.rb +++ b/spec/ruby/core/string/crypt_spec.rb @@ -25,6 +25,21 @@ 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) @@ -70,6 +85,21 @@ 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 deleted file mode 100644 index 57d2be2cfd..0000000000 --- a/spec/ruby/core/string/dedup_spec.rb +++ /dev/null @@ -1,8 +0,0 @@ -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 4214fdecce..8469791f74 100644 --- a/spec/ruby/core/string/delete_prefix_spec.rb +++ b/spec/ruby/core/string/delete_prefix_spec.rb @@ -21,8 +21,11 @@ describe "String#delete_prefix" do r.should == s end - it "does not remove partial bytes, only full characters" do - "\xe3\x81\x82".delete_prefix("\xe3").should == "\xe3\x81\x82" + 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 @@ -38,13 +41,18 @@ describe "String#delete_prefix" do 'hello'.delete_prefix(o).should == 'o' end - it "returns a String instance when called on a subclass instance" do - s = StringSpecs::MyString.new('hello') - s.delete_prefix('hell').should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns a subclass instance when called on a subclass instance" do + s = StringSpecs::MyString.new('hello') + s.delete_prefix('hell').should be_an_instance_of(StringSpecs::MyString) + end end - it "returns a String in the same encoding as self" do - 'hello'.encode("US-ASCII").delete_prefix('hell').encoding.should == Encoding::US_ASCII + ruby_version_is '3.0' do + it "returns a String instance when called on a subclass instance" do + s = StringSpecs::MyString.new('hello') + s.delete_prefix('hell').should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/delete_spec.rb b/spec/ruby/core/string/delete_spec.rb index 3b9aa4fb75..ebca0b7dae 100644 --- a/spec/ruby/core/string/delete_spec.rb +++ b/spec/ruby/core/string/delete_spec.rb @@ -68,6 +68,15 @@ 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") @@ -84,12 +93,16 @@ describe "String#delete" do -> { "hello world".delete(mock('x')) }.should raise_error(TypeError) end - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(StringSpecs::MyString) + end end - it "returns a String in the same encoding as self" do - "hello".encode("US-ASCII").delete("lo").encoding.should == Encoding::US_ASCII + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/delete_suffix_spec.rb b/spec/ruby/core/string/delete_suffix_spec.rb index 9381f4cee7..12d0ee175e 100644 --- a/spec/ruby/core/string/delete_suffix_spec.rb +++ b/spec/ruby/core/string/delete_suffix_spec.rb @@ -21,8 +21,11 @@ describe "String#delete_suffix" do r.should == s end - it "does not remove partial bytes, only full characters" do - "\xe3\x81\x82".delete_suffix("\x82").should == "\xe3\x81\x82" + 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 @@ -38,13 +41,18 @@ describe "String#delete_suffix" do 'hello'.delete_suffix(o).should == 'h' end - it "returns a String instance when called on a subclass instance" do - s = StringSpecs::MyString.new('hello') - s.delete_suffix('ello').should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns a subclass instance when called on a subclass instance" do + s = StringSpecs::MyString.new('hello') + s.delete_suffix('ello').should be_an_instance_of(StringSpecs::MyString) + end end - it "returns a String in the same encoding as self" do - "hello".encode("US-ASCII").delete_suffix("ello").encoding.should == Encoding::US_ASCII + ruby_version_is '3.0' do + it "returns a String instance when called on a subclass instance" do + s = StringSpecs::MyString.new('hello') + s.delete_suffix('ello').should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/downcase_spec.rb b/spec/ruby/core/string/downcase_spec.rb index 7ee9d6df1d..4427c9df10 100644 --- a/spec/ruby/core/string/downcase_spec.rb +++ b/spec/ruby/core/string/downcase_spec.rb @@ -8,10 +8,6 @@ describe "String#downcase" do "hello".downcase.should == "hello" end - it "returns a String in the same encoding as self" do - "hELLO".encode("US-ASCII").downcase.encoding.should == Encoding::US_ASCII - end - describe "full Unicode case mapping" do it "works for all of Unicode with no option" do "ÄÖÜ".downcase.should == "äöü" @@ -31,10 +27,6 @@ describe "String#downcase" do it "does not downcase non-ASCII characters" do "CÅR".downcase(:ascii).should == "cÅr" end - - it "works with substrings" do - "prefix TÉ"[-2..-1].downcase(:ascii).should == "tÉ" - end end describe "full Unicode case mapping adapted for Turkic languages" do @@ -76,8 +68,24 @@ describe "String#downcase" do -> { "ABC".downcase(:invalid_option) }.should raise_error(ArgumentError) end - it "returns a String instance for subclasses" do - StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(String) + 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) + end + end + + ruby_version_is '3.0' do + it "returns a String instance for subclasses" do + StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/dump_spec.rb b/spec/ruby/core/string/dump_spec.rb index cab8beff5a..817dec6c4d 100644 --- a/spec/ruby/core/string/dump_spec.rb +++ b/spec/ruby/core/string/dump_spec.rb @@ -3,12 +3,32 @@ 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 - it "returns a String instance" do - StringSpecs::MyString.new.dump.should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns a subclass instance" do + StringSpecs::MyString.new.dump.should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns a String instance" do + StringSpecs::MyString.new.dump.should be_an_instance_of(String) + end end it "wraps string with \"" do @@ -342,7 +362,7 @@ describe "String#dump" do ].should be_computed_by(:dump) end - it "returns a string with multi-byte UTF-8 characters less than or equal 0xFFFF replaced by \\uXXXX notation with upper-case hex digits" do + it "returns a string with multi-byte UTF-8 characters replaced by \\u{} notation with upper-case hex digits" do [ [0200.chr('utf-8'), '"\u0080"'], [0201.chr('utf-8'), '"\u0081"'], [0202.chr('utf-8'), '"\u0082"'], @@ -374,21 +394,15 @@ describe "String#dump" do [0235.chr('utf-8'), '"\u009D"'], [0236.chr('utf-8'), '"\u009E"'], [0237.chr('utf-8'), '"\u009F"'], - [0177777.chr('utf-8'), '"\uFFFF"'], ].should be_computed_by(:dump) end - it "returns a string with multi-byte UTF-8 characters greater than 0xFFFF replaced by \\u{XXXXXX} notation with upper-case hex digits" do - 0x10000.chr('utf-8').dump.should == '"\u{10000}"' - 0x10FFFF.chr('utf-8').dump.should == '"\u{10FFFF}"' - end - it "includes .force_encoding(name) if the encoding isn't ASCII compatible" do "\u{876}".encode('utf-16be').dump.should.end_with?(".force_encoding(\"UTF-16BE\")") "\u{876}".encode('utf-16le').dump.should.end_with?(".force_encoding(\"UTF-16LE\")") end - it "returns a String in the same encoding as self" do + it "keeps origin encoding" do "foo".encode("ISO-8859-1").dump.encoding.should == Encoding::ISO_8859_1 "foo".encode('windows-1251').dump.encoding.should == Encoding::Windows_1251 1.chr.dump.encoding.should == Encoding::US_ASCII diff --git a/spec/ruby/core/string/dup_spec.rb b/spec/ruby/core/string/dup_spec.rb index 73f71b8ffc..d650788210 100644 --- a/spec/ruby/core/string/dup_spec.rb +++ b/spec/ruby/core/string/dup_spec.rb @@ -49,17 +49,4 @@ describe "String#dup" do orig.should == "xtring" dup.should == "string" end - - it "does not modify the original setbyte-mutated string when changing dupped string" do - orig = "a" - orig.setbyte 0, "b".ord - copy = orig.dup - orig.setbyte 0, "c".ord - orig.should == "c" - copy.should == "b" - end - - it "returns a String in the same encoding as self" do - "hello".encode("US-ASCII").dup.encoding.should == Encoding::US_ASCII - end end diff --git a/spec/ruby/core/string/each_char_spec.rb b/spec/ruby/core/string/each_char_spec.rb index 36219f79db..aff98c0a5c 100644 --- a/spec/ruby/core/string/each_char_spec.rb +++ b/spec/ruby/core/string/each_char_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative 'shared/chars' require_relative 'shared/each_char_without_block' diff --git a/spec/ruby/core/string/each_grapheme_cluster_spec.rb b/spec/ruby/core/string/each_grapheme_cluster_spec.rb index e1fa4ae67b..b45d89ecb0 100644 --- a/spec/ruby/core/string/each_grapheme_cluster_spec.rb +++ b/spec/ruby/core/string/each_grapheme_cluster_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative 'shared/chars' require_relative 'shared/grapheme_clusters' require_relative 'shared/each_char_without_block' @@ -8,9 +7,11 @@ describe "String#each_grapheme_cluster" do it_behaves_like :string_grapheme_clusters, :each_grapheme_cluster it_behaves_like :string_each_char_without_block, :each_grapheme_cluster - it "yields String instances for subclasses" do - a = [] - StringSpecs::MyString.new("abc").each_grapheme_cluster { |s| a << s.class } - a.should == [String, String, String] + ruby_version_is '3.0' do + it "yields String instances for subclasses" do + a = [] + StringSpecs::MyString.new("abc").each_grapheme_cluster { |s| a << s.class } + a.should == [String, String, String] + end end end diff --git a/spec/ruby/core/string/element_set_spec.rb b/spec/ruby/core/string/element_set_spec.rb index fa041fa31d..c9e02a7381 100644 --- a/spec/ruby/core/string/element_set_spec.rb +++ b/spec/ruby/core/string/element_set_spec.rb @@ -14,6 +14,18 @@ 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" @@ -129,12 +141,6 @@ 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 @@ -357,11 +363,11 @@ describe "String#[]= with a Range index" do end it "raises a RangeError if negative Range begin is out of range" do - -> { "abc"[-4..-2] = "x" }.should raise_error(RangeError, "-4..-2 out of range") + -> { "abc"[-4..-2] = "x" }.should raise_error(RangeError) end it "raises a RangeError if positive Range begin is greater than String size" do - -> { "abc"[4..2] = "x" }.should raise_error(RangeError, "4..2 out of range") + -> { "abc"[4..2] = "x" }.should raise_error(RangeError) end it "uses the Range end as an index rather than a count" do @@ -481,6 +487,18 @@ 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/encode_spec.rb b/spec/ruby/core/string/encode_spec.rb index 35ed27bb40..5604ab7210 100644 --- a/spec/ruby/core/string/encode_spec.rb +++ b/spec/ruby/core/string/encode_spec.rb @@ -79,10 +79,6 @@ describe "String#encode" do encoded.encode("UTF-8").should == "ちfoofoo" end - it "replace multiple invalid bytes at the end with a single replacement character" do - "\xE3\x81\x93\xE3\x81".encode("UTF-8", invalid: :replace).should == "\u3053\ufffd" - end - it "replaces invalid encoding in source using a specified replacement even when a fallback is given" do encoded = "ち\xE3\x81\xFF".encode("UTF-16LE", invalid: :replace, replace: "foo", fallback: -> c { "bar" }) encoded.should == "\u3061foofoo".encode("UTF-16LE") diff --git a/spec/ruby/core/string/encoding_spec.rb b/spec/ruby/core/string/encoding_spec.rb index 574a1e2f92..4d17a39f29 100644 --- a/spec/ruby/core/string/encoding_spec.rb +++ b/spec/ruby/core/string/encoding_spec.rb @@ -10,7 +10,6 @@ describe "String#encoding" do it "is equal to the source encoding by default" do s = StringSpecs::ISO88599Encoding.new s.cedilla.encoding.should == s.source_encoding - s.cedilla.encode("utf-8").should == 350.chr(Encoding::UTF_8) # S-cedilla end it "returns the given encoding if #force_encoding has been called" do diff --git a/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb b/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb index cfa91dedc3..61a691ff78 100644 --- a/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb +++ b/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb @@ -4,6 +4,6 @@ module StringSpecs def source_encoding; __ENCODING__; end def x_escape; [0xDF].pack('C').force_encoding("iso-8859-9"); end def ascii_only; "glark"; end - def cedilla; ""; end # S-cedilla + def cedilla; "Ş"; end end end diff --git a/spec/ruby/core/string/fixtures/to_c.rb b/spec/ruby/core/string/fixtures/to_c.rb deleted file mode 100644 index 7776933263..0000000000 --- a/spec/ruby/core/string/fixtures/to_c.rb +++ /dev/null @@ -1,5 +0,0 @@ -module StringSpecs - def self.to_c_method(string) - string.to_c - end -end diff --git a/spec/ruby/core/string/grapheme_clusters_spec.rb b/spec/ruby/core/string/grapheme_clusters_spec.rb index 380a245083..3046265a12 100644 --- a/spec/ruby/core/string/grapheme_clusters_spec.rb +++ b/spec/ruby/core/string/grapheme_clusters_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative 'shared/chars' require_relative 'shared/grapheme_clusters' diff --git a/spec/ruby/core/string/gsub_spec.rb b/spec/ruby/core/string/gsub_spec.rb index 9e3b50322c..ad41b7e0a2 100644 --- a/spec/ruby/core/string/gsub_spec.rb +++ b/spec/ruby/core/string/gsub_spec.rb @@ -160,12 +160,56 @@ 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 @@ -192,13 +236,26 @@ describe "String#gsub with pattern and replacement" do -> { "hello".gsub(/[aeiou]/, nil) }.should raise_error(TypeError) end - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(String) - StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(String) - StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(String) - StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(StringSpecs::MyString) + end end + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(String) + StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(String) + StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(String) + StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(String) + end + end + + # Note: $~ cannot be tested because mspec messes with it + it "sets $~ to MatchData of last match and nil when there's none" do 'hello.'.gsub('hello', 'x') $~[0].should == 'hello' @@ -212,18 +269,6 @@ describe "String#gsub with pattern and replacement" do 'hello.'.gsub(/not/, 'x') $~.should == nil end - - it "handles a pattern in a superset encoding" do - result = 'abc'.force_encoding(Encoding::US_ASCII).gsub('é', 'è') - result.should == 'abc' - result.encoding.should == Encoding::US_ASCII - end - - it "handles a pattern in a subset encoding" do - result = 'été'.gsub('t'.force_encoding(Encoding::US_ASCII), 'u') - result.should == 'éué' - result.encoding.should == Encoding::UTF_8 - end end describe "String#gsub with pattern and Hash" do @@ -291,6 +336,28 @@ 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 @@ -359,6 +426,28 @@ 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 @@ -437,6 +526,28 @@ 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}" @@ -504,6 +615,20 @@ 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 @@ -520,27 +645,6 @@ describe "String#gsub! with pattern and replacement" do -> { s.gsub!(/e/, "e") }.should raise_error(FrozenError) -> { s.gsub!(/[aeiou]/, '*') }.should raise_error(FrozenError) end - - it "handles a pattern in a superset encoding" do - string = 'abc'.force_encoding(Encoding::US_ASCII) - - result = string.gsub!('é', 'è') - - result.should == nil - string.should == 'abc' - string.encoding.should == Encoding::US_ASCII - end - - it "handles a pattern in a subset encoding" do - string = 'été' - pattern = 't'.force_encoding(Encoding::US_ASCII) - - result = string.gsub!(pattern, 'u') - - result.should == string - string.should == 'éué' - string.encoding.should == Encoding::UTF_8 - end end describe "String#gsub! with pattern and block" do @@ -550,6 +654,20 @@ 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/include_spec.rb b/spec/ruby/core/string/include_spec.rb index 23e1e134ec..e32eb17c29 100644 --- a/spec/ruby/core/string/include_spec.rb +++ b/spec/ruby/core/string/include_spec.rb @@ -13,20 +13,6 @@ describe "String#include? with String" do StringSpecs::MyString.new("hello").include?(StringSpecs::MyString.new("lo")).should == true end - it "returns true if both strings are empty" do - "".should.include?("") - "".force_encoding("EUC-JP").should.include?("") - "".should.include?("".force_encoding("EUC-JP")) - "".force_encoding("EUC-JP").should.include?("".force_encoding("EUC-JP")) - end - - it "returns true if the RHS is empty" do - "a".should.include?("") - "a".force_encoding("EUC-JP").should.include?("") - "a".should.include?("".force_encoding("EUC-JP")) - "a".force_encoding("EUC-JP").should.include?("".force_encoding("EUC-JP")) - end - it "tries to convert other to string using to_str" do other = mock('lo') other.should_receive(:to_str).and_return("lo") diff --git a/spec/ruby/core/string/index_spec.rb b/spec/ruby/core/string/index_spec.rb index b500cf6ca7..5d77a88e4e 100644 --- a/spec/ruby/core/string/index_spec.rb +++ b/spec/ruby/core/string/index_spec.rb @@ -159,21 +159,6 @@ describe "String#index with String" do "あれ".index char end.should raise_error(Encoding::CompatibilityError) end - - it "handles a substring in a superset encoding" do - 'abc'.force_encoding(Encoding::US_ASCII).index('é').should == nil - end - - it "handles a substring in a subset encoding" do - 'été'.index('t'.force_encoding(Encoding::US_ASCII)).should == 1 - end - - it "raises an Encoding::CompatibilityError if the encodings are incompatible" do - str = 'abc'.force_encoding("ISO-2022-JP") - pattern = 'b'.force_encoding("EUC-JP") - - -> { str.index(pattern) }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: ISO-2022-JP and EUC-JP") - end end describe "String#index with Regexp" do @@ -319,17 +304,6 @@ describe "String#index with Regexp" do "われわわれ".index(/わ/, 3).should == 3 end - ruby_bug "#19763", ""..."3.3.0" do - it "raises an Encoding::CompatibilityError if the encodings are incompatible" do - re = Regexp.new "れ".encode(Encoding::EUC_JP) - -> do - "あれ".index re - end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)") - end - end - - # The exception message was incorrectly "incompatible character encodings: UTF-8 and EUC-JP" before 3.3.0 - # Still test that the right exception class is used before that. it "raises an Encoding::CompatibilityError if the encodings are incompatible" do re = Regexp.new "れ".encode(Encoding::EUC_JP) -> do diff --git a/spec/ruby/core/string/insert_spec.rb b/spec/ruby/core/string/insert_spec.rb index 0c87df3a95..752cbb2f37 100644 --- a/spec/ruby/core/string/insert_spec.rb +++ b/spec/ruby/core/string/insert_spec.rb @@ -41,6 +41,18 @@ 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) @@ -69,13 +81,4 @@ describe "String#insert with index, other" do "あれ".insert 0, pat end.should raise_error(Encoding::CompatibilityError) end - - it "should not call subclassed string methods" do - cls = Class.new(String) do - def replace(arg) - raise "should not call replace" - end - end - cls.new("abcd").insert(0, 'X').should == "Xabcd" - end end diff --git a/spec/ruby/core/string/inspect_spec.rb b/spec/ruby/core/string/inspect_spec.rb index 8bf3d3161f..98b5b32b61 100644 --- a/spec/ruby/core/string/inspect_spec.rb +++ b/spec/ruby/core/string/inspect_spec.rb @@ -3,6 +3,18 @@ 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 @@ -19,21 +31,6 @@ describe "String#inspect" do ].should be_computed_by(:inspect) end - it "returns a string with special characters replaced with \\<char> notation for UTF-16" do - pairs = [ - ["\a", '"\\a"'], - ["\b", '"\\b"'], - ["\t", '"\\t"'], - ["\n", '"\\n"'], - ["\v", '"\\v"'], - ["\f", '"\\f"'], - ["\r", '"\\r"'], - ["\e", '"\\e"'] - ].map { |str, result| [str.encode('UTF-16LE'), result] } - - pairs.should be_computed_by(:inspect) - end - it "returns a string with \" and \\ escaped with a backslash" do [ ["\"", '"\\""'], ["\\", '"\\\\"'] @@ -326,11 +323,6 @@ describe "String#inspect" do "\xF0\x9F".inspect.should == '"\\xF0\\x9F"' end - it "works for broken US-ASCII strings" do - s = "©".force_encoding("US-ASCII") - s.inspect.should == '"\xC2\xA9"' - end - describe "when default external is UTF-8" do before :each do @extenc, Encoding.default_external = Encoding.default_external, Encoding::UTF_8 diff --git a/spec/ruby/core/string/lines_spec.rb b/spec/ruby/core/string/lines_spec.rb index 40ab5f71d8..ad4b119074 100644 --- a/spec/ruby/core/string/lines_spec.rb +++ b/spec/ruby/core/string/lines_spec.rb @@ -1,6 +1,7 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative 'shared/each_line' +require_relative 'shared/each_line_without_block' describe "String#lines" do it_behaves_like :string_each_line, :lines diff --git a/spec/ruby/core/string/ljust_spec.rb b/spec/ruby/core/string/ljust_spec.rb index 9208ec5897..0c3b2a2f44 100644 --- a/spec/ruby/core/string/ljust_spec.rb +++ b/spec/ruby/core/string/ljust_spec.rb @@ -31,6 +31,16 @@ 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 == "^_^" @@ -64,13 +74,34 @@ describe "String#ljust with length, padding" do -> { "hello".ljust(10, '') }.should raise_error(ArgumentError) end - it "returns String instances when called on subclasses" do - StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(String) - StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(String) - StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on subclasses" do + StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString) + + "".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + "foo".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + end + end - "".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) - "foo".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + ruby_version_is '3.0' do + it "returns String instances when called on subclasses" do + StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(String) + StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(String) + StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + + "".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + "foo".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + 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 diff --git a/spec/ruby/core/string/lstrip_spec.rb b/spec/ruby/core/string/lstrip_spec.rb index 85685deb0a..20e4cdeabd 100644 --- a/spec/ruby/core/string/lstrip_spec.rb +++ b/spec/ruby/core/string/lstrip_spec.rb @@ -10,19 +10,21 @@ describe "String#lstrip" do " hello world ".lstrip.should == "hello world " "\n\r\t\n\v\r hello world ".lstrip.should == "hello world " "hello".lstrip.should == "hello" - " こにちわ".lstrip.should == "こにちわ" end - it "works with lazy substrings" do - " hello "[1...-1].lstrip.should == "hello " - " hello world "[1...-1].lstrip.should == "hello world " - "\n\r\t\n\v\r hello world "[1...-1].lstrip.should == "hello world " - " こにちわ "[1...-1].lstrip.should == "こにちわ" + ruby_version_is '3.1' do + it "strips leading \\0" do + "\x00hello".lstrip.should == "hello" + "\000 \000hello\000 \000".lstrip.should == "hello\000 \000" + end end - it "strips leading \\0" do - "\x00hello".lstrip.should == "hello" - "\000 \000hello\000 \000".lstrip.should == "hello\000 \000" + 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 @@ -33,24 +35,20 @@ describe "String#lstrip!" do a.should == "hello " end + ruby_version_is '3.1' do + it "strips leading \\0" do + a = "\000 \000hello\000 \000" + a.lstrip! + a.should == "hello\000 \000" + end + end + it "returns nil if no modifications were made" do a = "hello" a.lstrip!.should == nil a.should == "hello" end - it "makes a string empty if it is only whitespace" do - "".lstrip!.should == nil - " ".lstrip.should == "" - " ".lstrip.should == "" - end - - it "removes leading NULL bytes and whitespace" do - a = "\000 \000hello\000 \000" - a.lstrip! - a.should == "hello\000 \000" - end - it "raises a FrozenError on a frozen instance that is modified" do -> { " hello ".freeze.lstrip! }.should raise_error(FrozenError) end @@ -60,14 +58,4 @@ describe "String#lstrip!" do -> { "hello".freeze.lstrip! }.should raise_error(FrozenError) -> { "".freeze.lstrip! }.should raise_error(FrozenError) end - - it "raises an ArgumentError if the first non-space codepoint is invalid" do - s = "\xDFabc".force_encoding(Encoding::UTF_8) - s.valid_encoding?.should be_false - -> { s.lstrip! }.should raise_error(ArgumentError) - - s = " \xDFabc".force_encoding(Encoding::UTF_8) - s.valid_encoding?.should be_false - -> { s.lstrip! }.should raise_error(ArgumentError) - end end diff --git a/spec/ruby/core/string/modulo_spec.rb b/spec/ruby/core/string/modulo_spec.rb index bf96a82874..dc11ced4e2 100644 --- a/spec/ruby/core/string/modulo_spec.rb +++ b/spec/ruby/core/string/modulo_spec.rb @@ -302,6 +302,29 @@ 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" @@ -368,16 +391,8 @@ describe "String#%" do ("%c" % 'A').should == "A" end - ruby_version_is ""..."3.2" do - it "raises an exception for multiple character strings as argument for %c" do - -> { "%c" % 'AA' }.should raise_error(ArgumentError) - end - end - - ruby_version_is "3.2" do - it "supports only the first character as argument for %c" do - ("%c" % 'AA').should == "A" - end + it "raises an exception for multiple character strings as argument for %c" do + -> { "%c" % 'AA' }.should raise_error(ArgumentError) end it "calls to_str on argument for %c formats" do @@ -563,6 +578,20 @@ 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 == "" @@ -591,6 +620,13 @@ 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 @@ -750,6 +786,12 @@ 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/ord_spec.rb b/spec/ruby/core/string/ord_spec.rb index 4cf26990fe..cfc630a124 100644 --- a/spec/ruby/core/string/ord_spec.rb +++ b/spec/ruby/core/string/ord_spec.rb @@ -25,9 +25,4 @@ describe "String#ord" do it "raises an ArgumentError if called on an empty String" do -> { ''.ord }.should raise_error(ArgumentError) end - - it "raises ArgumentError if the character is broken" do - s = "©".force_encoding("US-ASCII") - -> { s.ord }.should raise_error(ArgumentError, "invalid byte sequence in US-ASCII") - end end diff --git a/spec/ruby/core/string/partition_spec.rb b/spec/ruby/core/string/partition_spec.rb index 9cb3672881..98311f2be4 100644 --- a/spec/ruby/core/string/partition_spec.rb +++ b/spec/ruby/core/string/partition_spec.rb @@ -38,26 +38,4 @@ describe "String#partition with String" do it "takes precedence over a given block" do "hello world".partition("o") { true }.should == ["hell", "o", " world"] end - - it "handles a pattern in a superset encoding" do - string = "hello".force_encoding(Encoding::US_ASCII) - - result = string.partition("é") - - result.should == ["hello", "", ""] - result[0].encoding.should == Encoding::US_ASCII - result[1].encoding.should == Encoding::US_ASCII - result[2].encoding.should == Encoding::US_ASCII - end - - it "handles a pattern in a subset encoding" do - pattern = "o".force_encoding(Encoding::US_ASCII) - - result = "héllo world".partition(pattern) - - result.should == ["héll", "o", " world"] - result[0].encoding.should == Encoding::UTF_8 - result[1].encoding.should == Encoding::US_ASCII - result[2].encoding.should == Encoding::UTF_8 - end end diff --git a/spec/ruby/core/string/plus_spec.rb b/spec/ruby/core/string/plus_spec.rb index 9da17451c6..9f0db6427c 100644 --- a/spec/ruby/core/string/plus_spec.rb +++ b/spec/ruby/core/string/plus_spec.rb @@ -3,9 +3,6 @@ require_relative 'fixtures/classes' require_relative 'shared/concat' describe "String#+" do - it_behaves_like :string_concat_encoding, :+ - it_behaves_like :string_concat_type_coercion, :+ - it "returns a new string containing the given string concatenated to self" do ("" + "").should == "" ("" + "Hello").should == "Hello" @@ -34,4 +31,19 @@ describe "String#+" do ("hello" + StringSpecs::MyString.new("foo")).should be_an_instance_of(String) ("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 a0393d4760..a6074be3c6 100644 --- a/spec/ruby/core/string/prepend_spec.rb +++ b/spec/ruby/core/string/prepend_spec.rb @@ -34,6 +34,16 @@ 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 e67122c05c..b45ff2cf6f 100644 --- a/spec/ruby/core/string/reverse_spec.rb +++ b/spec/ruby/core/string/reverse_spec.rb @@ -10,26 +10,31 @@ describe "String#reverse" do "".reverse.should == "" end - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new("stressed").reverse.should be_an_instance_of(String) - StringSpecs::MyString.new("m").reverse.should be_an_instance_of(String) - StringSpecs::MyString.new("").reverse.should be_an_instance_of(String) + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("stressed").reverse.should be_an_instance_of(String) + StringSpecs::MyString.new("m").reverse.should be_an_instance_of(String) + StringSpecs::MyString.new("").reverse.should be_an_instance_of(String) + end end - it "reverses a string with multi byte characters" do - "微軟正黑體".reverse.should == "體黑正軟微" + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("stressed").reverse.should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("m").reverse.should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("").reverse.should be_an_instance_of(StringSpecs::MyString) + end end - it "works with a broken string" do - str = "微軟\xDF\xDE正黑體".force_encoding(Encoding::UTF_8) - - str.valid_encoding?.should be_false - - str.reverse.should == "體黑正\xDE\xDF軟微" + 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 "returns a String in the same encoding as self" do - "stressed".encode("US-ASCII").reverse.encoding.should == Encoding::US_ASCII + it "reverses a string with multi byte characters" do + "微軟正黑體".reverse.should == "體黑正軟微" end end @@ -57,13 +62,4 @@ describe "String#reverse!" do str.reverse! str.should == "體黑正軟微" end - - it "works with a broken string" do - str = "微軟\xDF\xDE正黑體".force_encoding(Encoding::UTF_8) - - str.valid_encoding?.should be_false - str.reverse! - - str.should == "體黑正\xDE\xDF軟微" - end end diff --git a/spec/ruby/core/string/rindex_spec.rb b/spec/ruby/core/string/rindex_spec.rb index 45ff13a006..7a6af0c9d0 100644 --- a/spec/ruby/core/string/rindex_spec.rb +++ b/spec/ruby/core/string/rindex_spec.rb @@ -4,17 +4,13 @@ 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 or Regexp" do + it "raises a TypeError if obj isn't a String, Integer 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) @@ -196,21 +192,6 @@ describe "String#rindex with String" do it "raises a TypeError when given offset is nil" do -> { "str".rindex("st", nil) }.should raise_error(TypeError) end - - it "handles a substring in a superset encoding" do - 'abc'.force_encoding(Encoding::US_ASCII).rindex('é').should == nil - end - - it "handles a substring in a subset encoding" do - 'été'.rindex('t'.force_encoding(Encoding::US_ASCII)).should == 1 - end - - it "raises an Encoding::CompatibilityError if the encodings are incompatible" do - str = 'abc'.force_encoding("ISO-2022-JP") - pattern = 'b'.force_encoding("EUC-JP") - - -> { str.rindex(pattern) }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: ISO-2022-JP and EUC-JP") - end end describe "String#rindex with Regexp" do @@ -380,6 +361,6 @@ describe "String#rindex with Regexp" do re = Regexp.new "れ".encode(Encoding::EUC_JP) -> do "あれ".rindex re - end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)") + end.should raise_error(Encoding::CompatibilityError) end end diff --git a/spec/ruby/core/string/rjust_spec.rb b/spec/ruby/core/string/rjust_spec.rb index fcbaf3b938..f51aacff44 100644 --- a/spec/ruby/core/string/rjust_spec.rb +++ b/spec/ruby/core/string/rjust_spec.rb @@ -31,6 +31,16 @@ 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 == "^_^" @@ -64,13 +74,34 @@ describe "String#rjust with length, padding" do -> { "hello".rjust(10, '') }.should raise_error(ArgumentError) end - it "returns String instances when called on subclasses" do - StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(String) - StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(String) - StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on subclasses" do + StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString) + + "".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + "foo".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + end + end - "".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) - "foo".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + ruby_version_is '3.0' do + it "returns String instances when called on subclasses" do + StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(String) + StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(String) + StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + + "".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + "foo".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String) + 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 diff --git a/spec/ruby/core/string/rpartition_spec.rb b/spec/ruby/core/string/rpartition_spec.rb index 21e87f530a..c8f9afaee9 100644 --- a/spec/ruby/core/string/rpartition_spec.rb +++ b/spec/ruby/core/string/rpartition_spec.rb @@ -46,26 +46,4 @@ describe "String#rpartition with String" do ->{ "hello".rpartition(5) }.should raise_error(TypeError) ->{ "hello".rpartition(nil) }.should raise_error(TypeError) end - - it "handles a pattern in a superset encoding" do - string = "hello".force_encoding(Encoding::US_ASCII) - - result = string.rpartition("é") - - result.should == ["", "", "hello"] - result[0].encoding.should == Encoding::US_ASCII - result[1].encoding.should == Encoding::US_ASCII - result[2].encoding.should == Encoding::US_ASCII - end - - it "handles a pattern in a subset encoding" do - pattern = "o".force_encoding(Encoding::US_ASCII) - - result = "héllo world".rpartition(pattern) - - result.should == ["héllo w", "o", "rld"] - result[0].encoding.should == Encoding::UTF_8 - result[1].encoding.should == Encoding::US_ASCII - result[2].encoding.should == Encoding::UTF_8 - end end diff --git a/spec/ruby/core/string/rstrip_spec.rb b/spec/ruby/core/string/rstrip_spec.rb index e4cf93315e..a1453f91fe 100644 --- a/spec/ruby/core/string/rstrip_spec.rb +++ b/spec/ruby/core/string/rstrip_spec.rb @@ -11,19 +11,19 @@ describe "String#rstrip" do " hello world \n\r\t\n\v\r".rstrip.should == " hello world" "hello".rstrip.should == "hello" "hello\x00".rstrip.should == "hello" - "こにちわ ".rstrip.should == "こにちわ" - end - - it "works with lazy substrings" do - " hello "[1...-1].rstrip.should == " hello" - " hello world "[1...-1].rstrip.should == " hello world" - " hello world \n\r\t\n\v\r"[1...-1].rstrip.should == " hello world" - " こにちわ "[1...-1].rstrip.should == "こにちわ" end 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 @@ -45,18 +45,6 @@ describe "String#rstrip!" do a.should == "hello" end - it "makes a string empty if it is only whitespace" do - "".rstrip!.should == nil - " ".rstrip.should == "" - " ".rstrip.should == "" - end - - it "removes trailing NULL bytes and whitespace" do - a = "\000 goodbye \000" - a.rstrip! - a.should == "\000 goodbye" - end - it "raises a FrozenError on a frozen instance that is modified" do -> { " hello ".freeze.rstrip! }.should raise_error(FrozenError) end @@ -66,28 +54,4 @@ describe "String#rstrip!" do -> { "hello".freeze.rstrip! }.should raise_error(FrozenError) -> { "".freeze.rstrip! }.should raise_error(FrozenError) end - - ruby_version_is "3.2" do - it "raises an Encoding::CompatibilityError if the last non-space codepoint is invalid" do - s = "abc\xDF".force_encoding(Encoding::UTF_8) - s.valid_encoding?.should be_false - -> { s.rstrip! }.should raise_error(Encoding::CompatibilityError) - - s = "abc\xDF ".force_encoding(Encoding::UTF_8) - s.valid_encoding?.should be_false - -> { s.rstrip! }.should raise_error(Encoding::CompatibilityError) - end - end - - ruby_version_is ""..."3.2" do - it "raises an ArgumentError if the last non-space codepoint is invalid" do - s = "abc\xDF".force_encoding(Encoding::UTF_8) - s.valid_encoding?.should be_false - -> { s.rstrip! }.should raise_error(ArgumentError) - - s = "abc\xDF ".force_encoding(Encoding::UTF_8) - s.valid_encoding?.should be_false - -> { s.rstrip! }.should raise_error(ArgumentError) - end - end end diff --git a/spec/ruby/core/string/scan_spec.rb b/spec/ruby/core/string/scan_spec.rb index 70c3b7fb7b..5f86dbbecc 100644 --- a/spec/ruby/core/string/scan_spec.rb +++ b/spec/ruby/core/string/scan_spec.rb @@ -65,16 +65,32 @@ 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 == ["あああ", "あああ"] end - - it "returns Strings in the same encoding as self" do - "cruel world".encode("US-ASCII").scan(/\w+/).each do |s| - s.encoding.should == Encoding::US_ASCII - end - end end describe "String#scan with pattern and block" do @@ -157,6 +173,24 @@ 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'; @@ -165,9 +199,11 @@ describe "String#scan with pattern and block" do end end - it "yields String instances for subclasses" do - a = [] - StringSpecs::MyString.new("abc").scan(/./) { |s| a << s.class } - a.should == [String, String, String] + ruby_version_is '3.0' do + it "yields String instances for subclasses" do + a = [] + StringSpecs::MyString.new("abc").scan(/./) { |s| a << s.class } + a.should == [String, String, String] + end end end diff --git a/spec/ruby/core/string/scrub_spec.rb b/spec/ruby/core/string/scrub_spec.rb index bcee4db463..3137399291 100644 --- a/spec/ruby/core/string/scrub_spec.rb +++ b/spec/ruby/core/string/scrub_spec.rb @@ -14,11 +14,6 @@ describe "String#scrub with a default replacement" do "abc\u3042#{x81}".scrub.should == "abc\u3042\uFFFD" end - it "replaces invalid byte sequences in lazy substrings" do - x81 = [0x81].pack('C').force_encoding('utf-8') - "abc\u3042#{x81}def"[1...-1].scrub.should == "bc\u3042\uFFFDde" - end - it "returns a copy of self when the input encoding is BINARY" do input = "foo".encode('BINARY') @@ -31,15 +26,18 @@ describe "String#scrub with a default replacement" do input.scrub.should == "abc?????" end - it "returns a String in the same encoding as self" do - x81 = [0x81].pack('C').force_encoding('utf-8') - "abc\u3042#{x81}".scrub.encoding.should == Encoding::UTF_8 + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("foo").scrub.should be_an_instance_of(String) + input = [0x81].pack('C').force_encoding('utf-8') + StringSpecs::MyString.new(input).scrub.should be_an_instance_of(String) + end end - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new("foo").scrub.should be_an_instance_of(String) - input = [0x81].pack('C').force_encoding('utf-8') - StringSpecs::MyString.new(input).scrub.should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("foo").scrub.should be_an_instance_of(StringSpecs::MyString) + end end end @@ -77,11 +75,6 @@ describe "String#scrub with a custom replacement" do block.should raise_error(ArgumentError) end - it "returns a String in the same encoding as self" do - x81 = [0x81].pack('C').force_encoding('utf-8') - "abc\u3042#{x81}".scrub("*").encoding.should == Encoding::UTF_8 - end - it "raises TypeError when a non String replacement is given" do x81 = [0x81].pack('C').force_encoding('utf-8') block = -> { "foo#{x81}".scrub(1) } @@ -89,10 +82,12 @@ describe "String#scrub with a custom replacement" do block.should raise_error(TypeError) end - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new("foo").scrub("*").should be_an_instance_of(String) - input = [0x81].pack('C').force_encoding('utf-8') - StringSpecs::MyString.new(input).scrub("*").should be_an_instance_of(String) + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("foo").scrub("*").should be_an_instance_of(String) + input = [0x81].pack('C').force_encoding('utf-8') + StringSpecs::MyString.new(input).scrub("*").should be_an_instance_of(String) + end end end @@ -119,10 +114,12 @@ describe "String#scrub with a block" do replaced.should == "€€" end - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new("foo").scrub { |b| "*" }.should be_an_instance_of(String) - input = [0x81].pack('C').force_encoding('utf-8') - StringSpecs::MyString.new(input).scrub { |b| "<#{b.unpack("H*")[0]}>" }.should be_an_instance_of(String) + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("foo").scrub { |b| "*" }.should be_an_instance_of(String) + input = [0x81].pack('C').force_encoding('utf-8') + StringSpecs::MyString.new(input).scrub { |b| "<#{b.unpack("H*")[0]}>" }.should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/setbyte_spec.rb b/spec/ruby/core/string/setbyte_spec.rb index 77bff64038..03e5bad88b 100644 --- a/spec/ruby/core/string/setbyte_spec.rb +++ b/spec/ruby/core/string/setbyte_spec.rb @@ -36,12 +36,6 @@ describe "String#setbyte" do str.valid_encoding?.should be_true str.setbyte(2,253) str.valid_encoding?.should be_false - - str = "ABC" - str.setbyte(0, 0x20) # ' ' - str.should.valid_encoding? - str.setbyte(0, 0xE3) - str.should_not.valid_encoding? end it "regards a negative index as counting from the end of the String" do diff --git a/spec/ruby/core/string/shared/byte_index_common.rb b/spec/ruby/core/string/shared/byte_index_common.rb deleted file mode 100644 index 3de1453f4f..0000000000 --- a/spec/ruby/core/string/shared/byte_index_common.rb +++ /dev/null @@ -1,63 +0,0 @@ -# -*- encoding: utf-8 -*- -require_relative '../../../spec_helper' - -describe :byte_index_common, shared: true do - describe "raises on type errors" do - it "raises a TypeError if passed nil" do - -> { "abc".send(@method, nil) }.should raise_error(TypeError, "no implicit conversion of nil into String") - end - - it "raises a TypeError if passed a boolean" do - -> { "abc".send(@method, true) }.should raise_error(TypeError, "no implicit conversion of true into String") - end - - it "raises a TypeError if passed a Symbol" do - not_supported_on :opal do - -> { "abc".send(@method, :a) }.should raise_error(TypeError, "no implicit conversion of Symbol into String") - end - end - - it "raises a TypeError if passed a Symbol" do - obj = mock('x') - obj.should_not_receive(:to_int) - -> { "hello".send(@method, obj) }.should raise_error(TypeError, "no implicit conversion of MockObject into String") - end - - it "raises a TypeError if passed an Integer" do - -> { "abc".send(@method, 97) }.should raise_error(TypeError, "no implicit conversion of Integer into String") - end - end - - describe "with multibyte codepoints" do - it "raises an IndexError when byte offset lands in the middle of a multibyte character" do - -> { "わ".send(@method, "", 1) }.should raise_error(IndexError, "offset 1 does not land on character boundary") - -> { "わ".send(@method, "", 2) }.should raise_error(IndexError, "offset 2 does not land on character boundary") - -> { "わ".send(@method, "", -1) }.should raise_error(IndexError, "offset 2 does not land on character boundary") - -> { "わ".send(@method, "", -2) }.should raise_error(IndexError, "offset 1 does not land on character boundary") - end - - it "raises an Encoding::CompatibilityError if the encodings are incompatible" do - re = Regexp.new "れ".encode(Encoding::EUC_JP) - -> do - "あれ".send(@method, re) - end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)") - end - end - - describe "with global variables" do - it "doesn't set $~ for non regex search" do - $~ = nil - - 'hello.'.send(@method, 'll') - $~.should == nil - end - - it "sets $~ to MatchData of match and nil when there's none" do - 'hello.'.send(@method, /.e./) - $~[0].should == 'hel' - - 'hello.'.send(@method, /not/) - $~.should == nil - end - end -end diff --git a/spec/ruby/core/string/shared/chars.rb b/spec/ruby/core/string/shared/chars.rb index e9fdf89fd6..1f045e4530 100644 --- a/spec/ruby/core/string/shared/chars.rb +++ b/spec/ruby/core/string/shared/chars.rb @@ -63,4 +63,18 @@ 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 ee5ef2a98f..d6ffad7d4d 100644 --- a/spec/ruby/core/string/shared/concat.rb +++ b/spec/ruby/core/string/shared/concat.rb @@ -5,6 +5,18 @@ describe :string_concat, shared: true do str.should == "hello world" end + it "converts the given argument to a String using to_str" do + obj = mock('world!') + obj.should_receive(:to_str).and_return("world!") + a = 'hello '.send(@method, obj) + a.should == 'hello world!' + end + + it "raises a TypeError if the given argument can't be converted to a String" do + -> { 'hello '.send(@method, []) }.should raise_error(TypeError) + -> { 'hello '.send(@method, mock('x')) }.should raise_error(TypeError) + end + it "raises a FrozenError when self is frozen" do a = "hello" a.freeze @@ -27,6 +39,18 @@ 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) @@ -136,23 +160,3 @@ describe :string_concat_encoding, shared: true do end end end - -describe :string_concat_type_coercion, shared: true do - it "converts the given argument to a String using to_str" do - obj = mock('world!') - obj.should_receive(:to_str).and_return("world!") - a = 'hello '.send(@method, obj) - a.should == 'hello world!' - end - - it "raises a TypeError if the given argument can't be converted to a String" do - -> { 'hello '.send(@method, []) }.should raise_error(TypeError) - -> { 'hello '.send(@method, mock('x')) }.should raise_error(TypeError) - end - - it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do - obj = mock('world!') - obj.should_receive(:to_str).and_raise(NoMethodError) - -> { 'hello '.send(@method, obj) }.should raise_error(NoMethodError) - end -end diff --git a/spec/ruby/core/string/shared/dedup.rb b/spec/ruby/core/string/shared/dedup.rb deleted file mode 100644 index 893fd1e360..0000000000 --- a/spec/ruby/core/string/shared/dedup.rb +++ /dev/null @@ -1,55 +0,0 @@ -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 - - it "does not deduplicate a frozen string when it has instance variables" do - dynamic = %w(this string is frozen).join(' ') - dynamic.instance_variable_set(:@a, 1) - dynamic.freeze - - dynamic.send(@method).should_not equal("this string is frozen".freeze) - dynamic.send(@method).should_not equal("this string is frozen".send(@method).freeze) - dynamic.send(@method).should equal(dynamic) - end - - 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 diff --git a/spec/ruby/core/string/shared/each_line.rb b/spec/ruby/core/string/shared/each_line.rb index a14b4d7779..f9c910596a 100644 --- a/spec/ruby/core/string/shared/each_line.rb +++ b/spec/ruby/core/string/shared/each_line.rb @@ -40,6 +40,14 @@ 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 } @@ -85,10 +93,20 @@ describe :string_each_line, shared: true do end end - it "yields String instances for subclasses" do - a = [] - StringSpecs::MyString.new("hello\nworld").send(@method) { |s| a << s.class } - a.should == [String, String] + ruby_version_is ''...'3.0' do + it "yields subclass instances for subclasses" do + a = [] + StringSpecs::MyString.new("hello\nworld").send(@method) { |s| a << s.class } + a.should == [StringSpecs::MyString, StringSpecs::MyString] + end + end + + ruby_version_is '3.0' do + it "yields String instances for subclasses" do + a = [] + StringSpecs::MyString.new("hello\nworld").send(@method) { |s| a << s.class } + a.should == [String, String] + end end it "returns self" do @@ -112,12 +130,6 @@ describe :string_each_line, shared: true do out.should == ["hello\n", "world."] end - it "returns Strings in the same encoding as self" do - "one\ntwo\r\nthree".encode("US-ASCII").send(@method) do |s| - s.encoding.should == Encoding::US_ASCII - end - end - it "raises a TypeError when the separator can't be converted to a string" do -> { "hello world".send(@method, false) {} }.should raise_error(TypeError) -> { "hello world".send(@method, mock('x')) {} }.should raise_error(TypeError) diff --git a/spec/ruby/core/string/shared/eql.rb b/spec/ruby/core/string/shared/eql.rb index 6f268c929c..b57d6895ff 100644 --- a/spec/ruby/core/string/shared/eql.rb +++ b/spec/ruby/core/string/shared/eql.rb @@ -31,8 +31,4 @@ 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 94e5ec135b..e931961455 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.send(@method).should == 400 - utf8_str.encode(Encoding::UTF_32BE).send(@method).should == 400 - utf8_str.encode(Encoding::SHIFT_JIS).send(@method).should == 400 + utf8_str.size.should == 400 + utf8_str.encode(Encoding::UTF_32BE).size.should == 400 + utf8_str.encode(Encoding::SHIFT_JIS).size.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.send(@method).should == 2 + concat.size.should == 2 concat.force_encoding(Encoding::ASCII_8BIT) - concat.send(@method).should == 4 + concat.size.should == 4 end it "adds 1 for every invalid byte in UTF-8" do - "\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 + "\xF4\x90\x80\x80".size.should == 4 + "a\xF4\x90\x80\x80b".size.should == 6 + "é\xF4\x90\x80\x80è".size.should == 6 end it "adds 1 (and not 2) for a incomplete surrogate in UTF-16" do - "\x00\xd8".force_encoding("UTF-16LE").send(@method).should == 1 - "\xd8\x00".force_encoding("UTF-16BE").send(@method).should == 1 + "\x00\xd8".force_encoding("UTF-16LE").size.should == 1 + "\xd8\x00".force_encoding("UTF-16BE").size.should == 1 end it "adds 1 for a broken sequence in UTF-32" do - "\x04\x03\x02\x01".force_encoding("UTF-32LE").send(@method).should == 1 - "\x01\x02\x03\x04".force_encoding("UTF-32BE").send(@method).should == 1 + "\x04\x03\x02\x01".force_encoding("UTF-32LE").size.should == 1 + "\x01\x02\x03\x04".force_encoding("UTF-32BE").size.should == 1 end end diff --git a/spec/ruby/core/string/shared/partition.rb b/spec/ruby/core/string/shared/partition.rb index 4cac149ce5..7dc3d9cc0b 100644 --- a/spec/ruby/core/string/shared/partition.rb +++ b/spec/ruby/core/string/shared/partition.rb @@ -2,32 +2,35 @@ require_relative '../../../spec_helper' require_relative '../fixtures/classes' describe :string_partition, shared: true do - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new("hello").send(@method, "l").each do |item| - item.should be_an_instance_of(String) - end + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("hello").send(@method, "l").each do |item| + item.should be_an_instance_of(String) + end - StringSpecs::MyString.new("hello").send(@method, "x").each do |item| - item.should be_an_instance_of(String) - end + StringSpecs::MyString.new("hello").send(@method, "x").each do |item| + item.should be_an_instance_of(String) + end - StringSpecs::MyString.new("hello").send(@method, /l./).each do |item| - item.should be_an_instance_of(String) + StringSpecs::MyString.new("hello").send(@method, /l./).each do |item| + item.should be_an_instance_of(String) + end end end - it "returns before- and after- parts in the same encoding as self" do - strings = "hello".encode("US-ASCII").send(@method, "ello") - strings[0].encoding.should == Encoding::US_ASCII - strings[2].encoding.should == Encoding::US_ASCII + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("hello").send(@method, StringSpecs::MyString.new("l")).each do |item| + item.should be_an_instance_of(StringSpecs::MyString) + end - strings = "hello".encode("US-ASCII").send(@method, /ello/) - strings[0].encoding.should == Encoding::US_ASCII - strings[2].encoding.should == Encoding::US_ASCII - end + StringSpecs::MyString.new("hello").send(@method, "x").each do |item| + item.should be_an_instance_of(StringSpecs::MyString) + end - it "returns the matching part in the separator's encoding" do - strings = "hello".encode("US-ASCII").send(@method, "ello") - strings[1].encoding.should == Encoding::UTF_8 + StringSpecs::MyString.new("hello").send(@method, /l./).each do |item| + item.should be_an_instance_of(StringSpecs::MyString) + end + end end end diff --git a/spec/ruby/core/string/shared/replace.rb b/spec/ruby/core/string/shared/replace.rb index a5108d9e7c..8dfac49f02 100644 --- a/spec/ruby/core/string/shared/replace.rb +++ b/spec/ruby/core/string/shared/replace.rb @@ -10,6 +10,36 @@ 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 3ef4bc50d7..1db8fd6730 100644 --- a/spec/ruby/core/string/shared/slice.rb +++ b/spec/ruby/core/string/shared/slice.rb @@ -80,7 +80,18 @@ describe :string_slice_index_length, shared: true do "hello there".send(@method, -3,2).should == "er" end - it "returns a string with the same encoding as self" do + 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 @@ -152,11 +163,22 @@ describe :string_slice_index_length, shared: true do -> { "hello".send(@method, 0, bignum_value) }.should raise_error(RangeError) end - it "returns String instances" do - s = StringSpecs::MyString.new("hello") - s.send(@method, 0,0).should be_an_instance_of(String) - s.send(@method, 0,4).should be_an_instance_of(String) - s.send(@method, 1,4).should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, 0,0).should be_an_instance_of(StringSpecs::MyString) + s.send(@method, 0,4).should be_an_instance_of(StringSpecs::MyString) + s.send(@method, 1,4).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, 0,0).should be_an_instance_of(String) + s.send(@method, 0,4).should be_an_instance_of(String) + s.send(@method, 1,4).should be_an_instance_of(String) + end end it "handles repeated application" do @@ -195,10 +217,6 @@ describe :string_slice_range, shared: true do "x".send(@method, 1..-1).should == "" end - it "returns a String in the same encoding as self" do - "hello there".encode("US-ASCII").send(@method, 1..1).encoding.should == Encoding::US_ASCII - end - it "returns nil if the beginning of the range falls outside of self" do "hello there".send(@method, 12..-1).should == nil "hello there".send(@method, 20..25).should == nil @@ -231,11 +249,36 @@ describe :string_slice_range, shared: true do "x".send(@method, 1...-1).should == "" end - it "returns String instances" do - s = StringSpecs::MyString.new("hello") - s.send(@method, 0...0).should be_an_instance_of(String) - s.send(@method, 0..4).should be_an_instance_of(String) - s.send(@method, 1..4).should be_an_instance_of(String) + 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") + s.send(@method, 0...0).should be_an_instance_of(StringSpecs::MyString) + s.send(@method, 0..4).should be_an_instance_of(StringSpecs::MyString) + s.send(@method, 1..4).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, 0...0).should be_an_instance_of(String) + s.send(@method, 0..4).should be_an_instance_of(String) + s.send(@method, 1..4).should be_an_instance_of(String) + end end it "calls to_int on range arguments" do @@ -291,12 +334,14 @@ describe :string_slice_range, shared: true do "hello there".send(@method, eval("(-4...)")).should == "here" 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" + 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 end end @@ -310,14 +355,43 @@ describe :string_slice_regexp, shared: true do "hello there".send(@method, /xyz/).should == nil end - it "returns a String in the same encoding as self" do - "hello there".encode("US-ASCII").send(@method, /[aeiou](.)\1/).encoding.should == Encoding::US_ASCII + 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 + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, //).should be_an_instance_of(StringSpecs::MyString) + s.send(@method, /../).should be_an_instance_of(StringSpecs::MyString) + end end - it "returns String instances" do - s = StringSpecs::MyString.new("hello") - s.send(@method, //).should be_an_instance_of(String) - s.send(@method, /../).should be_an_instance_of(String) + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, //).should be_an_instance_of(String) + s.send(@method, /../).should be_an_instance_of(String) + end end it "sets $~ to MatchData when there is a match and nil when there's none" do @@ -344,28 +418,44 @@ describe :string_slice_regexp_index, shared: true do "har".send(@method, /(.)(.)(.)/, -3).should == "h" end - it "returns nil if there is no match" do - "hello there".send(@method, /(what?)/, 1).should == nil - 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 } - it "returns nil if the index is larger than the number of captures" do - "hello there".send(@method, /hello (.)/, 2).should == nil - # You can't refer to 0 using negative indices - "hello there".send(@method, /hello (.)/, -2).should == nil - end + strs.each do |str| + str.send(@method, //, 0).tainted?.should == str.tainted? + str.send(@method, /hello/, 0).tainted?.should == str.tainted? - it "returns nil if there is no capture for the given index" do - "hello there".send(@method, /[aeiou](.)\1/, 2).should == nil + 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 the given capture group was not matched but still sets $~" do - "test".send(@method, /te(z)?/, 1).should == nil - $~[0].should == "te" - $~[1].should == nil + it "returns nil if there is no match" do + "hello there".send(@method, /(what?)/, 1).should == nil end - it "returns a String in the same encoding as self" do - "hello there".encode("US-ASCII").send(@method, /[aeiou](.)\1/, 0).encoding.should == Encoding::US_ASCII + it "returns nil if there is no capture for the given index" do + "hello there".send(@method, /[aeiou](.)\1/, 2).should == nil + # You can't refer to 0 using negative indices + "hello there".send(@method, /[aeiou](.)\1/, -2).should == nil end it "calls to_int on the given index" do @@ -386,10 +476,20 @@ describe :string_slice_regexp_index, shared: true do -> { "hello".send(@method, /(.)(.)(.)/, nil) }.should raise_error(TypeError) end - it "returns String instances" do - s = StringSpecs::MyString.new("hello") - s.send(@method, /(.)(.)/, 0).should be_an_instance_of(String) - s.send(@method, /(.)(.)/, 1).should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, /(.)(.)/, 0).should be_an_instance_of(StringSpecs::MyString) + s.send(@method, /(.)(.)/, 1).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, /(.)(.)/, 0).should be_an_instance_of(String) + s.send(@method, /(.)(.)/, 1).should be_an_instance_of(String) + end end it "sets $~ to MatchData when there is a match and nil when there's none" do @@ -410,6 +510,21 @@ 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 @@ -428,11 +543,22 @@ describe :string_slice_string, shared: true do -> { "hello".send(@method, o) }.should raise_error(TypeError) end - it "returns a String instance when given a subclass instance" do - s = StringSpecs::MyString.new("el") - r = "hello".send(@method, s) - r.should == "el" - r.should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns a subclass instance when given a subclass instance" do + s = StringSpecs::MyString.new("el") + r = "hello".send(@method, s) + r.should == "el" + r.should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns a String instance when given a subclass instance" do + s = StringSpecs::MyString.new("el") + r = "hello".send(@method, s) + r.should == "el" + r.should be_an_instance_of(String) + end end end @@ -458,6 +584,30 @@ 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 @@ -478,9 +628,18 @@ describe :string_slice_regexp_group, shared: true do -> { "hello".send(@method, /(?<q>)/, '') }.should raise_error(IndexError) end - it "returns String instances" do - s = StringSpecs::MyString.new("hello") - s.send(@method, /(?<q>.)/, 'q').should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, /(?<q>.)/, 'q').should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.send(@method, /(?<q>.)/, 'q').should be_an_instance_of(String) + end end it "sets $~ to MatchData when there is a match and nil when there's none" do diff --git a/spec/ruby/core/string/shared/strip.rb b/spec/ruby/core/string/shared/strip.rb index 3af77b50fe..9c232b4694 100644 --- a/spec/ruby/core/string/shared/strip.rb +++ b/spec/ruby/core/string/shared/strip.rb @@ -2,13 +2,19 @@ require_relative '../../../spec_helper' require_relative '../fixtures/classes' describe :string_strip, shared: true do - it "returns a String in the same encoding as self" do - " hello ".encode("US-ASCII").send(@method).encoding.should == Encoding::US_ASCII + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new(" hello ").send(@method).should be_an_instance_of(String) + StringSpecs::MyString.new(" ").send(@method).should be_an_instance_of(String) + StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String) + end end - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new(" hello ").send(@method).should be_an_instance_of(String) - StringSpecs::MyString.new(" ").send(@method).should be_an_instance_of(String) - StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new(" hello ").send(@method).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new(" ").send(@method).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("").send(@method).should be_an_instance_of(StringSpecs::MyString) + end end end diff --git a/spec/ruby/core/string/shared/succ.rb b/spec/ruby/core/string/shared/succ.rb index 24a729ce26..25602103b6 100644 --- a/spec/ruby/core/string/shared/succ.rb +++ b/spec/ruby/core/string/shared/succ.rb @@ -59,14 +59,28 @@ describe :string_succ, shared: true do "\xFF\xFF".send(@method).should == "\x01\x00\x00" end - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String) - StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(String) - StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("").send(@method).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(StringSpecs::MyString) + end end - it "returns a String in the same encoding as self" do - "z".encode("US-ASCII").send(@method).encoding.should == Encoding::US_ASCII + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String) + StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(String) + 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 diff --git a/spec/ruby/core/string/shared/to_a.rb b/spec/ruby/core/string/shared/to_a.rb new file mode 100644 index 0000000000..bad3ea6584 --- /dev/null +++ b/spec/ruby/core/string/shared/to_a.rb @@ -0,0 +1,9 @@ +describe :string_to_a, shared: true do + it "returns an empty array for empty strings" do + "".send(@method).should == [] + end + + it "returns an array containing the string for non-empty strings" do + "hello".send(@method).should == ["hello"] + end +end diff --git a/spec/ruby/core/string/shared/to_s.rb b/spec/ruby/core/string/shared/to_s.rb index 4b87a6cbe1..b8c9b8ab44 100644 --- a/spec/ruby/core/string/shared/to_s.rb +++ b/spec/ruby/core/string/shared/to_s.rb @@ -10,4 +10,11 @@ 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 52d8314211..416f302aef 100644 --- a/spec/ruby/core/string/shared/to_sym.rb +++ b/spec/ruby/core/string/shared/to_sym.rb @@ -53,20 +53,11 @@ 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? -> { invalid_utf8.send(@method) - }.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"') + }.should raise_error(EncodingError, /invalid/) end end diff --git a/spec/ruby/core/string/slice_spec.rb b/spec/ruby/core/string/slice_spec.rb index 87c5a7ac37..83b475c8b5 100644 --- a/spec/ruby/core/string/slice_spec.rb +++ b/spec/ruby/core/string/slice_spec.rb @@ -94,6 +94,16 @@ 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 @@ -132,10 +142,20 @@ describe "String#slice! with index, length" do "hello".slice!(obj, obj).should == "ll" end - it "returns String instances" do - s = StringSpecs::MyString.new("hello") - s.slice!(0, 0).should be_an_instance_of(String) - s.slice!(0, 4).should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(0, 0).should be_an_instance_of(StringSpecs::MyString) + s.slice!(0, 4).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(0, 0).should be_an_instance_of(String) + s.slice!(0, 4).should be_an_instance_of(String) + end end it "returns the substring given by the character offsets" do @@ -175,10 +195,30 @@ describe "String#slice! Range" do b.should == "hello" end - it "returns String instances" do - s = StringSpecs::MyString.new("hello") - s.slice!(0...0).should be_an_instance_of(String) - s.slice!(0..4).should be_an_instance_of(String) + 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") + s.slice!(0...0).should be_an_instance_of(StringSpecs::MyString) + s.slice!(0..4).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(0...0).should be_an_instance_of(String) + s.slice!(0..4).should be_an_instance_of(String) + end end it "calls to_int on range arguments" do @@ -254,10 +294,44 @@ describe "String#slice! with Regexp" do s.should == "this is a string" end - it "returns String instances" do - s = StringSpecs::MyString.new("hello") - s.slice!(//).should be_an_instance_of(String) - s.slice!(/../).should be_an_instance_of(String) + 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") + s.slice!(//).should be_an_instance_of(StringSpecs::MyString) + s.slice!(/../).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(//).should be_an_instance_of(String) + s.slice!(/../).should be_an_instance_of(String) + end end it "returns the matching portion of self with a multi byte character" do @@ -291,6 +365,30 @@ 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 @@ -314,10 +412,20 @@ describe "String#slice! with Regexp, index" do "har".slice!(/(.)(.)(.)/, obj).should == "a" end - it "returns String instances" do - s = StringSpecs::MyString.new("hello") - s.slice!(/(.)(.)/, 0).should be_an_instance_of(String) - s.slice!(/(.)(.)/, 1).should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(/(.)(.)/, 0).should be_an_instance_of(StringSpecs::MyString) + s.slice!(/(.)(.)/, 1).should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + s = StringSpecs::MyString.new("hello") + s.slice!(/(.)(.)/, 0).should be_an_instance_of(String) + s.slice!(/(.)(.)/, 1).should be_an_instance_of(String) + end end it "returns the encoding aware capture for the given index" do @@ -355,6 +463,23 @@ 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 @@ -375,11 +500,22 @@ describe "String#slice! with String" do -> { "hello".slice!(o) }.should raise_error(TypeError) end - it "returns a subclass instance when given a subclass instance" do - s = StringSpecs::MyString.new("el") - r = "hello".slice!(s) - r.should == "el" - r.should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns a subclass instance when given a subclass instance" do + s = StringSpecs::MyString.new("el") + r = "hello".slice!(s) + r.should == "el" + r.should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns a subclass instance when given a subclass instance" do + s = StringSpecs::MyString.new("el") + r = "hello".slice!(s) + r.should == "el" + r.should be_an_instance_of(String) + end end it "raises a FrozenError if self is frozen" do diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb index c5cca651c2..a373be360d 100644 --- a/spec/ruby/core/string/split_spec.rb +++ b/spec/ruby/core/string/split_spec.rb @@ -3,17 +3,12 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' describe "String#split with String" do - it "throws an ArgumentError if the string is not a valid" do - s = "\xDF".force_encoding(Encoding::UTF_8) - - -> { s.split }.should raise_error(ArgumentError) - -> { s.split(':') }.should raise_error(ArgumentError) - end - it "throws an ArgumentError if the pattern is not a valid string" do str = 'проверка' - broken_str = "\xDF".force_encoding(Encoding::UTF_8) - + broken_str = 'проверка' + broken_str.force_encoding('binary') + broken_str.chop! + broken_str.force_encoding('utf-8') -> { str.split(broken_str) }.should raise_error(ArgumentError) end @@ -29,35 +24,9 @@ describe "String#split with String" do "1,2,,3,4,,".split(',').should == ["1", "2", "", "3", "4"] "1,2,,3,4,,".split(',', 0).should == ["1", "2", "", "3", "4"] " a b c\nd ".split(" ").should == ["", "a", "b", "c\nd"] - " a あ c\nd ".split(" ").should == ["", "a", "あ", "c\nd"] "hai".split("hai").should == [] ",".split(",").should == [] ",".split(",", 0).should == [] - "あ".split("あ").should == [] - "あ".split("あ", 0).should == [] - end - - it "does not suppress trailing empty fields when a positive limit is given" do - " 1 2 ".split(" ", 2).should == ["1", "2 "] - " 1 2 ".split(" ", 3).should == ["1", "2", ""] - " 1 2 ".split(" ", 4).should == ["1", "2", ""] - " 1 あ ".split(" ", 2).should == ["1", "あ "] - " 1 あ ".split(" ", 3).should == ["1", "あ", ""] - " 1 あ ".split(" ", 4).should == ["1", "あ", ""] - - "1,2,".split(',', 2).should == ["1", "2,"] - "1,2,".split(',', 3).should == ["1", "2", ""] - "1,2,".split(',', 4).should == ["1", "2", ""] - "1,あ,".split(',', 2).should == ["1", "あ,"] - "1,あ,".split(',', 3).should == ["1", "あ", ""] - "1,あ,".split(',', 4).should == ["1", "あ", ""] - - "1 2 ".split(/ /, 2).should == ["1", "2 "] - "1 2 ".split(/ /, 3).should == ["1", "2", ""] - "1 2 ".split(/ /, 4).should == ["1", "2", ""] - "1 あ ".split(/ /, 2).should == ["1", "あ "] - "1 あ ".split(/ /, 3).should == ["1", "あ", ""] - "1 あ ".split(/ /, 4).should == ["1", "あ", ""] end it "returns an array with one entry if limit is 1: the original string" do @@ -93,10 +62,6 @@ 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 = $; @@ -120,19 +85,21 @@ describe "String#split with String" do end end - context "when $; is not nil" do - before do - suppress_warning do - @old_value, $; = $;, 'foobar' + ruby_version_is "2.7" do + context "when $; is not nil" do + before do + suppress_warning do + @old_value, $; = $;, 'foobar' + end 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/) + it "warns" do + -> { "".split }.should complain(/warning: \$; is set to non-nil value/) + end end end end @@ -192,48 +159,70 @@ describe "String#split with String" do "foo".split("bar", 3).should == ["foo"] end - it "returns String instances based on self" do - ["", "x.y.z.", " x y "].each do |str| - ["", ".", " "].each do |pat| - [-1, 0, 1, 2].each do |limit| - StringSpecs::MyString.new(str).split(pat, limit).each do |x| - x.should be_an_instance_of(String) - end + ruby_version_is ''...'3.0' do + it "returns subclass instances based on self" do + ["", "x.y.z.", " x y "].each do |str| + ["", ".", " "].each do |pat| + [-1, 0, 1, 2].each do |limit| + StringSpecs::MyString.new(str).split(pat, limit).each do |x| + x.should be_an_instance_of(StringSpecs::MyString) + end - str.split(StringSpecs::MyString.new(pat), limit).each do |x| - x.should be_an_instance_of(String) + str.split(StringSpecs::MyString.new(pat), limit).each do |x| + x.should be_an_instance_of(String) + end end end end end - end - it "returns an empty array when whitespace is split on whitespace" do - " ".split(" ").should == [] - " \n ".split(" ").should == [] - " ".split(" ").should == [] - " \t ".split(" ").should == [] - end + it "does not call constructor on created subclass instances" do + # can't call should_not_receive on an object that doesn't yet exist + # so failure here is signalled by exception, not expectation failure - it "doesn't split on non-ascii whitespace" do - "a\u{2008}b".split(" ").should == ["a\u{2008}b"] + s = StringSpecs::StringWithRaisingConstructor.new('silly:string') + s.split(':').first.should == 'silly' + end end - it "returns Strings in the same encoding as self" do - strings = "hello world".encode("US-ASCII").split(" ") + ruby_version_is '3.0' do + it "returns String instances based on self" do + ["", "x.y.z.", " x y "].each do |str| + ["", ".", " "].each do |pat| + [-1, 0, 1, 2].each do |limit| + StringSpecs::MyString.new(str).split(pat, limit).each do |x| + x.should be_an_instance_of(String) + end - strings[0].encoding.should == Encoding::US_ASCII - strings[1].encoding.should == Encoding::US_ASCII + str.split(StringSpecs::MyString.new(pat), limit).each do |x| + x.should be_an_instance_of(String) + end + end + end + end + end end -end -describe "String#split with Regexp" do - it "throws an ArgumentError if the string is not a valid" do - s = "\xDF".force_encoding(Encoding::UTF_8) + 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 - -> { s.split(/./) }.should raise_error(ArgumentError) + str.split(pat.dup.taint).each do |x| + x.should_not.tainted? + end + end + end + end + end end +end +describe "String#split with Regexp" do it "divides self on regexp matches" do " now's the time".split(/ /).should == ["", "now's", "", "the", "time"] " x\ny ".split(/ /).should == ["", "x\ny"] @@ -386,24 +375,80 @@ describe "String#split with Regexp" do "foo".split(/bar/, 3).should == ["foo"] end - it "returns String instances based on self" do - ["", "x:y:z:", " x y "].each do |str| - [//, /:/, /\s+/].each do |pat| - [-1, 0, 1, 2].each do |limit| - StringSpecs::MyString.new(str).split(pat, limit).each do |x| - x.should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances based on self" do + ["", "x:y:z:", " x y "].each do |str| + [//, /:/, /\s+/].each do |pat| + [-1, 0, 1, 2].each do |limit| + StringSpecs::MyString.new(str).split(pat, limit).each do |x| + x.should be_an_instance_of(StringSpecs::MyString) + end end end end end + + it "does not call constructor on created subclass instances" do + # can't call should_not_receive on an object that doesn't yet exist + # so failure here is signalled by exception, not expectation failure + + s = StringSpecs::StringWithRaisingConstructor.new('silly:string') + s.split(/:/).first.should == 'silly' + end end - it "returns Strings in the same encoding as self" do + ruby_version_is '3.0' do + it "returns String instances based on self" do + ["", "x:y:z:", " x y "].each do |str| + [//, /:/, /\s+/].each do |pat| + [-1, 0, 1, 2].each do |limit| + StringSpecs::MyString.new(str).split(pat, limit).each do |x| + x.should be_an_instance_of(String) + end + end + end + end + 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 } encodings.should == [Encoding::UTF_8, Encoding::UTF_8, Encoding::UTF_8] end + it "splits a string on each character for a multibyte encoding and empty split" do "That's why efficiency could not be helped".split("").size.should == 39 end @@ -435,14 +480,6 @@ describe "String#split with Regexp" do a.should == ["Chunky", "Bacon"] end - it "yields each split substring with default pattern for a lazy substring" do - a = [] - returned_object = "chunky bacon"[1...-1].split { |str| a << str.capitalize } - - returned_object.should == "hunky baco" - a.should == ["Hunky", "Baco"] - end - it "yields each split substring with default pattern for a non-ASCII string" do a = [] returned_object = "l'été arrive bientôt".split { |str| a << str } @@ -451,14 +488,6 @@ describe "String#split with Regexp" do a.should == ["l'été", "arrive", "bientôt"] end - it "yields each split substring with default pattern for a non-ASCII lazy substring" do - a = [] - returned_object = "l'été arrive bientôt"[1...-1].split { |str| a << str } - - returned_object.should == "'été arrive bientô" - a.should == ["'été", "arrive", "bientô"] - end - it "yields the string when limit is 1" do a = [] returned_object = "chunky bacon".split("", 1) { |str| a << str.capitalize } @@ -517,30 +546,32 @@ describe "String#split with Regexp" do end describe "for a String subclass" do - it "yields instances of String" do - a = [] - StringSpecs::MyString.new("a|b").split("|") { |str| a << str } - first, last = a + ruby_version_is ''...'3.0' do + it "yields instances of the same subclass" do + a = [] + StringSpecs::MyString.new("a|b").split("|") { |str| a << str } + first, last = a - first.should be_an_instance_of(String) - first.should == "a" + first.should be_an_instance_of(StringSpecs::MyString) + first.should == "a" - last.should be_an_instance_of(String) - last.should == "b" + last.should be_an_instance_of(StringSpecs::MyString) + last.should == "b" + 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 + ruby_version_is '3.0' do + it "yields instances of String" do + a = [] + StringSpecs::MyString.new("a|b").split("|") { |str| a << str } + first, last = a - it "returns Strings in the same encoding as self" do - strings = "hello world".encode("US-ASCII").split(/ /) + first.should be_an_instance_of(String) + first.should == "a" - strings[0].encoding.should == Encoding::US_ASCII - strings[1].encoding.should == Encoding::US_ASCII + last.should be_an_instance_of(String) + last.should == "b" + end + end end end diff --git a/spec/ruby/core/string/squeeze_spec.rb b/spec/ruby/core/string/squeeze_spec.rb index 4796a170f2..6f75402c9c 100644 --- a/spec/ruby/core/string/squeeze_spec.rb +++ b/spec/ruby/core/string/squeeze_spec.rb @@ -54,6 +54,16 @@ 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") @@ -64,19 +74,22 @@ describe "String#squeeze" do "hello room".squeeze(other_string, other_string2).should == "hello rom" end - it "returns a String in the same encoding as self" do - "yellow moon".encode("US-ASCII").squeeze.encoding.should == Encoding::US_ASCII - "yellow moon".encode("US-ASCII").squeeze("a").encoding.should == Encoding::US_ASCII - end - it "raises a TypeError when one set arg can't be converted to a string" do -> { "hello world".squeeze([]) }.should raise_error(TypeError) -> { "hello world".squeeze(Object.new)}.should raise_error(TypeError) -> { "hello world".squeeze(mock('x')) }.should raise_error(TypeError) end - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/start_with_spec.rb b/spec/ruby/core/string/start_with_spec.rb index 35e33b46a6..aaed197ff3 100644 --- a/spec/ruby/core/string/start_with_spec.rb +++ b/spec/ruby/core/string/start_with_spec.rb @@ -5,23 +5,4 @@ require_relative '../../shared/string/start_with' describe "String#start_with?" do it_behaves_like :start_with, :to_s - - # Here and not in the shared examples because this is invalid as a Symbol - it "matches part of a character with the same part" do - "\xA9".should.start_with?("\xA9") # A9 is not a character head for UTF-8 - end - - ruby_version_is ""..."3.3" do - it "does not check we are matching only part of a character" do - "\xe3\x81\x82".size.should == 1 - "\xe3\x81\x82".should.start_with?("\xe3") - end - end - - ruby_version_is "3.3" do # #19784 - it "checks we are matching only part of a character" do - "\xe3\x81\x82".size.should == 1 - "\xe3\x81\x82".should_not.start_with?("\xe3") - end - end end diff --git a/spec/ruby/core/string/strip_spec.rb b/spec/ruby/core/string/strip_spec.rb index 5e90fe35d0..8517bf2d2a 100644 --- a/spec/ruby/core/string/strip_spec.rb +++ b/spec/ruby/core/string/strip_spec.rb @@ -11,8 +11,18 @@ describe "String#strip" do "\tgoodbye\r\v\n".strip.should == "goodbye" end - it "returns a copy of self without leading and trailing NULL bytes and whitespace" do - " \x00 goodbye \x00 ".strip.should == "goodbye" + ruby_version_is '3.1' 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 @@ -33,16 +43,12 @@ describe "String#strip!" do a.should == "hello" end - it "makes a string empty if it is only whitespace" do - "".strip!.should == nil - " ".strip.should == "" - " ".strip.should == "" - end - - it "removes leading and trailing NULL bytes and whitespace" do - a = "\000 goodbye \000" - a.strip! - a.should == "goodbye" + ruby_version_is '3.1' do + it "removes leading and trailing NULL bytes and whitespace" do + a = "\000 goodbye \000" + a.strip! + a.should == "goodbye" + end end it "raises a FrozenError on a frozen instance that is modified" do diff --git a/spec/ruby/core/string/sub_spec.rb b/spec/ruby/core/string/sub_spec.rb index 51920486f5..5ae9a4bbf3 100644 --- a/spec/ruby/core/string/sub_spec.rb +++ b/spec/ruby/core/string/sub_spec.rb @@ -137,6 +137,28 @@ 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(".") @@ -170,11 +192,22 @@ describe "String#sub with pattern, replacement" do -> { "hello".sub(/[aeiou]/, 99) }.should raise_error(TypeError) end - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(String) - StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(String) - StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(String) - StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(String) + StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(String) + StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(String) + StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(String) + end end it "sets $~ to MatchData of match and nil when there's none" do @@ -203,17 +236,6 @@ describe "String#sub with pattern, replacement" do "ababa".sub(/(b)/, '\\\\\1').should == "a\\baba" end - it "handles a pattern in a superset encoding" do - result = 'abc'.force_encoding(Encoding::US_ASCII).sub('é', 'è') - result.should == 'abc' - result.encoding.should == Encoding::US_ASCII - end - - it "handles a pattern in a subset encoding" do - result = 'été'.sub('t'.force_encoding(Encoding::US_ASCII), 'u') - result.should == 'éué' - result.encoding.should == Encoding::UTF_8 - end end describe "String#sub with pattern and block" do @@ -275,6 +297,28 @@ 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 @@ -284,6 +328,14 @@ 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 @@ -299,27 +351,6 @@ describe "String#sub! with pattern, replacement" do -> { s.sub!(/e/, "e") }.should raise_error(FrozenError) -> { s.sub!(/[aeiou]/, '*') }.should raise_error(FrozenError) end - - it "handles a pattern in a superset encoding" do - string = 'abc'.force_encoding(Encoding::US_ASCII) - - result = string.sub!('é', 'è') - - result.should == nil - string.should == 'abc' - string.encoding.should == Encoding::US_ASCII - end - - it "handles a pattern in a subset encoding" do - string = 'été' - pattern = 't'.force_encoding(Encoding::US_ASCII) - - result = string.sub!(pattern, 'u') - - result.should == string - string.should == 'éué' - string.encoding.should == Encoding::UTF_8 - end end describe "String#sub! with pattern and block" do @@ -347,6 +378,14 @@ 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 @@ -432,6 +471,28 @@ 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 @@ -496,6 +557,28 @@ 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 d740fb86c6..32b358607e 100644 --- a/spec/ruby/core/string/swapcase_spec.rb +++ b/spec/ruby/core/string/swapcase_spec.rb @@ -9,8 +9,11 @@ describe "String#swapcase" do "+++---111222???".swapcase.should == "+++---111222???" end - it "returns a String in the same encoding as self" do - "Hello".encode("US-ASCII").swapcase.encoding.should == Encoding::US_ASCII + 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 @@ -32,10 +35,6 @@ describe "String#swapcase" do it "does not swapcase non-ASCII characters" do "aßet".swapcase(:ascii).should == "AßET" end - - it "works with substrings" do - "prefix aTé"[-3..-1].swapcase(:ascii).should == "Até" - end end describe "full Unicode case mapping adapted for Turkic languages" do @@ -74,9 +73,18 @@ describe "String#swapcase" do -> { "abc".swapcase(:invalid_option) }.should raise_error(ArgumentError) end - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new("").swapcase.should be_an_instance_of(String) - StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("").swapcase.should be_an_instance_of(StringSpecs::MyString) + StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("").swapcase.should be_an_instance_of(String) + StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/to_c_spec.rb b/spec/ruby/core/string/to_c_spec.rb index 9d24f1f56c..9c84b14f4d 100644 --- a/spec/ruby/core/string/to_c_spec.rb +++ b/spec/ruby/core/string/to_c_spec.rb @@ -1,53 +1,99 @@ require_relative '../../spec_helper' -require_relative '../../shared/kernel/complex' -require_relative 'fixtures/to_c' describe "String#to_c" do - it_behaves_like :kernel_complex, :to_c_method, StringSpecs -end + it "returns a Complex object" do + '9'.to_c.should be_an_instance_of(Complex) + end -describe "String#to_c" do - it "returns a complex number with 0 as the real part, 0 as the imaginary part for unrecognised Strings" do - 'ruby'.to_c.should == Complex(0, 0) + it "understands integers" do + '20'.to_c.should == Complex(20) + end + + it "understands negative integers" do + '-3'.to_c.should == Complex(-3) + end + + it "understands fractions (numerator/denominator) for the real part" do + '2/3'.to_c.should == Complex(Rational(2, 3)) + end + + it "understands fractions (numerator/denominator) for the imaginary part" do + '4+2/3i'.to_c.should == Complex(4, Rational(2, 3)) + end + + it "understands negative fractions (-numerator/denominator) for the real part" do + '-2/3'.to_c.should == Complex(Rational(-2, 3)) + end + + it "understands negative fractions (-numerator/denominator) for the imaginary part" do + '7-2/3i'.to_c.should == Complex(7, Rational(-2, 3)) + end + + it "understands floats (a.b) for the real part" do + '2.3'.to_c.should == Complex(2.3) + end + + it "understands floats (a.b) for the imaginary part" do + '4+2.3i'.to_c.should == Complex(4, 2.3) end - it "ignores trailing garbage" do - '79+4iruby'.to_c.should == Complex(79, 4) - ruby_bug "[Bug #19087]", ""..."3.2" do - '7__9+4__0i'.to_c.should == Complex(7, 0) - end + it "understands negative floats (-a.b) for the real part" do + '-2.33'.to_c.should == Complex(-2.33) end - it "understands Float::INFINITY" do - 'Infinity'.to_c.should == Complex(0, 1) - '-Infinity'.to_c.should == Complex(0, -1) + it "understands negative floats (-a.b) for the imaginary part" do + '7-28.771i'.to_c.should == Complex(7, -28.771) end - it "understands Float::NAN" do - 'NaN'.to_c.should == Complex(0, 0) + it "understands an integer followed by 'i' to mean that integer is the imaginary part" do + '35i'.to_c.should == Complex(0,35) end - it "allows null-byte" do - "1-2i\0".to_c.should == Complex(1, -2) - "1\0-2i".to_c.should == Complex(1, 0) - "\01-2i".to_c.should == Complex(0, 0) + it "understands a negative integer followed by 'i' to mean that negative integer is the imaginary part" do + '-29i'.to_c.should == Complex(0,-29) end - it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do - -> { - '79+4i'.encode("UTF-16").to_c - }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16") + it "understands an 'i' by itself as denoting a complex number with an imaginary part of 1" do + 'i'.to_c.should == Complex(0,1) end - ruby_version_is "3.2" do - it "treats a sequence of underscores as an end of Complex string" do - "5+3_1i".to_c.should == Complex(5, 31) - "5+3__1i".to_c.should == Complex(5) - "5+3___1i".to_c.should == Complex(5) + it "understands a '-i' by itself as denoting a complex number with an imaginary part of -1" do + '-i'.to_c.should == Complex(0,-1) + end + + it "understands 'a+bi' to mean a complex number with 'a' as the real part, 'b' as the imaginary" do + '79+4i'.to_c.should == Complex(79,4) + end + + it "understands 'a-bi' to mean a complex number with 'a' as the real part, '-b' as the imaginary" do + '79-4i'.to_c.should == Complex(79,-4) + end + + it "understands scientific notation for the real part" do + '2e3+4i'.to_c.should == Complex(2e3,4) + end + + it "understands negative scientific notation for the real part" do + '-2e3+4i'.to_c.should == Complex(-2e3,4) + end - "12_3".to_c.should == Complex(123) - "12__3".to_c.should == Complex(12) - "12___3".to_c.should == Complex(12) - end + it "understands scientific notation for the imaginary part" do + '4+2e3i'.to_c.should == Complex(4, 2e3) + end + + it "understands negative scientific notation for the imaginary part" do + '4-2e3i'.to_c.should == Complex(4, -2e3) + end + + it "understands scientific notation for the real and imaginary part in the same String" do + '2e3+2e4i'.to_c.should == Complex(2e3,2e4) + end + + it "understands negative scientific notation for the real and imaginary part in the same String" do + '-2e3-2e4i'.to_c.should == Complex(-2e3,-2e4) + end + + it "returns a complex number with 0 as the real part, 0 as the imaginary part for unrecognised Strings" do + 'ruby'.to_c.should == Complex(0,0) end end diff --git a/spec/ruby/core/string/tr_s_spec.rb b/spec/ruby/core/string/tr_s_spec.rb index 3c31473044..c6ad12139e 100644 --- a/spec/ruby/core/string/tr_s_spec.rb +++ b/spec/ruby/core/string/tr_s_spec.rb @@ -17,15 +17,6 @@ describe "String#tr_s" do "hello ^--^".tr_s("---", "_").should == "hello ^_^" end - ruby_bug "#19769", ""..."3.3" do - it "accepts c1-c1 notation to denote range of one character" do - "hello".tr_s('e-e', 'x').should == "hxllo" - "123456789".tr_s("2-23","xy").should == "1xy456789" - "hello ^-^".tr_s("e-", "a-a_").should == "hallo ^_^" - "hello ^-^".tr_s("---o", "_a").should == "hella ^_^" - end - end - it "pads to_str with its last char if it is shorter than from_string" do "this".tr_s("this", "x").should == "x" end @@ -54,8 +45,29 @@ describe "String#tr_s" do "bla".tr_s(from_str, to_str).should == "BlA" end - it "returns String instances when called on a subclass" do - StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances when called on a subclass" do + StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(String) + 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 diff --git a/spec/ruby/core/string/tr_spec.rb b/spec/ruby/core/string/tr_spec.rb index d60480dc7e..06be1e6641 100644 --- a/spec/ruby/core/string/tr_spec.rb +++ b/spec/ruby/core/string/tr_spec.rb @@ -16,15 +16,6 @@ describe "String#tr" do "hello ^-^".tr("---", "_").should == "hello ^_^" end - ruby_bug "#19769", ""..."3.3" do - it "accepts c1-c1 notation to denote range of one character" do - "hello".tr('e-e', 'x').should == "hxllo" - "123456789".tr("2-23","xy").should == "1xy456789" - "hello ^-^".tr("e-", "a-a_").should == "hallo ^_^" - "hello ^-^".tr("---o", "_a").should == "hella ^_^" - end - end - it "pads to_str with its last char if it is shorter than from_string" do "this".tr("this", "x").should == "xxxx" "hello".tr("a-z", "A-H.").should == "HE..." @@ -66,8 +57,29 @@ describe "String#tr" do "bla".tr(from_str, to_str).should == "BlA" end - it "returns Stringinstances when called on a subclass" do - StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances when called on a subclass" do + StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(StringSpecs::MyString) + end + end + + ruby_version_is '3.0' do + it "returns Stringinstances when called on a subclass" do + StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(String) + 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 diff --git a/spec/ruby/core/string/try_convert_spec.rb b/spec/ruby/core/string/try_convert_spec.rb index 72ce5dd8b2..84415c4a75 100644 --- a/spec/ruby/core/string/try_convert_spec.rb +++ b/spec/ruby/core/string/try_convert_spec.rb @@ -39,7 +39,7 @@ describe "String.try_convert" do it "sends #to_str to the argument and raises TypeError if it's not a kind of String" do obj = mock("to_str") obj.should_receive(:to_str).and_return(Object.new) - -> { String.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to String (MockObject#to_str gives Object)") + -> { String.try_convert obj }.should raise_error(TypeError) end it "does not rescue exceptions raised by #to_str" do diff --git a/spec/ruby/core/string/uminus_spec.rb b/spec/ruby/core/string/uminus_spec.rb index 46d88f6704..800dca5044 100644 --- a/spec/ruby/core/string/uminus_spec.rb +++ b/spec/ruby/core/string/uminus_spec.rb @@ -1,6 +1,49 @@ require_relative '../../spec_helper' -require_relative 'shared/dedup' describe 'String#-@' do - it_behaves_like :string_dedup, :-@ + 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 end diff --git a/spec/ruby/core/string/undump_spec.rb b/spec/ruby/core/string/undump_spec.rb index 6ff220161c..b990aa25ee 100644 --- a/spec/ruby/core/string/undump_spec.rb +++ b/spec/ruby/core/string/undump_spec.rb @@ -3,6 +3,16 @@ 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 @@ -389,7 +399,7 @@ describe "String#undump" do '"\\bv".force_encoding("UTF-16BE")'.undump.should == "\u0876".encode('utf-16be') end - it "returns a String in the same encoding as self" do + it "keeps origin encoding" do '"foo"'.encode("ISO-8859-1").undump.encoding.should == Encoding::ISO_8859_1 '"foo"'.encode('windows-1251').undump.encoding.should == Encoding::Windows_1251 end diff --git a/spec/ruby/core/string/unpack/b_spec.rb b/spec/ruby/core/string/unpack/b_spec.rb index 5c53eff721..1a838d6c7c 100644 --- a/spec/ruby/core/string/unpack/b_spec.rb +++ b/spec/ruby/core/string/unpack/b_spec.rb @@ -86,30 +86,13 @@ describe "String#unpack with format 'B'" do ].should be_computed_by(:unpack, "BBB") end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "\x80\x00".unpack("B\x00B").should == ["1", "0"] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "\x80\x00".unpack("B\x00B") - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + "\x80\x00".unpack("B\x00B").should == ["1", "0"] end it "ignores spaces between directives" do "\x80\x00".unpack("B B").should == ["1", "0"] end - - it "decodes into US-ASCII string values" do - str = "s".force_encoding('UTF-8').unpack("B*")[0] - str.encoding.name.should == 'US-ASCII' - end end describe "String#unpack with format 'b'" do @@ -194,20 +177,8 @@ describe "String#unpack with format 'b'" do ].should be_computed_by(:unpack, "bbb") end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "\x01\x00".unpack("b\x00b").should == ["1", "0"] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "\x01\x00".unpack("b\x00b") - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + "\x01\x00".unpack("b\x00b").should == ["1", "0"] end it "ignores spaces between directives" do @@ -218,4 +189,5 @@ describe "String#unpack with format 'b'" do str = "s".force_encoding('UTF-8').unpack("b*")[0] str.encoding.name.should == 'US-ASCII' end + end diff --git a/spec/ruby/core/string/unpack/c_spec.rb b/spec/ruby/core/string/unpack/c_spec.rb index c2bf813954..ed8caa4895 100644 --- a/spec/ruby/core/string/unpack/c_spec.rb +++ b/spec/ruby/core/string/unpack/c_spec.rb @@ -35,20 +35,8 @@ describe :string_unpack_8bit, shared: true do ].should be_computed_by(:unpack, unpack_format(3)) end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "abc".unpack(unpack_format("\000", 2)).should == [97, 98] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "abc".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + "abc".unpack(unpack_format("\000", 2)).should == [97, 98] end it "ignores spaces between directives" do diff --git a/spec/ruby/core/string/unpack/h_spec.rb b/spec/ruby/core/string/unpack/h_spec.rb index 19c4d63664..f2f5dcf396 100644 --- a/spec/ruby/core/string/unpack/h_spec.rb +++ b/spec/ruby/core/string/unpack/h_spec.rb @@ -56,20 +56,8 @@ describe "String#unpack with format 'H'" do ].should be_computed_by(:unpack, "HHH") end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "\x01\x10".unpack("H\x00H").should == ["0", "1"] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "\x01\x10".unpack("H\x00H") - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + "\x01\x10".unpack("H\x00H").should == ["0", "1"] end it "ignores spaces between directives" do @@ -133,20 +121,8 @@ describe "String#unpack with format 'h'" do ].should be_computed_by(:unpack, "hhh") end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "\x01\x10".unpack("h\x00h").should == ["1", "0"] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "\x01\x10".unpack("h\x00h") - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + "\x01\x10".unpack("h\x00h").should == ["1", "0"] end it "ignores spaces between directives" do diff --git a/spec/ruby/core/string/unpack/m_spec.rb b/spec/ruby/core/string/unpack/m_spec.rb index c551c755d1..21134514a1 100644 --- a/spec/ruby/core/string/unpack/m_spec.rb +++ b/spec/ruby/core/string/unpack/m_spec.rb @@ -97,11 +97,6 @@ describe "String#unpack with format 'M'" do ["=FF=\n", ["\xff"]] ].should be_computed_by(:unpack, "M") end - - it "unpacks incomplete escape sequences as literal characters" do - "foo=".unpack("M").should == ["foo="] - "foo=4".unpack("M").should == ["foo=4"] - end end describe "String#unpack with format 'm'" do diff --git a/spec/ruby/core/string/unpack/p_spec.rb b/spec/ruby/core/string/unpack/p_spec.rb index cd48c0523d..3e187d674f 100644 --- a/spec/ruby/core/string/unpack/p_spec.rb +++ b/spec/ruby/core/string/unpack/p_spec.rb @@ -18,6 +18,12 @@ 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 @@ -41,4 +47,10 @@ 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/basic.rb b/spec/ruby/core/string/unpack/shared/basic.rb index bb5302edc5..f636f4689f 100644 --- a/spec/ruby/core/string/unpack/shared/basic.rb +++ b/spec/ruby/core/string/unpack/shared/basic.rb @@ -8,6 +8,20 @@ describe :string_unpack_basic, shared: true do d.should_receive(:to_str).and_return("a"+unpack_format) "abc".unpack(d).should be_an_instance_of(Array) end + + it "raises a TypeError when passed nil" do + -> { "abc".unpack(nil) }.should raise_error(TypeError) + end + + it "raises a TypeError when passed an Integer" do + -> { "abc".unpack(1) }.should raise_error(TypeError) + end + + ruby_version_is "3.1" do + it "starts unpacking from the given offset" do + "abc".unpack("CC", offset: 1).should == [98, 99] + end + end end describe :string_unpack_no_platform, shared: true do @@ -18,4 +32,18 @@ describe :string_unpack_no_platform, shared: true do it "raises an ArgumentError when the format modifier is '!'" do -> { "abcdefgh".unpack(unpack_format("!")) }.should raise_error(ArgumentError) end + + ruby_version_is "3.1" do + it "raises an ArgumentError when the offset is negative" do + -> { "a".unpack("C", offset: -1) }.should raise_error(ArgumentError) + end + + it "returns nil if the offset is at the end of the string" do + "a".unpack("C", offset: 1).should == [nil] + end + + it "raises an ArgumentError when the offset is larget than the string" do + -> { "a".unpack("C", offset: 2) }.should raise_error(ArgumentError) + end + end end diff --git a/spec/ruby/core/string/unpack/shared/float.rb b/spec/ruby/core/string/unpack/shared/float.rb index 93282bf4c9..99bd8a3401 100644 --- a/spec/ruby/core/string/unpack/shared/float.rb +++ b/spec/ruby/core/string/unpack/shared/float.rb @@ -56,21 +56,9 @@ describe :string_unpack_float_le, shared: true do [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - array = "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2)) - array.should == [2.9000000953674316, 1.399999976158142] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + array = "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2)) + array.should == [2.9000000953674316, 1.399999976158142] end it "ignores spaces between directives" do @@ -135,21 +123,9 @@ describe :string_unpack_float_be, shared: true do [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - array = "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2)) - array.should == [2.9000000953674316, 1.399999976158142] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + array = "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2)) + array.should == [2.9000000953674316, 1.399999976158142] end it "ignores spaces between directives" do @@ -217,20 +193,8 @@ describe :string_unpack_double_le, shared: true do [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)).should == [2.9, 1.4] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)).should == [2.9, 1.4] end it "ignores spaces between directives" do @@ -297,20 +261,8 @@ describe :string_unpack_double_be, shared: true do [nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)).should == [2.9, 1.4] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)).should == [2.9, 1.4] end it "ignores spaces between directives" do diff --git a/spec/ruby/core/string/unpack/shared/integer.rb b/spec/ruby/core/string/unpack/shared/integer.rb index d71a2cf00d..cbaa743683 100644 --- a/spec/ruby/core/string/unpack/shared/integer.rb +++ b/spec/ruby/core/string/unpack/shared/integer.rb @@ -32,20 +32,8 @@ describe :string_unpack_16bit_le, shared: true do ].should be_computed_by(:unpack, unpack_format(3)) end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "abcd".unpack(unpack_format("\000", 2)).should == [25185, 25699] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "abcd".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + "abcd".unpack(unpack_format("\000", 2)).should == [25185, 25699] end it "ignores spaces between directives" do @@ -97,20 +85,8 @@ describe :string_unpack_16bit_be, shared: true do ].should be_computed_by(:unpack, unpack_format(3)) end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "badc".unpack(unpack_format("\000", 2)).should == [25185, 25699] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "badc".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + "badc".unpack(unpack_format("\000", 2)).should == [25185, 25699] end it "ignores spaces between directives" do @@ -163,20 +139,8 @@ describe :string_unpack_32bit_le, shared: true do ].should be_computed_by(:unpack, unpack_format(3)) end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "abcdefgh".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "abcdefgh".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + "abcdefgh".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885] end it "ignores spaces between directives" do @@ -229,20 +193,8 @@ describe :string_unpack_32bit_be, shared: true do ].should be_computed_by(:unpack, unpack_format(3)) end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "dcbahgfe".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "dcbahgfe".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + "dcbahgfe".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885] end it "ignores spaces between directives" do @@ -291,21 +243,9 @@ describe :string_unpack_64bit_le, shared: true do "abc".unpack(unpack_format('*')).should == [] end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - array = "abcdefghabghefcd".unpack(unpack_format("\000", 2)) - array.should == [7523094288207667809, 7233738012216484449] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "badc".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + array = "abcdefghabghefcd".unpack(unpack_format("\000", 2)) + array.should == [7523094288207667809, 7233738012216484449] end it "ignores spaces between directives" do @@ -365,21 +305,9 @@ describe :string_unpack_64bit_be, shared: true do "abc".unpack(unpack_format('*')).should == [] end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - array = "hgfedcbadcfehgba".unpack(unpack_format("\000", 2)) - array.should == [7523094288207667809, 7233738012216484449] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "hgfedcbadcfehgba".unpack(unpack_format("\000", 2)) - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + array = "hgfedcbadcfehgba".unpack(unpack_format("\000", 2)) + array.should == [7523094288207667809, 7233738012216484449] end it "ignores spaces between directives" do diff --git a/spec/ruby/core/string/unpack/shared/taint.rb b/spec/ruby/core/string/unpack/shared/taint.rb index 79c7251f01..061a3e26ad 100644 --- a/spec/ruby/core/string/unpack/shared/taint.rb +++ b/spec/ruby/core/string/unpack/shared/taint.rb @@ -1,2 +1,83 @@ 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/unpack/shared/unicode.rb b/spec/ruby/core/string/unpack/shared/unicode.rb index 9fe07f53ae..a2b4e142b2 100644 --- a/spec/ruby/core/string/unpack/shared/unicode.rb +++ b/spec/ruby/core/string/unpack/shared/unicode.rb @@ -50,20 +50,8 @@ describe :string_unpack_unicode, shared: true do "\xc2\x80".unpack("UUUU").should == [0x80] end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "\x01\x02".unpack("U\x00U").should == [1, 2] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "\x01\x02".unpack("U\x00U") - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + "\x01\x02".unpack("U\x00U").should == [1, 2] end it "ignores spaces between directives" do diff --git a/spec/ruby/core/string/unpack/w_spec.rb b/spec/ruby/core/string/unpack/w_spec.rb index 6a1cff1965..011c75f5c4 100644 --- a/spec/ruby/core/string/unpack/w_spec.rb +++ b/spec/ruby/core/string/unpack/w_spec.rb @@ -15,20 +15,8 @@ describe "String#unpack with directive 'w'" do ].should be_computed_by(:unpack, "w") end - ruby_version_is ""..."3.3" do - it "ignores NULL bytes between directives" do - suppress_warning do - "\x01\x02\x03".unpack("w\x00w").should == [1, 2] - end - end - end - - ruby_version_is "3.3" do - it "raise ArgumentError for NULL bytes between directives" do - -> { - "\x01\x02\x03".unpack("w\x00w") - }.should raise_error(ArgumentError, /unknown unpack directive/) - end + it "ignores NULL bytes between directives" do + "\x01\x02\x03".unpack("w\x00w").should == [1, 2] end it "ignores spaces between directives" do diff --git a/spec/ruby/core/string/unpack/z_spec.rb b/spec/ruby/core/string/unpack/z_spec.rb index ce8da4b29e..552851ce04 100644 --- a/spec/ruby/core/string/unpack/z_spec.rb +++ b/spec/ruby/core/string/unpack/z_spec.rb @@ -20,9 +20,4 @@ describe "String#unpack with format 'Z'" do ["\x00a\x00 bc \x00", ["", "c"]] ].should be_computed_by(:unpack, "Z5Z") end - - it "does not advance past the null byte when given a 'Z' format specifier" do - "a\x00\x0f".unpack('Zxc').should == ['a', 15] - "a\x00\x0f".unpack('Zcc').should == ['a', 0, 15] - end end diff --git a/spec/ruby/core/string/unpack1_spec.rb b/spec/ruby/core/string/unpack1_spec.rb index df830916a3..f59bd92d6a 100644 --- a/spec/ruby/core/string/unpack1_spec.rb +++ b/spec/ruby/core/string/unpack1_spec.rb @@ -15,22 +15,16 @@ describe "String#unpack1" do "ZA".unpack1("B*", offset: 1).should == "01000001" end - it "traits offset as a bytes offset" do - "؈".unpack("CC").should == [216, 136] - "؈".unpack1("C").should == 216 - "؈".unpack1("C", offset: 1).should == 136 - end - it "raises an ArgumentError when the offset is negative" do - -> { "a".unpack1("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative") + -> { "a".unpack1("C", offset: -1) }.should raise_error(ArgumentError) end it "returns nil if the offset is at the end of the string" do "a".unpack1("C", offset: 1).should == nil end - it "raises an ArgumentError when the offset is larger than the string bytesize" do - -> { "a".unpack1("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string") + it "raises an ArgumentError when the offset is larget than the string" do + -> { "a".unpack1("C", offset: 2) }.should raise_error(ArgumentError) end end end diff --git a/spec/ruby/core/string/unpack_spec.rb b/spec/ruby/core/string/unpack_spec.rb deleted file mode 100644 index 52b4af3a95..0000000000 --- a/spec/ruby/core/string/unpack_spec.rb +++ /dev/null @@ -1,34 +0,0 @@ -require_relative '../../spec_helper' - -describe "String#unpack" do - it "raises a TypeError when passed nil" do - -> { "abc".unpack(nil) }.should raise_error(TypeError) - end - - it "raises a TypeError when passed an Integer" do - -> { "abc".unpack(1) }.should raise_error(TypeError) - end - - ruby_version_is "3.1" do - it "starts unpacking from the given offset" do - "abc".unpack("CC", offset: 1).should == [98, 99] - end - - it "traits offset as a bytes offset" do - "؈".unpack("CC").should == [216, 136] - "؈".unpack("CC", offset: 1).should == [136, nil] - end - - it "raises an ArgumentError when the offset is negative" do - -> { "a".unpack("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative") - end - - it "returns nil if the offset is at the end of the string" do - "a".unpack("C", offset: 1).should == [nil] - end - - it "raises an ArgumentError when the offset is larget than the string" do - -> { "a".unpack("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string") - end - end -end diff --git a/spec/ruby/core/string/upcase_spec.rb b/spec/ruby/core/string/upcase_spec.rb index a2e34f5f40..6cf44b4703 100644 --- a/spec/ruby/core/string/upcase_spec.rb +++ b/spec/ruby/core/string/upcase_spec.rb @@ -8,10 +8,6 @@ describe "String#upcase" do "hello".upcase.should == "HELLO" end - it "returns a String in the same encoding as self" do - "hello".encode("US-ASCII").upcase.encoding.should == Encoding::US_ASCII - end - describe "full Unicode case mapping" do it "works for all of Unicode with no option" do "äöü".upcase.should == "ÄÖÜ" @@ -31,10 +27,6 @@ describe "String#upcase" do it "does not upcase non-ASCII characters" do "aßet".upcase(:ascii).should == "AßET" end - - it "works with substrings" do - "prefix té"[-2..-1].upcase(:ascii).should == "Té" - end end describe "full Unicode case mapping adapted for Turkic languages" do @@ -73,8 +65,24 @@ describe "String#upcase" do -> { "abc".upcase(:invalid_option) }.should raise_error(ArgumentError) end - it "returns a String instance for subclasses" do - StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(String) + 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) + end + end + + ruby_version_is '3.0' do + it "returns a String instance for subclasses" do + StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(String) + end end end diff --git a/spec/ruby/core/string/uplus_spec.rb b/spec/ruby/core/string/uplus_spec.rb index 65b66260dd..038b283c90 100644 --- a/spec/ruby/core/string/uplus_spec.rb +++ b/spec/ruby/core/string/uplus_spec.rb @@ -7,9 +7,6 @@ describe 'String#+@' do output.should_not.frozen? output.should == 'foo' - - output << 'bar' - output.should == 'foobar' end it 'returns self if the String is not frozen' do diff --git a/spec/ruby/core/string/upto_spec.rb b/spec/ruby/core/string/upto_spec.rb index 3799e338e0..f8529b1d2b 100644 --- a/spec/ruby/core/string/upto_spec.rb +++ b/spec/ruby/core/string/upto_spec.rb @@ -80,12 +80,6 @@ describe "String#upto" do a.should == ["Σ", "Τ", "Υ", "Φ", "Χ", "Ψ", "Ω"] end - it "raises Encoding::CompatibilityError when incompatible characters are given" do - char1 = 'a'.force_encoding("EUC-JP") - char2 = 'b'.force_encoding("ISO-2022-JP") - -> { char1.upto(char2) {} }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: EUC-JP and ISO-2022-JP") - end - describe "on sequence of numbers" do it "calls the block as Integer#upto" do "8".upto("11").to_a.should == 8.upto(11).map(&:to_s) diff --git a/spec/ruby/core/string/valid_encoding/utf_8_spec.rb b/spec/ruby/core/string/valid_encoding/utf_8_spec.rb deleted file mode 100644 index a14c3af830..0000000000 --- a/spec/ruby/core/string/valid_encoding/utf_8_spec.rb +++ /dev/null @@ -1,214 +0,0 @@ -# -*- encoding: utf-8 -*- -require_relative '../../../spec_helper' - -describe "String#valid_encoding? and UTF-8" do - def utf8(bytes) - bytes.pack("C*").force_encoding("UTF-8") - end - - describe "1-byte character" do - it "is valid if is in format 0xxxxxxx" do - utf8([0b00000000]).valid_encoding?.should == true - utf8([0b01111111]).valid_encoding?.should == true - end - - it "is not valid if is not in format 0xxxxxxx" do - utf8([0b10000000]).valid_encoding?.should == false - utf8([0b11111111]).valid_encoding?.should == false - end - end - - describe "2-bytes character" do - it "is valid if in format [110xxxxx 10xxxxx]" do - utf8([0b11000010, 0b10000000]).valid_encoding?.should == true - utf8([0b11000010, 0b10111111]).valid_encoding?.should == true - - utf8([0b11011111, 0b10000000]).valid_encoding?.should == true - utf8([0b11011111, 0b10111111]).valid_encoding?.should == true - end - - it "is not valid if the first byte is not in format 110xxxxx" do - utf8([0b00000010, 0b10000000]).valid_encoding?.should == false - utf8([0b00100010, 0b10000000]).valid_encoding?.should == false - utf8([0b01000010, 0b10000000]).valid_encoding?.should == false - utf8([0b01100010, 0b10000000]).valid_encoding?.should == false - utf8([0b10000010, 0b10000000]).valid_encoding?.should == false - utf8([0b10100010, 0b10000000]).valid_encoding?.should == false - utf8([0b11000010, 0b10000000]).valid_encoding?.should == true # correct bytes - utf8([0b11100010, 0b10000000]).valid_encoding?.should == false - end - - it "is not valid if the second byte is not in format 10xxxxxx" do - utf8([0b11000010, 0b00000000]).valid_encoding?.should == false - utf8([0b11000010, 0b01000000]).valid_encoding?.should == false - utf8([0b11000010, 0b11000000]).valid_encoding?.should == false - end - - it "is not valid if is smaller than [xxxxxx10 xx000000] (codepoints < U+007F, that are encoded with the 1-byte format)" do - utf8([0b11000000, 0b10111111]).valid_encoding?.should == false - utf8([0b11000001, 0b10111111]).valid_encoding?.should == false - end - - it "is not valid if the first byte is missing" do - bytes = [0b11000010, 0b10000000] - utf8(bytes[1..1]).valid_encoding?.should == false - end - - it "is not valid if the second byte is missing" do - bytes = [0b11000010, 0b10000000] - utf8(bytes[0..0]).valid_encoding?.should == false - end - end - - describe "3-bytes character" do - it "is valid if in format [1110xxxx 10xxxxxx 10xxxxxx]" do - utf8([0b11100000, 0b10100000, 0b10000000]).valid_encoding?.should == true - utf8([0b11100000, 0b10100000, 0b10111111]).valid_encoding?.should == true - utf8([0b11100000, 0b10111111, 0b10111111]).valid_encoding?.should == true - utf8([0b11101111, 0b10111111, 0b10111111]).valid_encoding?.should == true - end - - it "is not valid if the first byte is not in format 1110xxxx" do - utf8([0b00000000, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b00010000, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b00100000, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b00110000, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b01000000, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b01010000, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b01100000, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b01110000, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b10000000, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b10010000, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b10100000, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b10110000, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b11000000, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b11010000, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b11100000, 0b10100000, 0b10000000]).valid_encoding?.should == true # correct bytes - utf8([0b11110000, 0b10100000, 0b10000000]).valid_encoding?.should == false - end - - it "is not valid if the second byte is not in format 10xxxxxx" do - utf8([0b11100000, 0b00100000, 0b10000000]).valid_encoding?.should == false - utf8([0b11100000, 0b01100000, 0b10000000]).valid_encoding?.should == false - utf8([0b11100000, 0b11100000, 0b10000000]).valid_encoding?.should == false - end - - it "is not valid if the third byte is not in format 10xxxxxx" do - utf8([0b11100000, 0b10100000, 0b00000000]).valid_encoding?.should == false - utf8([0b11100000, 0b10100000, 0b01000000]).valid_encoding?.should == false - utf8([0b11100000, 0b10100000, 0b01000000]).valid_encoding?.should == false - end - - it "is not valid if is smaller than [xxxx0000 xx100000 xx000000] (codepoints < U+07FF that are encoded with the 2-byte format)" do - utf8([0b11100000, 0b10010000, 0b10000000]).valid_encoding?.should == false - utf8([0b11100000, 0b10001000, 0b10000000]).valid_encoding?.should == false - utf8([0b11100000, 0b10000100, 0b10000000]).valid_encoding?.should == false - utf8([0b11100000, 0b10000010, 0b10000000]).valid_encoding?.should == false - utf8([0b11100000, 0b10000001, 0b10000000]).valid_encoding?.should == false - utf8([0b11100000, 0b10000000, 0b10000000]).valid_encoding?.should == false - end - - it "is not valid if in range [xxxx1101 xx100000 xx000000] - [xxxx1101 xx111111 xx111111] (codepoints U+D800 - U+DFFF)" do - utf8([0b11101101, 0b10100000, 0b10000000]).valid_encoding?.should == false - utf8([0b11101101, 0b10100000, 0b10000001]).valid_encoding?.should == false - utf8([0b11101101, 0b10111111, 0b10111111]).valid_encoding?.should == false - - utf8([0b11101101, 0b10011111, 0b10111111]).valid_encoding?.should == true # lower boundary - 1 - utf8([0b11101110, 0b10000000, 0b10000000]).valid_encoding?.should == true # upper boundary + 1 - end - - it "is not valid if the first byte is missing" do - bytes = [0b11100000, 0b10100000, 0b10000000] - utf8(bytes[2..3]).valid_encoding?.should == false - end - - it "is not valid if the second byte is missing" do - bytes = [0b11100000, 0b10100000, 0b10000000] - utf8([bytes[0], bytes[2]]).valid_encoding?.should == false - end - - it "is not valid if the second and the third bytes are missing" do - bytes = [0b11100000, 0b10100000, 0b10000000] - utf8(bytes[0..0]).valid_encoding?.should == false - end - end - - describe "4-bytes character" do - it "is valid if in format [11110xxx 10xxxxxx 10xxxxxx 10xxxxxx]" do - utf8([0b11110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == true - utf8([0b11110000, 0b10010000, 0b10000000, 0b10111111]).valid_encoding?.should == true - utf8([0b11110000, 0b10010000, 0b10111111, 0b10111111]).valid_encoding?.should == true - utf8([0b11110000, 0b10111111, 0b10111111, 0b10111111]).valid_encoding?.should == true - utf8([0b11110100, 0b10001111, 0b10111111, 0b10111111]).valid_encoding?.should == true - end - - it "is not valid if the first byte is not in format 11110xxx" do - utf8([0b11100000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false - utf8([0b11010000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false - utf8([0b10110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false - utf8([0b01110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false - end - - it "is not valid if the second byte is not in format 10xxxxxx" do - utf8([0b11110000, 0b00010000, 0b10000000, 0b10000000]).valid_encoding?.should == false - utf8([0b11110000, 0b01010000, 0b10000000, 0b10000000]).valid_encoding?.should == false - utf8([0b11110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == true # correct bytes - utf8([0b11110000, 0b11010000, 0b10000000, 0b10000000]).valid_encoding?.should == false - end - - it "is not valid if the third byte is not in format 10xxxxxx" do - utf8([0b11110000, 0b10010000, 0b00000000, 0b10000000]).valid_encoding?.should == false - utf8([0b11110000, 0b10010000, 0b01000000, 0b10000000]).valid_encoding?.should == false - utf8([0b11110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == true # correct bytes - utf8([0b11110000, 0b10010000, 0b11000000, 0b10000000]).valid_encoding?.should == false - end - - it "is not valid if the forth byte is not in format 10xxxxxx" do - utf8([0b11110000, 0b10010000, 0b10000000, 0b00000000]).valid_encoding?.should == false - utf8([0b11110000, 0b10010000, 0b10000000, 0b01000000]).valid_encoding?.should == false - utf8([0b11110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == true # correct bytes - utf8([0b11110000, 0b10010000, 0b10000000, 0b11000000]).valid_encoding?.should == false - end - - it "is not valid if is smaller than [xxxxx000 xx001000 xx000000 xx000000] (codepoint < U+10000)" do - utf8([0b11110000, 0b10000111, 0b10000000, 0b10000000]).valid_encoding?.should == false - utf8([0b11110000, 0b10000110, 0b10000000, 0b10000000]).valid_encoding?.should == false - utf8([0b11110000, 0b10000101, 0b10000000, 0b10000000]).valid_encoding?.should == false - utf8([0b11110000, 0b10000100, 0b10000000, 0b10000000]).valid_encoding?.should == false - utf8([0b11110000, 0b10000011, 0b10000000, 0b10000000]).valid_encoding?.should == false - utf8([0b11110000, 0b10000010, 0b10000000, 0b10000000]).valid_encoding?.should == false - utf8([0b11110000, 0b10000001, 0b10000000, 0b10000000]).valid_encoding?.should == false - utf8([0b11110000, 0b10000000, 0b10000000, 0b10000000]).valid_encoding?.should == false - end - - it "is not valid if is greater than [xxxxx100 xx001111 xx111111 xx111111] (codepoint > U+10FFFF)" do - utf8([0b11110100, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false - utf8([0b11110100, 0b10100000, 0b10000000, 0b10000000]).valid_encoding?.should == false - utf8([0b11110100, 0b10110000, 0b10000000, 0b10000000]).valid_encoding?.should == false - - utf8([0b11110101, 0b10001111, 0b10111111, 0b10111111]).valid_encoding?.should == false - utf8([0b11110110, 0b10001111, 0b10111111, 0b10111111]).valid_encoding?.should == false - utf8([0b11110111, 0b10001111, 0b10111111, 0b10111111]).valid_encoding?.should == false - end - - it "is not valid if the first byte is missing" do - bytes = [0b11110000, 0b10010000, 0b10000000, 0b10000000] - utf8(bytes[1..3]).valid_encoding?.should == false - end - - it "is not valid if the second byte is missing" do - bytes = [0b11110000, 0b10010000, 0b10000000, 0b10000000] - utf8([bytes[0], bytes[2], bytes[3]]).valid_encoding?.should == false - end - - it "is not valid if the second and the third bytes are missing" do - bytes = [0b11110000, 0b10010000, 0b10000000, 0b10000000] - utf8([bytes[0], bytes[3]]).valid_encoding?.should == false - end - - it "is not valid if the second, the third and the fourth bytes are missing" do - bytes = [0b11110000, 0b10010000, 0b10000000, 0b10000000] - utf8(bytes[0..0]).valid_encoding?.should == false - end - end -end diff --git a/spec/ruby/core/string/valid_encoding_spec.rb b/spec/ruby/core/string/valid_encoding_spec.rb index bb26062c0f..be7cef7a8e 100644 --- a/spec/ruby/core/string/valid_encoding_spec.rb +++ b/spec/ruby/core/string/valid_encoding_spec.rb @@ -100,10 +100,12 @@ describe "String#valid_encoding?" do str.force_encoding('UTF8-MAC').valid_encoding?.should be_true end - it "returns true for IBM720 encoding self is valid in" do - str = "\xE6\x9D\x94" - str.force_encoding('IBM720').valid_encoding?.should be_true - str.force_encoding('CP720').valid_encoding?.should be_true + ruby_version_is '3.0' do + it "returns true for IBM720 encoding self is valid in" do + str = "\xE6\x9D\x94" + str.force_encoding('IBM720').valid_encoding?.should be_true + str.force_encoding('CP720').valid_encoding?.should be_true + end end it "returns false if self is valid in one encoding, but invalid in the one it's tagged with" do diff --git a/spec/ruby/core/struct/constants_spec.rb b/spec/ruby/core/struct/constants_spec.rb deleted file mode 100644 index fa61a4b912..0000000000 --- a/spec/ruby/core/struct/constants_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative '../../spec_helper' - -ruby_version_is "3.2" do - describe "Struct::Group" do - it "is no longer defined" do - Struct.should_not.const_defined?(:Group) - end - end - - describe "Struct::Passwd" do - it "is no longer defined" do - Struct.should_not.const_defined?(:Passwd) - end - end -end diff --git a/spec/ruby/core/struct/deconstruct_keys_spec.rb b/spec/ruby/core/struct/deconstruct_keys_spec.rb index b4c84c49df..f0a1f50ad3 100644 --- a/spec/ruby/core/struct/deconstruct_keys_spec.rb +++ b/spec/ruby/core/struct/deconstruct_keys_spec.rb @@ -1,76 +1,78 @@ require_relative '../../spec_helper' -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 except 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/) +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 end end diff --git a/spec/ruby/core/struct/deconstruct_spec.rb b/spec/ruby/core/struct/deconstruct_spec.rb index 32d4f6bac4..7518a40987 100644 --- a/spec/ruby/core/struct/deconstruct_spec.rb +++ b/spec/ruby/core/struct/deconstruct_spec.rb @@ -1,10 +1,12 @@ require_relative '../../spec_helper' -describe "Struct#deconstruct" do - it "returns an array of attribute values" do - struct = Struct.new(:x, :y) - s = struct.new(1, 2) +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) - s.deconstruct.should == [1, 2] + s.deconstruct.should == [1, 2] + end end end diff --git a/spec/ruby/core/struct/fixtures/classes.rb b/spec/ruby/core/struct/fixtures/classes.rb index bf838d05df..6d620f9060 100644 --- a/spec/ruby/core/struct/fixtures/classes.rb +++ b/spec/ruby/core/struct/fixtures/classes.rb @@ -13,12 +13,6 @@ module StructClasses end end - class StructWithOverriddenName < Struct.new(:a) - def self.name - "A" - end - end - class SubclassX < Struct end diff --git a/spec/ruby/core/struct/initialize_spec.rb b/spec/ruby/core/struct/initialize_spec.rb index a5ebe9551c..e82289071a 100644 --- a/spec/ruby/core/struct/initialize_spec.rb +++ b/spec/ruby/core/struct/initialize_spec.rb @@ -40,22 +40,4 @@ describe "Struct#initialize" do it "can be overridden" do StructClasses::SubclassX.new(:y).new.key.should == :value end - - ruby_version_is "3.1"..."3.2" do - it "warns about passing only keyword arguments" do - -> { - StructClasses::Ruby.new(version: "3.1", platform: "OS") - }.should complain(/warning: Passing only keyword arguments/) - end - end - - ruby_version_is "3.2" do - it "can be initialized with keyword arguments" do - positional_args = StructClasses::Ruby.new("3.2", "OS") - keyword_args = StructClasses::Ruby.new(version: "3.2", platform: "OS") - - positional_args.version.should == keyword_args.version - positional_args.platform.should == keyword_args.platform - end - end end diff --git a/spec/ruby/core/struct/inspect_spec.rb b/spec/ruby/core/struct/inspect_spec.rb index 657b06abc1..83e13597ba 100644 --- a/spec/ruby/core/struct/inspect_spec.rb +++ b/spec/ruby/core/struct/inspect_spec.rb @@ -3,5 +3,10 @@ require_relative 'fixtures/classes' require_relative 'shared/inspect' describe "Struct#inspect" do + it "returns a string representation showing members and values" do + car = StructClasses::Car.new('Ford', 'Ranger') + car.inspect.should == '#<struct StructClasses::Car make="Ford", model="Ranger", year=nil>' + end + it_behaves_like :struct_inspect, :inspect end diff --git a/spec/ruby/core/struct/keyword_init_spec.rb b/spec/ruby/core/struct/keyword_init_spec.rb deleted file mode 100644 index 8de4c14351..0000000000 --- a/spec/ruby/core/struct/keyword_init_spec.rb +++ /dev/null @@ -1,40 +0,0 @@ -require_relative '../../spec_helper' - -ruby_version_is "3.1" do - # See https://bugs.ruby-lang.org/issues/18008 - describe "StructClass#keyword_init?" do - it "returns true for a struct that accepts keyword arguments to initialize" do - struct = Struct.new(:arg, keyword_init: true) - struct.keyword_init?.should be_true - end - - it "returns false for a struct that does not accept keyword arguments to initialize" do - struct = Struct.new(:arg, keyword_init: false) - struct.keyword_init?.should be_false - end - - it "returns nil for a struct that did not explicitly specify keyword_init" do - struct = Struct.new(:arg) - struct.keyword_init?.should be_nil - end - - it "returns nil for a struct that does specify keyword_init to be nil" do - struct = Struct.new(:arg, keyword_init: nil) - struct.keyword_init?.should be_nil - end - - it "returns true for any truthy value, not just for true" do - struct = Struct.new(:arg, keyword_init: 1) - struct.keyword_init?.should be_true - - struct = Struct.new(:arg, keyword_init: "") - struct.keyword_init?.should be_true - - struct = Struct.new(:arg, keyword_init: []) - struct.keyword_init?.should be_true - - struct = Struct.new(:arg, keyword_init: {}) - struct.keyword_init?.should be_true - end - end -end diff --git a/spec/ruby/core/struct/new_spec.rb b/spec/ruby/core/struct/new_spec.rb index 8758051a81..cbbec829d7 100644 --- a/spec/ruby/core/struct/new_spec.rb +++ b/spec/ruby/core/struct/new_spec.rb @@ -47,11 +47,6 @@ describe "Struct.new" do Struct.const_defined?("Animal2").should be_false end - it "allows non-ASCII member name" do - name = "r\xe9sum\xe9".force_encoding(Encoding::ISO_8859_1).to_sym - struct = Struct.new(name) - struct.new("foo").send(name).should == "foo" - end it "fails with invalid constant name as first argument" do -> { Struct.new('animal', :name, :legs, :eyeballs) }.should raise_error(NameError) @@ -67,34 +62,8 @@ describe "Struct.new" do -> { Struct.new(:animal, ['chris', 'evan']) }.should raise_error(TypeError) end - 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 - - ruby_version_is ""..."3.3" do - it "raises ArgumentError if not provided any arguments" do - -> { Struct.new }.should raise_error(ArgumentError) - end - end - - ruby_version_is "3.3" do - it "works when not provided any arguments" do - c = Struct.new - c.should be_kind_of(Class) - c.superclass.should == Struct - end + it "raises a ArgumentError if passed a Hash with an unknown key" do + -> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(ArgumentError) end it "raises ArgumentError when there is a duplicate member" do diff --git a/spec/ruby/core/struct/shared/inspect.rb b/spec/ruby/core/struct/shared/inspect.rb index 1a0fb6a6b2..90594a5452 100644 --- a/spec/ruby/core/struct/shared/inspect.rb +++ b/spec/ruby/core/struct/shared/inspect.rb @@ -1,40 +1,5 @@ describe :struct_inspect, shared: true do - it "returns a string representation showing members and values" do - car = StructClasses::Car.new('Ford', 'Ranger') - car.send(@method).should == '#<struct StructClasses::Car make="Ford", model="Ranger", year=nil>' - end - it "returns a string representation without the class name for anonymous structs" do Struct.new(:a).new("").send(@method).should == '#<struct a="">' end - - it "returns a string representation without the class name for structs nested in anonymous classes" do - c = Class.new - c.class_eval <<~DOC - class Foo < Struct.new(:a); end - DOC - - c::Foo.new("").send(@method).should == '#<struct a="">' - end - - it "returns a string representation without the class name for structs nested in anonymous modules" do - m = Module.new - m.module_eval <<~DOC - class Foo < Struct.new(:a); end - DOC - - m::Foo.new("").send(@method).should == '#<struct a="">' - end - - it "does not call #name method" do - struct = StructClasses::StructWithOverriddenName.new("") - struct.send(@method).should == '#<struct StructClasses::StructWithOverriddenName a="">' - end - - it "does not call #name method when struct is anonymous" do - struct = Struct.new(:a) - def struct.name; "A"; end - - struct.new("").send(@method).should == '#<struct a="">' - end end diff --git a/spec/ruby/core/struct/values_at_spec.rb b/spec/ruby/core/struct/values_at_spec.rb index 5e5a496600..e7d287cba2 100644 --- a/spec/ruby/core/struct/values_at_spec.rb +++ b/spec/ruby/core/struct/values_at_spec.rb @@ -1,59 +1,16 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -# Should be synchronized with core/array/values_at_spec.rb describe "Struct#values_at" do - before do + it "returns an array of values" do clazz = Struct.new(:name, :director, :year) - @movie = clazz.new('Sympathy for Mr. Vengeance', 'Chan-wook Park', 2002) - end - - context "when passed a list of Integers" do - it "returns an array containing each value given by one of integers" do - @movie.values_at(0, 1).should == ['Sympathy for Mr. Vengeance', 'Chan-wook Park'] - end - - it "raises IndexError if any of integers is out of range" do - -> { @movie.values_at(3) }.should raise_error(IndexError, "offset 3 too large for struct(size:3)") - -> { @movie.values_at(-4) }.should raise_error(IndexError, "offset -4 too small for struct(size:3)") - end - end - - context "when passed an integer Range" do - it "returns an array containing each value given by the elements of the range" do - @movie.values_at(0..2).should == ['Sympathy for Mr. Vengeance', 'Chan-wook Park', 2002] - end - - it "fills with nil values for range elements larger than the structure" do - @movie.values_at(0..3).should == ['Sympathy for Mr. Vengeance', 'Chan-wook Park', 2002, nil] - end - - it "raises RangeError if any element of the range is negative and out of range" do - -> { @movie.values_at(-4..3) }.should raise_error(RangeError, "-4..3 out of range") - end - - it "supports endless Range" do - @movie.values_at(0..).should == ["Sympathy for Mr. Vengeance", "Chan-wook Park", 2002] - end - - it "supports beginningless Range" do - @movie.values_at(..2).should == ["Sympathy for Mr. Vengeance", "Chan-wook Park", 2002] - end - end - - it "supports multiple integer Ranges" do - @movie.values_at(0..2, 1..2).should == ['Sympathy for Mr. Vengeance', 'Chan-wook Park', 2002, 'Chan-wook Park', 2002] - end - - it "supports mixing integer Ranges and Integers" do - @movie.values_at(0..2, 2).should == ['Sympathy for Mr. Vengeance', 'Chan-wook Park', 2002, 2002] - end - - it "returns a new empty Array if no arguments given" do - @movie.values_at().should == [] + movie = clazz.new('Sympathy for Mr. Vengeance', 'Chan-wook Park', 2002) + movie.values_at(0, 1).should == ['Sympathy for Mr. Vengeance', 'Chan-wook Park'] + movie.values_at(0..2).should == ['Sympathy for Mr. Vengeance', 'Chan-wook Park', 2002] end it "fails when passed unsupported types" do - -> { @movie.values_at('make') }.should raise_error(TypeError, "no implicit conversion of String into Integer") + car = StructClasses::Car.new('Ford', 'Ranger') + -> { car.values_at('make') }.should raise_error(TypeError) end end diff --git a/spec/ruby/core/symbol/casecmp_spec.rb b/spec/ruby/core/symbol/casecmp_spec.rb index 662a29a284..80ea51e910 100644 --- a/spec/ruby/core/symbol/casecmp_spec.rb +++ b/spec/ruby/core/symbol/casecmp_spec.rb @@ -56,10 +56,6 @@ describe "Symbol#casecmp with Symbol" do lower_a_tilde.casecmp(upper_a_tilde).should == 1 lower_a_umlaut.casecmp(upper_a_umlaut).should == 1 end - - it "returns 0 for empty strings in different encodings" do - ''.to_sym.casecmp(''.encode("UTF-32LE").to_sym).should == 0 - end end describe "Symbol#casecmp" do @@ -145,8 +141,4 @@ describe 'Symbol#casecmp?' do upper_a_tilde.casecmp?(lower_a_tilde).should == nil lower_a_tilde.casecmp?(upper_a_tilde).should == nil end - - it "returns true for empty symbols in different encodings" do - ''.to_sym.should.casecmp?(''.encode("UTF-32LE").to_sym) - end end diff --git a/spec/ruby/core/symbol/end_with_spec.rb b/spec/ruby/core/symbol/end_with_spec.rb index 4b9f5a4996..77dc4caf71 100644 --- a/spec/ruby/core/symbol/end_with_spec.rb +++ b/spec/ruby/core/symbol/end_with_spec.rb @@ -3,6 +3,8 @@ require_relative '../../spec_helper' require_relative '../../shared/string/end_with' -describe "Symbol#end_with?" do - it_behaves_like :end_with, :to_sym +ruby_version_is "2.7" do + describe "Symbol#end_with?" do + it_behaves_like :end_with, :to_sym + end end diff --git a/spec/ruby/core/symbol/inspect_spec.rb b/spec/ruby/core/symbol/inspect_spec.rb index 6dbb36c2ad..58402ab261 100644 --- a/spec/ruby/core/symbol/inspect_spec.rb +++ b/spec/ruby/core/symbol/inspect_spec.rb @@ -5,8 +5,6 @@ describe "Symbol#inspect" do fred: ":fred", :fred? => ":fred?", :fred! => ":fred!", - :BAD! => ":BAD!", - :_BAD! => ":_BAD!", :$ruby => ":$ruby", :@ruby => ":@ruby", :@@ruby => ":@@ruby", diff --git a/spec/ruby/core/symbol/name_spec.rb b/spec/ruby/core/symbol/name_spec.rb index f9b631266c..15b9aa75e9 100644 --- a/spec/ruby/core/symbol/name_spec.rb +++ b/spec/ruby/core/symbol/name_spec.rb @@ -1,17 +1,19 @@ require_relative '../../spec_helper' -describe "Symbol#name" do - it "returns string" do - :ruby.name.should == "ruby" - :ルビー.name.should == "ルビー" - end +ruby_version_is "3.0" do + describe "Symbol#name" do + it "returns string" do + :ruby.name.should == "ruby" + :ルビー.name.should == "ルビー" + end - it "returns same string instance" do - :"ruby_3".name.should.equal?(:ruby_3.name) - :"ruby_#{1+2}".name.should.equal?(:ruby_3.name) - end + it "returns same string instance" do + :"ruby_3".name.should.equal?(:ruby_3.name) + :"ruby_#{1+2}".name.should.equal?(:ruby_3.name) + end - it "returns frozen string" do - :symbol.name.should.frozen? + it "returns frozen string" do + :symbol.name.should.frozen? + end end end diff --git a/spec/ruby/core/symbol/shared/id2name.rb b/spec/ruby/core/symbol/shared/id2name.rb index d012b7634e..47f97bd332 100644 --- a/spec/ruby/core/symbol/shared/id2name.rb +++ b/spec/ruby/core/symbol/shared/id2name.rb @@ -6,11 +6,4 @@ describe :symbol_id2name, shared: true do :@ruby.send(@method).should == "@ruby" :@@ruby.send(@method).should == "@@ruby" end - - it "returns a String in the same encoding as self" do - string = "ruby".encode("US-ASCII") - symbol = string.to_sym - - symbol.send(@method).encoding.should == Encoding::US_ASCII - end end diff --git a/spec/ruby/core/symbol/shared/slice.rb b/spec/ruby/core/symbol/shared/slice.rb index 0df87e183d..3f07f6aedb 100644 --- a/spec/ruby/core/symbol/shared/slice.rb +++ b/spec/ruby/core/symbol/shared/slice.rb @@ -190,6 +190,16 @@ 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 @@ -211,6 +221,16 @@ 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 cd43279003..f54b3e499e 100644 --- a/spec/ruby/core/symbol/start_with_spec.rb +++ b/spec/ruby/core/symbol/start_with_spec.rb @@ -3,6 +3,8 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' require_relative '../../shared/string/start_with' -describe "Symbol#start_with?" do - it_behaves_like :start_with, :to_sym +ruby_version_is "2.7" do + describe "Symbol#start_with?" do + it_behaves_like :start_with, :to_sym + end end diff --git a/spec/ruby/core/symbol/to_proc_spec.rb b/spec/ruby/core/symbol/to_proc_spec.rb index 2cd013696a..47f2a939ab 100644 --- a/spec/ruby/core/symbol/to_proc_spec.rb +++ b/spec/ruby/core/symbol/to_proc_spec.rb @@ -12,45 +12,37 @@ describe "Symbol#to_proc" do :to_s.to_proc.call(obj).should == "Received #to_s" end - it "returns a Proc with #lambda? true" do - pr = :to_s.to_proc - pr.should.lambda? - end + ruby_version_is ""..."3.0" do + it "returns a Proc with #lambda? false" do + pr = :to_s.to_proc + pr.should_not.lambda? + end - it "produces a Proc with arity -2" do - pr = :to_s.to_proc - pr.arity.should == -2 - end + it "produces a Proc with arity -1" do + pr = :to_s.to_proc + pr.arity.should == -1 + end - it "produces a Proc that always returns [[:req], [:rest]] for #parameters" do - pr = :to_s.to_proc - pr.parameters.should == [[:req], [:rest]] + it "produces a Proc that always returns [[:rest]] for #parameters" do + pr = :to_s.to_proc + pr.parameters.should == [[:rest]] + end end - ruby_version_is "3.2" do - it "only calls public methods" do - body = proc do - public def pub; @a << :pub end - protected def pro; @a << :pro end - private def pri; @a << :pri end - attr_reader :a - end + ruby_version_is "3.0" do + it "returns a Proc with #lambda? true" do + pr = :to_s.to_proc + pr.should.lambda? + end - @a = [] - singleton_class.class_eval(&body) - tap(&:pub) - proc{tap(&:pro)}.should raise_error(NoMethodError, /protected method `pro' called/) - proc{tap(&:pri)}.should raise_error(NoMethodError, /private method `pri' called/) - @a.should == [:pub] + it "produces a Proc with arity -2" do + pr = :to_s.to_proc + pr.arity.should == -2 + end - @a = [] - c = Class.new(&body) - o = c.new - o.instance_variable_set(:@a, []) - o.tap(&:pub) - proc{tap(&:pro)}.should raise_error(NoMethodError, /protected method `pro' called/) - proc{o.tap(&:pri)}.should raise_error(NoMethodError, /private method `pri' called/) - o.a.should == [:pub] + it "produces a Proc that always returns [[:req], [:rest]] for #parameters" do + pr = :to_s.to_proc + pr.parameters.should == [[:req], [:rest]] end end diff --git a/spec/ruby/core/thread/backtrace/limit_spec.rb b/spec/ruby/core/thread/backtrace/limit_spec.rb deleted file mode 100644 index 26a87a806c..0000000000 --- a/spec/ruby/core/thread/backtrace/limit_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative '../../../spec_helper' - -ruby_version_is "3.1" do - describe "Thread::Backtrace.limit" do - it "returns maximum backtrace length set by --backtrace-limit command-line option" do - out = ruby_exe("print Thread::Backtrace.limit", options: "--backtrace-limit=2") - out.should == "2" - end - - it "returns -1 when --backtrace-limit command-line option is not set" do - out = ruby_exe("print Thread::Backtrace.limit") - out.should == "-1" - end - end -end diff --git a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb index e35e1fc0b4..4136f09348 100644 --- a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb +++ b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb @@ -17,15 +17,6 @@ describe 'Thread::Backtrace::Location#absolute_path' do end end - it 'returns the correct absolute path when using a relative main script path and changing CWD' do - script = fixture(__FILE__, 'subdir/absolute_path_main_chdir.rb') - sibling = fixture(__FILE__, 'subdir/sibling.rb') - subdir = File.dirname script - Dir.chdir(fixture(__FILE__)) do - ruby_exe('subdir/absolute_path_main_chdir.rb').should == "subdir/absolute_path_main_chdir.rb\n#{subdir}\n#{subdir}\n#{script}\n#{sibling}\n" - end - end - context "when used in eval with a given filename" do code = "caller_locations(0)[0].absolute_path" diff --git a/spec/ruby/core/thread/backtrace/location/fixtures/subdir/absolute_path_main_chdir.rb b/spec/ruby/core/thread/backtrace/location/fixtures/subdir/absolute_path_main_chdir.rb deleted file mode 100644 index 33c8fb36ef..0000000000 --- a/spec/ruby/core/thread/backtrace/location/fixtures/subdir/absolute_path_main_chdir.rb +++ /dev/null @@ -1,11 +0,0 @@ -puts __FILE__ -puts __dir__ -Dir.chdir __dir__ - -# Check __dir__ is still correct after chdir -puts __dir__ - -puts caller_locations(0)[0].absolute_path - -# require_relative also needs to know the absolute path of the current file so we test it here too -require_relative 'sibling' diff --git a/spec/ruby/core/thread/backtrace/location/fixtures/subdir/sibling.rb b/spec/ruby/core/thread/backtrace/location/fixtures/subdir/sibling.rb deleted file mode 100644 index 2a854ddccd..0000000000 --- a/spec/ruby/core/thread/backtrace/location/fixtures/subdir/sibling.rb +++ /dev/null @@ -1 +0,0 @@ -puts __FILE__ diff --git a/spec/ruby/core/thread/backtrace/location/path_spec.rb b/spec/ruby/core/thread/backtrace/location/path_spec.rb index 75f76833a9..7863c055d3 100644 --- a/spec/ruby/core/thread/backtrace/location/path_spec.rb +++ b/spec/ruby/core/thread/backtrace/location/path_spec.rb @@ -41,7 +41,7 @@ describe 'Thread::Backtrace::Location#path' do context 'when using a relative script path' do it 'returns a path relative to the working directory' do path = 'fixtures/main.rb' - directory = __dir__ + directory = File.dirname(__FILE__) Dir.chdir(directory) { ruby_exe(path) }.should == path diff --git a/spec/ruby/core/thread/backtrace_locations_spec.rb b/spec/ruby/core/thread/backtrace_locations_spec.rb index c970ae023b..237941c214 100644 --- a/spec/ruby/core/thread/backtrace_locations_spec.rb +++ b/spec/ruby/core/thread/backtrace_locations_spec.rb @@ -49,10 +49,12 @@ describe "Thread#backtrace_locations" do locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s) 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..)")] + 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 end it "returns nil if omitting more locations than available" do diff --git a/spec/ruby/core/thread/each_caller_location_spec.rb b/spec/ruby/core/thread/each_caller_location_spec.rb deleted file mode 100644 index dbece06cd8..0000000000 --- a/spec/ruby/core/thread/each_caller_location_spec.rb +++ /dev/null @@ -1,49 +0,0 @@ -require_relative '../../spec_helper' - -describe "Thread.each_caller_location" do - ruby_version_is "3.2" do - it "iterates through the current execution stack and matches caller_locations content and type" do - ScratchPad.record [] - Thread.each_caller_location { |l| ScratchPad << l; } - - ScratchPad.recorded.map(&:to_s).should == caller_locations.map(&:to_s) - ScratchPad.recorded[0].should be_kind_of(Thread::Backtrace::Location) - end - - it "returns subset of 'Thread.to_enum(:each_caller_location)' locations" do - ar = [] - ecl = Thread.each_caller_location { |x| ar << x } - - (ar.map(&:to_s) - Thread.to_enum(:each_caller_location).to_a.map(&:to_s)).should.empty? - end - - it "stops the backtrace iteration if 'break' occurs" do - i = 0 - ar = [] - ecl = Thread.each_caller_location do |x| - ar << x - i += 1 - break x if i == 2 - end - - ar.map(&:to_s).should == caller_locations(1, 2).map(&:to_s) - ecl.should be_kind_of(Thread::Backtrace::Location) - end - - it "returns nil" do - Thread.each_caller_location {}.should == nil - end - - it "raises LocalJumpError when called without a block" do - -> { - Thread.each_caller_location - }.should raise_error(LocalJumpError, "no block given") - end - - it "doesn't accept positional and keyword arguments" do - -> { - Thread.each_caller_location(12, foo: 10) {} - }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)") - end - end -end diff --git a/spec/ruby/core/thread/exclusive_spec.rb b/spec/ruby/core/thread/exclusive_spec.rb new file mode 100644 index 0000000000..37c4b19d1a --- /dev/null +++ b/spec/ruby/core/thread/exclusive_spec.rb @@ -0,0 +1,49 @@ +require_relative '../../spec_helper' + +ruby_version_is ''...'3.0' do + describe "Thread.exclusive" do + before :each do + ScratchPad.clear + $VERBOSE, @verbose = nil, $VERBOSE + end + + after :each do + $VERBOSE = @verbose + end + + it "yields to the block" do + Thread.exclusive { ScratchPad.record true } + ScratchPad.recorded.should == true + end + + it "returns the result of yielding" do + Thread.exclusive { :result }.should == :result + end + + it "blocks the caller if another thread is also in an exclusive block" do + m = Mutex.new + q1 = Queue.new + q2 = Queue.new + + t = Thread.new { + Thread.exclusive { + q1.push :ready + q2.pop + } + } + + q1.pop.should == :ready + + -> { Thread.exclusive { } }.should block_caller + + q2.push :done + t.join + end + + it "is not recursive" do + Thread.exclusive do + -> { Thread.exclusive { } }.should raise_error(ThreadError) + end + end + end +end diff --git a/spec/ruby/core/thread/ignore_deadlock_spec.rb b/spec/ruby/core/thread/ignore_deadlock_spec.rb index b48bc9f9b0..53cc2a7f5b 100644 --- a/spec/ruby/core/thread/ignore_deadlock_spec.rb +++ b/spec/ruby/core/thread/ignore_deadlock_spec.rb @@ -1,19 +1,21 @@ require_relative '../../spec_helper' -describe "Thread.ignore_deadlock" do - it "returns false by default" do - Thread.ignore_deadlock.should == false +ruby_version_is "3.0" do + describe "Thread.ignore_deadlock" do + it "returns false by default" do + Thread.ignore_deadlock.should == false + end end -end -describe "Thread.ignore_deadlock=" do - it "changes the value of Thread.ignore_deadlock" do - ignore_deadlock = Thread.ignore_deadlock - Thread.ignore_deadlock = true - begin - Thread.ignore_deadlock.should == true - ensure - Thread.ignore_deadlock = ignore_deadlock + describe "Thread.ignore_deadlock=" do + it "changes the value of Thread.ignore_deadlock" do + ignore_deadlock = Thread.ignore_deadlock + Thread.ignore_deadlock = true + begin + Thread.ignore_deadlock.should == true + ensure + Thread.ignore_deadlock = ignore_deadlock + end end end end diff --git a/spec/ruby/core/thread/kill_spec.rb b/spec/ruby/core/thread/kill_spec.rb index 4b62c686c7..f932bf5232 100644 --- a/spec/ruby/core/thread/kill_spec.rb +++ b/spec/ruby/core/thread/kill_spec.rb @@ -9,6 +9,10 @@ platform_is_not :mingw do it_behaves_like :thread_exit, :kill end + describe "Thread#kill!" do + it "needs to be reviewed for spec completeness" + end + describe "Thread.kill" do it "causes the given thread to exit" do thread = Thread.new { sleep } diff --git a/spec/ruby/core/thread/native_thread_id_spec.rb b/spec/ruby/core/thread/native_thread_id_spec.rb deleted file mode 100644 index 17a08c8a15..0000000000 --- a/spec/ruby/core/thread/native_thread_id_spec.rb +++ /dev/null @@ -1,37 +0,0 @@ -require_relative '../../spec_helper' - -ruby_version_is "3.1" do - platform_is :linux, :darwin, :windows, :freebsd do - describe "Thread#native_thread_id" do - it "returns an integer when the thread is alive" do - Thread.current.native_thread_id.should be_kind_of(Integer) - end - - it "returns nil when the thread is not running" do - t = Thread.new {} - t.join - t.native_thread_id.should == nil - end - - it "each thread has different native thread id" do - t = Thread.new { sleep } - Thread.pass until t.stop? - main_thread_id = Thread.current.native_thread_id - t_thread_id = t.native_thread_id - - if ruby_version_is "3.3" - # native_thread_id can be nil on a M:N scheduler - t_thread_id.should be_kind_of(Integer) if t_thread_id != nil - else - t_thread_id.should be_kind_of(Integer) - end - - main_thread_id.should_not == t_thread_id - - t.run - t.join - t.native_thread_id.should == nil - end - end - end -end diff --git a/spec/ruby/core/thread/raise_spec.rb b/spec/ruby/core/thread/raise_spec.rb index 49323cf270..27de3cc627 100644 --- a/spec/ruby/core/thread/raise_spec.rb +++ b/spec/ruby/core/thread/raise_spec.rb @@ -102,30 +102,6 @@ describe "Thread#raise on a sleeping thread" do raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:") end end - - it "calls #exception in both the caller and in the target thread" do - cls = Class.new(Exception) do - attr_accessor :log - def initialize(*args) - @log = [] # This is shared because the super #exception uses a shallow clone - super - end - - def exception(*args) - @log << [self, Thread.current, args] - super - end - end - exc = cls.new - - @thr.raise exc, "Thread#raise #exception spec" - @thr.join - ScratchPad.recorded.should.is_a?(cls) - exc.log.should == [ - [exc, Thread.current, ["Thread#raise #exception spec"]], - [ScratchPad.recorded, @thr, []] - ] - end end describe "Thread#raise on a running thread" do diff --git a/spec/ruby/core/thread/report_on_exception_spec.rb b/spec/ruby/core/thread/report_on_exception_spec.rb index ab0af0972e..bf50a167df 100644 --- a/spec/ruby/core/thread/report_on_exception_spec.rb +++ b/spec/ruby/core/thread/report_on_exception_spec.rb @@ -60,55 +60,6 @@ describe "Thread#report_on_exception=" do t.join }.should raise_error(RuntimeError, "Thread#report_on_exception specs") end - - 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 (4 levels) in <top (required)>' -ERR - - -> { - t.join - }.should raise_error(RuntimeError, "Thread#report_on_exception specs backtrace order") - 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 13e8832684..40dc478947 100644 --- a/spec/ruby/core/thread/shared/exit.rb +++ b/spec/ruby/core/thread/shared/exit.rb @@ -66,26 +66,6 @@ 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 @@ -93,7 +73,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 @@ -113,25 +93,6 @@ describe :thread_exit, shared: true do ScratchPad.recorded.should == nil end - it "kills other fibers of that thread without running their ensure clauses" do - t = Thread.new do - f = Fiber.new do - ScratchPad.record :fiber_resumed - begin - Fiber.yield - ensure - ScratchPad.record :fiber_ensure - end - end - f.resume - sleep - end - Thread.pass until t.stop? - t.send(@method) - t.join - ScratchPad.recorded.should == :fiber_resumed - end - # This spec is a mess. It fails randomly, it hangs on MRI, it needs to be removed quarantine! do it "killing dying running does nothing" do diff --git a/spec/ruby/core/thread/shared/to_s.rb b/spec/ruby/core/thread/shared/to_s.rb index 43640deb33..45c04af627 100644 --- a/spec/ruby/core/thread/shared/to_s.rb +++ b/spec/ruby/core/thread/shared/to_s.rb @@ -1,10 +1,12 @@ 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:([^ ]*?) #{Regexp.escape __FILE__}:#{line} \w+>$/ + thread.send(@method).should =~ /^#<Thread:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{line} \w+>$/ end it "has a binary encoding" do diff --git a/spec/ruby/core/time/at_spec.rb b/spec/ruby/core/time/at_spec.rb index 0459589f01..2cc46ab8c9 100644 --- a/spec/ruby/core/time/at_spec.rb +++ b/spec/ruby/core/time/at_spec.rb @@ -251,22 +251,6 @@ describe "Time.at" do time.to_i.should == @epoch_time end - it "could be UTC offset as a 'UTC' String" do - time = Time.at(@epoch_time, in: "UTC") - - time.utc_offset.should == 0 - time.zone.should == "UTC" - time.to_i.should == @epoch_time - end - - it "could be UTC offset as a military zone A-Z" do - time = Time.at(@epoch_time, in: "B") - - time.utc_offset.should == 3600 * 2 - time.zone.should == nil - time.to_i.should == @epoch_time - end - it "could be a timezone object" do zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo") time = Time.at(@epoch_time, in: zone) @@ -282,10 +266,5 @@ describe "Time.at" do time.zone.should == zone time.to_i.should == @epoch_time end - - it "raises ArgumentError if format is invalid" do - -> { Time.at(@epoch_time, in: "+09:99") }.should raise_error(ArgumentError) - -> { Time.at(@epoch_time, in: "ABC") }.should raise_error(ArgumentError) - end end end diff --git a/spec/ruby/core/time/ceil_spec.rb b/spec/ruby/core/time/ceil_spec.rb index 9d624a1ed0..86029554db 100644 --- a/spec/ruby/core/time/ceil_spec.rb +++ b/spec/ruby/core/time/ceil_spec.rb @@ -1,44 +1,46 @@ require_relative '../../spec_helper' -describe "Time#ceil" do - before do - @time = Time.utc(2010, 3, 30, 5, 43, "25.0123456789".to_r) - end +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 + 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 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 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 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 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 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 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 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 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 "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 "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 "copies own timezone to the returning value" do - @time.zone.should == @time.ceil.zone + it "copies own timezone to the returning value" do + @time.zone.should == @time.ceil.zone - time = with_timezone "JST-9" do - Time.at 0, 1 - end + time = with_timezone "JST-9" do + Time.at 0, 1 + end - time.zone.should == time.ceil.zone + time.zone.should == time.ceil.zone + end end end diff --git a/spec/ruby/core/time/deconstruct_keys_spec.rb b/spec/ruby/core/time/deconstruct_keys_spec.rb deleted file mode 100644 index fbb0ec2164..0000000000 --- a/spec/ruby/core/time/deconstruct_keys_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -require_relative '../../spec_helper' - -ruby_version_is "3.2" do - describe "Time#deconstruct_keys" do - it "returns whole hash for nil as an argument" do - d = Time.utc(2022, 10, 5, 13, 30) - res = { year: 2022, month: 10, day: 5, yday: 278, wday: 3, hour: 13, - min: 30, sec: 0, subsec: 0, dst: false, zone: "UTC" } - d.deconstruct_keys(nil).should == res - end - - it "returns only specified keys" do - d = Time.utc(2022, 10, 5, 13, 39) - d.deconstruct_keys([:zone, :subsec]).should == { zone: "UTC", subsec: 0 } - end - - it "requires one argument" do - -> { - Time.new(2022, 10, 5, 13, 30).deconstruct_keys - }.should raise_error(ArgumentError) - end - - it "it raises error when argument is neither nil nor array" do - d = Time.new(2022, 10, 5, 13, 30) - - -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)") - -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)") - -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)") - -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)") - end - - it "returns {} when passed []" do - Time.new(2022, 10, 5, 13, 30).deconstruct_keys([]).should == {} - end - - it "ignores non-Symbol keys" do - Time.new(2022, 10, 5, 13, 30).deconstruct_keys(['year', []]).should == {} - end - - it "ignores not existing Symbol keys" do - Time.new(2022, 10, 5, 13, 30).deconstruct_keys([:year, :a]).should == { year: 2022 } - end - end -end diff --git a/spec/ruby/core/time/floor_spec.rb b/spec/ruby/core/time/floor_spec.rb index b0003469c9..a19585b787 100644 --- a/spec/ruby/core/time/floor_spec.rb +++ b/spec/ruby/core/time/floor_spec.rb @@ -1,36 +1,38 @@ require_relative '../../spec_helper' -describe "Time#floor" do - before do - @time = Time.utc(2010, 3, 30, 5, 43, "25.123456789".to_r) - end +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 + 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 0 decimal places with an explicit argument" do - @time.floor(0).should == Time.utc(2010, 3, 30, 5, 43, 25.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 "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 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 "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 "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 "copies own timezone to the returning value" do - @time.zone.should == @time.floor.zone + it "copies own timezone to the returning value" do + @time.zone.should == @time.floor.zone - time = with_timezone "JST-9" do - Time.at 0, 1 - end + time = with_timezone "JST-9" do + Time.at 0, 1 + end - time.zone.should == time.floor.zone + time.zone.should == time.floor.zone + end end end diff --git a/spec/ruby/core/time/inspect_spec.rb b/spec/ruby/core/time/inspect_spec.rb index c3a4519a24..6f1b2e3ef1 100644 --- a/spec/ruby/core/time/inspect_spec.rb +++ b/spec/ruby/core/time/inspect_spec.rb @@ -4,30 +4,32 @@ require_relative 'shared/inspect' describe "Time#inspect" do it_behaves_like :inspect, :inspect - 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 + 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 "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" + 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 end diff --git a/spec/ruby/core/time/localtime_spec.rb b/spec/ruby/core/time/localtime_spec.rb index 609b6532a1..2975e112d0 100644 --- a/spec/ruby/core/time/localtime_spec.rb +++ b/spec/ruby/core/time/localtime_spec.rb @@ -29,10 +29,10 @@ describe "Time#localtime" do time.localtime.should equal(time) end - it "raises a FrozenError if the time has a different time zone" do + it "raises a RuntimeError if the time has a different time zone" do time = Time.gm(2007, 1, 9, 12, 0, 0) time.freeze - -> { time.localtime }.should raise_error(FrozenError) + -> { time.localtime }.should raise_error(RuntimeError) end end @@ -79,18 +79,6 @@ describe "Time#localtime" do t.utc_offset.should == -3600 end - it "returns a Time with a UTC offset specified as UTC" do - t = Time.new(2007, 1, 9, 12, 0, 0, 3600) - t.localtime("UTC") - t.utc_offset.should == 0 - end - - it "returns a Time with a UTC offset specified as A-Z military zone" do - t = Time.new(2007, 1, 9, 12, 0, 0, 3600) - t.localtime("B") - t.utc_offset.should == 3600 * 2 - end - platform_is_not :windows do it "changes the timezone according to the set one" do t = Time.new(2005, 2, 27, 22, 50, 0, -3600) diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb index 18d7396269..09b4d03a44 100644 --- a/spec/ruby/core/time/new_spec.rb +++ b/spec/ruby/core/time/new_spec.rb @@ -58,32 +58,6 @@ describe "Time.new with a utc_offset argument" do Time.new(2000, 1, 1, 0, 0, 0, "-04:10:43").utc_offset.should == -15043 end - ruby_bug '#13669', ''...'3.1' do - it "returns a Time with a UTC offset specified as +HH" do - Time.new(2000, 1, 1, 0, 0, 0, "+05").utc_offset.should == 3600 * 5 - end - - it "returns a Time with a UTC offset specified as -HH" do - Time.new(2000, 1, 1, 0, 0, 0, "-05").utc_offset.should == -3600 * 5 - end - - it "returns a Time with a UTC offset specified as +HHMM" do - Time.new(2000, 1, 1, 0, 0, 0, "+0530").utc_offset.should == 19800 - end - - it "returns a Time with a UTC offset specified as -HHMM" do - Time.new(2000, 1, 1, 0, 0, 0, "-0530").utc_offset.should == -19800 - end - - it "returns a Time with a UTC offset specified as +HHMMSS" do - Time.new(2000, 1, 1, 0, 0, 0, "+053037").utc_offset.should == 19837 - end - - it "returns a Time with a UTC offset specified as -HHMMSS" do - Time.new(2000, 1, 1, 0, 0, 0, "-053037").utc_offset.should == -19837 - end - end - describe "with an argument that responds to #to_str" do it "coerces using #to_str" do o = mock('string') @@ -92,57 +66,6 @@ describe "Time.new with a utc_offset argument" do end end - it "returns a Time with UTC offset specified as UTC" do - Time.new(2000, 1, 1, 0, 0, 0, "UTC").utc_offset.should == 0 - end - - it "returns a Time with UTC offset specified as a single letter military timezone" do - [ - ["A", 3600], - ["B", 3600 * 2], - ["C", 3600 * 3], - ["D", 3600 * 4], - ["E", 3600 * 5], - ["F", 3600 * 6], - ["G", 3600 * 7], - ["H", 3600 * 8], - ["I", 3600 * 9], - # J is not supported - ["K", 3600 * 10], - ["L", 3600 * 11], - ["M", 3600 * 12], - ["N", 3600 * -1], - ["O", 3600 * -2], - ["P", 3600 * -3], - ["Q", 3600 * -4], - ["R", 3600 * -5], - ["S", 3600 * -6], - ["T", 3600 * -7], - ["U", 3600 * -8], - ["V", 3600 * -9], - ["W", 3600 * -10], - ["X", 3600 * -11], - ["Y", 3600 * -12], - ["Z", 0] - ].each do |letter, offset| - Time.new(2000, 1, 1, 0, 0, 0, letter).utc_offset.should == offset - end - end - - ruby_version_is ""..."3.1" do - it "raises ArgumentError if the string argument is J" do - message = '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset' - -> { Time.new(2000, 1, 1, 0, 0, 0, "J") }.should raise_error(ArgumentError, message) - end - end - - ruby_version_is "3.1" do - it "raises ArgumentError if the string argument is J" do - message = '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: J' - -> { Time.new(2000, 1, 1, 0, 0, 0, "J") }.should raise_error(ArgumentError, message) - end - end - it "returns a local Time if the argument is nil" do with_timezone("PST", -8) do t = Time.new(2000, 1, 1, 0, 0, 0, nil) @@ -170,12 +93,7 @@ describe "Time.new with a utc_offset argument" do end it "raises ArgumentError if the String argument is not in an ASCII-compatible encoding" do - # Don't check exception message - it was changed in previous CRuby versions: - # - "string contains null byte" - # - '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset' - -> { - Time.new(2000, 1, 1, 0, 0, 0, "-04:10".encode("UTF-16LE")) - }.should raise_error(ArgumentError) + -> { Time.new(2000, 1, 1, 0, 0, 0, "-04:10".encode("UTF-16LE")) }.should raise_error(ArgumentError) end it "raises ArgumentError if the argument represents a value less than or equal to -86400 seconds" do @@ -188,9 +106,19 @@ describe "Time.new with a utc_offset argument" do -> { Time.new(2000, 1, 1, 0, 0, 0, 86400) }.should raise_error(ArgumentError) end + it "raises ArgumentError if the seconds argument is negative" do + -> { Time.new(2000, 1, 1, 0, 0, -1) }.should raise_error(ArgumentError) + end + it "raises ArgumentError if the utc_offset argument is greater than or equal to 10e9" do -> { Time.new(2000, 1, 1, 0, 0, 0, 1000000000) }.should raise_error(ArgumentError) end + + it "raises ArgumentError if the month is greater than 12" do + # For some reason MRI uses a different message for month in 13-15 and month>=16 + -> { Time.new(2000, 13, 1, 0, 0, 0, "+01:00") }.should raise_error(ArgumentError, /(mon|argument) out of range/) + -> { Time.new(2000, 16, 1, 0, 0, 0, "+01:00") }.should raise_error(ArgumentError, "argument out of range") + end end describe "Time.new with a timezone argument" do @@ -200,8 +128,10 @@ describe "Time.new with a timezone argument" do time.zone.should == zone time.utc_offset.should == 5*3600+30*60 - time.wday.should == 6 - time.yday.should == 1 + ruby_version_is "3.0" do + time.wday.should == 6 + time.yday.should == 1 + end end it "accepts timezone argument that must have #local_to_utc and #utc_to_local methods" do @@ -402,245 +332,4 @@ describe "Time.new with a timezone argument" do end end end - - ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/17485 - describe ":in keyword argument" do - it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do - time = Time.new(2000, 1, 1, 12, 0, 0, in: "+05:00") - - time.utc_offset.should == 5*60*60 - time.zone.should == nil - - time = Time.new(2000, 1, 1, 12, 0, 0, in: "-09:00") - - time.utc_offset.should == -9*60*60 - time.zone.should == nil - end - - it "could be UTC offset as a number of seconds" do - time = Time.new(2000, 1, 1, 12, 0, 0, in: 5*60*60) - - time.utc_offset.should == 5*60*60 - time.zone.should == nil - - time = Time.new(2000, 1, 1, 12, 0, 0, in: -9*60*60) - - time.utc_offset.should == -9*60*60 - time.zone.should == nil - end - - it "returns a Time with UTC offset specified as a single letter military timezone" do - Time.new(2000, 1, 1, 0, 0, 0, in: "W").utc_offset.should == 3600 * -10 - end - - it "could be a timezone object" do - zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo") - time = Time.new(2000, 1, 1, 12, 0, 0, in: zone) - - time.utc_offset.should == 5*3600+30*60 - time.zone.should == zone - - zone = TimeSpecs::TimezoneWithName.new(name: "PST") - time = Time.new(2000, 1, 1, 12, 0, 0, in: zone) - - time.utc_offset.should == -9*60*60 - time.zone.should == zone - end - - it "allows omitting minor arguments" do - Time.new(2000, 1, 1, 12, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 1, "+05:00") - Time.new(2000, 1, 1, 12, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 0, "+05:00") - Time.new(2000, 1, 1, 12, in: "+05:00").should == Time.new(2000, 1, 1, 12, 0, 0, "+05:00") - Time.new(2000, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00") - Time.new(2000, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00") - Time.new(2000, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00") - Time.new(in: "+05:00").should be_close(Time.now.getlocal("+05:00"), TIME_TOLERANCE) - end - - it "converts to a provided timezone if all the positional arguments are omitted" do - Time.new(in: "+05:00").utc_offset.should == 5*3600 - end - - it "raises ArgumentError if format is invalid" do - -> { Time.new(2000, 1, 1, 12, 0, 0, in: "+09:99") }.should raise_error(ArgumentError) - -> { Time.new(2000, 1, 1, 12, 0, 0, in: "ABC") }.should raise_error(ArgumentError) - end - - it "raises ArgumentError if two offset arguments are given" do - -> { - Time.new(2000, 1, 1, 12, 0, 0, "+05:00", in: "+05:00") - }.should raise_error(ArgumentError, "timezone argument given as positional and keyword arguments") - end - end - end - - ruby_version_is "3.2" do - describe "Time.new with a String argument" do - it "parses an ISO-8601 like format" do - t = Time.utc(2020, 12, 24, 15, 56, 17) - - Time.new("2020-12-24T15:56:17Z").should == t - Time.new("2020-12-25 00:56:17 +09:00").should == t - Time.new("2020-12-25 00:57:47 +09:01:30").should == t - Time.new("2020-12-25 00:56:17 +0900").should == t - Time.new("2020-12-25 00:57:47 +090130").should == t - Time.new("2020-12-25T00:56:17+09:00").should == t - end - - it "accepts precision keyword argument and truncates specified digits of sub-second part" do - Time.new("2021-12-25 00:00:00.123456789876 +09:00").subsec.should == 0.123456789r - Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: nil).subsec.should == 0.123456789876r - Time.new("2021-12-25 00:00:00 +09:00", precision: 0).subsec.should == 0 - Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: -1).subsec.should == 0.123456789876r - end - - it "returns Time in local timezone if not provided in the String argument" do - Time.new("2021-12-25 00:00:00").zone.should == Time.new(2021, 12, 25).zone - Time.new("2021-12-25 00:00:00").utc_offset.should == Time.new(2021, 12, 25).utc_offset - end - - it "returns Time in timezone specified in the String argument" do - Time.new("2021-12-25 00:00:00 +05:00").to_s.should == "2021-12-25 00:00:00 +0500" - end - - it "returns Time in timezone specified in the String argument even if the in keyword argument provided" do - Time.new("2021-12-25 00:00:00 +09:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 +0900" - end - - it "returns Time in timezone specified with in keyword argument if timezone isn't provided in the String argument" do - Time.new("2021-12-25 00:00:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 -0100" - end - - it "converts precision keyword argument into Integer if is not nil" do - obj = Object.new - def obj.to_int; 3; end - - Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 1.2).subsec.should == 0.1r - Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: obj).subsec.should == 0.123r - Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 3r).subsec.should == 0.123r - end - - ruby_version_is ""..."3.3" do - it "raise TypeError is can't convert precision keyword argument into Integer" do - -> { - Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: "") - }.should raise_error(TypeError, "no implicit conversion from string") - end - end - - ruby_version_is "3.3" do - it "raise TypeError is can't convert precision keyword argument into Integer" do - -> { - Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: "") - }.should raise_error(TypeError, "no implicit conversion of String into Integer") - end - end - - it "raises ArgumentError if part of time string is missing" do - -> { - Time.new("2020-12-25 00:56 +09:00") - }.should raise_error(ArgumentError, "missing sec part: 00:56 ") - - -> { - Time.new("2020-12-25 00 +09:00") - }.should raise_error(ArgumentError, "missing min part: 00 ") - end - - it "raises ArgumentError if subsecond is missing after dot" do - -> { - Time.new("2020-12-25 00:56:17. +0900") - }.should raise_error(ArgumentError, "subsecond expected after dot: 00:56:17. ") - end - - it "raises ArgumentError if String argument is not in the supported format" do - -> { - Time.new("021-12-25 00:00:00.123456 +09:00") - }.should raise_error(ArgumentError, "year must be 4 or more digits: 021") - - -> { - Time.new("2020-012-25 00:56:17 +0900") - }.should raise_error(ArgumentError, "two digits mon is expected after `-': -012-25 00:") - - -> { - Time.new("2020-2-25 00:56:17 +0900") - }.should raise_error(ArgumentError, "two digits mon is expected after `-': -2-25 00:56") - - -> { - Time.new("2020-12-215 00:56:17 +0900") - }.should raise_error(ArgumentError, "two digits mday is expected after `-': -215 00:56:") - - -> { - Time.new("2020-12-25 000:56:17 +0900") - }.should raise_error(ArgumentError, "two digits hour is expected: 000:56:17 ") - - -> { - Time.new("2020-12-25 0:56:17 +0900") - }.should raise_error(ArgumentError, "two digits hour is expected: 0:56:17 +0") - - -> { - Time.new("2020-12-25 00:516:17 +0900") - }.should raise_error(ArgumentError, "two digits min is expected after `:': :516:17 +09") - - -> { - Time.new("2020-12-25 00:6:17 +0900") - }.should raise_error(ArgumentError, "two digits min is expected after `:': :6:17 +0900") - - -> { - Time.new("2020-12-25 00:56:137 +0900") - }.should raise_error(ArgumentError, "two digits sec is expected after `:': :137 +0900") - - -> { - Time.new("2020-12-25 00:56:7 +0900") - }.should raise_error(ArgumentError, "two digits sec is expected after `:': :7 +0900") - - -> { - Time.new("2020-12-25 00:56. +0900") - }.should raise_error(ArgumentError, "fraction min is not supported: 00:56.") - - -> { - Time.new("2020-12-25 00. +0900") - }.should raise_error(ArgumentError, "fraction hour is not supported: 00.") - end - - it "raises ArgumentError if date/time parts values are not valid" do - -> { - Time.new("2020-13-25 00:56:17 +09:00") - }.should raise_error(ArgumentError, "mon out of range") - - -> { - Time.new("2020-12-32 00:56:17 +09:00") - }.should raise_error(ArgumentError, "mday out of range") - - -> { - Time.new("2020-12-25 25:56:17 +09:00") - }.should raise_error(ArgumentError, "hour out of range") - - -> { - Time.new("2020-12-25 00:61:17 +09:00") - }.should raise_error(ArgumentError, "min out of range") - - -> { - Time.new("2020-12-25 00:56:61 +09:00") - }.should raise_error(ArgumentError, "sec out of range") - - -> { - Time.new("2020-12-25 00:56:17 +23:59:60") - }.should raise_error(ArgumentError, "utc_offset out of range") - - -> { - Time.new("2020-12-25 00:56:17 +24:00") - }.should raise_error(ArgumentError, "utc_offset out of range") - - -> { - Time.new("2020-12-25 00:56:17 +23:61") - }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +23:61') - end - - it "raises ArgumentError if string has not ascii-compatible encoding" do - -> { - Time.new("2021-11-31 00:00:60 +09:00".encode("utf-32le")) - }.should raise_error(ArgumentError, "time string should have ASCII compatible encoding") - end - end - end end diff --git a/spec/ruby/core/time/now_spec.rb b/spec/ruby/core/time/now_spec.rb index d47f00723e..7dc7951996 100644 --- a/spec/ruby/core/time/now_spec.rb +++ b/spec/ruby/core/time/now_spec.rb @@ -3,55 +3,4 @@ require_relative 'shared/now' describe "Time.now" do it_behaves_like :time_now, :now - - ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/17485 - describe ":in keyword argument" do - it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do - time = Time.now(in: "+05:00") - - time.utc_offset.should == 5*60*60 - time.zone.should == nil - - time = Time.now(in: "-09:00") - - time.utc_offset.should == -9*60*60 - time.zone.should == nil - end - - it "could be UTC offset as a number of seconds" do - time = Time.now(in: 5*60*60) - - time.utc_offset.should == 5*60*60 - time.zone.should == nil - - time = Time.now(in: -9*60*60) - - time.utc_offset.should == -9*60*60 - time.zone.should == nil - end - - it "returns a Time with UTC offset specified as a single letter military timezone" do - Time.now(in: "W").utc_offset.should == 3600 * -10 - end - - it "could be a timezone object" do - zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo") - time = Time.now(in: zone) - - time.utc_offset.should == 5*3600+30*60 - time.zone.should == zone - - zone = TimeSpecs::TimezoneWithName.new(name: "PST") - time = Time.now(in: zone) - - time.utc_offset.should == -9*60*60 - time.zone.should == zone - end - - it "raises ArgumentError if format is invalid" do - -> { Time.now(in: "+09:99") }.should raise_error(ArgumentError) - -> { Time.now(in: "ABC") }.should raise_error(ArgumentError) - end - end - end end diff --git a/spec/ruby/core/time/shared/gmtime.rb b/spec/ruby/core/time/shared/gmtime.rb index bae19da462..5ed64c2ab6 100644 --- a/spec/ruby/core/time/shared/gmtime.rb +++ b/spec/ruby/core/time/shared/gmtime.rb @@ -22,11 +22,11 @@ describe :time_gmtime, shared: true do time.send(@method).should equal(time) end - it "raises a FrozenError if the time is not UTC" do + it "raises a RuntimeError if the time is not UTC" do with_timezone("CST", -6) do time = Time.now time.freeze - -> { time.send(@method) }.should raise_error(FrozenError) + -> { time.send(@method) }.should raise_error(RuntimeError) end end end diff --git a/spec/ruby/core/time/shared/local.rb b/spec/ruby/core/time/shared/local.rb index 068e314999..c4aa7a7ea9 100644 --- a/spec/ruby/core/time/shared/local.rb +++ b/spec/ruby/core/time/shared/local.rb @@ -7,10 +7,12 @@ describe :time_local, shared: true do end platform_is_not :windows do - it "uses the 'CET' timezone with TZ=Europe/Amsterdam in 1970" do - with_timezone("Europe/Amsterdam") do - Time.send(@method, 1970, 5, 16).to_a.should == - [0, 0, 0, 16, 5, 1970, 6, 136, false, "CET"] + describe "timezone changes" do + it "correctly adjusts the timezone change to 'CET' on 'Europe/Amsterdam'" do + with_timezone("Europe/Amsterdam") do + Time.send(@method, 1970, 5, 16).to_a.should == + [0, 0, 0, 16, 5, 1970, 6, 136, false, "CET"] + end end end end @@ -39,4 +41,5 @@ describe :time_local_10_arg, shared: true do end end end + end diff --git a/spec/ruby/core/time/shared/time_params.rb b/spec/ruby/core/time/shared/time_params.rb index b6a6c88c8e..63d0dbc120 100644 --- a/spec/ruby/core/time/shared/time_params.rb +++ b/spec/ruby/core/time/shared/time_params.rb @@ -145,10 +145,9 @@ describe :time_params, shared: true do end it "raises an ArgumentError for out of range month" do - # For some reason MRI uses a different message for month in 13-15 and month>=16 -> { - Time.send(@method, 2008, 16, 31, 23, 59, 59) - }.should raise_error(ArgumentError, /(mon|argument) out of range/) + Time.send(@method, 2008, 13, 31, 23, 59, 59) + }.should raise_error(ArgumentError) end it "raises an ArgumentError for out of range day" do @@ -170,13 +169,9 @@ describe :time_params, shared: true do end it "raises an ArgumentError for out of range second" do - # For some reason MRI uses different messages for seconds 61-63 and seconds >= 64 -> { Time.send(@method, 2008, 12, 31, 23, 59, 61) - }.should raise_error(ArgumentError, /(sec|argument) out of range/) - -> { - Time.send(@method, 2008, 12, 31, 23, 59, -1) - }.should raise_error(ArgumentError, "argument out of range") + }.should raise_error(ArgumentError) end it "raises ArgumentError when given 9 arguments" do diff --git a/spec/ruby/core/time/strftime_spec.rb b/spec/ruby/core/time/strftime_spec.rb index 4cb300c916..1bd24b0538 100644 --- a/spec/ruby/core/time/strftime_spec.rb +++ b/spec/ruby/core/time/strftime_spec.rb @@ -49,45 +49,4 @@ describe "Time#strftime" do time = @new_time_with_offset[2012, 1, 1, 0, 0, 0, Rational(36645, 10)] time.strftime("%::z").should == "+01:01:05" end - - ruby_version_is "3.1" do - it "supports RFC 3339 UTC for unknown offset local time, -0000, as %-z" do - time = Time.gm(2022) - - time.strftime("%z").should == "+0000" - time.strftime("%-z").should == "-0000" - time.strftime("%-:z").should == "-00:00" - time.strftime("%-::z").should == "-00:00:00" - end - - it "applies '-' flag to UTC time" do - time = Time.utc(2022) - time.strftime("%-z").should == "-0000" - - time = Time.gm(2022) - time.strftime("%-z").should == "-0000" - - time = Time.new(2022, 1, 1, 0, 0, 0, "Z") - time.strftime("%-z").should == "-0000" - - time = Time.new(2022, 1, 1, 0, 0, 0, "-00:00") - time.strftime("%-z").should == "-0000" - - time = Time.new(2022, 1, 1, 0, 0, 0, "+03:00").utc - time.strftime("%-z").should == "-0000" - end - - it "ignores '-' flag for non-UTC time" do - time = Time.new(2022, 1, 1, 0, 0, 0, "+03:00") - time.strftime("%-z").should == "+0300" - end - - it "works correctly with width, _ and 0 flags, and :" do - Time.now.utc.strftime("%-_10z").should == " -000" - Time.now.utc.strftime("%-10z").should == "-000000000" - Time.now.utc.strftime("%-010:z").should == "-000000:00" - Time.now.utc.strftime("%-_10:z").should == " -0:00" - Time.now.utc.strftime("%-_10::z").should == " -0:00:00" - end - end end diff --git a/spec/ruby/core/time/succ_spec.rb b/spec/ruby/core/time/succ_spec.rb new file mode 100644 index 0000000000..e8249059d1 --- /dev/null +++ b/spec/ruby/core/time/succ_spec.rb @@ -0,0 +1,39 @@ +ruby_version_is ""..."3.0" do + require_relative '../../spec_helper' + require_relative 'fixtures/classes' + + describe "Time#succ" do + it "returns a new time one second later than time" do + suppress_warning { + @result = Time.at(100).succ + } + + @result.should == Time.at(101) + end + + it "returns a new instance" do + time = Time.at(100) + + suppress_warning { + @result = time.succ + } + + @result.should_not equal time + end + + it "is obsolete" do + -> { + Time.at(100).succ + }.should complain(/Time#succ is obsolete/) + end + + context "zone is a timezone object" do + it "preserves time zone" do + zone = TimeSpecs::Timezone.new(offset: (5*3600+30*60)) + time = Time.new(2012, 1, 1, 12, 0, 0, zone) - 1 + + time.zone.should == zone + end + end + end +end diff --git a/spec/ruby/core/time/utc_spec.rb b/spec/ruby/core/time/utc_spec.rb index 566509fd33..74c17a93d1 100644 --- a/spec/ruby/core/time/utc_spec.rb +++ b/spec/ruby/core/time/utc_spec.rb @@ -4,55 +4,8 @@ require_relative 'shared/gmtime' require_relative 'shared/time_params' describe "Time#utc?" do - it "returns true only if time represents a time in UTC (GMT)" do - Time.now.utc?.should == false - Time.now.utc.utc?.should == true - end - - it "treats time as UTC what was created in different ways" do - Time.now.utc.utc?.should == true - Time.now.gmtime.utc?.should == true - Time.now.getgm.utc?.should == true - Time.now.getutc.utc?.should == true - Time.utc(2022).utc?.should == true - end - - it "does treat time with 'UTC' offset as UTC" do - Time.new(2022, 1, 1, 0, 0, 0, "UTC").utc?.should == true - Time.now.localtime("UTC").utc?.should == true - Time.at(Time.now, in: 'UTC').utc?.should == true - - ruby_version_is "3.1" do - Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").utc?.should == true - Time.now(in: "UTC").utc?.should == true - end - end - - it "does treat time with Z offset as UTC" do - Time.new(2022, 1, 1, 0, 0, 0, "Z").utc?.should == true - Time.now.localtime("Z").utc?.should == true - Time.at(Time.now, in: 'Z').utc?.should == true - - ruby_version_is "3.1" do - Time.new(2022, 1, 1, 0, 0, 0, in: "Z").utc?.should == true - Time.now(in: "Z").utc?.should == true - end - end - - ruby_version_is "3.1" do - it "does treat time with -00:00 offset as UTC" do - Time.new(2022, 1, 1, 0, 0, 0, "-00:00").utc?.should == true - Time.now.localtime("-00:00").utc?.should == true - Time.at(Time.now, in: '-00:00').utc?.should == true - end - end - - it "does not treat time with +00:00 offset as UTC" do - Time.new(2022, 1, 1, 0, 0, 0, "+00:00").utc?.should == false - end - - it "does not treat time with 0 offset as UTC" do - Time.new(2022, 1, 1, 0, 0, 0, 0).utc?.should == false + it "returns true if time represents a time in UTC (GMT)" do + Time.now.should_not.utc? end end diff --git a/spec/ruby/core/time/zone_spec.rb b/spec/ruby/core/time/zone_spec.rb index 63c92602d1..907ccf9f4b 100644 --- a/spec/ruby/core/time/zone_spec.rb +++ b/spec/ruby/core/time/zone_spec.rb @@ -52,39 +52,14 @@ describe "Time#zone" do end it "doesn't raise errors for a Time with a fixed offset" do - Time.new(2001, 1, 1, 0, 0, 0, "+05:00").zone.should == nil + -> { + Time.new(2001, 1, 1, 0, 0, 0, "+05:00").zone + }.should_not raise_error end end it "returns UTC when called on a UTC time" do Time.now.utc.zone.should == "UTC" - Time.now.gmtime.zone.should == "UTC" - Time.now.getgm.zone.should == "UTC" - Time.now.getutc.zone.should == "UTC" - Time.utc(2022).zone.should == "UTC" - Time.new(2022, 1, 1, 0, 0, 0, "UTC").zone.should == "UTC" - Time.new(2022, 1, 1, 0, 0, 0, "Z").zone.should == "UTC" - Time.now.localtime("UTC").zone.should == "UTC" - Time.now.localtime("Z").zone.should == "UTC" - Time.at(Time.now, in: 'UTC').zone.should == "UTC" - Time.at(Time.now, in: 'Z').zone.should == "UTC" - - ruby_version_is "3.1" do - Time.new(2022, 1, 1, 0, 0, 0, "-00:00").zone.should == "UTC" - Time.now.localtime("-00:00").zone.should == "UTC" - Time.at(Time.now, in: '-00:00').zone.should == "UTC" - end - - ruby_version_is "3.1" do - Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").zone.should == "UTC" - Time.new(2022, 1, 1, 0, 0, 0, in: "Z").zone.should == "UTC" - - Time.now(in: 'UTC').zone.should == "UTC" - Time.now(in: 'Z').zone.should == "UTC" - - Time.at(Time.now, in: 'UTC').zone.should == "UTC" - Time.at(Time.now, in: 'Z').zone.should == "UTC" - end end platform_is_not :aix, :windows do diff --git a/spec/ruby/core/tracepoint/allow_reentry_spec.rb b/spec/ruby/core/tracepoint/allow_reentry_spec.rb deleted file mode 100644 index 6bff1bed76..0000000000 --- a/spec/ruby/core/tracepoint/allow_reentry_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/classes' - -ruby_version_is "3.1" do - describe 'TracePoint.allow_reentry' do - it 'allows the reentrance in a given block' do - event_lines = [] - l1 = l2 = l3 = l4 = nil - TracePoint.new(:line) do |tp| - next unless TracePointSpec.target_thread? - - event_lines << tp.lineno - next if (__LINE__ + 2 .. __LINE__ + 4).cover?(tp.lineno) - TracePoint.allow_reentry do - a = 1; l3 = __LINE__ - b = 2; l4 = __LINE__ - end - end.enable do - c = 3; l1 = __LINE__ - d = 4; l2 = __LINE__ - end - - event_lines.should == [l1, l3, l4, l2, l3, l4] - end - - it 'raises RuntimeError when not called inside a TracePoint' do - -> { - TracePoint.allow_reentry{} - }.should raise_error(RuntimeError) - end - end -end diff --git a/spec/ruby/core/tracepoint/enable_spec.rb b/spec/ruby/core/tracepoint/enable_spec.rb index 6cc8bb3897..ab392c7583 100644 --- a/spec/ruby/core/tracepoint/enable_spec.rb +++ b/spec/ruby/core/tracepoint/enable_spec.rb @@ -57,50 +57,25 @@ describe 'TracePoint#enable' do end.enable { event_name.should equal(:line) } 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 - end - thread.join - end - - threads = threads.uniq - threads.should.include?(Thread.current) - threads.should_not.include?(thread) + 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 - end - - 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 + thread = nil + trace.enable do + line_event = true + thread = Thread.new do + event_in_other_thread = true end - - threads = threads.uniq - threads.should.include?(Thread.current) - threads.should.include?(thread) + thread.join end + + threads = threads.uniq + threads.should.include?(Thread.current) + threads.should.include?(thread) end it 'can accept arguments within a block but it should not yield arguments' do @@ -149,7 +124,13 @@ describe 'TracePoint#enable' do describe "when nested" do before do - @path_prefix = ' ' + ruby_version_is ""..."3.0" do + @path_prefix = '@' + end + + ruby_version_is "3.0" do + @path_prefix = ' ' + end end it "enables both TracePoints but only calls the respective callbacks" do diff --git a/spec/ruby/core/tracepoint/inspect_spec.rb b/spec/ruby/core/tracepoint/inspect_spec.rb index 21d62e9e26..b9d7f35c32 100644 --- a/spec/ruby/core/tracepoint/inspect_spec.rb +++ b/spec/ruby/core/tracepoint/inspect_spec.rb @@ -3,22 +3,19 @@ require_relative 'fixtures/classes' describe 'TracePoint#inspect' do before do - @path_prefix = ' ' + ruby_version_is ""..."3.0" do + @path_prefix = '@' + end + + ruby_version_is "3.0" do + @path_prefix = ' ' + end end it 'returns a string containing a human-readable TracePoint status' do TracePoint.new(:line) {}.inspect.should == '#<TracePoint:disabled>' end - it "shows only whether it's enabled when outside the TracePoint handler" do - trace = TracePoint.new(:line) {} - trace.enable - - trace.inspect.should == '#<TracePoint:enabled>' - - trace.disable - end - it 'returns a String showing the event, path and line' do inspect = nil line = nil @@ -101,7 +98,7 @@ describe 'TracePoint#inspect' do TracePoint.new(:thread_begin) { |tp| next unless Thread.current == thread inspect ||= tp.inspect - }.enable(target_thread: nil) do + }.enable do thread = Thread.new {} thread_inspection = thread.inspect thread.join @@ -117,7 +114,7 @@ describe 'TracePoint#inspect' do TracePoint.new(:thread_end) { |tp| next unless Thread.current == thread inspect ||= tp.inspect - }.enable(target_thread: nil) do + }.enable do thread = Thread.new {} thread_inspection = thread.inspect thread.join diff --git a/spec/ruby/core/tracepoint/path_spec.rb b/spec/ruby/core/tracepoint/path_spec.rb index dc2ca840b8..5b6c6d4cfc 100644 --- a/spec/ruby/core/tracepoint/path_spec.rb +++ b/spec/ruby/core/tracepoint/path_spec.rb @@ -13,29 +13,14 @@ describe 'TracePoint#path' do path.should == "#{__FILE__}" end - ruby_version_is ""..."3.3" do - it 'equals (eval) inside an eval for :end event' do - path = nil - TracePoint.new(:end) { |tp| - next unless TracePointSpec.target_thread? - path = tp.path - }.enable do - eval("module TracePointSpec; end") - end - path.should == '(eval)' - end - end - - ruby_version_is "3.3" do - it 'equals "(eval at __FILE__:__LINE__)" inside an eval for :end event' do - path = nil - TracePoint.new(:end) { |tp| - next unless TracePointSpec.target_thread? - path = tp.path - }.enable do - eval("module TracePointSpec; end") - end - path.should == "(eval at #{__FILE__}:#{__LINE__ - 2})" + it 'equals (eval) inside an eval for :end event' do + path = nil + TracePoint.new(:end) { |tp| + next unless TracePointSpec.target_thread? + path = tp.path + }.enable do + eval("module TracePointSpec; end") end + path.should == '(eval)' end end diff --git a/spec/ruby/core/true/singleton_method_spec.rb b/spec/ruby/core/true/singleton_method_spec.rb deleted file mode 100644 index c06793850f..0000000000 --- a/spec/ruby/core/true/singleton_method_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative '../../spec_helper' - -describe "TrueClass#singleton_method" do - ruby_version_is '3.3' do - it "raises regardless of whether TrueClass defines the method" do - -> { true.singleton_method(:foo) }.should raise_error(NameError) - begin - def (true).foo; end - -> { true.singleton_method(:foo) }.should raise_error(NameError) - ensure - TrueClass.send(:remove_method, :foo) - end - end - end -end diff --git a/spec/ruby/core/true/to_s_spec.rb b/spec/ruby/core/true/to_s_spec.rb index fa1b53a580..f26cd138e2 100644 --- a/spec/ruby/core/true/to_s_spec.rb +++ b/spec/ruby/core/true/to_s_spec.rb @@ -5,11 +5,13 @@ describe "TrueClass#to_s" do true.to_s.should == "true" end - it "returns a frozen string" do - true.to_s.should.frozen? - end + ruby_version_is "2.7" do + 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) + it "always returns the same string" do + true.to_s.should equal(true.to_s) + end end end diff --git a/spec/ruby/core/unboundmethod/bind_call_spec.rb b/spec/ruby/core/unboundmethod/bind_call_spec.rb index 80b2095d86..c5d392156c 100644 --- a/spec/ruby/core/unboundmethod/bind_call_spec.rb +++ b/spec/ruby/core/unboundmethod/bind_call_spec.rb @@ -1,58 +1,52 @@ require_relative '../../spec_helper' require_relative 'fixtures/classes' -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 - @normal_um_super = UnboundMethodSpecs::Mod.instance_method(:foo_super) - @parent_um_super = UnboundMethodSpecs::Parent.new.method(:foo_super).unbind - end +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 - 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 + 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 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 - - it "allows calling super for module methods bound to hierarchies that do not already have that module" do - p = UnboundMethodSpecs::Parent.new - - @normal_um_super.bind_call(p).should == true end end diff --git a/spec/ruby/core/unboundmethod/bind_spec.rb b/spec/ruby/core/unboundmethod/bind_spec.rb index 7658b664e5..03aaa22e74 100644 --- a/spec/ruby/core/unboundmethod/bind_spec.rb +++ b/spec/ruby/core/unboundmethod/bind_spec.rb @@ -7,8 +7,6 @@ describe "UnboundMethod#bind" do @parent_um = UnboundMethodSpecs::Parent.new.method(:foo).unbind @child1_um = UnboundMethodSpecs::Child1.new.method(:foo).unbind @child2_um = UnboundMethodSpecs::Child2.new.method(:foo).unbind - @normal_um_super = UnboundMethodSpecs::Mod.instance_method(:foo_super) - @parent_um_super = UnboundMethodSpecs::Parent.new.method(:foo_super).unbind end it "raises TypeError if object is not kind_of? the Module the method defined in" do @@ -60,10 +58,4 @@ describe "UnboundMethod#bind" do um = p.method(:singleton_method).unbind ->{ um.bind(other) }.should raise_error(TypeError) end - - it "allows calling super for module methods bound to hierarchies that do not already have that module" do - p = UnboundMethodSpecs::Parent.new - - @normal_um_super.bind(p).call.should == true - end end diff --git a/spec/ruby/core/unboundmethod/clone_spec.rb b/spec/ruby/core/unboundmethod/clone_spec.rb index 1e7fb18744..098ee61476 100644 --- a/spec/ruby/core/unboundmethod/clone_spec.rb +++ b/spec/ruby/core/unboundmethod/clone_spec.rb @@ -1,13 +1,12 @@ require_relative '../../spec_helper' -require_relative 'shared/dup' +require_relative 'fixtures/classes' describe "UnboundMethod#clone" do - it_behaves_like :unboundmethod_dup, :clone + it "returns a copy of the UnboundMethod" do + um1 = UnboundMethodSpecs::Methods.instance_method(:foo) + um2 = um1.clone - it "preserves frozen status" do - method = Class.instance_method(:instance_method) - method.freeze - method.frozen?.should == true - method.clone.frozen?.should == true + (um1 == um2).should == true + um1.bind(UnboundMethodSpecs::Methods.new).call.should == um2.bind(UnboundMethodSpecs::Methods.new).call end end diff --git a/spec/ruby/core/unboundmethod/dup_spec.rb b/spec/ruby/core/unboundmethod/dup_spec.rb deleted file mode 100644 index 5a78dd8e36..0000000000 --- a/spec/ruby/core/unboundmethod/dup_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'shared/dup' - -describe "UnboundMethod#dup" do - ruby_version_is "3.4" do - it_behaves_like :unboundmethod_dup, :dup - - it "resets frozen status" do - method = Class.instance_method(:instance_method) - method.freeze - method.frozen?.should == true - method.dup.frozen?.should == false - end - end -end diff --git a/spec/ruby/core/unboundmethod/equal_value_spec.rb b/spec/ruby/core/unboundmethod/equal_value_spec.rb index 036c6b7f8c..b21677687e 100644 --- a/spec/ruby/core/unboundmethod/equal_value_spec.rb +++ b/spec/ruby/core/unboundmethod/equal_value_spec.rb @@ -76,38 +76,19 @@ describe "UnboundMethod#==" do (@identical_body == @original_body).should == false end - ruby_version_is ""..."3.2" do - it "returns false if same method but one extracted from a subclass" do - (@parent == @child1).should == false - (@child1 == @parent).should == false - end - - it "returns false if same method but extracted from two different subclasses" do - (@child2 == @child1).should == false - (@child1 == @child2).should == false - end - - it "returns false if methods are the same but added from an included Module" do - (@includee == @includer).should == false - (@includer == @includee).should == false - end + it "returns false if same method but one extracted from a subclass" do + (@parent == @child1).should == false + (@child1 == @parent).should == false end - ruby_version_is "3.2" do - it "returns true if same method but one extracted from a subclass" do - (@parent == @child1).should == true - (@child1 == @parent).should == true - end - - it "returns false if same method but extracted from two different subclasses" do - (@child2 == @child1).should == true - (@child1 == @child2).should == true - end + it "returns false if same method but extracted from two different subclasses" do + (@child2 == @child1).should == false + (@child1 == @child2).should == false + end - it "returns true if methods are the same but added from an included Module" do - (@includee == @includer).should == true - (@includer == @includee).should == true - end + it "returns false if methods are the same but added from an included Module" do + (@includee == @includer).should == false + (@includer == @includee).should == false end it "returns false if both have same Module, same name, identical body but not the same" do diff --git a/spec/ruby/core/unboundmethod/fixtures/classes.rb b/spec/ruby/core/unboundmethod/fixtures/classes.rb index 28d8e0a965..46b1c51669 100644 --- a/spec/ruby/core/unboundmethod/fixtures/classes.rb +++ b/spec/ruby/core/unboundmethod/fixtures/classes.rb @@ -22,7 +22,6 @@ module UnboundMethodSpecs module Mod def from_mod; end - def foo_super; super; end end class Methods @@ -54,19 +53,10 @@ module UnboundMethodSpecs def discard_1(); :discard; end def discard_2(); :discard; end - - def my_public_method; end - def my_protected_method; end - def my_private_method; end - protected :my_protected_method - private :my_private_method end class Parent def foo; end - def foo_super - true - end def self.class_method "I am #{name}" end @@ -94,14 +84,4 @@ module UnboundMethodSpecs class C < B def overridden; end end - - module HashSpecs - class SuperClass - def foo - end - end - - class SubClass < SuperClass - end - end end diff --git a/spec/ruby/core/unboundmethod/hash_spec.rb b/spec/ruby/core/unboundmethod/hash_spec.rb index 6888675bc1..12dce0020f 100644 --- a/spec/ruby/core/unboundmethod/hash_spec.rb +++ b/spec/ruby/core/unboundmethod/hash_spec.rb @@ -12,11 +12,4 @@ describe "UnboundMethod#hash" do to_s, inspect = Array.instance_method(:to_s), Array.instance_method(:inspect) to_s.hash.should == inspect.hash end - - it "equals a hash of the same method in the superclass" do - foo_in_superclass = UnboundMethodSpecs::HashSpecs::SuperClass.instance_method(:foo) - foo = UnboundMethodSpecs::HashSpecs::SubClass.instance_method(:foo) - - foo.hash.should == foo_in_superclass.hash - end end diff --git a/spec/ruby/core/unboundmethod/private_spec.rb b/spec/ruby/core/unboundmethod/private_spec.rb deleted file mode 100644 index 8ea50bb5d4..0000000000 --- a/spec/ruby/core/unboundmethod/private_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/classes' - -describe "UnboundMethod#private?" do - ruby_version_is "3.1"..."3.2" do - it "returns false when the method is public" do - obj = UnboundMethodSpecs::Methods.new - obj.method(:my_public_method).unbind.private?.should == false - end - - it "returns false when the method is protected" do - obj = UnboundMethodSpecs::Methods.new - obj.method(:my_protected_method).unbind.private?.should == false - end - - it "returns true when the method is private" do - obj = UnboundMethodSpecs::Methods.new - obj.method(:my_private_method).unbind.private?.should == true - end - end - - ruby_version_is "3.2" do - it "has been removed" do - obj = UnboundMethodSpecs::Methods.new - obj.method(:my_private_method).unbind.should_not.respond_to?(:private?) - end - end -end diff --git a/spec/ruby/core/unboundmethod/protected_spec.rb b/spec/ruby/core/unboundmethod/protected_spec.rb deleted file mode 100644 index 0c215d8638..0000000000 --- a/spec/ruby/core/unboundmethod/protected_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/classes' - -describe "UnboundMethod#protected?" do - ruby_version_is "3.1"..."3.2" do - it "returns false when the method is public" do - obj = UnboundMethodSpecs::Methods.new - obj.method(:my_public_method).unbind.protected?.should == false - end - - it "returns true when the method is protected" do - obj = UnboundMethodSpecs::Methods.new - obj.method(:my_protected_method).unbind.protected?.should == true - end - - it "returns false when the method is private" do - obj = UnboundMethodSpecs::Methods.new - obj.method(:my_private_method).unbind.protected?.should == false - end - end - - ruby_version_is "3.2" do - it "has been removed" do - obj = UnboundMethodSpecs::Methods.new - obj.method(:my_protected_method).unbind.should_not.respond_to?(:protected?) - end - end -end diff --git a/spec/ruby/core/unboundmethod/public_spec.rb b/spec/ruby/core/unboundmethod/public_spec.rb deleted file mode 100644 index 552bbf6eab..0000000000 --- a/spec/ruby/core/unboundmethod/public_spec.rb +++ /dev/null @@ -1,28 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/classes' - -describe "UnboundMethod#public?" do - ruby_version_is "3.1"..."3.2" do - it "returns true when the method is public" do - obj = UnboundMethodSpecs::Methods.new - obj.method(:my_public_method).unbind.public?.should == true - end - - it "returns false when the method is protected" do - obj = UnboundMethodSpecs::Methods.new - obj.method(:my_protected_method).unbind.public?.should == false - end - - it "returns false when the method is private" do - obj = UnboundMethodSpecs::Methods.new - obj.method(:my_private_method).unbind.public?.should == false - end - end - - ruby_version_is "3.2" do - it "has been removed" do - obj = UnboundMethodSpecs::Methods.new - obj.method(:my_public_method).unbind.should_not.respond_to?(:public?) - end - end -end diff --git a/spec/ruby/core/unboundmethod/shared/dup.rb b/spec/ruby/core/unboundmethod/shared/dup.rb deleted file mode 100644 index 943a7faaa3..0000000000 --- a/spec/ruby/core/unboundmethod/shared/dup.rb +++ /dev/null @@ -1,32 +0,0 @@ -describe :unboundmethod_dup, shared: true do - it "returns a copy of self" do - a = Class.instance_method(:instance_method) - b = a.send(@method) - - a.should == b - a.should_not equal(b) - end - - ruby_version_is "3.4" do - it "copies instance variables" do - method = Class.instance_method(:instance_method) - method.instance_variable_set(:@ivar, 1) - cl = method.send(@method) - cl.instance_variables.should == [:@ivar] - end - - it "copies the finalizer" do - code = <<-RUBY - obj = Class.instance_method(:instance_method) - - ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" }) - - obj.clone - - exit 0 - RUBY - - ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"] - end - end -end diff --git a/spec/ruby/core/unboundmethod/shared/to_s.rb b/spec/ruby/core/unboundmethod/shared/to_s.rb index b92bb0b207..38503c3c60 100644 --- a/spec/ruby/core/unboundmethod/shared/to_s.rb +++ b/spec/ruby/core/unboundmethod/shared/to_s.rb @@ -20,22 +20,12 @@ describe :unboundmethod_to_s, shared: true do it "the String shows the method name, Module defined in and Module extracted from" do @from_module.send(@method).should =~ /\bfrom_mod\b/ @from_module.send(@method).should =~ /\bUnboundMethodSpecs::Mod\b/ - - ruby_version_is ""..."3.2" do - @from_method.send(@method).should =~ /\bUnboundMethodSpecs::Methods\b/ - end + @from_method.send(@method).should =~ /\bUnboundMethodSpecs::Methods\b/ end it "returns a String including all details" do - ruby_version_is ""..."3.2" do - @from_module.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Methods(UnboundMethodSpecs::Mod)#from_mod" - @from_method.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Methods(UnboundMethodSpecs::Mod)#from_mod" - end - - ruby_version_is "3.2" do - @from_module.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod" - @from_method.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod" - end + @from_module.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Methods(UnboundMethodSpecs::Mod)#from_mod" + @from_method.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Methods(UnboundMethodSpecs::Mod)#from_mod" end it "does not show the defining module if it is the same as the origin" do diff --git a/spec/ruby/core/unboundmethod/source_location_spec.rb b/spec/ruby/core/unboundmethod/source_location_spec.rb index 5c2f14362c..96933a5d40 100644 --- a/spec/ruby/core/unboundmethod/source_location_spec.rb +++ b/spec/ruby/core/unboundmethod/source_location_spec.rb @@ -9,7 +9,7 @@ describe "UnboundMethod#source_location" do it "sets the first value to the path of the file in which the method was defined" do file = @method.source_location.first file.should be_an_instance_of(String) - file.should == File.realpath('fixtures/classes.rb', __dir__) + file.should == File.realpath('../fixtures/classes.rb', __FILE__) end it "sets the last value to an Integer representing the line on which the method was defined" do @@ -49,11 +49,4 @@ describe "UnboundMethod#source_location" do method.source_location[0].should =~ /#{__FILE__}/ method.source_location[1].should == line end - - it "works for eval with a given line" do - c = Class.new do - eval('def m; end', nil, "foo", 100) - end - c.instance_method(:m).source_location.should == ["foo", 100] - end end diff --git a/spec/ruby/core/warning/element_reference_spec.rb b/spec/ruby/core/warning/element_reference_spec.rb index 8cb4018c20..f51cc87de5 100644 --- a/spec/ruby/core/warning/element_reference_spec.rb +++ b/spec/ruby/core/warning/element_reference_spec.rb @@ -1,25 +1,22 @@ require_relative '../../spec_helper' -describe "Warning.[]" do - it "returns default values for categories :deprecated and :experimental" do - ruby_exe('p [Warning[:deprecated], Warning[:experimental]]').chomp.should == "[false, true]" - ruby_exe('p [Warning[:deprecated], Warning[:experimental]]', options: "-w").chomp.should == "[true, true]" - end - - ruby_version_is '3.3' do - it "returns default values for :performance category" do - ruby_exe('p Warning[:performance]').chomp.should == "false" - ruby_exe('p Warning[:performance]', options: "-w").chomp.should == "false" +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 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) + 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 end diff --git a/spec/ruby/core/warning/element_set_spec.rb b/spec/ruby/core/warning/element_set_spec.rb index d59a7d4c9e..611060fb3a 100644 --- a/spec/ruby/core/warning/element_set_spec.rb +++ b/spec/ruby/core/warning/element_set_spec.rb @@ -1,41 +1,37 @@ require_relative '../../spec_helper' -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 - @src = 'warn "This is experimental warning.", category: :experimental' +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 - 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 + describe ":experimental" do + before do + ruby_version_is ""..."3.0" do + @src = 'case [0, 1]; in [a, b]; end' + end + + ruby_version_is "3.0" do + @src = 'warn "This is experimental warning.", category: :experimental' + end + end - ruby_version_is '3.3' do - it "enables or disables performance warnings" do - original = Warning[:performance] - begin - Warning[:performance] = !original - Warning[:performance].should == !original - ensure - Warning[:performance] = original + 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 - end - it "raises for unknown category" do - -> { Warning[:noop] = false }.should raise_error(ArgumentError, /unknown category: noop/) - 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) + 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 end diff --git a/spec/ruby/core/warning/warn_spec.rb b/spec/ruby/core/warning/warn_spec.rb index 8f96fe9287..5ccff3aa2b 100644 --- a/spec/ruby/core/warning/warn_spec.rb +++ b/spec/ruby/core/warning/warn_spec.rb @@ -51,85 +51,40 @@ describe "Warning.warn" do end end - it "is called by Kernel.warn with nil category keyword" do - Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil) - verbose = $VERBOSE - $VERBOSE = false - begin - Kernel.warn("Chunky bacon!") - ensure - $VERBOSE = verbose - end - end - - it "is called by Kernel.warn with given category keyword converted to a symbol" do - Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated) - verbose = $VERBOSE - $VERBOSE = false - begin - Kernel.warn("Chunky bacon!", category: "deprecated") - ensure - $VERBOSE = verbose - end - end - - it "warns when category is :deprecated and Warning[:deprecated] is true" do - warn_deprecated = Warning[:deprecated] - Warning[:deprecated] = true - begin - -> { - Warning.warn("foo", category: :deprecated) - }.should complain("foo") - ensure - Warning[:deprecated] = warn_deprecated - end - end - - it "warns when category is :experimental and Warning[:experimental] is true" do - warn_experimental = Warning[:experimental] - Warning[:experimental] = true - begin - -> { - Warning.warn("foo", category: :experimental) - }.should complain("foo") - ensure - Warning[:experimental] = warn_experimental + ruby_version_is '3.0' do + it "is called by Kernel.warn with nil category keyword" do + Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil) + verbose = $VERBOSE + $VERBOSE = false + begin + Kernel.warn("Chunky bacon!") + ensure + $VERBOSE = verbose + end end - end - it "doesn't print message when category is :deprecated but Warning[:deprecated] is false" do - warn_deprecated = Warning[:deprecated] - Warning[:deprecated] = false - begin - -> { - Warning.warn("foo", category: :deprecated) - }.should_not complain - ensure - Warning[:deprecated] = warn_deprecated + it "is called by Kernel.warn with given category keyword converted to a symbol" do + Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated) + verbose = $VERBOSE + $VERBOSE = false + begin + Kernel.warn("Chunky bacon!", category: "deprecated") + ensure + $VERBOSE = verbose + end end end - it "doesn't print message when category is :experimental but Warning[:experimental] is false" do - warn_experimental = Warning[:experimental] - Warning[:experimental] = false - begin - -> { - Warning.warn("foo", category: :experimental) - }.should_not complain - ensure - Warning[:experimental] = warn_experimental + ruby_version_is ''...'3.0' do + it "is called by Kernel.warn" do + Warning.should_receive(:warn).with("Chunky bacon!\n") + verbose = $VERBOSE + $VERBOSE = false + begin + Kernel.warn("Chunky bacon!") + ensure + $VERBOSE = verbose + end end end - - it "prints the message when VERBOSE is false" do - -> { Warning.warn("foo") }.should complain("foo") - end - - it "prints the message when VERBOSE is nil" do - -> { Warning.warn("foo") }.should complain("foo", verbose: nil) - end - - it "prints the message when VERBOSE is true" do - -> { Warning.warn("foo") }.should complain("foo", verbose: true) - end end diff --git a/spec/ruby/fixtures/class.rb b/spec/ruby/fixtures/class.rb index 98cb6c82a2..68fbca7ba7 100644 --- a/spec/ruby/fixtures/class.rb +++ b/spec/ruby/fixtures/class.rb @@ -122,10 +122,6 @@ module ClassSpecs end end end - - DEFINE_CLASS = -> do - class ::A; end - end end class Class diff --git a/spec/ruby/fixtures/code/c/load_fixture.rb b/spec/ruby/fixtures/code/c/load_fixture.rb deleted file mode 100644 index 4a6e9c9601..0000000000 --- a/spec/ruby/fixtures/code/c/load_fixture.rb +++ /dev/null @@ -1 +0,0 @@ -ScratchPad << :loaded diff --git a/spec/ruby/fixtures/code/d/load_fixture.rb.rb b/spec/ruby/fixtures/code/d/load_fixture.rb.rb deleted file mode 100644 index 7e9217729a..0000000000 --- a/spec/ruby/fixtures/code/d/load_fixture.rb.rb +++ /dev/null @@ -1 +0,0 @@ -ScratchPad << :rbrb diff --git a/spec/ruby/fixtures/code/load_wrap_fixture.rb b/spec/ruby/fixtures/code/wrap_fixture.rb index 526bbf8c82..7ddf5a62e0 100644 --- a/spec/ruby/fixtures/code/load_wrap_fixture.rb +++ b/spec/ruby/fixtures/code/wrap_fixture.rb @@ -2,10 +2,7 @@ class LoadSpecWrap ScratchPad << String end -LOAD_WRAP_SPECS_TOP_LEVEL_CONSTANT = 1 - def load_wrap_specs_top_level_method - :load_wrap_specs_top_level_method end ScratchPad << method(:load_wrap_specs_top_level_method).owner diff --git a/spec/ruby/fixtures/constants.rb b/spec/ruby/fixtures/constants.rb index ffe45fb1f6..37271ddcc8 100644 --- a/spec/ruby/fixtures/constants.rb +++ b/spec/ruby/fixtures/constants.rb @@ -44,7 +44,6 @@ module ConstantSpecs # Included in ParentA module ModuleB - LINE = __LINE__ - 1 CS_CONST10 = :const10_9 CS_CONST11 = :const11_2 CS_CONST12 = :const12_1 @@ -76,19 +75,12 @@ module ConstantSpecs CS_CONST10 = :const10_8 end - # Included in ContainerA - module ModuleIncludePrepended - prepend ModuleD - - CS_CONST11 = :const11_8 - end - # The following classes/modules have all the constants set "statically". # Contrast with the classes below where the constants are set as the specs # are run. class ClassA - LINE = __LINE__ - 1 + CS_CLASS_A_LINE = __LINE__ - 1 CS_CONST10 = :const10_10 CS_CONST10_LINE = __LINE__ - 1 CS_CONST16 = :const16 @@ -177,10 +169,6 @@ module ConstantSpecs def const10; CS_CONST10; end end - class ContainerPrepend - include ModuleIncludePrepended - end - class ContainerA::ChildA def self.const23; CS_CONST23; end end @@ -311,14 +299,4 @@ 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/END_spec.rb b/spec/ruby/language/END_spec.rb index c84f0cc9ac..762a8db0c0 100644 --- a/spec/ruby/language/END_spec.rb +++ b/spec/ruby/language/END_spec.rb @@ -1,33 +1,15 @@ require_relative '../spec_helper' -require_relative '../shared/kernel/at_exit' describe "The END keyword" do - it_behaves_like :kernel_at_exit, :END - it "runs only once for multiple calls" do ruby_exe("10.times { END { puts 'foo' }; } ").should == "foo\n" end - it "is affected by the toplevel assignment" do - ruby_exe("foo = 'foo'; END { puts foo }").should == "foo\n" - end - - it "warns when END is used in a method" do - ruby_exe(<<~ruby, args: "2>&1").should =~ /warning: END in method; use at_exit/ - def foo - END { } - end - ruby + it "runs last in a given code unit" do + ruby_exe("END { puts 'bar' }; puts'foo'; ").should == "foo\nbar\n" end - context "END blocks and at_exit callbacks are mixed" do - it "runs them all in reverse order of registration" do - ruby_exe(<<~ruby).should == "at_exit#2\nEND#2\nat_exit#1\nEND#1\n" - END { puts 'END#1' } - at_exit { puts 'at_exit#1' } - END { puts 'END#2' } - at_exit { puts 'at_exit#2' } - ruby - end + it "runs multiple ends in LIFO order" do + ruby_exe("END { puts 'foo' }; END { puts 'bar' }").should == "bar\nfoo\n" end end diff --git a/spec/ruby/language/alias_spec.rb b/spec/ruby/language/alias_spec.rb index 61fddb0184..d1d06e3fac 100644 --- a/spec/ruby/language/alias_spec.rb +++ b/spec/ruby/language/alias_spec.rb @@ -52,15 +52,6 @@ describe "The alias keyword" do @obj.a.should == 5 end - it "works with an interpolated symbol with non-literal embedded expression on the left-hand side" do - @meta.class_eval do - eval %Q{ - alias :"#{'a' + ''.to_s}" value - } - end - @obj.a.should == 5 - end - it "works with a simple symbol on the right-hand side" do @meta.class_eval do alias a :value @@ -89,15 +80,6 @@ describe "The alias keyword" do @obj.a.should == 5 end - it "works with an interpolated symbol with non-literal embedded expression on the right-hand side" do - @meta.class_eval do - eval %Q{ - alias a :"#{'value' + ''.to_s}" - } - end - @obj.a.should == 5 - end - it "adds the new method to the list of methods" do original_methods = @obj.methods @meta.class_eval do @@ -252,7 +234,7 @@ describe "The alias keyword" do it "on top level defines the alias on Object" do # because it defines on the default definee / current module - ruby_exe("def foo; end; alias bla foo; print method(:bla).owner").should == "Object" + ruby_exe("def foo; end; alias bla foo; print method(:bla).owner", escape: true).should == "Object" end it "raises a NameError when passed a missing name" do @@ -261,19 +243,6 @@ 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 90329e2f6f..b2a3cc84c4 100644 --- a/spec/ruby/language/block_spec.rb +++ b/spec/ruby/language/block_spec.rb @@ -40,31 +40,80 @@ 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 - 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], {}] + it "assigns elements to required arguments when a keyword rest argument is present" do + m([1, 2]) { |a, **k| [a, k] }.should == [1, {}] + end + + ruby_version_is ''..."3.0" do + it "assigns elements to mixed argument types" do + suppress_keyword_warning do + result = m([1, 2, 3, {x: 9}]) { |a, b=5, *c, d, e: 2, **k| [a, b, c, d, e, k] } + result.should == [1, 2, [], 3, 2, {x: 9}] + end + end + + it "assigns symbol keys from a Hash to keyword arguments" do + suppress_keyword_warning do + result = m(["a" => 1, a: 10]) { |a=nil, **b| [a, b] } + result.should == [{"a" => 1}, a: 10] + end + end + + it "assigns symbol keys from a Hash returned by #to_hash to keyword arguments" do + suppress_keyword_warning 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 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, {}] + ruby_version_is "3.0" do + it "assigns elements to mixed argument types" do + result = m([1, 2, 3, {x: 9}]) { |a, b=5, *c, d, e: 2, **k| [a, b, c, d, e, k] } + result.should == [1, 2, [3], {x: 9}, 2, {}] + end + + it "does not treat final Hash as keyword arguments and does not autosplat" do + result = m(["a" => 1, a: 10]) { |a=nil, **b| [a, b] } + result.should == [[{"a" => 1, a: 10}], {}] + end + + it "does not call #to_hash on final argument to get keyword arguments and does not autosplat" do + suppress_keyword_warning do + obj = mock("coerce block keyword arguments") + obj.should_not_receive(:to_hash) + + result = m([obj]) { |a=nil, **b| [a, b] } + result.should == [[obj], {}] + end end end - it "assigns elements to mixed argument types" do - result = m([1, 2, 3, {x: 9}]) { |a, b=5, *c, d, e: 2, **k| [a, b, c, d, e, k] } - result.should == [1, 2, [3], {x: 9}, 2, {}] + 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 - it "does not treat final Hash as keyword arguments and does not autosplat" do - result = m(["a" => 1, a: 10]) { |a=nil, **b| [a, b] } - result.should == [[{"a" => 1, a: 10}], {}] + ruby_version_is "2.7"...'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}) + + result = m([obj]) { |a=nil, **b| [a, b] } + result.should == [obj, {}] + end end - it "does not call #to_hash on final argument to get keyword arguments and does not autosplat" do - suppress_keyword_warning do + ruby_version_is "3.0" do + it "does not call #to_hash on the argument when optional argument and keyword argument accepted and does not autosplat" do obj = mock("coerce block keyword arguments") obj.should_not_receive(:to_hash) @@ -73,42 +122,102 @@ describe "A block yielded a single" do end end - it "does not call #to_hash on the argument when optional argument and keyword argument accepted and does not autosplat" do - obj = mock("coerce block keyword arguments") - obj.should_not_receive(:to_hash) + describe "when non-symbol keys are in a keyword arguments Hash" do + ruby_version_is ""..."3.0" do + it "separates non-symbol keys and symbol keys" do + suppress_keyword_warning do + result = m(["a" => 10, b: 2]) { |a=nil, **b| [a, b] } + result.should == [{"a" => 10}, {b: 2}] + end + end + end + ruby_version_is "3.0" do + it "does not separate non-symbol keys and symbol keys and does not autosplat" do + suppress_keyword_warning do + result = m(["a" => 10, b: 2]) { |a=nil, **b| [a, b] } + result.should == [[{"a" => 10, b: 2}], {}] + end + end + end + end - result = m([obj]) { |a=nil, **b| [a, b] } - result.should == [[obj], {}] + ruby_version_is ""..."3.0" do + it "does not treat hashes with string keys as keyword arguments" do + result = m(["a" => 10]) { |a = nil, **b| [a, b] } + result.should == [{"a" => 10}, {}] + end end - describe "when non-symbol keys are in a keyword arguments Hash" do - it "does not separate non-symbol keys and symbol keys and does not autosplat" do + ruby_version_is "3.0" do + it "does not treat hashes with string keys as keyword arguments and does not autosplat" do + result = m(["a" => 10]) { |a = nil, **b| [a, b] } + result.should == [[{"a" => 10}], {}] + end + end + + ruby_version_is ''...'3.0' do + it "calls #to_hash on the last element if keyword arguments are present" do suppress_keyword_warning do - result = m(["a" => 10, b: 2]) { |a=nil, **b| [a, b] } - result.should == [[{"a" => 10, b: 2}], {}] + obj = mock("destructure block keyword arguments") + obj.should_receive(:to_hash).and_return({x: 9}) + + result = m([1, 2, 3, obj]) { |a, *b, c, **k| [a, b, c, k] } + result.should == [1, [2], 3, {x: 9}] end end - end - it "does not treat hashes with string keys as keyword arguments and does not autosplat" do - result = m(["a" => 10]) { |a = nil, **b| [a, b] } - result.should == [[{"a" => 10}], {}] - end + it "assigns the last element to a non-keyword argument if #to_hash returns nil" do + suppress_keyword_warning do + obj = mock("destructure block keyword arguments") + obj.should_receive(:to_hash).and_return(nil) - it "does not call #to_hash on the last element if keyword arguments are present" do - obj = mock("destructure block keyword arguments") - obj.should_not_receive(:to_hash) + result = m([1, 2, 3, obj]) { |a, *b, c, **k| [a, b, c, k] } + result.should == [1, [2, 3], obj, {}] + end + end + + it "calls #to_hash on the last element when there are more arguments than parameters" do + suppress_keyword_warning do + x = mock("destructure matching block keyword argument") + x.should_receive(:to_hash).and_return({x: 9}) + + result = m([1, 2, 3, {y: 9}, 4, 5, x]) { |a, b=5, c, **k| [a, b, c, k] } + result.should == [1, 2, 3, {x: 9}] + end + end - result = m([1, 2, 3, obj]) { |a, *b, c, **k| [a, b, c, k] } - result.should == [1, [2, 3], obj, {}] + it "raises a TypeError if #to_hash does not return a Hash" do + obj = mock("destructure block keyword arguments") + obj.should_receive(:to_hash).and_return(1) + + -> { m([1, 2, 3, obj]) { |a, *b, c, **k| } }.should raise_error(TypeError) + end + + it "raises the error raised inside #to_hash" do + obj = mock("destructure block keyword arguments") + error = RuntimeError.new("error while converting to a hash") + obj.should_receive(:to_hash).and_raise(error) + + -> { m([1, 2, 3, obj]) { |a, *b, c, **k| } }.should raise_error(error) + end end - it "does not call #to_hash on the last element when there are more arguments than parameters" do - x = mock("destructure matching block keyword argument") - x.should_not_receive(:to_hash) + ruby_version_is '3.0' do + it "does not call #to_hash on the last element if keyword arguments are present" do + obj = mock("destructure block keyword arguments") + obj.should_not_receive(:to_hash) + + result = m([1, 2, 3, obj]) { |a, *b, c, **k| [a, b, c, k] } + result.should == [1, [2, 3], obj, {}] + end + + it "does not call #to_hash on the last element when there are more arguments than parameters" do + x = mock("destructure matching block keyword argument") + x.should_not_receive(:to_hash) - result = m([1, 2, 3, {y: 9}, 4, 5, x]) { |a, b=5, c, **k| [a, b, c, k] } - result.should == [1, 2, 3, {}] + result = m([1, 2, 3, {y: 9}, 4, 5, x]) { |a, b=5, c, **k| [a, b, c, k] } + result.should == [1, 2, 3, {}] + end end it "does not call #to_ary on the Array" do @@ -155,55 +264,12 @@ describe "A block yielded a single" do m(obj) { |a, b, c| [a, b, c] }.should == [obj, nil, nil] end - it "receives the object if it does not respond to #to_ary" do - obj = Object.new - - m(obj) { |a, b, c| [a, b, c] }.should == [obj, nil, nil] - end - - it "calls #respond_to? to check if object has method #to_ary" do - obj = mock("destructure block arguments") - obj.should_receive(:respond_to?).with(:to_ary, true).and_return(true) - obj.should_receive(:to_ary).and_return([1, 2]) - - m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil] - end - - it "receives the object if it does not respond to #respond_to?" do - obj = BasicObject.new - - m(obj) { |a, b, c| [a, b, c] }.should == [obj, nil, nil] - end - - it "calls #to_ary on the object when it is defined dynamically" do - obj = Object.new - def obj.method_missing(name, *args, &block) - if name == :to_ary - [1, 2] - else - super - end - end - def obj.respond_to_missing?(name, include_private) - name == :to_ary - end - - m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil] - end - it "raises a TypeError if #to_ary does not return an Array" do obj = mock("destructure block arguments") obj.should_receive(:to_ary).and_return(1) -> { m(obj) { |a, b| } }.should raise_error(TypeError) end - - it "raises error transparently if #to_ary raises error on its own" do - obj = Object.new - def obj.to_ary; raise "Exception raised in #to_ary" end - - -> { m(obj) { |a, b| } }.should raise_error(RuntimeError, "Exception raised in #to_ary") - end end end @@ -883,18 +949,38 @@ describe "Post-args" do end describe "with a circular argument reference" 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) + 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 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) + 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 end it "calls an existing method with the same name as the argument if explicitly using ()" do @@ -918,77 +1004,3 @@ describe "Post-args" do end end end - -describe "Anonymous block forwarding" do - ruby_version_is "3.1" do - it "forwards blocks to other functions that formally declare anonymous blocks" do - eval <<-EOF - def b(&); c(&) end - def c(&); yield :non_null end - EOF - - b { |c| c }.should == :non_null - end - - it "requires the anonymous block parameter to be declared if directly passing a block" do - -> { eval "def a; b(&); end; def b; end" }.should raise_error(SyntaxError) - end - - it "works when it's the only declared parameter" do - eval <<-EOF - def inner; yield end - def block_only(&); inner(&) end - EOF - - block_only { 1 }.should == 1 - end - - it "works alongside positional parameters" do - eval <<-EOF - def inner; yield end - def pos(arg1, &); inner(&) end - EOF - - pos(:a) { 1 }.should == 1 - end - - it "works alongside positional arguments and splatted keyword arguments" do - eval <<-EOF - def inner; yield end - def pos_kwrest(arg1, **kw, &); inner(&) end - EOF - - pos_kwrest(:a, arg: 3) { 1 }.should == 1 - end - - it "works alongside positional arguments and disallowed keyword arguments" do - eval <<-EOF - def inner; yield end - def no_kw(arg1, **nil, &); inner(&) end - EOF - - no_kw(:a) { 1 }.should == 1 - end - end - - ruby_version_is "3.2" do - it "works alongside explicit keyword arguments" do - eval <<-EOF - def inner; yield end - def rest_kw(*a, kwarg: 1, &); inner(&) end - def kw(kwarg: 1, &); inner(&) end - def pos_kw_kwrest(arg1, kwarg: 1, **kw, &); inner(&) end - def pos_rkw(arg1, kwarg1:, &); inner(&) end - def all(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, &); inner(&) end - def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, **kw, &); inner(&) end - EOF - - rest_kw { 1 }.should == 1 - kw { 1 }.should == 1 - pos_kw_kwrest(:a) { 1 }.should == 1 - pos_rkw(:a, kwarg1: 3) { 1 }.should == 1 - all(:a, :b, :c, :d, :e, okw1: 'x', okw2: 'y') { 1 }.should == 1 - all_kwrest(:a, :b, :c, :d, :e, okw1: 'x', okw2: 'y') { 1 }.should == 1 - end - end -end diff --git a/spec/ruby/language/case_spec.rb b/spec/ruby/language/case_spec.rb index 1a3925c9c6..410cb9afb1 100644 --- a/spec/ruby/language/case_spec.rb +++ b/spec/ruby/language/case_spec.rb @@ -103,7 +103,7 @@ describe "The 'case'-construct" do $1.should == "42" end - it "tests with a string interpolated in a regexp" do + it "tests with a regexp interpolated within another regexp" do digits = '\d+' case "foo44" when /oo(#{digits})/ @@ -116,7 +116,7 @@ describe "The 'case'-construct" do $1.should == "44" end - it "tests with a regexp interpolated within another regexp" do + it "tests with a string interpolated in a regexp" do digits_regexp = /\d+/ case "foo43" when /oo(#{digits_regexp})/ @@ -156,15 +156,6 @@ 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'] @@ -329,6 +320,49 @@ describe "The 'case'-construct" do 100 end.should == 100 end +end + +describe "The 'case'-construct with no target expression" do + it "evaluates the body of the first clause when at least one of its condition expressions is true" do + case + when true, false; 'foo' + end.should == 'foo' + end + + it "evaluates the body of the first when clause that is not false/nil" do + case + when false; 'foo' + when 2; 'bar' + when 1 == 1; 'baz' + end.should == 'bar' + + case + when false; 'foo' + when nil; 'foo' + when 1 == 1; 'bar' + end.should == 'bar' + end + + it "evaluates the body of the else clause if all when clauses are false/nil" do + case + when false; 'foo' + when nil; 'foo' + when 1 == 2; 'bar' + else 'baz' + end.should == 'baz' + end + + it "evaluates multiple conditional expressions as a boolean disjunction" do + case + when true, false; 'foo' + else 'bar' + end.should == 'foo' + + case + when false, true; 'foo' + else 'bar' + end.should == 'foo' + end it "evaluates true as only 'true' when true is the first clause" do case 1 @@ -391,58 +425,6 @@ describe "The 'case'-construct" do end.should == :called end - it "only matches last value in complex expressions within ()" do - case 'a' - when ('a'; 'b') - :wrong_called - when ('b'; 'a') - :called - end.should == :called - end -end - -describe "The 'case'-construct with no target expression" do - it "evaluates the body of the first clause when at least one of its condition expressions is true" do - case - when true, false; 'foo' - end.should == 'foo' - end - - it "evaluates the body of the first when clause that is not false/nil" do - case - when false; 'foo' - when 2; 'bar' - when 1 == 1; 'baz' - end.should == 'bar' - - case - when false; 'foo' - when nil; 'foo' - when 1 == 1; 'bar' - end.should == 'bar' - end - - it "evaluates the body of the else clause if all when clauses are false/nil" do - case - when false; 'foo' - when nil; 'foo' - when 1 == 2; 'bar' - else 'baz' - end.should == 'baz' - end - - it "evaluates multiple conditional expressions as a boolean disjunction" do - case - when true, false; 'foo' - else 'bar' - end.should == 'foo' - - case - when false, true; 'foo' - else 'bar' - end.should == 'foo' - end - # Homogeneous cases are often optimized to avoid === using a jump table, and should be tested separately. # See https://github.com/jruby/jruby/issues/6440 it "handles homogeneous cases" do @@ -451,13 +433,4 @@ describe "The 'case'-construct with no target expression" do when 2; 'bar' end.should == 'foo' end - - it "expands arrays to lists of values" do - case - when *[false] - "foo" - when *[true] - "bar" - end.should == "bar" - end end diff --git a/spec/ruby/language/class_spec.rb b/spec/ruby/language/class_spec.rb index eab3cd0651..83db164e1a 100644 --- a/spec/ruby/language/class_spec.rb +++ b/spec/ruby/language/class_spec.rb @@ -17,19 +17,6 @@ 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 @@ -308,10 +295,20 @@ describe "A class definition extending an object (sclass)" do -> { class TestClass < BasicObject.new; end }.should raise_error(TypeError, error_msg) end - it "does not allow accessing the block of the original scope" do - -> { - ClassSpecs.sclass_with_block { 123 } - }.should raise_error(SyntaxError) + ruby_version_is ""..."3.0" do + it "allows accessing the block of the original scope" do + suppress_warning do + ClassSpecs.sclass_with_block { 123 }.should == 123 + end + end + end + + ruby_version_is "3.0" do + it "does not allow accessing the block of the original scope" do + -> { + ClassSpecs.sclass_with_block { 123 } + }.should raise_error(SyntaxError) + end end it "can use return to cause the enclosing method to return" do diff --git a/spec/ruby/language/class_variable_spec.rb b/spec/ruby/language/class_variable_spec.rb index a26a3fb8de..f98deaa081 100644 --- a/spec/ruby/language/class_variable_spec.rb +++ b/spec/ruby/language/class_variable_spec.rb @@ -83,32 +83,34 @@ describe 'A class variable definition' do end end -describe 'Accessing a class variable' do - it "raises a RuntimeError when accessed from the toplevel scope (not in some module or class)" do - -> { - eval "@@cvar_toplevel1" - }.should raise_error(RuntimeError, 'class variable access from toplevel') - -> { - eval "@@cvar_toplevel2 = 2" - }.should raise_error(RuntimeError, 'class variable access from toplevel') - end - - it "does not raise an error when checking if defined from the toplevel scope" do - -> { - eval "defined?(@@cvar_toplevel1)" - }.should_not raise_error - end - - it "raises a RuntimeError when a class variable is overtaken in an ancestor class" do - parent = Class.new() - subclass = Class.new(parent) - subclass.class_variable_set(:@@cvar_overtaken, :subclass) - parent.class_variable_set(:@@cvar_overtaken, :parent) - - -> { - subclass.class_variable_get(:@@cvar_overtaken) - }.should raise_error(RuntimeError, /class variable @@cvar_overtaken of .+ is overtaken by .+/) - - parent.class_variable_get(:@@cvar_overtaken).should == :parent +ruby_version_is "3.0" do + describe 'Accessing a class variable' do + it "raises a RuntimeError when accessed from the toplevel scope (not in some module or class)" do + -> { + eval "@@cvar_toplevel1" + }.should raise_error(RuntimeError, 'class variable access from toplevel') + -> { + eval "@@cvar_toplevel2 = 2" + }.should raise_error(RuntimeError, 'class variable access from toplevel') + end + + it "does not raise an error when checking if defined from the toplevel scope" do + -> { + eval "defined?(@@cvar_toplevel1)" + }.should_not raise_error + end + + it "raises a RuntimeError when a class variable is overtaken in an ancestor class" do + parent = Class.new() + subclass = Class.new(parent) + subclass.class_variable_set(:@@cvar_overtaken, :subclass) + parent.class_variable_set(:@@cvar_overtaken, :parent) + + -> { + subclass.class_variable_get(:@@cvar_overtaken) + }.should raise_error(RuntimeError, /class variable @@cvar_overtaken of .+ is overtaken by .+/) + + parent.class_variable_get(:@@cvar_overtaken).should == :parent + end end end diff --git a/spec/ruby/language/comment_spec.rb b/spec/ruby/language/comment_spec.rb index dd788e681c..690e844dc0 100644 --- a/spec/ruby/language/comment_spec.rb +++ b/spec/ruby/language/comment_spec.rb @@ -1,13 +1,15 @@ require_relative '../spec_helper' describe "The comment" do - it "can be placed between fluent dot now" do - code = <<~CODE - 10 - # some comment - .to_s - CODE + ruby_version_is "2.7" do + it "can be placed between fluent dot now" do + code = <<~CODE + 10 + # some comment + .to_s + CODE - eval(code).should == '10' + eval(code).should == '10' + end end end diff --git a/spec/ruby/language/constants_spec.rb b/spec/ruby/language/constants_spec.rb index 08c534487e..03f1272401 100644 --- a/spec/ruby/language/constants_spec.rb +++ b/spec/ruby/language/constants_spec.rb @@ -135,34 +135,18 @@ describe "Literal (A::X) constant resolution" do ConstantSpecs::ClassB::CS_CONST109.should == :const109_2 end - ruby_version_is "3.2" do - it "evaluates left-to-right" do - mod = Module.new + it "evaluates the right hand side before evaluating a constant path" do + mod = Module.new - mod.module_eval <<-EOC - order = [] - ConstantSpecsRHS = Module.new - (order << :lhs; ConstantSpecsRHS)::B = (order << :rhs) - EOC + mod.module_eval <<-EOC + ConstantSpecsRHS::B = begin + module ConstantSpecsRHS; end - 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 + "hello" + end + EOC - mod::ConstantSpecsRHS::B.should == 'hello' - end + mod::ConstantSpecsRHS::B.should == 'hello' end end @@ -170,32 +154,34 @@ describe "Literal (A::X) constant resolution" do -> { ConstantSpecs::ParentA::CS_CONSTX }.should raise_error(NameError) end - it "uses the module or class #name to craft the error message" do - mod = Module.new do - def self.name - "ModuleName" - end + ruby_version_is "3.0" do + it "uses the module or class #name to craft the error message" do + mod = Module.new do + def self.name + "ModuleName" + end - def self.inspect - "<unusable info>" + def self.inspect + "<unusable info>" + end end + + -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant ModuleName::DOES_NOT_EXIST/) end - -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant ModuleName::DOES_NOT_EXIST/) - end + it "uses the module or class #inspect to craft the error message if they are anonymous" do + mod = Module.new do + def self.name + nil + end - it "uses the module or class #inspect to craft the error message if they are anonymous" do - mod = Module.new do - def self.name - nil + def self.inspect + "<unusable info>" + end end - def self.inspect - "<unusable info>" - end + -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant <unusable info>::DOES_NOT_EXIST/) end - - -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant <unusable info>::DOES_NOT_EXIST/) end it "sends #const_missing to the original class or module scope" do @@ -732,17 +718,3 @@ 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 c8531343c0..6b0be19d90 100644 --- a/spec/ruby/language/def_spec.rb +++ b/spec/ruby/language/def_spec.rb @@ -197,15 +197,32 @@ describe "An instance method with a default argument" do foo(2,3,3).should == [2,3,[3]] end - it "raises a SyntaxError when there is an existing method with the same name as the local variable" do - def bar - 1 + 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) 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 b84fe9394a..38345c3727 100644 --- a/spec/ruby/language/defined_spec.rb +++ b/spec/ruby/language/defined_spec.rb @@ -48,20 +48,6 @@ 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) @@ -180,32 +166,6 @@ describe "The defined? keyword when called with a method name" do ScratchPad.recorded.should == :defined_specs_fixnum_method end end - - describe "having a throw in the receiver" do - it "escapes defined? and performs the throw semantics as normal" do - defined_returned = false - catch(:out) { - # NOTE: defined? behaves differently if it is called in a void context, see below - defined?(throw(:out, 42).foo).should == :unreachable - defined_returned = true - }.should == 42 - defined_returned.should == false - end - end - - describe "in a void context" do - it "does not execute the receiver" do - ScratchPad.record :not_executed - defined?(DefinedSpecs.side_effects / 2) - ScratchPad.recorded.should == :not_executed - end - - it "warns about the void context when parsing it" do - -> { - eval "defined?(DefinedSpecs.side_effects / 2); 42" - }.should complain(/warning: possibly useless use of defined\? in void context/, verbose: true) - end - end end describe "The defined? keyword for an expression" do diff --git a/spec/ruby/language/delegation_spec.rb b/spec/ruby/language/delegation_spec.rb index 020787aff6..8e4183cbcc 100644 --- a/spec/ruby/language/delegation_spec.rb +++ b/spec/ruby/language/delegation_spec.rb @@ -1,63 +1,68 @@ require_relative '../spec_helper' require_relative 'fixtures/delegation' -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 - - it "delegates block" do - a = Class.new(DelegationSpecs::Target) - a.class_eval(<<-RUBY) - def delegate_block(...) - target_block(...) - end - RUBY +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 - a.new.delegate_block(1, b: 2) { |x| x }.should == [{b: 2}, [1]] - end + a.new.delegate(1, b: 2).should == [[1], {b: 2}] + end - it "parses as open endless Range when brackets are omitted" do - a = Class.new(DelegationSpecs::Target) - suppress_warning do + it "delegates block" do + a = Class.new(DelegationSpecs::Target) a.class_eval(<<-RUBY) - def delegate(...) - target ... + def delegate_block(...) + target_block(...) end - RUBY - end + RUBY + + a.new.delegate_block(1, b: 2) { |x| x }.should == [{b: 2}, [1]] + end - a.new.delegate(1, b: 2).should == Range.new([[], {}], nil, true) + 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 end end -describe "delegation with def(x, ...)" do - it "delegates rest and kwargs" do - a = Class.new(DelegationSpecs::Target) - a.class_eval(<<-RUBY) - def delegate(x, ...) - target(...) - end - RUBY +ruby_version_is "2.7.3" do + describe "delegation with def(x, ...)" do + it "delegates rest and kwargs" do + a = Class.new(DelegationSpecs::Target) + a.class_eval(<<-RUBY) + def delegate(x, ...) + target(...) + end + RUBY - a.new.delegate(0, 1, b: 2).should == [[1], {b: 2}] - end + a.new.delegate(0, 1, b: 2).should == [[1], {b: 2}] + end + + it "delegates block" do + a = Class.new(DelegationSpecs::Target) + a.class_eval(<<-RUBY) + def delegate_block(x, ...) + target_block(...) + end + RUBY - it "delegates block" do - a = Class.new(DelegationSpecs::Target) - a.class_eval(<<-RUBY) - def delegate_block(x, ...) - target_block(...) - end - RUBY + a.new.delegate_block(0, 1, b: 2) { |x| x }.should == [{b: 2}, [1]] + end - a.new.delegate_block(0, 1, b: 2) { |x| x }.should == [{b: 2}, [1]] end end diff --git a/spec/ruby/language/file_spec.rb b/spec/ruby/language/file_spec.rb index 59563d9642..729dee1008 100644 --- a/spec/ruby/language/file_spec.rb +++ b/spec/ruby/language/file_spec.rb @@ -7,23 +7,23 @@ describe "The __FILE__ pseudo-variable" do -> { eval("__FILE__ = 1") }.should raise_error(SyntaxError) end - ruby_version_is ""..."3.3" do - it "equals (eval) inside an eval" do - eval("__FILE__").should == "(eval)" - end + it "equals (eval) inside an eval" do + eval("__FILE__").should == "(eval)" end +end - ruby_version_is "3.3" do - it "equals (eval at __FILE__:__LINE__) inside an eval" do - eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})" - end - end +describe "The __FILE__ pseudo-variable" do + it_behaves_like :language___FILE__, :require, CodeLoadingSpecs::Method.new end -describe "The __FILE__ pseudo-variable with require" do +describe "The __FILE__ pseudo-variable" do it_behaves_like :language___FILE__, :require, Kernel end -describe "The __FILE__ pseudo-variable with load" do +describe "The __FILE__ pseudo-variable" do + it_behaves_like :language___FILE__, :load, CodeLoadingSpecs::Method.new +end + +describe "The __FILE__ pseudo-variable" 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 a9552619bf..8b6004c19f 100644 --- a/spec/ruby/language/fixtures/defined.rb +++ b/spec/ruby/language/fixtures/defined.rb @@ -19,9 +19,6 @@ module DefinedSpecs DefinedSpecs end - def self.any_args(*) - end - class Basic A = 42 diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb b/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb Binary files differindex f72a32e879..d0558a2251 100644 --- a/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb +++ b/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb 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 cccc5969bd..a4d655ad02 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".equal?("abc") +p "abc".object_id == "abc".object_id diff --git a/spec/ruby/language/fixtures/super.rb b/spec/ruby/language/fixtures/super.rb index 94a2a91be0..218f1e4970 100644 --- a/spec/ruby/language/fixtures/super.rb +++ b/spec/ruby/language/fixtures/super.rb @@ -556,20 +556,6 @@ module SuperSpecs end end - module ZSuperInBlock - class A - def m(arg:) - arg - end - end - - class B < A - def m(arg:) - proc { super }.call - end - end - end - module Keywords class Arguments def foo(**args) diff --git a/spec/ruby/language/fixtures/variables.rb b/spec/ruby/language/fixtures/variables.rb index 527caa7a78..07265dbb2b 100644 --- a/spec/ruby/language/fixtures/variables.rb +++ b/spec/ruby/language/fixtures/variables.rb @@ -82,76 +82,4 @@ module VariablesSpecs def self.false false end - - class EvalOrder - attr_reader :order - - def initialize - @order = [] - end - - def reset - @order = [] - end - - def foo - self << "foo" - FooClass.new(self) - end - - def bar - self << "bar" - BarClass.new(self) - end - - def a - self << "a" - end - - def b - self << "b" - end - - def node - self << "node" - - node = Node.new - node.left = Node.new - node.left.right = Node.new - - node - end - - def <<(value) - order << value - end - - class FooClass - attr_reader :evaluator - - def initialize(evaluator) - @evaluator = evaluator - end - - def []=(_index, _value) - evaluator << "foo[]=" - end - end - - class BarClass - attr_reader :evaluator - - def initialize(evaluator) - @evaluator = evaluator - end - - def baz=(_value) - evaluator << "bar.baz=" - end - end - - class Node - attr_accessor :left, :right - end - end end diff --git a/spec/ruby/language/hash_spec.rb b/spec/ruby/language/hash_spec.rb index 6ac382c42c..2f8b97199a 100644 --- a/spec/ruby/language/hash_spec.rb +++ b/spec/ruby/language/hash_spec.rb @@ -127,24 +127,11 @@ describe "Hash literal" do {a: 1, **h, c: 4}.should == {a: 1, b: 2, c: 4} end - it "expands an '**{}' or '**obj' element with the last key/value pair taking precedence" do + it "expands an '**{}' element with the last key/value pair taking precedence" do -> { @h = eval "{a: 1, **{a: 2, b: 3, c: 1}, c: 3}" }.should complain(/key :a is duplicated|duplicated key/) @h.should == {a: 2, b: 3, c: 3} - - -> { - h = {a: 2, b: 3, c: 1} - @h = eval "{a: 1, **h, c: 3}" - }.should_not complain - @h.should == {a: 2, b: 3, c: 3} - end - - it "expands an '**{}' and warns when finding an additional duplicate key afterwards" do - -> { - @h = eval "{d: 1, **{a: 2, b: 3, c: 1}, c: 3}" - }.should complain(/key :c is duplicated|duplicated key/) - @h.should == {a: 2, b: 3, c: 3, d: 1} end it "merges multiple nested '**obj' in Hash literals" do @@ -161,9 +148,18 @@ describe "Hash literal" do {a: 1, **obj, c: 3}.should == {a:1, b: 2, c: 3, d: 4} 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} + 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 end it "raises a TypeError if #to_hash does not return a Hash" do @@ -190,22 +186,6 @@ describe "Hash literal" do utf8_hash.keys.first.should == usascii_hash.keys.first usascii_hash.keys.first.encoding.should == Encoding::US_ASCII end - - it "raises an EncodingError at parse time when Symbol key with invalid bytes" do - ScratchPad.record [] - -> { - eval 'ScratchPad << 1; {:"\xC3" => 1}' - }.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"') - ScratchPad.recorded.should == [] - end - - it "raises an EncodingError at parse time when Symbol key with invalid bytes and 'key: value' syntax used" do - ScratchPad.record [] - -> { - eval 'ScratchPad << 1; {"\xC3": 1}' - }.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"') - ScratchPad.recorded.should == [] - end end describe "The ** operator" do @@ -220,8 +200,8 @@ describe "The ** operator" do h.should == { one: 1, two: 2 } end - ruby_bug "#20012", ""..."3.3" do - it "makes a copy when calling a method taking a positional Hash" do + ruby_version_is ""..."3.0" do + it "makes a caller-side copy when calling a method taking a positional Hash" do def m(h) h.delete(:one); h end @@ -233,6 +213,19 @@ describe "The ** operator" do end end + ruby_version_is "3.0" do + it "does not copy when calling a method taking a positional Hash" do + def m(h) + h.delete(:one); h + end + + h = { one: 1, two: 2 } + m(**h).should == { two: 2 } + m(**h).should.equal?(h) + h.should == { two: 2 } + end + end + ruby_version_is "3.1" do describe "hash with omitted value" do it "accepts short notation 'key' for 'key: value' syntax" do diff --git a/spec/ruby/language/heredoc_spec.rb b/spec/ruby/language/heredoc_spec.rb index b3b160fd11..61a27ad8e0 100644 --- a/spec/ruby/language/heredoc_spec.rb +++ b/spec/ruby/language/heredoc_spec.rb @@ -59,10 +59,20 @@ HERE s.encoding.should == Encoding::US_ASCII 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) + 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 end it "allows HEREDOC with <<~'identifier', allowing to indent identifier and content" do diff --git a/spec/ruby/language/if_spec.rb b/spec/ruby/language/if_spec.rb index a5da696000..d1d95c1607 100644 --- a/spec/ruby/language/if_spec.rb +++ b/spec/ruby/language/if_spec.rb @@ -306,49 +306,6 @@ describe "The if expression" do ScratchPad.recorded.should == [4, 5, 4, 5] end end - - describe "when a branch syntactically does not return a value" do - it "raises SyntaxError if both do not return a value" do - -> { - eval <<~RUBY - def m - a = if rand - return - else - return - end - a - end - RUBY - }.should raise_error(SyntaxError, /void value expression/) - end - - it "does not raise SyntaxError if one branch returns a value" do - eval(<<~RUBY).should == 1 - def m - a = if false # using false to make it clear that's not checked for - 42 - else - return 1 - end - a - end - m - RUBY - - eval(<<~RUBY).should == 1 - def m - a = if true # using true to make it clear that's not checked for - return 1 - else - 42 - end - a - end - m - RUBY - end - end end describe "The postfix if form" do diff --git a/spec/ruby/language/keyword_arguments_spec.rb b/spec/ruby/language/keyword_arguments_spec.rb deleted file mode 100644 index ffb5b1fab0..0000000000 --- a/spec/ruby/language/keyword_arguments_spec.rb +++ /dev/null @@ -1,398 +0,0 @@ -require_relative '../spec_helper' - -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') - -> { m(kw: 1, a: 1, b: 2, c: 3) }.should raise_error(ArgumentError, 'unknown keywords: :a, :b, :c') - end - - it "raises ArgumentError exception when required keyword argument is not passed" do - def m(a:, b:, c:) - [a, b, c] - end - - -> { m(a: 1, b: 2) }.should raise_error(ArgumentError, /missing keyword: :c/) - -> { m() }.should raise_error(ArgumentError, /missing keywords: :a, :b, :c/) - end - - it "raises ArgumentError for missing keyword arguments even if there are extra ones" do - def m(a:) - a - end - - -> { m(b: 1) }.should raise_error(ArgumentError, /missing keyword: :a/) - end - - it "handle * and ** at the same call site" do - def m(*a) - a - end - - m(*[], **{}).should == [] - m(*[], 42, **{}).should == [42] - end - - context "**" do - ruby_version_is "3.3" do - it "copies a non-empty Hash for a method taking (*args)" do - def m(*args) - args[0] - end - - h = {a: 1} - m(**h).should_not.equal?(h) - h.should == {a: 1} - end - 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.1" do - describe "omitted values" do - it "accepts short notation 'key' for 'key: value' syntax" do - def m(a:, b:) - [a, b] - end - - a = 1 - b = 2 - - eval('m(a:, b:).should == [1, 2]') - end - end - 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 diff --git a/spec/ruby/language/lambda_spec.rb b/spec/ruby/language/lambda_spec.rb index 3ab3569ebe..6393fb5c47 100644 --- a/spec/ruby/language/lambda_spec.rb +++ b/spec/ruby/language/lambda_spec.rb @@ -177,16 +177,34 @@ describe "A lambda literal -> () { }" do result.should == [1, 2, 3, [4, 5], 6, [7, 8], 9, 10, 11, 12] end - evaluate <<-ruby do - @a = -> (*, **k) { k } - ruby + ruby_version_is ''...'3.0' do + evaluate <<-ruby do + @a = -> (*, **k) { k } + ruby + + @a.().should == {} + @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5} + + suppress_keyword_warning do + h = mock("keyword splat") + h.should_receive(:to_hash).and_return({a: 1}) + @a.(h).should == {a: 1} + end + end + end - @a.().should == {} - @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5} + ruby_version_is '3.0' do + evaluate <<-ruby do + @a = -> (*, **k) { k } + ruby - h = mock("keyword splat") - h.should_not_receive(:to_hash) - @a.(h).should == {} + @a.().should == {} + @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5} + + h = mock("keyword splat") + h.should_not_receive(:to_hash) + @a.(h).should == {} + end end evaluate <<-ruby do @@ -263,18 +281,38 @@ describe "A lambda literal -> () { }" do end describe "with circular optional argument reference" 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) + 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 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) + 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 end it "calls an existing method with the same name as the argument if explicitly using ()" do @@ -322,12 +360,26 @@ describe "A lambda expression 'lambda { ... }'" do def meth; lambda; end end - it "raises ArgumentError" do - implicit_lambda = nil - suppress_warning do + ruby_version_is ""..."2.7" do + it "can be created" do + implicit_lambda = nil -> { - meth { 1 } - }.should raise_error(ArgumentError, /tried to create Proc object without a block/) + 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 end end end @@ -496,16 +548,34 @@ describe "A lambda expression 'lambda { ... }'" do result.should == [1, 2, 3, [4, 5], 6, [7, 8], 9, 10, 11, 12] end - evaluate <<-ruby do - @a = lambda { |*, **k| k } - ruby + ruby_version_is ''...'3.0' do + evaluate <<-ruby do + @a = lambda { |*, **k| k } + ruby - @a.().should == {} - @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5} + @a.().should == {} + @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5} + + suppress_keyword_warning do + h = mock("keyword splat") + h.should_receive(:to_hash).and_return({a: 1}) + @a.(h).should == {a: 1} + end + end + end + + ruby_version_is '3.0' do + evaluate <<-ruby do + @a = lambda { |*, **k| k } + ruby - h = mock("keyword splat") - h.should_not_receive(:to_hash) - @a.(h).should == {} + @a.().should == {} + @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5} + + h = mock("keyword splat") + h.should_not_receive(:to_hash) + @a.(h).should == {} + end end evaluate <<-ruby do diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb index 5f42c52341..0a5bb99d0b 100644 --- a/spec/ruby/language/method_spec.rb +++ b/spec/ruby/language/method_spec.rb @@ -572,13 +572,6 @@ describe "A method" do end evaluate <<-ruby do - def m(a:, **kw) [a, kw] end - ruby - - -> { m(b: 1) }.should raise_error(ArgumentError) - end - - evaluate <<-ruby do def m(a: 1) a end ruby @@ -609,11 +602,13 @@ describe "A method" do -> { m(2) }.should raise_error(ArgumentError) end - evaluate <<-ruby do - def m(**k); k end; - ruby + ruby_version_is "2.7" do + evaluate <<-ruby do + def m(**k); k end; + ruby - m("a" => 1).should == { "a" => 1 } + m("a" => 1).should == { "a" => 1 } + end end evaluate <<-ruby do @@ -749,31 +744,68 @@ describe "A method" do end end - evaluate <<-ruby do - def m(a, b: 1) [a, b] end - ruby + ruby_version_is ""..."3.0" do + evaluate <<-ruby do + def m(a, b: 1) [a, b] end + ruby - m(2).should == [2, 1] - m(1, b: 2).should == [1, 2] - -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError) - end + m(2).should == [2, 1] + m(1, b: 2).should == [1, 2] + suppress_keyword_warning do + m("a" => 1, b: 2).should == [{"a" => 1, b: 2}, 1] + end + end - evaluate <<-ruby do - def m(a, **) a end - ruby + evaluate <<-ruby do + def m(a, **) a end + ruby - m(1).should == 1 - m(1, a: 2, b: 3).should == 1 - -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError) + m(1).should == 1 + m(1, a: 2, b: 3).should == 1 + suppress_keyword_warning do + m("a" => 1, b: 2).should == {"a" => 1, b: 2} + end + end + + evaluate <<-ruby do + def m(a, **k) [a, k] end + ruby + + m(1).should == [1, {}] + m(1, a: 2, b: 3).should == [1, {a: 2, b: 3}] + suppress_keyword_warning do + m("a" => 1, b: 2).should == [{"a" => 1, b: 2}, {}] + end + end end - evaluate <<-ruby do - def m(a, **k) [a, k] end - ruby + ruby_version_is "3.0" do + evaluate <<-ruby do + def m(a, b: 1) [a, b] end + ruby - m(1).should == [1, {}] - m(1, a: 2, b: 3).should == [1, {a: 2, b: 3}] - -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError) + m(2).should == [2, 1] + m(1, b: 2).should == [1, 2] + -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError) + end + + evaluate <<-ruby do + def m(a, **) a end + ruby + + m(1).should == 1 + m(1, a: 2, b: 3).should == 1 + -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError) + end + + evaluate <<-ruby do + def m(a, **k) [a, k] end + ruby + + m(1).should == [1, {}] + m(1, a: 2, b: 3).should == [1, {a: 2, b: 3}] + -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError) + end end evaluate <<-ruby do @@ -884,32 +916,72 @@ describe "A method" do result.should == [[1, 2, 3], 4, [5, 6], 7, [], 8] end - evaluate <<-ruby do - def m(a=1, b:) [a, b] end - ruby + ruby_version_is ""..."3.0" do + evaluate <<-ruby do + def m(a=1, b:) [a, b] end + ruby + + m(b: 2).should == [1, 2] + m(2, b: 1).should == [2, 1] + suppress_keyword_warning do + m("a" => 1, b: 2).should == [{"a" => 1}, 2] + end + end - m(b: 2).should == [1, 2] - m(2, b: 1).should == [2, 1] - -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError) + evaluate <<-ruby do + def m(a=1, b: 2) [a, b] end + ruby + + m().should == [1, 2] + m(2).should == [2, 2] + m(b: 3).should == [1, 3] + suppress_keyword_warning do + m("a" => 1, b: 2).should == [{"a" => 1}, 2] + end + end end - evaluate <<-ruby do - def m(a=1, b: 2) [a, b] end - ruby + ruby_version_is "3.0" do + evaluate <<-ruby do + def m(a=1, b:) [a, b] end + ruby - m().should == [1, 2] - m(2).should == [2, 2] - m(b: 3).should == [1, 3] - -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError) + m(b: 2).should == [1, 2] + m(2, b: 1).should == [2, 1] + -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError) + end + + evaluate <<-ruby do + def m(a=1, b: 2) [a, b] end + ruby + + m().should == [1, 2] + m(2).should == [2, 2] + m(b: 3).should == [1, 3] + -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError) + end end - evaluate <<-ruby do - def m(a=1, **) a end - ruby + 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 == 1 + 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 + + m().should == 1 + m(2, a: 1, b: 0).should == 2 + m("a" => 1, a: 2).should == 1 + end end evaluate <<-ruby do @@ -949,6 +1021,449 @@ 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 + 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(*a, **) a end + ruby + + m().should == [] + m(1, 2, 3, a: 4, b: 5).should == [1, 2, 3] + m("a" => 1, a: 1).should == [] + 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, a: 1} + + h = mock("keyword splat") + h.should_receive(:to_hash).and_return({a: 1}) + suppress_warning do + m(h).should == {a: 1} + end + end + + evaluate <<-ruby do + def m(a = nil, **k) [a, k] end + ruby + + m().should == [nil, {}] + m("a" => 1).should == [nil, {"a" => 1}] + m(a: 1).should == [nil, {a: 1}] + m("a" => 1, a: 1).should == [nil, {"a" => 1, a: 1}] + m({ "a" => 1 }, a: 1).should == [{"a" => 1}, {a: 1}] + suppress_warning do + 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 + 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}] + suppress_warning do + m({a: 1}, {}).should == [[{a: 1}], {}] + end + 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 + + 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(*a, **) a end + ruby + + m().should == [] + m(1, 2, 3, a: 4, b: 5).should == [1, 2, 3] + m("a" => 1, a: 1).should == [] + 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, a: 1} + + h = mock("keyword splat") + h.should_receive(:to_hash).and_return({a: 1}) + suppress_keyword_warning do + m(h).should == {a: 1} + end + end + + evaluate <<-ruby do + def m(a = nil, **k) [a, k] end + ruby + + m().should == [nil, {}] + m("a" => 1).should == [nil, {"a" => 1}] + m(a: 1).should == [nil, {a: 1}] + m("a" => 1, a: 1).should == [nil, {"a" => 1, a: 1}] + m({ "a" => 1 }, a: 1).should == [{"a" => 1}, {a: 1}] + suppress_keyword_warning do + m({a: 1}, {}).should == [{a: 1}, {}] + end + + h = {"a" => 1, b: 2} + suppress_keyword_warning do + m(h).should == [{"a" => 1}, {b: 2}] + end + h.should == {"a" => 1, b: 2} + + h = {"a" => 1} + m(h).first.should == h + + h = {} + suppress_keyword_warning do + m(h).should == [nil, {}] + end + + hh = {} + h = mock("keyword splat empty hash") + h.should_receive(:to_hash).and_return({a: 1}) + suppress_keyword_warning do + m(h).should == [nil, {a: 1}] + end + + h = mock("keyword splat") + h.should_receive(:to_hash).and_return({"a" => 1}) + m(h).should == [h, {}] + 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}] + suppress_keyword_warning do + m({a: 1}, {}).should == [[{a: 1}], {}] + end + 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 + evaluate <<-ruby do def m(*, &b) b end ruby @@ -988,22 +1503,44 @@ describe "A method" do end end - evaluate <<-ruby do - def m(a:, **) a end - ruby + 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 + 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 + + 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 end - evaluate <<-ruby do - def m(a:, **k) [a, k] end - ruby + 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 - 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}] + 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 end evaluate <<-ruby do @@ -1100,66 +1637,125 @@ describe "A method" do result.should == [1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l] end - evaluate <<-ruby do - def m(a, **nil); a end; - ruby + ruby_version_is "2.7" do + 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, 'no keywords accepted') - -> { m(**{a: 1}) }.should raise_error(ArgumentError, 'no keywords accepted') - -> { m("a" => 1) }.should raise_error(ArgumentError, 'no keywords accepted') + -> { m(a: 1) }.should raise_error(ArgumentError) + -> { m(**{a: 1}) }.should raise_error(ArgumentError) + -> { m("a" => 1) }.should raise_error(ArgumentError) + end end - evaluate <<-ruby do - def m(a, b = nil, c = nil, d, e: nil, **f) - [a, b, c, d, e, f] + ruby_version_is ''...'3.0' do + evaluate <<-ruby do + def m(a, b = nil, c = nil, d, e: nil, **f) + [a, b, c, d, e, f] + end + ruby + + result = m(1, 2) + result.should == [1, nil, nil, 2, nil, {}] + + suppress_warning do + result = m(1, 2, {foo: :bar}) + result.should == [1, nil, nil, 2, nil, {foo: :bar}] end - ruby - result = m(1, 2) - result.should == [1, nil, nil, 2, nil, {}] + result = m(1, {foo: :bar}) + result.should == [1, nil, nil, {foo: :bar}, nil, {}] + end + end + + ruby_version_is '3.0' do + evaluate <<-ruby do + def m(a, b = nil, c = nil, d, e: nil, **f) + [a, b, c, d, e, f] + end + ruby + + result = m(1, 2) + result.should == [1, nil, nil, 2, nil, {}] - result = m(1, 2, {foo: :bar}) - result.should == [1, 2, nil, {foo: :bar}, nil, {}] + result = m(1, 2, {foo: :bar}) + result.should == [1, 2, nil, {foo: :bar}, nil, {}] - result = m(1, {foo: :bar}) - result.should == [1, nil, nil, {foo: :bar}, nil, {}] + result = m(1, {foo: :bar}) + result.should == [1, nil, nil, {foo: :bar}, nil, {}] + end end end - 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 + 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 - h = {} - m(**h).should == [] + h = {} + m(**h).should == [] + end end end - 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 = {} + ruby_version_is '2.7'...'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 + ruby + h = {} - -> do - m(**h).should == {} - end.should raise_error(ArgumentError) + -> do + m(**h).should == {} + end.should complain(/warning: Passing the keyword argument as the last hash parameter is deprecated/) + end end end - context "raises ArgumentError if passing hash as keyword arguments" do - evaluate <<-ruby do - def m(a: nil); a; end - ruby + ruby_version_is ''...'3.0' do + context "assigns keyword arguments from a passed Hash without modifying it" do + evaluate <<-ruby do + def m(a: nil); a; end + ruby + + options = {a: 1}.freeze + -> do + suppress_warning do + m(options).should == 1 + end + end.should_not raise_error + options.should == {a: 1} + end + end + end + + 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 + ruby + h = {} - options = {a: 1}.freeze - -> do - m(options) - end.should raise_error(ArgumentError) + -> do + m(**h).should == {} + end.should raise_error(ArgumentError) + end + end + + context "raises ArgumentError if passing hash as keyword arguments" do + evaluate <<-ruby do + def m(a: nil); a; end + ruby + + options = {a: 1}.freeze + -> do + m(options) + end.should raise_error(ArgumentError) + end end end @@ -1193,42 +1789,14 @@ describe "A method call with a space between method name and parentheses" do end end - context "when a single argument is provided" do - it "assigns a simple expression" do - args = m (1) - args.should == [1] - end - - it "assigns an expression consisting of multiple statements" do - args = m ((0; 1)) - args.should == [1] - end - - it "assigns one single statement, without the need of parentheses" do + context "when a single argument provided" do + it "assigns it" do args = m (1 == 1 ? true : false) args.should == [true] end - - ruby_version_is "3.3" do - it "supports multiple statements" do - eval("m (1; 2)").should == [2] - end - end - end - - context "when multiple arguments are provided" do - it "assigns simple expressions" do - args = m (1), (2) - args.should == [1, 2] - end - - it "assigns expressions consisting of multiple statements" do - args = m ((0; 1)), ((2; 3)) - args.should == [1, 3] - end end - context "when the argument looks like an argument list" do + context "when 2+ arguments provided" do it "raises a syntax error" do -> { eval("m (1, 2)") @@ -1293,107 +1861,86 @@ describe "An array-dereference method ([])" do end end -describe "An endless method definition" do - context "without arguments" do - evaluate <<-ruby do - def m() = 42 - ruby +ruby_version_is "3.0" do + describe "An endless method definition" do + context "without arguments" do + evaluate <<-ruby do + def m() = 42 + ruby - m.should == 42 + m.should == 42 + end end - context "without parenthesis" do + context "with arguments" do evaluate <<-ruby do - def m = 42 - ruby + def m(a, b) = a + b + ruby - m.should == 42 + m(1, 4).should == 5 end end - end - context "with arguments" do - evaluate <<-ruby do - def m(a, b) = a + b - ruby + context "with multiline body" do + evaluate <<-ruby do + def m(n) = + if n > 2 + m(n - 2) + m(n - 1) + else + 1 + end + ruby - m(1, 4).should == 5 + m(6).should == 8 + end end - end - context "with multiline body" do - evaluate <<-ruby do - def m(n) = - if n > 2 - m(n - 2) + m(n - 1) - else - 1 + context "with args forwarding" do + evaluate <<-ruby do + def mm(word, num:) + word * num end - ruby - m(6).should == 8 + def m(...) = mm(...) + mm(...) + ruby + + m("meow", num: 2).should == "meow" * 4 + end end end - context "with args forwarding" do - evaluate <<-ruby do - def mm(word, num:) - word * num + describe "Keyword arguments are now separated from positional arguments" do + context "when the method has only positional parameters" do + it "treats incoming keyword arguments as positional for compatibility" do + def foo(a, b, c, hsh) + hsh[:key] end - def m(...) = mm(...) + mm(...) - ruby - - m("meow", num: 2).should == "meow" * 4 - end - end -end - -describe "Keyword arguments are now separated from positional arguments" do - context "when the method has only positional parameters" do - it "treats incoming keyword arguments as positional for compatibility" do - def foo(a, b, c, hsh) - hsh[:key] + foo(1, 2, 3, key: 42).should == 42 end - - foo(1, 2, 3, key: 42).should == 42 end - end - context "when the method takes a ** parameter" do - it "captures the passed literal keyword arguments" do - def foo(a, b, c, **hsh) - hsh[:key] - end - - foo(1, 2, 3, key: 42).should == 42 - end + context "when the method takes a ** parameter" do + it "captures the passed literal keyword arguments" do + def foo(a, b, c, **hsh) + hsh[:key] + end - it "captures the passed ** keyword arguments" do - def foo(a, b, c, **hsh) - hsh[:key] + foo(1, 2, 3, key: 42).should == 42 end - h = { key: 42 } - foo(1, 2, 3, **h).should == 42 - end + it "captures the passed ** keyword arguments" do + def foo(a, b, c, **hsh) + hsh[:key] + end - it "does not convert a positional Hash to keyword arguments" do - def foo(a, b, c, **hsh) - hsh[:key] + h = { key: 42 } + foo(1, 2, 3, **h).should == 42 end - -> { - foo(1, 2, 3, { key: 42 }) - }.should raise_error(ArgumentError, 'wrong number of arguments (given 4, expected 3)') - end - end - - context "when the method takes a key: parameter" do - context "when it's called with a positional Hash and no **" do - it "raises ArgumentError" do - def foo(a, b, c, key: 1) - key + it "does not convert a positional Hash to keyword arguments" do + def foo(a, b, c, **hsh) + hsh[:key] end -> { @@ -1402,14 +1949,28 @@ describe "Keyword arguments are now separated from positional arguments" do end end - context "when it's called with **" do - it "captures the passed keyword arguments" do - def foo(a, b, c, key: 1) - key + context "when the method takes a key: parameter" do + context "when it's called with a positional Hash and no **" do + it "raises ArgumentError" do + def foo(a, b, c, key: 1) + key + end + + -> { + foo(1, 2, 3, { key: 42 }) + }.should raise_error(ArgumentError, 'wrong number of arguments (given 4, expected 3)') end + end - h = { key: 42 } - foo(1, 2, 3, **h).should == 42 + context "when it's called with **" do + it "captures the passed keyword arguments" do + def foo(a, b, c, key: 1) + key + end + + h = { key: 42 } + foo(1, 2, 3, **h).should == 42 + end end end end @@ -1454,14 +2015,4 @@ ruby_version_is "3.1" do end end end - - describe "Inside 'endless' method definitions" do - it "allows method calls without parenthesis" do - eval <<-ruby - def greet(person) = "Hi, ".concat person - ruby - - greet("Homer").should == "Hi, Homer" - end - end end diff --git a/spec/ruby/language/module_spec.rb b/spec/ruby/language/module_spec.rb index fffcf9c90d..1a5fcaf46f 100644 --- a/spec/ruby/language/module_spec.rb +++ b/spec/ruby/language/module_spec.rb @@ -28,18 +28,9 @@ describe "The module keyword" do ModuleSpecs::Reopened.should be_true end - ruby_version_is '3.2' do - it "does not reopen a module included in Object" do - module IncludedModuleSpecs; Reopened = true; end - ModuleSpecs::IncludedInObject::IncludedModuleSpecs.should_not == Object::IncludedModuleSpecs - end - end - - ruby_version_is ''...'3.2' do - it "reopens a module included in Object" do - module IncludedModuleSpecs; Reopened = true; end - ModuleSpecs::IncludedInObject::IncludedModuleSpecs::Reopened.should be_true - end + it "reopens a module included in Object" do + module IncludedModuleSpecs; Reopened = true; end + ModuleSpecs::IncludedInObject::IncludedModuleSpecs::Reopened.should be_true end it "raises a TypeError if the constant is a Class" do @@ -78,10 +69,20 @@ describe "Assigning an anonymous module to a constant" do mod.name.should == "ModuleSpecs_CS1" end - it "sets the name of a module scoped by an anonymous module" do - a, b = Module.new, Module.new - a::B = b - b.name.should.end_with? '::B' + ruby_version_is ""..."3.0" do + it "does not set the name of a module scoped by an anonymous module" do + a, b = Module.new, Module.new + a::B = b + b.name.should be_nil + end + end + + ruby_version_is "3.0" do + it "sets the name of a module scoped by an anonymous module" do + a, b = Module.new, Module.new + a::B = b + b.name.should.end_with? '::B' + end end it "sets the name of contained modules when assigning a toplevel anonymous module" do diff --git a/spec/ruby/language/numbered_parameters_spec.rb b/spec/ruby/language/numbered_parameters_spec.rb index 3a35cf1465..838822b2d6 100644 --- a/spec/ruby/language/numbered_parameters_spec.rb +++ b/spec/ruby/language/numbered_parameters_spec.rb @@ -1,104 +1,120 @@ require_relative '../spec_helper' -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 +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 - 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 "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 "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 "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 "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 "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 "cannot be overwritten with local variable" do - -> { - eval <<~CODE - _1 = 0 - proc { _1 }.call("a").should == 0 - CODE - }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/) - 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 "errors when numbered parameter is overwritten with local variable" do - -> { - eval("_1 = 0") - }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/) - 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 + end + + it "warns when numbered parameter is overwritten with local variable" do + -> { + eval("_1 = 0") + }.should complain(/warning: `_1' is reserved for numbered parameter; consider another name/) + end + end - it "raises SyntaxError when block parameters are specified explicitly" do - -> { eval("-> () { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) - -> { eval("-> (x) { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + ruby_version_is '3.0' do + it "cannot be overwritten with local variable" do + -> { + eval <<~CODE + _1 = 0 + proc { _1 }.call("a").should == 0 + CODE + }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/) + end + + it "errors when numbered parameter is overwritten with local variable" do + -> { + eval("_1 = 0") + }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/) + end + end - -> { eval("proc { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) - -> { eval("proc { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + it "raises SyntaxError when block parameters are specified explicitly" do + -> { eval("-> () { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + -> { eval("-> (x) { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) - -> { eval("lambda { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) - -> { eval("lambda { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + -> { eval("proc { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + -> { eval("proc { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) - -> { eval("['a'].map { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) - -> { eval("['a'].map { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) - end + -> { eval("lambda { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + -> { eval("lambda { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) - describe "assigning to a numbered parameter" do - it "raises SyntaxError" do - -> { eval("proc { _1 = 0 }") }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/) + -> { eval("['a'].map { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + -> { eval("['a'].map { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) end - end - - it "affects block arity" do - -> { _1 }.arity.should == 1 - -> { _2 }.arity.should == 2 - -> { _3 }.arity.should == 3 - -> { _4 }.arity.should == 4 - -> { _5 }.arity.should == 5 - -> { _6 }.arity.should == 6 - -> { _7 }.arity.should == 7 - -> { _8 }.arity.should == 8 - -> { _9 }.arity.should == 9 - - -> { _9 }.arity.should == 9 - proc { _9 }.arity.should == 9 - lambda { _9 }.arity.should == 9 - end - it "affects block parameters" do - -> { _1 }.parameters.should == [[:req, :_1]] - -> { _2 }.parameters.should == [[:req, :_1], [:req, :_2]] - - proc { _1 }.parameters.should == [[:opt, :_1]] - proc { _2 }.parameters.should == [[:opt, :_1], [:opt, :_2]] - end + describe "assigning to a numbered parameter" do + ruby_version_is '2.7'...'3.0' do + it "warns" do + -> { eval("proc { _1 = 0 }") }.should complain(/warning: `_1' is reserved for numbered parameter; consider another name/) + end + end + + ruby_version_is '3.0' do + it "raises SyntaxError" do + -> { eval("proc { _1 = 0 }") }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/) + end + end + end - it "affects binding local variables" do - -> { _1; binding.local_variables }.call("a").should == [:_1] - -> { _2; binding.local_variables }.call("a", "b").should == [:_1, :_2] - end + it "affects block arity" do + -> { _1 }.arity.should == 1 + -> { _2 }.arity.should == 2 + -> { _3 }.arity.should == 3 + -> { _4 }.arity.should == 4 + -> { _5 }.arity.should == 5 + -> { _6 }.arity.should == 6 + -> { _7 }.arity.should == 7 + -> { _8 }.arity.should == 8 + -> { _9 }.arity.should == 9 + + -> { _9 }.arity.should == 9 + proc { _9 }.arity.should == 9 + lambda { _9 }.arity.should == 9 + end - it "does not work in methods" do - obj = Object.new - def obj.foo; _1 end + it "does not work in methods" do + obj = Object.new + def obj.foo; _1 end - -> { obj.foo("a") }.should raise_error(ArgumentError, /wrong number of arguments/) + -> { obj.foo("a") }.should raise_error(ArgumentError, /wrong number of arguments/) + end end end diff --git a/spec/ruby/language/numbers_spec.rb b/spec/ruby/language/numbers_spec.rb index a8e023efb6..2d8e19c40a 100644 --- a/spec/ruby/language/numbers_spec.rb +++ b/spec/ruby/language/numbers_spec.rb @@ -53,7 +53,7 @@ describe "A number literal" do eval('0.0174532925199432957r').should == Rational(174532925199432957, 10000000000000000000) end - it "can be a bignum literal with trailing 'r' to represent a Rational" do + it "can be an bignum literal with trailing 'r' to represent a Rational" do eval('1111111111111111111111111111111111111111111111r').should == Rational(1111111111111111111111111111111111111111111111, 1) eval('-1111111111111111111111111111111111111111111111r').should == Rational(-1111111111111111111111111111111111111111111111, 1) end diff --git a/spec/ruby/language/optional_assignments_spec.rb b/spec/ruby/language/optional_assignments_spec.rb index 02461655d6..217dcab74b 100644 --- a/spec/ruby/language/optional_assignments_spec.rb +++ b/spec/ruby/language/optional_assignments_spec.rb @@ -300,44 +300,6 @@ describe 'Optional variable assignments' do (@b[:k] ||= 12).should == 12 end - it 'correctly handles a splatted argument for the index' do - (@b[*[:k]] ||= 12).should == 12 - end - - it "evaluates the index precisely once" do - ary = [:x, :y] - @a[:x] = 15 - @a[ary.pop] ||= 25 - ary.should == [:x] - @a.should == { x: 15, y: 25 } - end - - it "evaluates the index arguments in the correct order" do - ary = Class.new(Array) do - def [](x, y) - super(x + 3 * y) - end - - def []=(x, y, value) - super(x + 3 * y, value) - end - end.new - ary[0, 0] = 1 - ary[1, 0] = 1 - ary[2, 0] = nil - ary[3, 0] = 1 - ary[4, 0] = 1 - ary[5, 0] = 1 - ary[6, 0] = nil - - foo = [0, 2] - - ary[foo.pop, foo.pop] ||= 2 - - ary[2, 0].should == 2 - ary[6, 0].should == nil - end - it 'returns the assigned value, not the result of the []= method with +=' do @b[:k] = 17 (@b[:k] += 12).should == 29 diff --git a/spec/ruby/language/pattern_matching_spec.rb b/spec/ruby/language/pattern_matching_spec.rb index 050a8a052d..e4abae9412 100644 --- a/spec/ruby/language/pattern_matching_spec.rb +++ b/spec/ruby/language/pattern_matching_spec.rb @@ -1,370 +1,196 @@ require_relative '../spec_helper' -describe "Pattern matching" do - # TODO: Remove excessive eval calls when Ruby 3 is the minimum version. - # It is best to keep the eval's longer if other Ruby impls cannot parse pattern matching yet. +ruby_version_is "2.7" do + describe "Pattern matching" do + # TODO: Remove excessive eval calls when support of previous version + # Ruby 2.6 will be dropped - before :each do - ScratchPad.record [] - end - - describe "can be standalone assoc operator that" do - it "deconstructs value" do - suppress_warning do - eval(<<-RUBY).should == [0, 1] - [0, 1] => [a, b] - [a, b] - RUBY - end + before :each do + ScratchPad.record [] end - it "deconstructs value and properly scopes variables" do - suppress_warning do - eval(<<-RUBY).should == [0, nil] - a = nil - eval(<<-PATTERN) + ruby_version_is "3.0" do + it "can be standalone assoc operator that deconstructs value" do + suppress_warning do + eval(<<-RUBY).should == [0, 1] [0, 1] => [a, b] - PATTERN - [a, defined?(b)] - RUBY - end - end - end - - describe "find pattern" do - it "captures preceding elements to the pattern" do - eval(<<~RUBY).should == [0, 1] - case [0, 1, 2, 3] - in [*pre, 2, 3] - pre - else - false - end - RUBY - end - - it "captures following elements to the pattern" do - eval(<<~RUBY).should == [2, 3] - case [0, 1, 2, 3] - in [0, 1, *post] - post - else - false + [a, b] + RUBY end - RUBY - end - - it "captures both preceding and following elements to the pattern" do - eval(<<~RUBY).should == [[0, 1], [3, 4]] - case [0, 1, 2, 3, 4] - in [*pre, 2, *post] - [pre, post] - else - false - end - RUBY - end - - it "can capture the entirety of the pattern" do - eval(<<~RUBY).should == [0, 1, 2, 3, 4] - case [0, 1, 2, 3, 4] - in [*everything] - everything - else - false - end - RUBY - end - - it "will match an empty Array-like structure" do - eval(<<~RUBY).should == [] - case [] - in [*everything] - everything - else - false - end - RUBY - end - - it "can be nested" do - eval(<<~RUBY).should == [[0, [2, 4, 6]], [[4, 16, 64]], 27] - case [0, [2, 4, 6], [3, 9, 27], [4, 16, 64]] - in [*pre, [*, 9, a], *post] - [pre, post, a] - else - false - end - RUBY - end + end - it "can be nested with an array pattern" do - eval(<<~RUBY).should == [[4, 16, 64]] - case [0, [2, 4, 6], [3, 9, 27], [4, 16, 64]] - in [_, _, [*, 9, *], *post] - post - else - false + describe "find pattern" do + it "captures preceding elements to the pattern" do + eval(<<~RUBY).should == [0, 1] + case [0, 1, 2, 3] + in [*pre, 2, 3] + pre + else + false + end + RUBY + end + + it "captures following elements to the pattern" do + eval(<<~RUBY).should == [2, 3] + case [0, 1, 2, 3] + in [0, 1, *post] + post + else + false + end + RUBY + end + + it "captures both preceding and following elements to the pattern" do + eval(<<~RUBY).should == [[0, 1], [3, 4]] + case [0, 1, 2, 3, 4] + in [*pre, 2, *post] + [pre, post] + else + false + end + RUBY + end + + it "can capture the entirety of the pattern" do + eval(<<~RUBY).should == [0, 1, 2, 3, 4] + case [0, 1, 2, 3, 4] + in [*everything] + everything + else + false + end + RUBY + end + + it "will match an empty Array-like structure" do + eval(<<~RUBY).should == [] + case [] + in [*everything] + everything + else + false + end + RUBY end - RUBY + end end - it "can be nested within a hash pattern" do - eval(<<~RUBY).should == [27] - case {a: [3, 9, 27]} - in {a: [*, 9, *post]} - post - else - false + it "extends case expression with case/in construction" do + eval(<<~RUBY).should == :bar + case [0, 1] + in [0] + :foo + in [0, 1] + :bar end RUBY end - it "can nest hash and array patterns" do - eval(<<~RUBY).should == [42, 2] - case [0, {a: 42, b: [0, 1]}, {a: 42, b: [1, 2]}] - in [*, {a:, b: [1, c]}, *] - [a, c] - else - false + it "allows using then operator" do + eval(<<~RUBY).should == :bar + case [0, 1] + in [0] then :foo + in [0, 1] then :bar end RUBY end - end - - it "extends case expression with case/in construction" do - eval(<<~RUBY).should == :bar - case [0, 1] - in [0] - :foo - in [0, 1] - :bar - end - RUBY - end - - it "allows using then operator" do - eval(<<~RUBY).should == :bar - case [0, 1] - in [0] then :foo - in [0, 1] then :bar - end - RUBY - end - - describe "warning" do - before :each do - @experimental, Warning[:experimental] = Warning[:experimental], true - end - - after :each do - Warning[:experimental] = @experimental - end - context 'when regular form' do + describe "warning" do before :each do - @src = 'case [0, 1]; in [a, b]; end' + @experimental, Warning[:experimental] = Warning[:experimental], true end - it "does not warn about pattern matching is experimental feature" do - -> { eval @src }.should_not complain - end - end - - context 'when one-line form' do - before :each do - @src = '[0, 1] => [a, b]' + after :each do + Warning[:experimental] = @experimental end - ruby_version_is ""..."3.1" do - it "warns about pattern matching is experimental feature" do - -> { eval @src }.should complain(/pattern matching is experimental, and the behavior may change in future versions of Ruby!/i) + context 'when regular form' do + before :each do + @src = 'case [0, 1]; in [a, b]; end' end - end - ruby_version_is "3.1" do - it "does not warn about pattern matching is experimental feature" do - -> { eval @src }.should_not complain - end - end - end - end - - it "binds variables" do - eval(<<~RUBY).should == 1 - case [0, 1] - in [0, a] - a - end - RUBY - end - - it "cannot mix in and when operators" do - -> { - eval <<~RUBY - case [] - when 1 == 1 - in [] + ruby_version_is ""..."3.0" do + it "warns about pattern matching is experimental feature" do + -> { eval @src }.should complain(/pattern matching is experimental, and the behavior may change in future versions of Ruby!/i) + end end - RUBY - }.should raise_error(SyntaxError, /syntax error, unexpected `in'|\(eval\):3: syntax error, unexpected keyword_in/) - -> { - eval <<~RUBY - case [] - in [] - when 1 == 1 + ruby_version_is "3.0" do + it "does not warn about pattern matching is experimental feature" do + -> { eval @src }.should_not complain + end end - RUBY - }.should raise_error(SyntaxError, /syntax error, unexpected `when'|\(eval\):3: syntax error, unexpected keyword_when/) - end - - it "checks patterns until the first matching" do - eval(<<~RUBY).should == :bar - case [0, 1] - in [0] - :foo - in [0, 1] - :bar - in [0, 1] - :baz - end - RUBY - end - - it "executes else clause if no pattern matches" do - eval(<<~RUBY).should == false - case [0, 1] - in [0] - true - else - false end - RUBY - end - it "raises NoMatchingPatternError if no pattern matches and no else clause" do - -> { - eval <<~RUBY - case [0, 1] - in [0] - end - RUBY - }.should raise_error(NoMatchingPatternError, /\[0, 1\]/) - end + context 'when one-line form' do + ruby_version_is '3.0' do + before :each do + @src = '[0, 1] => [a, b]' + end - it "raises NoMatchingPatternError if no pattern matches and evaluates the expression only once" do - evals = 0 - -> { - eval <<~RUBY - case (evals += 1; [0, 1]) - in [0] - end - RUBY - }.should raise_error(NoMatchingPatternError, /\[0, 1\]/) - evals.should == 1 - end + ruby_version_is ""..."3.1" do + it "warns about pattern matching is experimental feature" do + -> { eval @src }.should complain(/pattern matching is experimental, and the behavior may change in future versions of Ruby!/i) + end + end - it "does not allow calculation or method calls in a pattern" do - -> { - eval <<~RUBY - case 0 - in 1 + 1 - true + ruby_version_is "3.1" do + it "does not warn about pattern matching is experimental feature" do + -> { eval @src }.should_not complain + end + end end - RUBY - }.should raise_error(SyntaxError, /unexpected/) - end - - it "evaluates the case expression once for multiple patterns, caching the result" do - eval(<<~RUBY).should == true - case (ScratchPad << :foo; 1) - in 0 - false - in 1 - true end - RUBY - - ScratchPad.recorded.should == [:foo] - end - - describe "guards" do - it "supports if guard" do - eval(<<~RUBY).should == false - case 0 - in 0 if false - true - else - false - end - RUBY - - eval(<<~RUBY).should == true - case 0 - in 0 if true - true - else - false - end - RUBY - end - - it "supports unless guard" do - eval(<<~RUBY).should == false - case 0 - in 0 unless true - true - else - false - end - RUBY - - eval(<<~RUBY).should == true - case 0 - in 0 unless false - true - else - false - end - RUBY end - it "makes bound variables visible in guard" do - eval(<<~RUBY).should == true + it "binds variables" do + eval(<<~RUBY).should == 1 case [0, 1] - in [a, 1] if a >= 0 - true + in [0, a] + a end RUBY end - it "does not evaluate guard if pattern does not match" do - eval <<~RUBY - case 0 - in 1 if (ScratchPad << :foo) || true - else - end - RUBY + it "cannot mix in and when operators" do + -> { + eval <<~RUBY + case [] + when 1 == 1 + in [] + end + RUBY + }.should raise_error(SyntaxError, /syntax error, unexpected `in'/) - ScratchPad.recorded.should == [] + -> { + eval <<~RUBY + case [] + in [] + when 1 == 1 + end + RUBY + }.should raise_error(SyntaxError, /syntax error, unexpected `when'/) end - it "takes guards into account when there are several matching patterns" do + it "checks patterns until the first matching" do eval(<<~RUBY).should == :bar - case 0 - in 0 if false + case [0, 1] + in [0] :foo - in 0 if true + in [0, 1] :bar + in [0, 1] + :baz end RUBY end - it "executes else clause if no guarded pattern matches" do + it "executes else clause if no pattern matches" do eval(<<~RUBY).should == false - case 0 - in 0 if false + case [0, 1] + in [0] true else false @@ -372,1044 +198,1105 @@ describe "Pattern matching" do RUBY end - it "raises NoMatchingPatternError if no guarded pattern matches and no else clause" do + it "raises NoMatchingPatternError if no pattern matches and no else clause" do -> { eval <<~RUBY case [0, 1] - in [0, 1] if false + in [0] end RUBY }.should raise_error(NoMatchingPatternError, /\[0, 1\]/) end - end - - describe "value pattern" do - it "matches an object such that pattern === object" do - eval(<<~RUBY).should == true - case 0 - in 0 - true - end - RUBY - eval(<<~RUBY).should == true - case 0 - in (-1..1) - true - end - RUBY - - eval(<<~RUBY).should == true - case 0 - in Integer - true - end - RUBY - - eval(<<~RUBY).should == true - case "0" - in /0/ - true - end - RUBY - - eval(<<~RUBY).should == true - case "0" - in ->(s) { s == "0" } - true - end - RUBY + it "does not allow calculation or method calls in a pattern" do + -> { + eval <<~RUBY + case 0 + in 1 + 1 + true + end + RUBY + }.should raise_error(SyntaxError, /unexpected/) end - it "allows string literal with interpolation" do - x = "x" - + it "evaluates the case expression once for multiple patterns, caching the result" do eval(<<~RUBY).should == true - case "x" - in "#{x + ""}" + case (ScratchPad << :foo; 1) + in 0 + false + in 1 true end RUBY - end - end - - describe "variable pattern" do - it "matches a value and binds variable name to this value" do - eval(<<~RUBY).should == 0 - case 0 - in a - a - end - RUBY - end - it "makes bounded variable visible outside a case statement scope" do - eval(<<~RUBY).should == 0 - case 0 - in a - end - - a - RUBY + ScratchPad.recorded.should == [:foo] end - it "create local variables even if a pattern doesn't match" do - eval(<<~RUBY).should == [0, nil, nil] - case 0 - in a - in b - in c - end - - [a, b, c] - RUBY - end + describe "guards" do + it "supports if guard" do + eval(<<~RUBY).should == false + case 0 + in 0 if false + true + else + false + end + RUBY - it "allow using _ name to drop values" do - eval(<<~RUBY).should == 0 - case [0, 1] - in [a, _] - a - end - RUBY - end + eval(<<~RUBY).should == true + case 0 + in 0 if true + true + else + false + end + RUBY + end - it "supports using _ in a pattern several times" do - eval(<<~RUBY).should == true - case [0, 1, 2] - in [0, _, _] - true - end - RUBY - end + it "supports unless guard" do + eval(<<~RUBY).should == false + case 0 + in 0 unless true + true + else + false + end + RUBY - it "supports using any name with _ at the beginning in a pattern several times" do - eval(<<~RUBY).should == true - case [0, 1, 2] - in [0, _x, _x] - true - end - RUBY + eval(<<~RUBY).should == true + case 0 + in 0 unless false + true + else + false + end + RUBY + end - eval(<<~RUBY).should == true - case {a: 0, b: 1, c: 2} - in {a: 0, b: _x, c: _x} - true - end - RUBY - end + it "makes bound variables visible in guard" do + eval(<<~RUBY).should == true + case [0, 1] + in [a, 1] if a >= 0 + true + end + RUBY + end - it "does not support using variable name (except _) several times" do - -> { + it "does not evaluate guard if pattern does not match" do eval <<~RUBY - case [0] - in [a, a] + case 0 + in 1 if (ScratchPad << :foo) || true + else end RUBY - }.should raise_error(SyntaxError, /duplicated variable name/) - end - - it "supports existing variables in a pattern specified with ^ operator" do - a = 0 - - eval(<<~RUBY).should == true - case 0 - in ^a - true - end - RUBY - end - it "allows applying ^ operator to bound variables" do - eval(<<~RUBY).should == 1 - case [1, 1] - in [n, ^n] - n - end - RUBY + ScratchPad.recorded.should == [] + end - eval(<<~RUBY).should == false - case [1, 2] - in [n, ^n] - true - else - false - end - RUBY - end + it "takes guards into account when there are several matching patterns" do + eval(<<~RUBY).should == :bar + case 0 + in 0 if false + :foo + in 0 if true + :bar + end + RUBY + end - it "requires bound variable to be specified in a pattern before ^ operator when it relies on a bound variable" do - -> { - eval <<~RUBY - case [1, 2] - in [^n, n] + it "executes else clause if no guarded pattern matches" do + eval(<<~RUBY).should == false + case 0 + in 0 if false true else false end RUBY - }.should raise_error(SyntaxError, /n: no such local variable/) - end - end + end - describe "alternative pattern" do - it "matches if any of patterns matches" do - eval(<<~RUBY).should == true - case 0 - in 0 | 1 | 2 - true - end - RUBY + it "raises NoMatchingPatternError if no guarded pattern matches and no else clause" do + -> { + eval <<~RUBY + case [0, 1] + in [0, 1] if false + end + RUBY + }.should raise_error(NoMatchingPatternError, /\[0, 1\]/) + end end - it "does not support variable binding" do - -> { - eval <<~RUBY - case [0, 1] - in [0, 0] | [0, a] + describe "value pattern" do + it "matches an object such that pattern === object" do + eval(<<~RUBY).should == true + case 0 + in 0 + true end RUBY - }.should raise_error(SyntaxError, /illegal variable in alternative pattern/) - end - - it "support underscore prefixed variables in alternation" do - eval(<<~RUBY).should == true - case [0, 1] - in [1, _] - false - in [0, 0] | [0, _a] - true - end - RUBY - end - it "can be used as a nested pattern" do - eval(<<~RUBY).should == true - case [[1], ["2"]] - in [[0] | nil, _] - false - in [[1], [1]] - false - in [[1], [2 | "2"]] + eval(<<~RUBY).should == true + case 0 + in (-1..1) true - end - RUBY + end + RUBY - eval(<<~RUBY).should == true - case [1, 2] - in [0, _] | {a: 0} - false - in {a: 1, b: 2} | [1, 2] + eval(<<~RUBY).should == true + case 0 + in Integer true - end - RUBY - end - end + end + RUBY - describe "AS pattern" do - it "binds a variable to a value if pattern matches" do - eval(<<~RUBY).should == 0 - case 0 - in Integer => n - n - end - RUBY - end + eval(<<~RUBY).should == true + case "0" + in /0/ + true + end + RUBY - it "can be used as a nested pattern" do - eval(<<~RUBY).should == [2, 3] - case [1, [2, 3]] - in [1, Array => ary] - ary - end - RUBY - end - end + eval(<<~RUBY).should == true + case "0" + in ->(s) { s == "0" } + true + end + RUBY + end - describe "Array pattern" do - it "supports form Constant(pat, pat, ...)" do - eval(<<~RUBY).should == true - case [0, 1, 2] - in Array(0, 1, 2) - true - end - RUBY - end + it "allows string literal with interpolation" do + x = "x" - it "supports form Constant[pat, pat, ...]" do - eval(<<~RUBY).should == true - case [0, 1, 2] - in Array[0, 1, 2] - true - end - RUBY + eval(<<~RUBY).should == true + case "x" + in "#{x + ""}" + true + end + RUBY + end end - it "supports form [pat, pat, ...]" do - eval(<<~RUBY).should == true - case [0, 1, 2] - in [0, 1, 2] - true - end - RUBY - end + describe "variable pattern" do + it "matches a value and binds variable name to this value" do + eval(<<~RUBY).should == 0 + case 0 + in a + a + end + RUBY + end - it "supports form pat, pat, ..." do - eval(<<~RUBY).should == true - case [0, 1, 2] - in 0, 1, 2 - true - end - RUBY + it "makes bounded variable visible outside a case statement scope" do + eval(<<~RUBY).should == 0 + case 0 + in a + end - eval(<<~RUBY).should == 1 - case [0, 1, 2] - in 0, a, 2 a - end - RUBY + RUBY + end - eval(<<~RUBY).should == [1, 2] - case [0, 1, 2] - in 0, *rest - rest - end - RUBY - end + it "create local variables even if a pattern doesn't match" do + eval(<<~RUBY).should == [0, nil, nil] + case 0 + in a + in b + in c + end - it "matches an object with #deconstruct method which returns an array and each element in array matches element in pattern" do - obj = Object.new - def obj.deconstruct; [0, 1] end + [a, b, c] + RUBY + end - eval(<<~RUBY).should == true - case obj - in [Integer, Integer] - true - end - RUBY - end + it "allow using _ name to drop values" do + eval(<<~RUBY).should == 0 + case [0, 1] + in [a, _] + a + end + RUBY + end - it "calls #deconstruct once for multiple patterns, caching the result" do - obj = Object.new + it "supports using _ in a pattern several times" do + eval(<<~RUBY).should == true + case [0, 1, 2] + in [0, _, _] + true + end + RUBY + end - def obj.deconstruct - ScratchPad << :deconstruct - [0, 1] + it "supports using any name with _ at the beginning in a pattern several times" do + eval(<<~RUBY).should == true + case [0, 1, 2] + in [0, _x, _x] + true + end + RUBY + + eval(<<~RUBY).should == true + case {a: 0, b: 1, c: 2} + in {a: 0, b: _x, c: _x} + true + end + RUBY end - eval(<<~RUBY).should == true - case obj - in [1, 2] - false - in [0, 1] - true - end - RUBY + it "does not support using variable name (except _) several times" do + -> { + eval <<~RUBY + case [0] + in [a, a] + end + RUBY + }.should raise_error(SyntaxError, /duplicated variable name/) + end - ScratchPad.recorded.should == [:deconstruct] - end + it "supports existing variables in a pattern specified with ^ operator" do + a = 0 - it "calls #deconstruct even on objects that are already an array" do - obj = [1, 2] - def obj.deconstruct - ScratchPad << :deconstruct - [3, 4] + eval(<<~RUBY).should == true + case 0 + in ^a + true + end + RUBY end - eval(<<~RUBY).should == true - case obj - in [3, 4] - true - else - false - end - RUBY + it "allows applying ^ operator to bound variables" do + eval(<<~RUBY).should == 1 + case [1, 1] + in [n, ^n] + n + end + RUBY - ScratchPad.recorded.should == [:deconstruct] - end + eval(<<~RUBY).should == false + case [1, 2] + in [n, ^n] + true + else + false + end + RUBY + end - it "does not match object if Constant === object returns false" do - eval(<<~RUBY).should == false - case [0, 1, 2] - in String[0, 1, 2] - true - else - false - end - RUBY + it "requires bound variable to be specified in a pattern before ^ operator when it relies on a bound variable" do + -> { + eval <<~RUBY + case [1, 2] + in [^n, n] + true + else + false + end + RUBY + }.should raise_error(SyntaxError, /n: no such local variable/) + end end - it "does not match object without #deconstruct method" do - obj = Object.new - obj.should_receive(:respond_to?).with(:deconstruct) + describe "alternative pattern" do + it "matches if any of patterns matches" do + eval(<<~RUBY).should == true + case 0 + in 0 | 1 | 2 + true + end + RUBY + end - eval(<<~RUBY).should == false - case obj - in Object[] - true - else - false - end - RUBY - end + it "does not support variable binding" do + -> { + eval <<~RUBY + case [0, 1] + in [0, 0] | [0, a] + end + RUBY + }.should raise_error(SyntaxError, /illegal variable in alternative pattern/) + end - it "raises TypeError if #deconstruct method does not return array" do - obj = Object.new - def obj.deconstruct; "" end + it "support underscore prefixed variables in alternation" do + eval(<<~RUBY).should == true + case [0, 1] + in [1, _] + false + in [0, 0] | [0, _a] + true + end + RUBY + end - -> { - eval <<~RUBY - case obj - in Object[] - else + it "can be used as a nested pattern" do + eval(<<~RUBY).should == true + case [[1], ["2"]] + in [[0] | nil, _] + false + in [[1], [1]] + false + in [[1], [2 | "2"]] + true end RUBY - }.should raise_error(TypeError, /deconstruct must return Array/) + + eval(<<~RUBY).should == true + case [1, 2] + in [0, _] | {a: 0} + false + in {a: 1, b: 2} | [1, 2] + true + end + RUBY + end end - it "accepts a subclass of Array from #deconstruct" do - obj = Object.new - def obj.deconstruct - subarray = Class.new(Array).new(2) - def subarray.[](n) - n - end - subarray + describe "AS pattern" do + it "binds a variable to a value if pattern matches" do + eval(<<~RUBY).should == 0 + case 0 + in Integer => n + n + end + RUBY end - eval(<<~RUBY).should == true - case obj - in [1, 2] - false - in [0, 1] - true - end - RUBY + it "can be used as a nested pattern" do + eval(<<~RUBY).should == [2, 3] + case [1, [2, 3]] + in [1, Array => ary] + ary + end + RUBY + end end - it "does not match object if elements of array returned by #deconstruct method does not match elements in pattern" do - obj = Object.new - def obj.deconstruct; [1] end + describe "Array pattern" do + it "supports form Constant(pat, pat, ...)" do + eval(<<~RUBY).should == true + case [0, 1, 2] + in Array(0, 1, 2) + true + end + RUBY + end - eval(<<~RUBY).should == false - case obj - in Object[0] - true - else - false - end - RUBY - end + it "supports form Constant[pat, pat, ...]" do + eval(<<~RUBY).should == true + case [0, 1, 2] + in Array[0, 1, 2] + true + end + RUBY + end - it "binds variables" do - eval(<<~RUBY).should == [0, 1, 2] - case [0, 1, 2] - in [a, b, c] - [a, b, c] - end - RUBY - end + it "supports form [pat, pat, ...]" do + eval(<<~RUBY).should == true + case [0, 1, 2] + in [0, 1, 2] + true + end + RUBY + end - it "supports splat operator *rest" do - eval(<<~RUBY).should == [1, 2] - case [0, 1, 2] - in [0, *rest] - rest - end - RUBY - end + it "supports form pat, pat, ..." do + eval(<<~RUBY).should == true + case [0, 1, 2] + in 0, 1, 2 + true + end + RUBY - it "does not match partially by default" do - eval(<<~RUBY).should == false - case [0, 1, 2, 3] - in [1, 2] - true - else - false - end - RUBY - end + eval(<<~RUBY).should == 1 + case [0, 1, 2] + in 0, a, 2 + a + end + RUBY - it "does match partially from the array beginning if list + , syntax used" do - eval(<<~RUBY).should == true - case [0, 1, 2, 3] - in [0, 1,] - true - end - RUBY + eval(<<~RUBY).should == [1, 2] + case [0, 1, 2] + in 0, *rest + rest + end + RUBY + end - eval(<<~RUBY).should == true - case [0, 1, 2, 3] - in 0, 1,; - true - end - RUBY - end + it "matches an object with #deconstruct method which returns an array and each element in array matches element in pattern" do + obj = Object.new + def obj.deconstruct; [0, 1] end - it "matches [] with []" do - eval(<<~RUBY).should == true - case [] - in [] - true + eval(<<~RUBY).should == true + case obj + in [Integer, Integer] + true + end + RUBY + end + + ruby_version_is "3.0" do + it "calls #deconstruct once for multiple patterns, caching the result" do + obj = Object.new + + def obj.deconstruct + ScratchPad << :deconstruct + [0, 1] + end + + eval(<<~RUBY).should == true + case obj + in [1, 2] + false + in [0, 1] + true + end + RUBY + + ScratchPad.recorded.should == [:deconstruct] end - RUBY - end + end - it "matches anything with *" do - eval(<<~RUBY).should == true - case [0, 1] - in *; - true + it "calls #deconstruct even on objects that are already an array" do + obj = [1, 2] + def obj.deconstruct + ScratchPad << :deconstruct + [3, 4] end - RUBY - end - it "can be used as a nested pattern" do - eval(<<~RUBY).should == true - case [[1], ["2"]] - in [[0] | nil, _] + eval(<<~RUBY).should == true + case obj + in [3, 4] + true + else false - in [[1], [1]] + end + RUBY + + ScratchPad.recorded.should == [:deconstruct] + end + + it "does not match object if Constant === object returns false" do + eval(<<~RUBY).should == false + case [0, 1, 2] + in String[0, 1, 2] + true + else false - in [[1], [2 | "2"]] + end + RUBY + end + + it "does not match object without #deconstruct method" do + obj = Object.new + obj.should_receive(:respond_to?).with(:deconstruct) + + eval(<<~RUBY).should == false + case obj + in Object[] true + else + false + end + RUBY + end + + it "raises TypeError if #deconstruct method does not return array" do + obj = Object.new + def obj.deconstruct; "" end + + -> { + eval <<~RUBY + case obj + in Object[] + else + end + RUBY + }.should raise_error(TypeError, /deconstruct must return Array/) + end + + it "accepts a subclass of Array from #deconstruct" do + obj = Object.new + def obj.deconstruct + subarray = Class.new(Array).new(2) + def subarray.[](n) + n + end + subarray end - RUBY - eval(<<~RUBY).should == true - case [1, 2] - in [0, _] | {a: 0} + eval(<<~RUBY).should == true + case obj + in [1, 2] false - in {a: 1, b: 2} | [1, 2] + in [0, 1] true - end - RUBY - end - end + end + RUBY + end - describe "Hash pattern" do - it "supports form Constant(id: pat, id: pat, ...)" do - eval(<<~RUBY).should == true - case {a: 0, b: 1} - in Hash(a: 0, b: 1) - true - end - RUBY - end + it "does not match object if elements of array returned by #deconstruct method does not match elements in pattern" do + obj = Object.new + def obj.deconstruct; [1] end - it "supports form Constant[id: pat, id: pat, ...]" do - eval(<<~RUBY).should == true - case {a: 0, b: 1} - in Hash[a: 0, b: 1] - true - end - RUBY - end + eval(<<~RUBY).should == false + case obj + in Object[0] + true + else + false + end + RUBY + end - it "supports form {id: pat, id: pat, ...}" do - eval(<<~RUBY).should == true - case {a: 0, b: 1} - in {a: 0, b: 1} - true - end - RUBY - end + it "binds variables" do + eval(<<~RUBY).should == [0, 1, 2] + case [0, 1, 2] + in [a, b, c] + [a, b, c] + end + RUBY + end - it "supports form id: pat, id: pat, ..." do - eval(<<~RUBY).should == true - case {a: 0, b: 1} - in a: 0, b: 1 - true - end - RUBY + it "supports splat operator *rest" do + eval(<<~RUBY).should == [1, 2] + case [0, 1, 2] + in [0, *rest] + rest + end + RUBY + end - eval(<<~RUBY).should == [0, 1] - case {a: 0, b: 1} - in a: a, b: b - [a, b] - end - RUBY + it "does not match partially by default" do + eval(<<~RUBY).should == false + case [0, 1, 2, 3] + in [1, 2] + true + else + false + end + RUBY + end - eval(<<~RUBY).should == { b: 1, c: 2 } - case {a: 0, b: 1, c: 2} - in a: 0, **rest - rest - end - RUBY - end + it "does match partially from the array beginning if list + , syntax used" do + eval(<<~RUBY).should == true + case [0, 1, 2, 3] + in [0, 1,] + true + end + RUBY - it "supports a: which means a: a" do - eval(<<~RUBY).should == [0, 1] - case {a: 0, b: 1} - in Hash(a:, b:) - [a, b] - end - RUBY + eval(<<~RUBY).should == true + case [0, 1, 2, 3] + in 0, 1,; + true + end + RUBY + end - a = b = nil - eval(<<~RUBY).should == [0, 1] - case {a: 0, b: 1} - in Hash[a:, b:] - [a, b] - end - RUBY + it "matches [] with []" do + eval(<<~RUBY).should == true + case [] + in [] + true + end + RUBY + end - a = b = nil - eval(<<~RUBY).should == [0, 1] - case {a: 0, b: 1} - in {a:, b:} - [a, b] - end - RUBY + it "matches anything with *" do + eval(<<~RUBY).should == true + case [0, 1] + in *; + true + end + RUBY + end - a = nil - eval(<<~RUBY).should == [0, {b: 1, c: 2}] - case {a: 0, b: 1, c: 2} - in {a:, **rest} - [a, rest] - end - RUBY + it "can be used as a nested pattern" do + eval(<<~RUBY).should == true + case [[1], ["2"]] + in [[0] | nil, _] + false + in [[1], [1]] + false + in [[1], [2 | "2"]] + true + end + RUBY - a = b = nil - eval(<<~RUBY).should == [0, 1] - case {a: 0, b: 1} - in a:, b: - [a, b] - end - RUBY + eval(<<~RUBY).should == true + case [1, 2] + in [0, _] | {a: 0} + false + in {a: 1, b: 2} | [1, 2] + true + end + RUBY + end end - it "can mix key (a:) and key-value (a: b) declarations" do - eval(<<~RUBY).should == [0, 1] - case {a: 0, b: 1} - in Hash(a:, b: x) - [a, x] - end - RUBY - end + describe "Hash pattern" do + it "supports form Constant(id: pat, id: pat, ...)" do + eval(<<~RUBY).should == true + case {a: 0, b: 1} + in Hash(a: 0, b: 1) + true + end + RUBY + end - it "supports 'string': key literal" do - eval(<<~RUBY).should == true - case {a: 0} - in {"a": 0} - true - end - RUBY - end + it "supports form Constant[id: pat, id: pat, ...]" do + eval(<<~RUBY).should == true + case {a: 0, b: 1} + in Hash[a: 0, b: 1] + true + end + RUBY + end - it "does not support non-symbol keys" do - -> { - eval <<~RUBY - case {a: 1} - in {"a" => 1} + it "supports form {id: pat, id: pat, ...}" do + eval(<<~RUBY).should == true + case {a: 0, b: 1} + in {a: 0, b: 1} + true end RUBY - }.should raise_error(SyntaxError, /unexpected/) - end + end - it "does not support string interpolation in keys" do - x = "a" + it "supports form id: pat, id: pat, ..." do + eval(<<~RUBY).should == true + case {a: 0, b: 1} + in a: 0, b: 1 + true + end + RUBY - -> { - eval <<~'RUBY' - case {a: 1} - in {"#{x}": 1} + eval(<<~RUBY).should == [0, 1] + case {a: 0, b: 1} + in a: a, b: b + [a, b] end RUBY - }.should raise_error(SyntaxError, /symbol literal with interpolation is not allowed/) - end - it "raise SyntaxError when keys duplicate in pattern" do - -> { - eval <<~RUBY - case {a: 1} - in {a: 1, b: 2, a: 3} + eval(<<~RUBY).should == { b: 1, c: 2 } + case {a: 0, b: 1, c: 2} + in a: 0, **rest + rest end RUBY - }.should raise_error(SyntaxError, /duplicated key name/) - end + end - it "matches an object with #deconstruct_keys method which returns a Hash with equal keys and each value in Hash matches value in pattern" do - obj = Object.new - def obj.deconstruct_keys(*); {a: 1} end + it "supports a: which means a: a" do + eval(<<~RUBY).should == [0, 1] + case {a: 0, b: 1} + in Hash(a:, b:) + [a, b] + end + RUBY - eval(<<~RUBY).should == true - case obj - in {a: 1} - true - end - RUBY - end + a = b = nil + eval(<<~RUBY).should == [0, 1] + case {a: 0, b: 1} + in Hash[a:, b:] + [a, b] + end + RUBY + + a = b = nil + eval(<<~RUBY).should == [0, 1] + case {a: 0, b: 1} + in {a:, b:} + [a, b] + end + RUBY - it "calls #deconstruct_keys per pattern" do - obj = Object.new + a = nil + eval(<<~RUBY).should == [0, {b: 1, c: 2}] + case {a: 0, b: 1, c: 2} + in {a:, **rest} + [a, rest] + end + RUBY - def obj.deconstruct_keys(*) - ScratchPad << :deconstruct_keys - {a: 1} + a = b = nil + eval(<<~RUBY).should == [0, 1] + case {a: 0, b: 1} + in a:, b: + [a, b] + end + RUBY end - eval(<<~RUBY).should == true - case obj - in {b: 1} - false - in {a: 1} - true - end - RUBY + it "can mix key (a:) and key-value (a: b) declarations" do + eval(<<~RUBY).should == [0, 1] + case {a: 0, b: 1} + in Hash(a:, b: x) + [a, x] + end + RUBY + end - ScratchPad.recorded.should == [:deconstruct_keys, :deconstruct_keys] - end + it "supports 'string': key literal" do + eval(<<~RUBY).should == true + case {a: 0} + in {"a": 0} + true + end + RUBY + end - it "does not match object if Constant === object returns false" do - eval(<<~RUBY).should == false - case {a: 1} - in String[a: 1] - true - else - false - end - RUBY - end + it "does not support non-symbol keys" do + -> { + eval <<~RUBY + case {a: 1} + in {"a" => 1} + end + RUBY + }.should raise_error(SyntaxError, /unexpected/) + end - it "does not match object without #deconstruct_keys method" do - obj = Object.new - obj.should_receive(:respond_to?).with(:deconstruct_keys) + it "does not support string interpolation in keys" do + x = "a" - eval(<<~RUBY).should == false - case obj - in Object[a: 1] - true - else - false - end - RUBY - end + -> { + eval <<~'RUBY' + case {a: 1} + in {"#{x}": 1} + end + RUBY + }.should raise_error(SyntaxError, /symbol literal with interpolation is not allowed/) + end - it "does not match object if #deconstruct_keys method does not return Hash" do - obj = Object.new - def obj.deconstruct_keys(*); "" end + it "raise SyntaxError when keys duplicate in pattern" do + -> { + eval <<~RUBY + case {a: 1} + in {a: 1, b: 2, a: 3} + end + RUBY + }.should raise_error(SyntaxError, /duplicated key name/) + end - -> { - eval <<~RUBY + it "matches an object with #deconstruct_keys method which returns a Hash with equal keys and each value in Hash matches value in pattern" do + obj = Object.new + def obj.deconstruct_keys(*); {a: 1} end + + eval(<<~RUBY).should == true case obj - in Object[a: 1] + in {a: 1} + true end RUBY - }.should raise_error(TypeError, /deconstruct_keys must return Hash/) - end - - it "does not match object if #deconstruct_keys method returns Hash with non-symbol keys" do - obj = Object.new - def obj.deconstruct_keys(*); {"a" => 1} end - - eval(<<~RUBY).should == false - case obj - in Object[a: 1] - true - else - false - end - RUBY - end + end - it "does not match object if elements of Hash returned by #deconstruct_keys method does not match values in pattern" do - obj = Object.new - def obj.deconstruct_keys(*); {a: 1} end + it "calls #deconstruct_keys per pattern" do + obj = Object.new - eval(<<~RUBY).should == false - case obj - in Object[a: 2] - true - else - false + def obj.deconstruct_keys(*) + ScratchPad << :deconstruct_keys + {a: 1} end - RUBY - end - it "passes keys specified in pattern as arguments to #deconstruct_keys method" do - obj = Object.new + eval(<<~RUBY).should == true + case obj + in {b: 1} + false + in {a: 1} + true + end + RUBY - def obj.deconstruct_keys(*args) - ScratchPad << args - {a: 1, b: 2, c: 3} + ScratchPad.recorded.should == [:deconstruct_keys, :deconstruct_keys] end - eval <<~RUBY - case obj - in Object[a: 1, b: 2, c: 3] - end - RUBY + it "does not match object if Constant === object returns false" do + eval(<<~RUBY).should == false + case {a: 1} + in String[a: 1] + true + else + false + end + RUBY + end - ScratchPad.recorded.sort.should == [[[:a, :b, :c]]] - end + it "does not match object without #deconstruct_keys method" do + obj = Object.new + obj.should_receive(:respond_to?).with(:deconstruct_keys) - it "passes keys specified in pattern to #deconstruct_keys method if pattern contains double splat operator **" do - obj = Object.new + eval(<<~RUBY).should == false + case obj + in Object[a: 1] + true + else + false + end + RUBY + end - def obj.deconstruct_keys(*args) - ScratchPad << args - {a: 1, b: 2, c: 3} + it "does not match object if #deconstruct_keys method does not return Hash" do + obj = Object.new + def obj.deconstruct_keys(*); "" end + + -> { + eval <<~RUBY + case obj + in Object[a: 1] + end + RUBY + }.should raise_error(TypeError, /deconstruct_keys must return Hash/) end - eval <<~RUBY - case obj - in Object[a: 1, b: 2, **] - end - RUBY + it "does not match object if #deconstruct_keys method returns Hash with non-symbol keys" do + obj = Object.new + def obj.deconstruct_keys(*); {"a" => 1} end - ScratchPad.recorded.sort.should == [[[:a, :b]]] - end + eval(<<~RUBY).should == false + case obj + in Object[a: 1] + true + else + false + end + RUBY + end - it "passes nil to #deconstruct_keys method if pattern contains double splat operator **rest" do - obj = Object.new + it "does not match object if elements of Hash returned by #deconstruct_keys method does not match values in pattern" do + obj = Object.new + def obj.deconstruct_keys(*); {a: 1} end - def obj.deconstruct_keys(*args) - ScratchPad << args - {a: 1, b: 2} + eval(<<~RUBY).should == false + case obj + in Object[a: 2] + true + else + false + end + RUBY end - eval <<~RUBY - case obj - in Object[a: 1, **rest] - end - RUBY + it "passes keys specified in pattern as arguments to #deconstruct_keys method" do + obj = Object.new - ScratchPad.recorded.should == [[nil]] - end - - it "binds variables" do - eval(<<~RUBY).should == [0, 1, 2] - case {a: 0, b: 1, c: 2} - in {a: x, b: y, c: z} - [x, y, z] + def obj.deconstruct_keys(*args) + ScratchPad << args + {a: 1, b: 2, c: 3} end - RUBY - end - it "supports double splat operator **rest" do - eval(<<~RUBY).should == {b: 1, c: 2} - case {a: 0, b: 1, c: 2} - in {a: 0, **rest} - rest - end - RUBY - end + eval <<~RUBY + case obj + in Object[a: 1, b: 2, c: 3] + end + RUBY - it "treats **nil like there should not be any other keys in a matched Hash" do - eval(<<~RUBY).should == true - case {a: 1, b: 2} - in {a: 1, b: 2, **nil} - true - end - RUBY + ScratchPad.recorded.sort.should == [[[:a, :b, :c]]] + end - eval(<<~RUBY).should == false - case {a: 1, b: 2} - in {a: 1, **nil} - true - else - false - end - RUBY - end + it "passes keys specified in pattern to #deconstruct_keys method if pattern contains double splat operator **" do + obj = Object.new - it "can match partially" do - eval(<<~RUBY).should == true - case {a: 1, b: 2} - in {a: 1} - true + def obj.deconstruct_keys(*args) + ScratchPad << args + {a: 1, b: 2, c: 3} end - RUBY - end - it "matches {} with {}" do - eval(<<~RUBY).should == true - case {} - in {} - true - end - RUBY - end + eval <<~RUBY + case obj + in Object[a: 1, b: 2, **] + end + RUBY - it "matches anything with **" do - eval(<<~RUBY).should == true - case {a: 1} - in **; - true - end - RUBY - end + ScratchPad.recorded.sort.should == [[[:a, :b]]] + end - it "can be used as a nested pattern" do - eval(<<~RUBY).should == true - case {a: {a: 1, b: 1}, b: {a: 1, b: 2}} - in {a: {a: 0}} - false - in {a: {a: 1}, b: {b: 1}} - false - in {a: {a: 1}, b: {b: 2}} - true - end - RUBY + it "passes nil to #deconstruct_keys method if pattern contains double splat operator **rest" do + obj = Object.new - eval(<<~RUBY).should == true - case [{a: 1, b: [1]}, {a: 1, c: ["2"]}] - in [{a:, c:},] - false - in [{a: 1, b:}, {a: 1, c: [Integer]}] - false - in [_, {a: 1, c: [String]}] - true + def obj.deconstruct_keys(*args) + ScratchPad << args + {a: 1, b: 2} end - RUBY - end - end - describe "refinements" do - it "are used for #deconstruct" do - refinery = Module.new do - refine Array do - def deconstruct - [0] + eval <<~RUBY + case obj + in Object[a: 1, **rest] end - end + RUBY + + ScratchPad.recorded.should == [[nil]] end - result = nil - Module.new do - using refinery + it "binds variables" do + eval(<<~RUBY).should == [0, 1, 2] + case {a: 0, b: 1, c: 2} + in {a: x, b: y, c: z} + [x, y, z] + end + RUBY + end - result = eval(<<~RUBY) - case [] - in [0] - true + it "supports double splat operator **rest" do + eval(<<~RUBY).should == {b: 1, c: 2} + case {a: 0, b: 1, c: 2} + in {a: 0, **rest} + rest end RUBY end - result.should == true - end + it "treats **nil like there should not be any other keys in a matched Hash" do + eval(<<~RUBY).should == true + case {a: 1, b: 2} + in {a: 1, b: 2, **nil} + true + end + RUBY - it "are used for #deconstruct_keys" do - refinery = Module.new do - refine Hash do - def deconstruct_keys(_) - {a: 0} + eval(<<~RUBY).should == false + case {a: 1, b: 2} + in {a: 1, **nil} + true + else + false end - end + RUBY end - result = nil - Module.new do - using refinery + it "can match partially" do + eval(<<~RUBY).should == true + case {a: 1, b: 2} + in {a: 1} + true + end + RUBY + end - result = eval(<<~RUBY) + it "matches {} with {}" do + eval(<<~RUBY).should == true case {} - in a: 0 + in {} true end RUBY end - result.should == true - end - - it "are used for #=== in constant pattern" do - refinery = Module.new do - refine Array.singleton_class do - def ===(obj) - obj.is_a?(Hash) + it "matches anything with **" do + eval(<<~RUBY).should == true + case {a: 1} + in **; + true end - end + RUBY end - result = nil - Module.new do - using refinery + it "can be used as a nested pattern" do + eval(<<~RUBY).should == true + case {a: {a: 1, b: 1}, b: {a: 1, b: 2}} + in {a: {a: 0}} + false + in {a: {a: 1}, b: {b: 1}} + false + in {a: {a: 1}, b: {b: 2}} + true + end + RUBY - result = eval(<<~RUBY) - case {} - in Array - true + eval(<<~RUBY).should == true + case [{a: 1, b: [1]}, {a: 1, c: ["2"]}] + in [{a:, c:},] + false + in [{a: 1, b:}, {a: 1, c: [Integer]}] + false + in [_, {a: 1, c: [String]}] + true end RUBY end - - result.should == true end - end - ruby_version_is "3.1" do - it "can omit parentheses in one line pattern matching" do - eval(<<~RUBY).should == [1, 2] - [1, 2] => a, b - [a, b] - RUBY + describe "refinements" do + it "are used for #deconstruct" do + refinery = Module.new do + refine Array do + def deconstruct + [0] + end + end + end - eval(<<~RUBY).should == 1 - {a: 1} => a: - a - RUBY - end + result = nil + Module.new do + using refinery - it "supports pinning instance variables" do - eval(<<~RUBY).should == true - @a = /a/ - case 'abc' - in ^@a - true + result = eval(<<~RUBY) + case [] + in [0] + true + end + RUBY end - RUBY - end - it "supports pinning class variables" do - result = nil - Module.new do - result = module_eval(<<~RUBY) - @@a = 0..10 + result.should == true + end - case 2 - in ^@@a - true + it "are used for #deconstruct_keys" do + refinery = Module.new do + refine Hash do + def deconstruct_keys(_) + {a: 0} + end end - RUBY - end + end - result.should == true - end + result = nil + Module.new do + using refinery - it "supports pinning global variables" do - eval(<<~RUBY).should == true - $a = /a/ - case 'abc' - in ^$a - true + result = eval(<<~RUBY) + case {} + in a: 0 + true + end + RUBY end - RUBY - end - it "supports pinning expressions" do - eval(<<~RUBY).should == true - case 'abc' - in ^(/a/) - true - end - RUBY + result.should == true + end - eval(<<~RUBY).should == true - case {name: '2.6', released_at: Time.new(2018, 12, 25)} - in {released_at: ^(Time.new(2010)..Time.new(2020))} - true + it "are used for #=== in constant pattern" do + refinery = Module.new do + refine Array.singleton_class do + def ===(obj) + obj.is_a?(Hash) + end + end end - RUBY - eval(<<~RUBY).should == true - case 0 - in ^(0+0) - true + result = nil + Module.new do + using refinery + + result = eval(<<~RUBY) + case {} + in Array + true + end + RUBY end - RUBY + + result.should == true + end + end + + ruby_version_is "3.1" do + it "can omit parentheses in one line pattern matching" do + eval(<<~RUBY).should == [1, 2] + [1, 2] => a, b + [a, b] + RUBY + + eval(<<~RUBY).should == 1 + {a: 1} => a: + a + RUBY + end end end end diff --git a/spec/ruby/language/precedence_spec.rb b/spec/ruby/language/precedence_spec.rb index c5adcca2c0..5a3c2861ce 100644 --- a/spec/ruby/language/precedence_spec.rb +++ b/spec/ruby/language/precedence_spec.rb @@ -14,44 +14,46 @@ require_relative 'fixtures/precedence' # the level below (as well as showing associativity within # the precedence level). -# Excerpted from 'Programming Ruby: The Pragmatic Programmer's Guide' -# Second Edition by Dave Thomas, Chad Fowler, and Andy Hunt, page 324 -# -# Table 22.4. Ruby operators (high to low precedence) -# Method Operator Description -# ----------------------------------------------------------------------- -# :: . -# x* [ ] [ ]= Element reference, element set -# x ** Exponentiation -# x ! ~ + - Not, complement, unary plus and minus -# (method names for the last two are +@ and -@) -# x * / % Multiply, divide, and modulo -# x + - Plus and minus -# x >> << Right and left shift -# x & “And” (bitwise for integers) -# x ^ | Exclusive “or” and regular “or” (bitwise for integers) -# x <= < > >= Comparison operators -# x <=> == === != =~ !~ Equality and pattern match operators (!= -# and !~ may not be defined as methods) -# && Logical “and” -# || Logical “or” -# .. ... Range (inclusive and exclusive) -# ? : Ternary if-then-else -# = %= /= -= += |= &= Assignment -# >>= <<= *= &&= ||= **= -# defined? Check if symbol defined -# not Logical negation -# or and Logical composition -# if unless while until Expression modifiers -# begin/end Block expression -# ----------------------------------------------------------------------- -# -# * Operators marked with 'x' in the Method column are implemented as methods -# and can be overridden (except != and !~ as noted). (But see the specs -# below for implementations that define != and !~ as methods.) -# -# ** These are not included in the excerpted table but are shown here for -# completeness. +=begin +Excerpted from 'Programming Ruby: The Pragmatic Programmer's Guide' +Second Edition by Dave Thomas, Chad Fowler, and Andy Hunt, page 324 + +Table 22.4. Ruby operators (high to low precedence) +Method Operator Description +----------------------------------------------------------------------- + :: . + x* [ ] [ ]= Element reference, element set + x ** Exponentiation + x ! ~ + - Not, complement, unary plus and minus + (method names for the last two are +@ and -@) + x * / % Multiply, divide, and modulo + x + - Plus and minus + x >> << Right and left shift + x & “And” (bitwise for integers) + x ^ | Exclusive “or” and regular “or” (bitwise for integers) + x <= < > >= Comparison operators + x <=> == === != =~ !~ Equality and pattern match operators (!= + and !~ may not be defined as methods) + && Logical “and” + || Logical “or” + .. ... Range (inclusive and exclusive) + ? : Ternary if-then-else + = %= /= -= += |= &= Assignment + >>= <<= *= &&= ||= **= + defined? Check if symbol defined + not Logical negation + or and Logical composition + if unless while until Expression modifiers + begin/end Block expression +----------------------------------------------------------------------- + +* Operators marked with 'x' in the Method column are implemented as methods +and can be overridden (except != and !~ as noted). (But see the specs +below for implementations that define != and !~ as methods.) + +** These are not included in the excerpted table but are shown here for +completeness. +=end # ----------------------------------------------------------------------- # It seems that this table is not correct anymore diff --git a/spec/ruby/language/predefined_spec.rb b/spec/ruby/language/predefined_spec.rb index fe865cc325..d311750200 100644 --- a/spec/ruby/language/predefined_spec.rb +++ b/spec/ruby/language/predefined_spec.rb @@ -7,33 +7,37 @@ require 'stringio' # Entries marked [r/o] are read-only and an error will be raised of the program attempts to # modify them. Entries marked [thread] are thread local. -# Exception Information -# --------------------------------------------------------------------------------------------------- -# -# $! Exception The exception object passed to raise. [thread] -# $@ Array The stack backtrace generated by the last exception. [thread] - -# Pattern Matching Variables -# --------------------------------------------------------------------------------------------------- -# -# These variables are set to nil after an unsuccessful pattern match. -# -# $& String The string matched (following a successful pattern match). This variable is -# local to the current scope. [r/o, thread] -# $+ String The contents of the highest-numbered group matched following a successful -# pattern match. Thus, in "cat" =~/(c|a)(t|z)/, $+ will be set to “t”. This -# variable is local to the current scope. [r/o, thread] -# $` String The string preceding the match in a successful pattern match. This variable -# is local to the current scope. [r/o, thread] -# $' String The string following the match in a successful pattern match. This variable -# is local to the current scope. [r/o, thread] -# $1 to $<N> String The contents of successive groups matched in a successful pattern match. In -# "cat" =~/(c|a)(t|z)/, $1 will be set to “a” and $2 to “t”. This variable -# is local to the current scope. [r/o, thread] -# $~ MatchData An object that encapsulates the results of a successful pattern match. The -# variables $&, $`, $', and $1 to $<N> are all derived from $~. Assigning to $~ -# changes the values of these derived variables. This variable is local to the -# current scope. [thread] +=begin +Exception Information +--------------------------------------------------------------------------------------------------- + +$! Exception The exception object passed to raise. [thread] +$@ Array The stack backtrace generated by the last exception. [thread] +=end + +=begin +Pattern Matching Variables +--------------------------------------------------------------------------------------------------- + +These variables are set to nil after an unsuccessful pattern match. + +$& String The string matched (following a successful pattern match). This variable is + local to the current scope. [r/o, thread] +$+ String The contents of the highest-numbered group matched following a successful + pattern match. Thus, in "cat" =~/(c|a)(t|z)/, $+ will be set to “t”. This + variable is local to the current scope. [r/o, thread] +$` String The string preceding the match in a successful pattern match. This variable + is local to the current scope. [r/o, thread] +$' String The string following the match in a successful pattern match. This variable + is local to the current scope. [r/o, thread] +$1 to $<N> String The contents of successive groups matched in a successful pattern match. In + "cat" =~/(c|a)(t|z)/, $1 will be set to “a” and $2 to “t”. This variable + is local to the current scope. [r/o, thread] +$~ MatchData An object that encapsulates the results of a successful pattern match. The + variables $&, $`, $', and $1 to $<N> are all derived from $~. Assigning to $~ + changes the values of these derived variables. This variable is local to the + current scope. [thread] +=end describe "Predefined global $~" do @@ -502,39 +506,41 @@ describe "Predefined global $!" do end end -# Input/Output Variables -# --------------------------------------------------------------------------------------------------- -# -# $/ String The input record separator (newline by default). This is the value that rou- -# tines such as Kernel#gets use to determine record boundaries. If set to -# nil, gets will read the entire file. -# $-0 String Synonym for $/. -# $\ String The string appended to the output of every call to methods such as -# Kernel#print and IO#write. The default value is nil. -# $, String The separator string output between the parameters to methods such as -# Kernel#print and Array#join. Defaults to nil, which adds no text. -# $. Integer The number of the last line read from the current input file. -# $; String The default separator pattern used by String#split. May be set from the -# command line using the -F flag. -# $< Object An object that provides access to the concatenation of the contents of all -# the files given as command-line arguments or $stdin (in the case where -# there are no arguments). $< supports methods similar to a File object: -# binmode, close, closed?, each, each_byte, each_line, eof, eof?, -# file, filename, fileno, getc, gets, lineno, lineno=, path, pos, pos=, -# read, readchar, readline, readlines, rewind, seek, skip, tell, to_a, -# to_i, to_io, to_s, along with the methods in Enumerable. The method -# file returns a File object for the file currently being read. This may change -# as $< reads through the files on the command line. [r/o] -# $> IO The destination of output for Kernel#print and Kernel#printf. The -# default value is $stdout. -# $_ String The last line read by Kernel#gets or Kernel#readline. Many string- -# related functions in the Kernel module operate on $_ by default. The vari- -# able is local to the current scope. [thread] -# $-F String Synonym for $;. -# $stderr IO The current standard error output. -# $stdin IO The current standard input. -# $stdout IO The current standard output. Assignment to $stdout is deprecated: use -# $stdout.reopen instead. +=begin +Input/Output Variables +--------------------------------------------------------------------------------------------------- + +$/ String The input record separator (newline by default). This is the value that rou- + tines such as Kernel#gets use to determine record boundaries. If set to + nil, gets will read the entire file. +$-0 String Synonym for $/. +$\ String The string appended to the output of every call to methods such as + Kernel#print and IO#write. The default value is nil. +$, String The separator string output between the parameters to methods such as + Kernel#print and Array#join. Defaults to nil, which adds no text. +$. Integer The number of the last line read from the current input file. +$; String The default separator pattern used by String#split. May be set from the + command line using the -F flag. +$< Object An object that provides access to the concatenation of the contents of all + the files given as command-line arguments or $stdin (in the case where + there are no arguments). $< supports methods similar to a File object: + binmode, close, closed?, each, each_byte, each_line, eof, eof?, + file, filename, fileno, getc, gets, lineno, lineno=, path, pos, pos=, + read, readchar, readline, readlines, rewind, seek, skip, tell, to_a, + to_i, to_io, to_s, along with the methods in Enumerable. The method + file returns a File object for the file currently being read. This may change + as $< reads through the files on the command line. [r/o] +$> IO The destination of output for Kernel#print and Kernel#printf. The + default value is $stdout. +$_ String The last line read by Kernel#gets or Kernel#readline. Many string- + related functions in the Kernel module operate on $_ by default. The vari- + able is local to the current scope. [thread] +$-F String Synonym for $;. +$stderr IO The current standard error output. +$stdin IO The current standard input. +$stdout IO The current standard output. Assignment to $stdout is deprecated: use + $stdout.reopen instead. +=end describe "Predefined global $/" do before :each do @@ -564,6 +570,7 @@ describe "Predefined global $/" do ($/ = "xyz").should == "xyz" end + it "changes $-0" do $/ = "xyz" $-0.should equal($/) @@ -634,45 +641,6 @@ describe "Predefined global $-0" do end end -describe "Predefined global $\\" do - before :each do - @verbose, $VERBOSE = $VERBOSE, nil - @dollar_backslash = $\ - end - - after :each do - $\ = @dollar_backslash - $VERBOSE = @verbose - end - - it "can be assigned a String" do - str = "abc" - $\ = str - $\.should equal(str) - end - - it "can be assigned nil" do - $\ = nil - $\.should be_nil - end - - it "returns the value assigned" do - ($\ = "xyz").should == "xyz" - end - - it "does not call #to_str to convert the object to a String" do - obj = mock("$\\ value") - obj.should_not_receive(:to_str) - - -> { $\ = obj }.should raise_error(TypeError) - end - - it "raises a TypeError if assigned not String" do - -> { $\ = 1 }.should raise_error(TypeError) - -> { $\ = true }.should raise_error(TypeError) - end -end - describe "Predefined global $," do after :each do $, = nil @@ -686,8 +654,10 @@ describe "Predefined global $," do -> { $, = Object.new }.should raise_error(TypeError) end - it "warns if assigned non-nil" do - -> { $, = "_" }.should complain(/warning: `\$,' is deprecated/) + ruby_version_is "2.7" do + it "warns if assigned non-nil" do + -> { $, = "_" }.should complain(/warning: `\$,' is deprecated/) + end end end @@ -723,8 +693,10 @@ describe "Predefined global $;" do $; = nil end - it "warns if assigned non-nil" do - -> { $; = "_" }.should complain(/warning: `\$;' is deprecated/) + ruby_version_is "2.7" do + it "warns if assigned non-nil" do + -> { $; = "_" }.should complain(/warning: `\$;' is deprecated/) + end end end @@ -797,52 +769,54 @@ describe "Predefined global $_" do end end -# Execution Environment Variables -# --------------------------------------------------------------------------------------------------- -# -# $0 String The name of the top-level Ruby program being executed. Typically this will -# be the program’s filename. On some operating systems, assigning to this -# variable will change the name of the process reported (for example) by the -# ps(1) command. -# $* Array An array of strings containing the command-line options from the invoca- -# tion of the program. Options used by the Ruby interpreter will have been -# removed. [r/o] -# $" Array An array containing the filenames of modules loaded by require. [r/o] -# $$ Integer The process number of the program being executed. [r/o] -# $? Process::Status The exit status of the last child process to terminate. [r/o, thread] -# $: Array An array of strings, where each string specifies a directory to be searched for -# Ruby scripts and binary extensions used by the load and require methods. -# The initial value is the value of the arguments passed via the -I command- -# line option, followed by an installation-defined standard library location, fol- -# lowed by the current directory (“.”). This variable may be set from within a -# program to alter the default search path; typically, programs use $: << dir -# to append dir to the path. [r/o] -# $-a Object True if the -a option is specified on the command line. [r/o] -# $-d Object Synonym for $DEBUG. -# $DEBUG Object Set to true if the -d command-line option is specified. -# __FILE__ String The name of the current source file. [r/o] -# $F Array The array that receives the split input line if the -a command-line option is -# used. -# $FILENAME String The name of the current input file. Equivalent to $<.filename. [r/o] -# $-i String If in-place edit mode is enabled (perhaps using the -i command-line -# option), $-i holds the extension used when creating the backup file. If you -# set a value into $-i, enables in-place edit mode. -# $-I Array Synonym for $:. [r/o] -# $-K String Sets the multibyte coding system for strings and regular expressions. Equiv- -# alent to the -K command-line option. -# $-l Object Set to true if the -l option (which enables line-end processing) is present -# on the command line. [r/o] -# __LINE__ String The current line number in the source file. [r/o] -# $LOAD_PATH Array A synonym for $:. [r/o] -# $-p Object Set to true if the -p option (which puts an implicit while gets . . . end -# loop around your program) is present on the command line. [r/o] -# $VERBOSE Object Set to true if the -v, --version, -W, or -w option is specified on the com- -# mand line. Set to false if no option, or -W1 is given. Set to nil if -W0 -# was specified. Setting this option to true causes the interpreter and some -# library routines to report additional information. Setting to nil suppresses -# all warnings (including the output of Kernel.warn). -# $-v Object Synonym for $VERBOSE. -# $-w Object Synonym for $VERBOSE. +=begin +Execution Environment Variables +--------------------------------------------------------------------------------------------------- + +$0 String The name of the top-level Ruby program being executed. Typically this will + be the program’s filename. On some operating systems, assigning to this + variable will change the name of the process reported (for example) by the + ps(1) command. +$* Array An array of strings containing the command-line options from the invoca- + tion of the program. Options used by the Ruby interpreter will have been + removed. [r/o] +$" Array An array containing the filenames of modules loaded by require. [r/o] +$$ Integer The process number of the program being executed. [r/o] +$? Process::Status The exit status of the last child process to terminate. [r/o, thread] +$: Array An array of strings, where each string specifies a directory to be searched for + Ruby scripts and binary extensions used by the load and require methods. + The initial value is the value of the arguments passed via the -I command- + line option, followed by an installation-defined standard library location, fol- + lowed by the current directory (“.”). This variable may be set from within a + program to alter the default search path; typically, programs use $: << dir + to append dir to the path. [r/o] +$-a Object True if the -a option is specified on the command line. [r/o] +$-d Object Synonym for $DEBUG. +$DEBUG Object Set to true if the -d command-line option is specified. +__FILE__ String The name of the current source file. [r/o] +$F Array The array that receives the split input line if the -a command-line option is + used. +$FILENAME String The name of the current input file. Equivalent to $<.filename. [r/o] +$-i String If in-place edit mode is enabled (perhaps using the -i command-line + option), $-i holds the extension used when creating the backup file. If you + set a value into $-i, enables in-place edit mode. +$-I Array Synonym for $:. [r/o] +$-K String Sets the multibyte coding system for strings and regular expressions. Equiv- + alent to the -K command-line option. +$-l Object Set to true if the -l option (which enables line-end processing) is present + on the command line. [r/o] +__LINE__ String The current line number in the source file. [r/o] +$LOAD_PATH Array A synonym for $:. [r/o] +$-p Object Set to true if the -p option (which puts an implicit while gets . . . end + loop around your program) is present on the command line. [r/o] +$VERBOSE Object Set to true if the -v, --version, -W, or -w option is specified on the com- + mand line. Set to false if no option, or -W1 is given. Set to nil if -W0 + was specified. Setting this option to true causes the interpreter and some + library routines to report additional information. Setting to nil suppresses + all warnings (including the output of Kernel.warn). +$-v Object Synonym for $VERBOSE. +$-w Object Synonym for $VERBOSE. +=end describe "Execution variable $:" do it "is initialized to an array of strings" do $:.is_a?(Array).should == true @@ -861,8 +835,6 @@ describe "Execution variable $:" do it "can be changed via <<" do $: << "foo" $:.should include("foo") - ensure - $:.delete("foo") end it "is read-only" do @@ -878,16 +850,6 @@ describe "Execution variable $:" do $-I = [] }.should raise_error(NameError) end - - it "default $LOAD_PATH entries until sitelibdir included have @gem_prelude_index set" do - skip "no sense in ruby itself" if MSpecScript.instance_variable_defined?(:@testing_ruby) - - $:.should.include?(RbConfig::CONFIG['sitelibdir']) - idx = $:.index(RbConfig::CONFIG['sitelibdir']) - - $:[idx..-1].all? { |p| p.instance_variable_defined?(:@gem_prelude_index) }.should be_true - $:[0...idx].all? { |p| !p.instance_variable_defined?(:@gem_prelude_index) }.should be_true - end end describe "Global variable $\"" do @@ -979,10 +941,6 @@ describe "Global variable $VERBOSE" do $VERBOSE = @verbose end - it "is false by default" do - $VERBOSE.should be_false - end - it "converts truthy values to true" do [true, 1, 0, [], ""].each do |true_value| $VERBOSE = true_value @@ -1037,7 +995,7 @@ describe "Global variable $0" do it "is the path given as the main script and the same as __FILE__" do script = "fixtures/dollar_zero.rb" - Dir.chdir(__dir__) do + Dir.chdir(File.dirname(__FILE__)) do ruby_exe(script).should == "#{script}\n#{script}\nOK" end end @@ -1064,20 +1022,22 @@ describe "Global variable $0" do end end -# Standard Objects -# --------------------------------------------------------------------------------------------------- -# -# ARGF Object A synonym for $<. -# ARGV Array A synonym for $*. -# ENV Object A hash-like object containing the program’s environment variables. An -# instance of class Object, ENV implements the full set of Hash methods. Used -# to query and set the value of an environment variable, as in ENV["PATH"] -# and ENV["term"]="ansi". -# false FalseClass Singleton instance of class FalseClass. [r/o] -# nil NilClass The singleton instance of class NilClass. The value of uninitialized -# instance and global variables. [r/o] -# self Object The receiver (object) of the current method. [r/o] -# true TrueClass Singleton instance of class TrueClass. [r/o] +=begin +Standard Objects +--------------------------------------------------------------------------------------------------- + +ARGF Object A synonym for $<. +ARGV Array A synonym for $*. +ENV Object A hash-like object containing the program’s environment variables. An + instance of class Object, ENV implements the full set of Hash methods. Used + to query and set the value of an environment variable, as in ENV["PATH"] + and ENV["term"]="ansi". +false FalseClass Singleton instance of class FalseClass. [r/o] +nil NilClass The singleton instance of class NilClass. The value of uninitialized + instance and global variables. [r/o] +self Object The receiver (object) of the current method. [r/o] +true TrueClass Singleton instance of class TrueClass. [r/o] +=end describe "The predefined standard objects" do it "includes ARGF" do @@ -1130,51 +1090,80 @@ describe "The self pseudo-variable" do end end -# Global Constants -# --------------------------------------------------------------------------------------------------- -# -# The following constants are defined by the Ruby interpreter. -# -# DATA IO If the main program file contains the directive __END__, then -# the constant DATA will be initialized so that reading from it will -# return lines following __END__ from the source file. -# FALSE FalseClass Synonym for false (deprecated, removed in Ruby 3). -# NIL NilClass Synonym for nil (deprecated, removed in Ruby 3). -# RUBY_PLATFORM String The identifier of the platform running this program. This string -# is in the same form as the platform identifier used by the GNU -# configure utility (which is not a coincidence). -# RUBY_RELEASE_DATE String The date of this release. -# RUBY_VERSION String The version number of the interpreter. -# STDERR IO The actual standard error stream for the program. The initial -# value of $stderr. -# STDIN IO The actual standard input stream for the program. The initial -# value of $stdin. -# STDOUT IO The actual standard output stream for the program. The initial -# value of $stdout. -# SCRIPT_LINES__ Hash If a constant SCRIPT_LINES__ is defined and references a Hash, -# Ruby will store an entry containing the contents of each file it -# parses, with the file’s name as the key and an array of strings as -# the value. -# TOPLEVEL_BINDING Binding A Binding object representing the binding at Ruby’s top level— -# the level where programs are initially executed. -# TRUE TrueClass Synonym for true (deprecated, removed in Ruby 3). +=begin +Global Constants +--------------------------------------------------------------------------------------------------- + +The following constants are defined by the Ruby interpreter. + +DATA IO If the main program file contains the directive __END__, then + the constant DATA will be initialized so that reading from it will + return lines following __END__ from the source file. +FALSE FalseClass Synonym for false (deprecated, removed in Ruby 3). +NIL NilClass Synonym for nil (deprecated, removed in Ruby 3). +RUBY_PLATFORM String The identifier of the platform running this program. This string + is in the same form as the platform identifier used by the GNU + configure utility (which is not a coincidence). +RUBY_RELEASE_DATE String The date of this release. +RUBY_VERSION String The version number of the interpreter. +STDERR IO The actual standard error stream for the program. The initial + value of $stderr. +STDIN IO The actual standard input stream for the program. The initial + value of $stdin. +STDOUT IO The actual standard output stream for the program. The initial + value of $stdout. +SCRIPT_LINES__ Hash If a constant SCRIPT_LINES__ is defined and references a Hash, + Ruby will store an entry containing the contents of each file it + parses, with the file’s name as the key and an array of strings as + the value. +TOPLEVEL_BINDING Binding A Binding object representing the binding at Ruby’s top level— + the level where programs are initially executed. +TRUE TrueClass Synonym for true (deprecated, removed in Ruby 3). +=end describe "The predefined global constants" do describe "TRUE" do - it "is no longer defined" do - Object.const_defined?(:TRUE).should == false + ruby_version_is "3.0" do + it "is no longer defined" do + Object.const_defined?(:TRUE).should == false + end + end + + ruby_version_is ""..."3.0" do + it "includes TRUE" do + Object.const_defined?(:TRUE).should == true + -> { TRUE }.should complain(/constant ::TRUE is deprecated/) + end end end describe "FALSE" do - it "is no longer defined" do - Object.const_defined?(:FALSE).should == false + ruby_version_is "3.0" do + it "is no longer defined" do + Object.const_defined?(:FALSE).should == false + end + end + + ruby_version_is ""..."3.0" do + it "includes FALSE" do + Object.const_defined?(:FALSE).should == true + -> { FALSE }.should complain(/constant ::FALSE is deprecated/) + end end end describe "NIL" do - it "is no longer defined" do - Object.const_defined?(:NIL).should == false + ruby_version_is "3.0" do + it "is no longer defined" do + Object.const_defined?(:NIL).should == false + end + end + + ruby_version_is ""..."3.0" do + it "includes NIL" do + Object.const_defined?(:NIL).should == true + -> { NIL }.should complain(/constant ::NIL is deprecated/) + end end end @@ -1315,57 +1304,32 @@ describe "The predefined global constant" do end end -describe "$LOAD_PATH.resolve_feature_path" do - it "returns what will be loaded without actual loading, .rb file" do - extension, path = $LOAD_PATH.resolve_feature_path('set') - extension.should == :rb - path.should.end_with?('/set.rb') - end - - it "returns what will be loaded without actual loading, .so file" do - require 'rbconfig' - skip "no dynamically loadable standard extension" if RbConfig::CONFIG["EXTSTATIC"] == "static" +ruby_version_is "2.7" do + describe "$LOAD_PATH.resolve_feature_path" do + it "returns what will be loaded without actual loading, .rb file" do + extension, path = $LOAD_PATH.resolve_feature_path('set') + extension.should == :rb + path.should.end_with?('/set.rb') + end - extension, path = $LOAD_PATH.resolve_feature_path('etc') - extension.should == :so - path.should.end_with?("/etc.#{RbConfig::CONFIG['DLEXT']}") - end + it "returns what will be loaded without actual loading, .so file" do + require 'rbconfig' - ruby_version_is ""..."3.1" do - it "raises LoadError if feature cannot be found" do - -> { $LOAD_PATH.resolve_feature_path('noop') }.should raise_error(LoadError) + extension, path = $LOAD_PATH.resolve_feature_path('etc') + extension.should == :so + path.should.end_with?("/etc.#{RbConfig::CONFIG['DLEXT']}") end - end - ruby_version_is "3.1" do - it "return nil if feature cannot be found" do - $LOAD_PATH.resolve_feature_path('noop').should be_nil + ruby_version_is "2.7"..."3.1" do + it "raises LoadError if feature cannot be found" do + -> { $LOAD_PATH.resolve_feature_path('noop') }.should raise_error(LoadError) + end end - end -end - -# Some other pre-defined global variables - -describe "Predefined global $=" do - before :each do - @verbose, $VERBOSE = $VERBOSE, nil - @dollar_assign = $= - end - - after :each do - $= = @dollar_assign - $VERBOSE = @verbose - end - - it "warns when accessed" do - -> { a = $= }.should complain(/is no longer effective/) - end - it "warns when assigned" do - -> { $= = "_" }.should complain(/is no longer effective/) - end - - it "returns the value assigned" do - ($= = "xyz").should == "xyz" + ruby_version_is "3.1" do + it "return nil if feature cannot be found" do + $LOAD_PATH.resolve_feature_path('noop').should be_nil + end + end end end diff --git a/spec/ruby/language/proc_spec.rb b/spec/ruby/language/proc_spec.rb index cc69b7799c..ef4a43bed6 100644 --- a/spec/ruby/language/proc_spec.rb +++ b/spec/ruby/language/proc_spec.rb @@ -161,18 +161,6 @@ describe "A Proc" do end end - describe "taking |*a, b| arguments" do - it "assigns [] to the argument when passed no values" do - proc { |*a, b| [a, b] }.call.should == [[], nil] - end - end - - describe "taking |a, *b, c| arguments" do - it "assigns [] to the argument when passed no values" do - proc { |a, *b, c| [a, b, c] }.call.should == [nil, [], nil] - end - end - describe "taking |a, | arguments" do before :each do @l = lambda { |a, | a } @@ -235,15 +223,24 @@ describe "A Proc" do @p = proc { |*a, **kw| [a, kw] } end - it 'does not autosplat keyword arguments' do - @p.call([1, {a: 1}]).should == [[[1, {a: 1}]], {}] + ruby_version_is ""..."2.7" do + it 'autosplats keyword arguments' do + @p.call([1, {a: 1}]).should == [[1], {a: 1}] + end + end + + ruby_version_is "2.7"..."3.0" do + it 'autosplats keyword arguments and warns' do + -> { + @p.call([1, {a: 1}]).should == [[1], {a: 1}] + }.should complain(/warning: Using the last argument as keyword parameters is deprecated; maybe \*\* should be added to the call/) + end end - end - describe "taking |required keyword arguments, **kw| arguments" do - it "raises ArgumentError for missing required argument" do - p = proc { |a:, **kw| [a, kw] } - -> { p.call() }.should raise_error(ArgumentError) + ruby_version_is "3.0" do + it 'does not autosplat keyword arguments' do + @p.call([1, {a: 1}]).should == [[[1, {a: 1}]], {}] + end end end end diff --git a/spec/ruby/language/range_spec.rb b/spec/ruby/language/range_spec.rb index ccc9f55537..4cde7e9488 100644 --- a/spec/ruby/language/range_spec.rb +++ b/spec/ruby/language/range_spec.rb @@ -10,21 +10,21 @@ describe "Literal Ranges" do (1...10).should == Range.new(1, 10, true) end - it "creates a simple range as an object literal" do - ary = [] - 2.times do - ary.push(1..3) - end - ary[0].should.equal?(ary[1]) - end - it "creates endless ranges" do (1..).should == Range.new(1, nil) (1...).should == Range.new(1, nil, true) end - it "creates beginless ranges" do - (..1).should == Range.new(nil, 1) - (...1).should == Range.new(nil, 1, true) + ruby_version_is "3.0" do + it "is frozen" do + (42..).should.frozen? + end + end + + ruby_version_is "2.7" do + it "creates beginless ranges" do + eval("(..1)").should == Range.new(nil, 1) + eval("(...1)").should == Range.new(nil, 1, true) + end end end diff --git a/spec/ruby/language/regexp/character_classes_spec.rb b/spec/ruby/language/regexp/character_classes_spec.rb index 98d431a817..0cf1e9b6f4 100644 --- a/spec/ruby/language/regexp/character_classes_spec.rb +++ b/spec/ruby/language/regexp/character_classes_spec.rb @@ -609,13 +609,10 @@ describe "Regexp with character classes" do "루비(Ruby)".match(/\p{Hangul}+/u).to_a.should == ["루비"] end - it "supports negated property condition" do - "a".match(eval("/\P{L}/")).should be_nil - "1".match(eval("/\P{N}/")).should be_nil - end - - it "raises a RegexpError for an unterminated unicode property" do - -> { Regexp.new('\p{') }.should raise_error(RegexpError) + ruby_bug "#17340", ''...'3.0' do + it "raises a RegexpError for an unterminated unicode property" do + -> { Regexp.new('\p{') }.should raise_error(RegexpError) + end end it "supports \\X (unicode 9.0 with UTR #51 workarounds)" do diff --git a/spec/ruby/language/regexp/escapes_spec.rb b/spec/ruby/language/regexp/escapes_spec.rb index 16a4d8c23b..2e5fe5ad2e 100644 --- a/spec/ruby/language/regexp/escapes_spec.rb +++ b/spec/ruby/language/regexp/escapes_spec.rb @@ -2,10 +2,8 @@ require_relative '../../spec_helper' require_relative '../fixtures/classes' -# TODO: synchronize with spec/core/regexp/new_spec.rb - -# escaping is also tested there describe "Regexps with escape characters" do - it "supports escape sequences" do + it "they're supported" do /\t/.match("\t").to_a.should == ["\t"] # horizontal tab /\v/.match("\v").to_a.should == ["\v"] # vertical tab /\n/.match("\n").to_a.should == ["\n"] # newline @@ -17,7 +15,9 @@ describe "Regexps with escape characters" do # \nnn octal char (encoded byte value) end - it "supports quoting meta-characters via escape sequence" do + it "support quoting meta-characters via escape sequence" do + /\\/.match("\\").to_a.should == ["\\"] + /\//.match("/").to_a.should == ["/"] # parenthesis, etc /\(/.match("(").to_a.should == ["("] /\)/.match(")").to_a.should == [")"] @@ -25,8 +25,6 @@ describe "Regexps with escape characters" do /\]/.match("]").to_a.should == ["]"] /\{/.match("{").to_a.should == ["{"] /\}/.match("}").to_a.should == ["}"] - /\</.match("<").to_a.should == ["<"] - /\>/.match(">").to_a.should == [">"] # alternation separator /\|/.match("|").to_a.should == ["|"] # quantifiers @@ -39,81 +37,11 @@ describe "Regexps with escape characters" do /\$/.match("$").to_a.should == ["$"] end - it "supports quoting meta-characters via escape sequence when used as a terminator" do - # parenthesis, etc - # %r[[, %r((, etc literals - are forbidden - %r(\().match("(").to_a.should == ["("] - %r(\)).match(")").to_a.should == [")"] - %r)\().match("(").to_a.should == ["("] - %r)\)).match(")").to_a.should == [")"] - - %r[\[].match("[").to_a.should == ["["] - %r[\]].match("]").to_a.should == ["]"] - %r]\[].match("[").to_a.should == ["["] - %r]\]].match("]").to_a.should == ["]"] - - %r{\{}.match("{").to_a.should == ["{"] - %r{\}}.match("}").to_a.should == ["}"] - %r}\{}.match("{").to_a.should == ["{"] - %r}\}}.match("}").to_a.should == ["}"] - - %r<\<>.match("<").to_a.should == ["<"] - %r<\>>.match(">").to_a.should == [">"] - %r>\<>.match("<").to_a.should == ["<"] - %r>\>>.match(">").to_a.should == [">"] - - # alternation separator - %r|\||.match("|").to_a.should == ["|"] - # quantifiers - %r?\??.match("?").to_a.should == ["?"] - %r.\...match(".").to_a.should == ["."] - %r*\**.match("*").to_a.should == ["*"] - %r+\++.match("+").to_a.should == ["+"] - # line anchors - %r^\^^.match("^").to_a.should == ["^"] - %r$\$$.match("$").to_a.should == ["$"] - end - - it "supports quoting non-meta-characters via escape sequence when used as a terminator" do - non_meta_character_terminators = [ - '!', '"', '#', '%', '&', "'", ',', '-', ':', ';', '@', '_', '`', '/', '=', '~' - ] - - non_meta_character_terminators.each do |c| - pattern = eval("%r" + c + "\\" + c + c) - pattern.match(c).to_a.should == [c] - end - end - - it "does not change semantics of escaped non-meta-character when used as a terminator" do - all_terminators = [*("!".."/"), *(":".."@"), *("[".."`"), *("{".."~")] - meta_character_terminators = ["$", "^", "*", "+", ".", "?", "|", "}", ")", ">", "]"] - special_cases = ['(', '{', '[', '<', '\\'] - - # it should be equivalent to - # [ '!', '"', '#', '%', '&', "'", ',', '-', ':', ';', '@', '_', '`', '/', '=', '~' ] - non_meta_character_terminators = all_terminators - meta_character_terminators - special_cases - - non_meta_character_terminators.each do |c| - pattern = eval("%r" + c + "\\" + c + c) - pattern.should == /#{c}/ - end - end - - it "does not change semantics of escaped meta-character when used as a terminator" do - meta_character_terminators = ["$", "^", "*", "+", ".", "?", "|", "}", ")", ">", "]"] - - meta_character_terminators.each do |c| - pattern = eval("%r" + c + "\\" + c + c) - pattern.should == eval("/\\#{c}/") - end - end - it "allows any character to be escaped" do /\y/.match("y").to_a.should == ["y"] end - it "supports \\x (hex characters)" do + it "support \\x (hex characters)" do /\xA/.match("\nxyz").to_a.should == ["\n"] /\x0A/.match("\n").to_a.should == ["\n"] /\xAA/.match("\nA").should be_nil @@ -125,7 +53,7 @@ describe "Regexps with escape characters" do # \x{7HHHHHHH} wide hexadecimal char (character code point value) end - it "supports \\c (control characters)" do + it "support \\c (control characters)" do #/\c \c@\c`/.match("\00\00\00").to_a.should == ["\00\00\00"] /\c#\cc\cC/.match("\03\03\03").to_a.should == ["\03\03\03"] /\c'\cG\cg/.match("\a\a\a").to_a.should == ["\a\a\a"] diff --git a/spec/ruby/language/regexp/repetition_spec.rb b/spec/ruby/language/regexp/repetition_spec.rb index d76619688f..9a191d74e2 100644 --- a/spec/ruby/language/regexp/repetition_spec.rb +++ b/spec/ruby/language/regexp/repetition_spec.rb @@ -87,7 +87,9 @@ describe "Regexps with repetition" do /a+?*/.match("a")[0].should == "a" /(a+?)*/.match("a")[0].should == "a" - /a+?*/.match("aa")[0].should == "aa" + ruby_bug '#17341', ''...'3.0' do + /a+?*/.match("aa")[0].should == "aa" + end /(a+?)*/.match("aa")[0].should == "aa" # a+?+ should not be reduced, it should be equivalent to (a+?)+ @@ -98,7 +100,9 @@ describe "Regexps with repetition" do /a+?+/.match("a")[0].should == "a" /(a+?)+/.match("a")[0].should == "a" - /a+?+/.match("aa")[0].should == "aa" + ruby_bug '#17341', ''...'3.0' do + /a+?+/.match("aa")[0].should == "aa" + end /(a+?)+/.match("aa")[0].should == "aa" # both a**? and a+*? should be equivalent to (a+)?? diff --git a/spec/ruby/language/regexp_spec.rb b/spec/ruby/language/regexp_spec.rb index cdafd29f49..f607fa6010 100644 --- a/spec/ruby/language/regexp_spec.rb +++ b/spec/ruby/language/regexp_spec.rb @@ -18,8 +18,10 @@ describe "Literal Regexps" do /Hello/.should be_kind_of(Regexp) end - it "is frozen" do - /Hello/.should.frozen? + ruby_version_is "3.0" do + it "is frozen" do + /Hello/.should.frozen? + end end it "caches the Regexp object" do @@ -94,6 +96,7 @@ describe "Literal Regexps" do /./.match("\0").to_a.should == ["\0"] end + it "supports | (alternations)" do /a|b/.match("a").to_a.should == ["a"] end @@ -112,7 +115,7 @@ describe "Literal Regexps" do /foo.(?<=\d)/.match("fooA foo1").to_a.should == ["foo1"] end - ruby_bug "#13671", ""..."3.4" do # https://bugs.ruby-lang.org/issues/13671 + ruby_bug "#13671", ""..."3.2" do # https://bugs.ruby-lang.org/issues/13671 it "handles a lookbehind with ss characters" do r = Regexp.new("(?<!dss)", Regexp::IGNORECASE) r.should =~ "✨" @@ -158,6 +161,26 @@ describe "Literal Regexps" do pattern.should_not =~ 'T' end + escapable_terminators = ['!', '"', '#', '%', '&', "'", ',', '-', ':', ';', '@', '_', '`'] + + it "supports escaping characters when used as a terminator" do + escapable_terminators.each do |c| + ref = "(?-mix:#{c})" + pattern = eval("%r" + c + "\\" + c + c) + pattern.to_s.should == ref + end + end + + it "treats an escaped non-escapable character normally when used as a terminator" do + all_terminators = [*("!".."/"), *(":".."@"), *("[".."`"), *("{".."~")] + special_cases = ['(', '{', '[', '<', '\\', '=', '~'] + (all_terminators - special_cases - escapable_terminators).each do |c| + ref = "(?-mix:\\#{c})" + pattern = eval("%r" + c + "\\" + c + c) + pattern.to_s.should == ref + end + end + it "support handling unicode 9.0 characters with POSIX bracket expressions" do char_lowercase = "\u{104D8}" # OSAGE SMALL LETTER A /[[:lower:]]/.match(char_lowercase).to_s.should == char_lowercase diff --git a/spec/ruby/language/rescue_spec.rb b/spec/ruby/language/rescue_spec.rb index b91b52fa0f..4d164b38c6 100644 --- a/spec/ruby/language/rescue_spec.rb +++ b/spec/ruby/language/rescue_spec.rb @@ -115,18 +115,6 @@ describe "The rescue keyword" do end end - it "converts the splatted list of exceptions using #to_a" do - exceptions = mock("to_a") - exceptions.should_receive(:to_a).and_return(exception_list) - caught_it = false - begin - raise SpecificExampleException, "not important" - rescue *exceptions - caught_it = true - end - caught_it.should be_true - end - it "can combine a splatted list of exceptions with a literal list of exceptions" do caught_it = false begin @@ -504,12 +492,14 @@ describe "The rescue keyword" do }.should raise_error(Exception) end - it "rescues with multiple assignment" do + ruby_version_is "2.7" do + it "rescues with multiple assignment" do - a, b = raise rescue [1, 2] + a, b = raise rescue [1, 2] - a.should == 1 - b.should == 2 + a.should == 1 + b.should == 2 + end end end end diff --git a/spec/ruby/language/return_spec.rb b/spec/ruby/language/return_spec.rb index a62ed1242d..d8506834c8 100644 --- a/spec/ruby/language/return_spec.rb +++ b/spec/ruby/language/return_spec.rb @@ -422,31 +422,18 @@ describe "The return keyword" do end describe "within a block within a class" do - it "is not allowed" do - File.write(@filename, <<-END_OF_CODE) - class ReturnSpecs::A - ScratchPad << "before return" - 1.times { return } - ScratchPad << "after return" - end - END_OF_CODE - - -> { load @filename }.should raise_error(LocalJumpError) - end - end - - describe "within BEGIN" do - it "is allowed" do - File.write(@filename, <<-END_OF_CODE) - BEGIN { - ScratchPad << "before call" - return - ScratchPad << "after call" - } - END_OF_CODE - - load @filename - ScratchPad.recorded.should == ["before call"] + ruby_version_is "2.7" do + it "is not allowed" do + File.write(@filename, <<-END_OF_CODE) + class ReturnSpecs::A + ScratchPad << "before return" + 1.times { return } + ScratchPad << "after return" + end + END_OF_CODE + + -> { load @filename }.should raise_error(LocalJumpError) + end end end @@ -477,13 +464,25 @@ describe "The return keyword" do end describe "return with argument" do - it "warns but does not affect exit status" do - err = ruby_exe(<<-END_OF_CODE, args: "2>&1") - return 10 - END_OF_CODE - $?.exitstatus.should == 0 + ruby_version_is ""..."2.7" do + it "does not affect exit status" do + ruby_exe(<<-END_OF_CODE).should == "" + return 10 + END_OF_CODE + + $?.exitstatus.should == 0 + end + end + + ruby_version_is "2.7" do + it "warns but does not affect exit status" do + err = ruby_exe(<<-END_OF_CODE, args: "2>&1") + return 10 + END_OF_CODE + $?.exitstatus.should == 0 - err.should =~ /warning: argument of top-level return is ignored/ + err.should =~ /warning: argument of top-level return is ignored/ + end end end end diff --git a/spec/ruby/language/safe_spec.rb b/spec/ruby/language/safe_spec.rb index 03ae96148e..89830a2069 100644 --- a/spec/ruby/language/safe_spec.rb +++ b/spec/ruby/language/safe_spec.rb @@ -1,11 +1,119 @@ require_relative '../spec_helper' describe "The $SAFE variable" do - it "$SAFE is a regular global variable" do - $SAFE.should == nil - $SAFE = 42 - $SAFE.should == 42 - ensure - $SAFE = nil + ruby_version_is ""..."2.7" do + after :each do + $SAFE = 0 + end + + it "is 0 by default" do + $SAFE.should == 0 + proc { + $SAFE.should == 0 + }.call + end + + it "can be set to 0" do + proc { + $SAFE = 0 + $SAFE.should == 0 + }.call + end + + it "can be set to 1" do + proc { + $SAFE = 1 + $SAFE.should == 1 + }.call + end + + [2, 3, 4].each do |n| + it "cannot be set to #{n}" do + -> { + proc { + $SAFE = n + }.call + }.should raise_error(ArgumentError, /\$SAFE=2 to 4 are obsolete/) + end + end + + it "raises ArgumentError when set to values below 0" do + -> { + proc { + $SAFE = -100 + }.call + }.should raise_error(ArgumentError, "$SAFE should be >= 0") + end + + it "cannot be set to values above 4" do + -> { + proc { + $SAFE = 100 + }.call + }.should raise_error(ArgumentError, /\$SAFE=2 to 4 are obsolete/) + end + + it "can be manually lowered" do + $SAFE = 1 + $SAFE = 0 + $SAFE.should == 0 + end + + it "is not Proc local" do + $SAFE.should == 0 + proc { + $SAFE = 1 + }.call + $SAFE.should == 1 + end + + it "is not lambda local" do + $SAFE.should == 0 + -> { + $SAFE = 1 + }.call + $SAFE.should == 1 + end + + it "is global like regular global variables" do + Thread.new { $SAFE }.value.should == 0 + $SAFE = 1 + Thread.new { $SAFE }.value.should == 1 + end + + it "can be read when default from Thread#safe_level" do + Thread.current.safe_level.should == 0 + end + + it "can be read when modified from Thread#safe_level" do + proc { + $SAFE = 1 + Thread.current.safe_level.should == 1 + }.call + end + end + + ruby_version_is "2.7"..."3.0" do + it "warn when access" do + -> { + $SAFE + }.should complain(/\$SAFE will become a normal global variable in Ruby 3.0/) + end + + it "warn when set" do + -> { + $SAFE = 1 + }.should complain(/\$SAFE will become a normal global variable in Ruby 3.0/) + end + end + + ruby_version_is "3.0" do + it "$SAFE is a regular global variable" do + $SAFE.should == nil + $SAFE = 42 + $SAFE.should == 42 + ensure + $SAFE = nil + end end end diff --git a/spec/ruby/language/send_spec.rb b/spec/ruby/language/send_spec.rb index a1656559fe..e57e2c65dc 100644 --- a/spec/ruby/language/send_spec.rb +++ b/spec/ruby/language/send_spec.rb @@ -258,10 +258,20 @@ describe "Invoking a private setter method" do end describe "Invoking a private getter method" do - it "permits self as a receiver" do - receiver = LangSendSpecs::PrivateGetter.new - receiver.call_self_foo_or_equals(6) - receiver.call_self_foo.should == 6 + ruby_version_is ""..."2.7" do + it "does not permit self as a receiver" do + receiver = LangSendSpecs::PrivateGetter.new + -> { receiver.call_self_foo }.should raise_error(NoMethodError) + -> { receiver.call_self_foo_or_equals(6) }.should raise_error(NoMethodError) + end + end + + ruby_version_is "2.7" do + it "permits self as a receiver" do + receiver = LangSendSpecs::PrivateGetter.new + receiver.call_self_foo_or_equals(6) + receiver.call_self_foo.should == 6 + end end end @@ -411,18 +421,36 @@ describe "Invoking a method" do specs.rest_len(0,*a,4,*5,6,7,*c,-1).should == 11 end - it "expands the Array elements from the splat before applying block argument operations" do - def self.m(*args, &block) - [args, block] + ruby_version_is ""..."3.0" do + it "expands the Array elements from the splat after executing the arguments and block if no other arguments follow the splat" do + def self.m(*args, &block) + [args, block] + end + + args = [1, nil] + m(*args, &args.pop).should == [[1], nil] + + args = [1, nil] + order = [] + m(*(order << :args; args), &(order << :block; args.pop)).should == [[1], nil] + order.should == [:args, :block] end + end - args = [1, nil] - m(*args, &args.pop).should == [[1, nil], nil] + ruby_version_is "3.0" do + it "expands the Array elements from the splat before applying block argument operations" do + def self.m(*args, &block) + [args, block] + end - args = [1, nil] - order = [] - m(*(order << :args; args), &(order << :block; args.pop)).should == [[1, nil], nil] - order.should == [:args, :block] + args = [1, nil] + m(*args, &args.pop).should == [[1, nil], nil] + + args = [1, nil] + order = [] + m(*(order << :args; args), &(order << :block; args.pop)).should == [[1, nil], nil] + order.should == [:args, :block] + end end it "evaluates the splatted arguments before the block if there are other arguments after the splat" do diff --git a/spec/ruby/language/singleton_class_spec.rb b/spec/ruby/language/singleton_class_spec.rb index 9d037717b2..c1fb682ea0 100644 --- a/spec/ruby/language/singleton_class_spec.rb +++ b/spec/ruby/language/singleton_class_spec.rb @@ -291,27 +291,3 @@ describe "Instantiating a singleton class" do }.should raise_error(TypeError) end end - -describe "Frozen properties" do - it "is frozen if the object it is created from is frozen" do - o = Object.new - o.freeze - klass = o.singleton_class - klass.frozen?.should == true - end - - it "will be frozen if the object it is created from becomes frozen" do - o = Object.new - klass = o.singleton_class - klass.frozen?.should == false - o.freeze - klass.frozen?.should == true - end - - it "will be unfrozen if the frozen object is cloned with freeze set to false" do - o = Object.new - o.freeze - o2 = o.clone(freeze: false) - o2.singleton_class.frozen?.should == false - end -end diff --git a/spec/ruby/language/source_encoding_spec.rb b/spec/ruby/language/source_encoding_spec.rb index 7135bc0a70..19364fc676 100644 --- a/spec/ruby/language/source_encoding_spec.rb +++ b/spec/ruby/language/source_encoding_spec.rb @@ -15,7 +15,7 @@ describe "Source files" do end describe "encoded in UTF-16 LE without a BOM" do - it "are parsed as empty because they contain a NUL byte before the encoding comment" do + it "are parsed because empty as they contain a NUL byte before the encoding comment" do ruby_exe(fixture(__FILE__, "utf16-le-nobom.rb"), args: "2>&1").should == "" end end diff --git a/spec/ruby/language/string_spec.rb b/spec/ruby/language/string_spec.rb index 418dc2ca7d..ce4941569e 100644 --- a/spec/ruby/language/string_spec.rb +++ b/spec/ruby/language/string_spec.rb @@ -56,6 +56,28 @@ describe "Ruby character strings" do "#\$".should == '#$' end + ruby_version_is ''...'2.7' do + it "taints the result of interpolation when an interpolated value is tainted" do + "#{"".taint}".tainted?.should be_true + + @ip.taint + "#@ip".tainted?.should be_true + + $ip.taint + "#$ip".tainted?.should be_true + end + + it "untrusts the result of interpolation when an interpolated value is untrusted" do + "#{"".untrust}".untrusted?.should be_true + + @ip.untrust + "#@ip".untrusted?.should be_true + + $ip.untrust + "#$ip".untrusted?.should be_true + end + end + it "allows using non-alnum characters as string delimiters" do %(hey #{@ip}).should == "hey xxx" %[hey #{@ip}].should == "hey xxx" @@ -277,11 +299,23 @@ describe "Ruby String interpolation" do eval(code).should_not.frozen? end - it "creates a non-frozen String when # frozen-string-literal: true is used" do - code = <<~'RUBY' - # frozen-string-literal: true - "a#{6*7}c" - RUBY - eval(code).should_not.frozen? + ruby_version_is "3.0" do + it "creates a non-frozen String when # frozen-string-literal: true is used" do + code = <<~'RUBY' + # frozen-string-literal: true + "a#{6*7}c" + RUBY + eval(code).should_not.frozen? + end + end + + ruby_version_is ""..."3.0" do + it "creates a frozen String when # frozen-string-literal: true is used" do + code = <<~'RUBY' + # frozen-string-literal: true + "a#{6*7}c" + RUBY + eval(code).should.frozen? + end end end diff --git a/spec/ruby/language/super_spec.rb b/spec/ruby/language/super_spec.rb index d22c603605..1ac5c5e1be 100644 --- a/spec/ruby/language/super_spec.rb +++ b/spec/ruby/language/super_spec.rb @@ -203,25 +203,6 @@ describe "The super keyword" do -> { klass.new.a(:a_called) }.should raise_error(RuntimeError) end - it "is able to navigate to super, when a method is defined dynamically on the singleton class" do - foo_class = Class.new do - def bar - "bar" - end - end - - mixin_module = Module.new do - def bar - "super_" + super - end - end - - foo = foo_class.new - foo.singleton_class.define_method(:bar, mixin_module.instance_method(:bar)) - - foo.bar.should == "super_bar" - end - # Rubinius ticket github#157 it "calls method_missing when a superclass method is not found" do SuperSpecs::MM_B.new.is_a?(Hash).should == false @@ -341,10 +322,6 @@ describe "The super keyword" do SuperSpecs::ZSuperWithUnderscores::B.new.m_modified(1, 2).should == [14, 2] end - it "should pass method arguments when called within a closure" do - SuperSpecs::ZSuperInBlock::B.new.m(arg: 1).should == 1 - end - describe 'when using keyword arguments' do before :each do @req = SuperSpecs::Keywords::RequiredArguments.new diff --git a/spec/ruby/language/symbol_spec.rb b/spec/ruby/language/symbol_spec.rb index 7c1898efc2..d6a41d3059 100644 --- a/spec/ruby/language/symbol_spec.rb +++ b/spec/ruby/language/symbol_spec.rb @@ -96,11 +96,11 @@ describe "A Symbol literal" do %I{a b #{"c"}}.should == [:a, :b, :c] end - it "raises an EncodingError at parse time when Symbol with invalid bytes" do + it "with invalid bytes raises an EncodingError at parse time" do ScratchPad.record [] -> { eval 'ScratchPad << 1; :"\xC3"' - }.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"') + }.should raise_error(EncodingError, /invalid/) ScratchPad.recorded.should == [] end end diff --git a/spec/ruby/language/undef_spec.rb b/spec/ruby/language/undef_spec.rb index 29dba4afb4..4e473b803f 100644 --- a/spec/ruby/language/undef_spec.rb +++ b/spec/ruby/language/undef_spec.rb @@ -38,19 +38,12 @@ describe "The undef keyword" do -> { @obj.meth(5) }.should raise_error(NoMethodError) end - it "with an interpolated symbol" do + it "with a interpolated symbol" do @undef_class.class_eval do undef :"#{'meth'}" end -> { @obj.meth(5) }.should raise_error(NoMethodError) end - - it "with an interpolated symbol when interpolated expression is not a String literal" do - @undef_class.class_eval do - undef :"#{'meth'.to_sym}" - end - -> { @obj.meth(5) }.should raise_error(NoMethodError) - end end it "allows undefining multiple methods at a time" do diff --git a/spec/ruby/language/variables_spec.rb b/spec/ruby/language/variables_spec.rb index 23c2cdb557..699187335c 100644 --- a/spec/ruby/language/variables_spec.rb +++ b/spec/ruby/language/variables_spec.rb @@ -1,86 +1,6 @@ require_relative '../spec_helper' require_relative 'fixtures/variables' -describe "Evaluation order during assignment" do - context "with single assignment" do - it "evaluates from left to right" do - obj = VariablesSpecs::EvalOrder.new - obj.instance_eval do - foo[0] = a - end - - obj.order.should == ["foo", "a", "foo[]="] - end - end - - context "with multiple assignment" do - ruby_version_is ""..."3.1" do - it "does not evaluate from left to right" do - obj = VariablesSpecs::EvalOrder.new - - obj.instance_eval do - foo[0], bar.baz = a, b - end - - obj.order.should == ["a", "b", "foo", "foo[]=", "bar", "bar.baz="] - end - - it "cannot be used to swap variables with nested method calls" do - node = VariablesSpecs::EvalOrder.new.node - - original_node = node - original_node_left = node.left - original_node_left_right = node.left.right - - node.left, node.left.right, node = node.left.right, node, node.left - # Should evaluate in the order of: - # RHS: node.left.right, node, node.left - # LHS: - # * node(original_node), original_node.left = original_node_left_right - # * node(original_node), node.left(changed in the previous assignment to original_node_left_right), - # original_node_left_right.right = original_node - # * node = original_node_left - - node.should == original_node_left - node.right.should_not == original_node - node.right.left.should_not == original_node_left_right - end - end - - ruby_version_is "3.1" do - it "evaluates from left to right, receivers first then methods" do - obj = VariablesSpecs::EvalOrder.new - obj.instance_eval do - foo[0], bar.baz = a, b - end - - obj.order.should == ["foo", "bar", "a", "b", "foo[]=", "bar.baz="] - end - - it "can be used to swap variables with nested method calls" do - node = VariablesSpecs::EvalOrder.new.node - - original_node = node - original_node_left = node.left - original_node_left_right = node.left.right - - node.left, node.left.right, node = node.left.right, node, node.left - # Should evaluate in the order of: - # LHS: node, node.left(original_node_left) - # RHS: original_node_left_right, original_node, original_node_left - # Ops: - # * node(original_node), original_node.left = original_node_left_right - # * original_node_left.right = original_node - # * node = original_node_left - - node.should == original_node_left - node.right.should == original_node - node.right.left.should == original_node_left_right - end - end - end -end - describe "Multiple assignment" do context "with a single RHS value" do it "assigns a simple MLHS" do @@ -877,6 +797,17 @@ describe 'Local variable shadowing' do end describe 'Allowed characters' do + # new feature in 2.6 -- https://bugs.ruby-lang.org/issues/13770 + it 'does not allow non-ASCII upcased characters at the beginning' do + -> do + eval <<-CODE + def test + ἍBB = 1 + end + CODE + end.should raise_error(SyntaxError, /dynamic constant assignment/) + end + it 'allows non-ASCII lowercased characters at the beginning' do result = nil @@ -890,50 +821,33 @@ describe 'Allowed characters' do result.should == 1 end - - it 'parses a non-ASCII upcased character as a constant identifier' do - -> do - eval <<-CODE - def test - ἍBB = 1 - end - CODE - end.should raise_error(SyntaxError, /dynamic constant assignment/) - end end describe "Instance variables" do context "when instance variable is uninitialized" do - it "doesn't warn about accessing uninitialized instance variable" do - obj = Object.new - def obj.foobar; a = @a; end - - -> { obj.foobar }.should_not complain(verbose: true) - end - - it "doesn't warn at lazy initialization" do - obj = Object.new - def obj.foobar; @a ||= 42; end - - -> { obj.foobar }.should_not complain(verbose: true) - end - end - - describe "global variable" do - context "when global variable is uninitialized" do - it "warns about accessing uninitialized global variable in verbose mode" do + ruby_version_is ""..."3.0" do + it "warns about accessing uninitialized instance variable" do obj = Object.new - def obj.foobar; a = $specs_uninitialized_global_variable; end + def obj.foobar; a = @a; end - -> { obj.foobar }.should complain(/warning: global variable `\$specs_uninitialized_global_variable' not initialized/, verbose: true) + -> { obj.foobar }.should complain(/warning: instance variable @a not initialized/, verbose: true) end + end - it "doesn't warn at lazy initialization" do + ruby_version_is "3.0" do + it "doesn't warn about accessing uninitialized instance variable" do obj = Object.new - def obj.foobar; $specs_uninitialized_global_variable_lazy ||= 42; end + def obj.foobar; a = @a; end -> { obj.foobar }.should_not complain(verbose: true) end end + + it "doesn't warn at lazy initialization" do + obj = Object.new + def obj.foobar; @a ||= 42; end + + -> { obj.foobar }.should_not complain(verbose: true) + end end end diff --git a/spec/ruby/language/yield_spec.rb b/spec/ruby/language/yield_spec.rb index 5283517636..3db6d353a9 100644 --- a/spec/ruby/language/yield_spec.rb +++ b/spec/ruby/language/yield_spec.rb @@ -186,23 +186,30 @@ describe "The yield call" do end describe "Using yield in a singleton class literal" do - it 'raises a SyntaxError' do - code = <<~RUBY - class << Object.new - yield - end - RUBY + ruby_version_is "2.7"..."3.0" do + it 'emits a deprecation warning' do + code = <<~RUBY + def m + class << Object.new + yield + end + end + m { :ok } + RUBY - -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/) + -> { eval(code) }.should complain(/warning: `yield' in class syntax will not be supported from Ruby 3.0/) + end end -end -describe "Using yield in non-lambda block" do - it 'raises a SyntaxError' do - code = <<~RUBY - 1.times { yield } + ruby_version_is "3.0" do + it 'raises a SyntaxError' do + code = <<~RUBY + class << Object.new + yield + end RUBY - -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/) + -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/) + end end end diff --git a/spec/ruby/library/English/English_spec.rb b/spec/ruby/library/English/English_spec.rb index 4d615d1e25..480602d5e5 100644 --- a/spec/ruby/library/English/English_spec.rb +++ b/spec/ruby/library/English/English_spec.rb @@ -130,15 +130,13 @@ describe "English" do $LAST_MATCH_INFO.should == $~ end - ruby_version_is ""..."3.3" do - it "aliases $IGNORECASE to $=" do - $VERBOSE, verbose = nil, $VERBOSE - begin - $IGNORECASE.should_not be_nil - $IGNORECASE.should == $= - ensure - $VERBOSE = verbose - end + it "aliases $IGNORECASE to $=" do + $VERBOSE, verbose = nil, $VERBOSE + begin + $IGNORECASE.should_not be_nil + $IGNORECASE.should == $= + ensure + $VERBOSE = verbose end end diff --git a/spec/ruby/library/bigdecimal/add_spec.rb b/spec/ruby/library/bigdecimal/add_spec.rb index 542713011d..bea8b8f764 100644 --- a/spec/ruby/library/bigdecimal/add_spec.rb +++ b/spec/ruby/library/bigdecimal/add_spec.rb @@ -24,7 +24,7 @@ describe "BigDecimal#add" do end it "returns a + b with given precision" do - # documentation states that precision is optional, but it ain't, + # documentation states, that precision ist optional, but it ain't, @two.add(@one, 1).should == @three @one .add(@two, 1).should == @three @one.add(@one_minus, 1).should == @zero @@ -60,7 +60,7 @@ describe "BigDecimal#add" do end # TODO: -# https://blade.ruby-lang.org/ruby-core/17374 +# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/17374 # # This doesn't work on MRI and looks like a bug to me: # one can use BigDecimal + Float, but not Bigdecimal.add(Float) diff --git a/spec/ruby/library/bigdecimal/exponent_spec.rb b/spec/ruby/library/bigdecimal/exponent_spec.rb index 8877147955..f63c4e5798 100644 --- a/spec/ruby/library/bigdecimal/exponent_spec.rb +++ b/spec/ruby/library/bigdecimal/exponent_spec.rb @@ -18,6 +18,17 @@ describe "BigDecimal#exponent" do BigDecimal("1234567E10").exponent.should == 17 end +# commenting this spec out after discussion with Defiler, since it seems to be an MRI bug, not a real feature +=begin + platform_is wordsize: 32 do + # TODO: write specs for both 32 and 64 bit + it "returns 0 if exponent can't be represented as Integer" do + BigDecimal("2E1000000000000000").exponent.should == 0 + BigDecimal("-5E-999999999999999").exponent.should == 0 + end + end +=end + it "returns 0 if self is 0" do BigDecimal("0").exponent.should == 0 BigDecimal("+0").exponent.should == 0 diff --git a/spec/ruby/library/bigdecimal/remainder_spec.rb b/spec/ruby/library/bigdecimal/remainder_spec.rb index bac5f37ba9..1866f665cd 100644 --- a/spec/ruby/library/bigdecimal/remainder_spec.rb +++ b/spec/ruby/library/bigdecimal/remainder_spec.rb @@ -54,23 +54,21 @@ describe "BigDecimal#remainder" do @nan.remainder(@infinity).should.nan? end - version_is BigDecimal::VERSION, ""..."3.1.4" do #ruby_version_is ""..."3.3" do - it "returns NaN if Infinity is involved" do - @infinity.remainder(@infinity).should.nan? - @infinity.remainder(@one).should.nan? - @infinity.remainder(@mixed).should.nan? - @infinity.remainder(@one_minus).should.nan? - @infinity.remainder(@frac_1).should.nan? - @one.remainder(@infinity).should.nan? + it "returns NaN if Infinity is involved" do + @infinity.remainder(@infinity).should.nan? + @infinity.remainder(@one).should.nan? + @infinity.remainder(@mixed).should.nan? + @infinity.remainder(@one_minus).should.nan? + @infinity.remainder(@frac_1).should.nan? + @one.remainder(@infinity).should.nan? - @infinity_minus.remainder(@infinity_minus).should.nan? - @infinity_minus.remainder(@one).should.nan? - @one.remainder(@infinity_minus).should.nan? - @frac_2.remainder(@infinity_minus).should.nan? + @infinity_minus.remainder(@infinity_minus).should.nan? + @infinity_minus.remainder(@one).should.nan? + @one.remainder(@infinity_minus).should.nan? + @frac_2.remainder(@infinity_minus).should.nan? - @infinity.remainder(@infinity_minus).should.nan? - @infinity_minus.remainder(@infinity).should.nan? - end + @infinity.remainder(@infinity_minus).should.nan? + @infinity_minus.remainder(@infinity).should.nan? end it "coerces arguments to BigDecimal if possible" do diff --git a/spec/ruby/library/bigdecimal/round_spec.rb b/spec/ruby/library/bigdecimal/round_spec.rb index fba52df65d..501a1a7342 100644 --- a/spec/ruby/library/bigdecimal/round_spec.rb +++ b/spec/ruby/library/bigdecimal/round_spec.rb @@ -228,15 +228,7 @@ describe "BigDecimal#round" do -> { BigDecimal('-Infinity').round(2) }.should_not raise_error(FloatDomainError) end - version_is BigDecimal::VERSION, ''...'3.1.3' do #ruby_version_is ''...'3.2' do - it 'raise for a non-existent round mode' do - -> { @p1_50.round(0, :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode") - end - end - - version_is BigDecimal::VERSION, '3.1.3' do #ruby_version_is '3.2' do - it 'raise for a non-existent round mode' do - -> { @p1_50.round(0, :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode (nonsense)") - end + it "raise for a non-existent round mode" do + -> { @p1_50.round(0, :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode") end end diff --git a/spec/ruby/library/bigdecimal/shared/to_int.rb b/spec/ruby/library/bigdecimal/shared/to_int.rb index 44b6a3c7b2..0f16251612 100644 --- a/spec/ruby/library/bigdecimal/shared/to_int.rb +++ b/spec/ruby/library/bigdecimal/shared/to_int.rb @@ -1,6 +1,6 @@ require 'bigdecimal' -describe :bigdecimal_to_int, shared: true do +describe :bigdecimal_to_int , shared: true do it "raises FloatDomainError if BigDecimal is infinity or NaN" do -> { BigDecimal("Infinity").send(@method) }.should raise_error(FloatDomainError) -> { BigDecimal("NaN").send(@method) }.should raise_error(FloatDomainError) diff --git a/spec/ruby/library/bigdecimal/to_r_spec.rb b/spec/ruby/library/bigdecimal/to_r_spec.rb index c350beff08..91d2b33993 100644 --- a/spec/ruby/library/bigdecimal/to_r_spec.rb +++ b/spec/ruby/library/bigdecimal/to_r_spec.rb @@ -13,16 +13,4 @@ describe "BigDecimal#to_r" do r.denominator.should eql(1000000000000000000000000) end - it "returns a Rational from a BigDecimal with an exponent" do - r = BigDecimal("1E2").to_r - r.numerator.should eql(100) - r.denominator.should eql(1) - end - - it "returns a Rational from a negative BigDecimal with an exponent" do - r = BigDecimal("-1E2").to_r - r.numerator.should eql(-100) - r.denominator.should eql(1) - end - end diff --git a/spec/ruby/library/bigdecimal/to_s_spec.rb b/spec/ruby/library/bigdecimal/to_s_spec.rb index ba9f960eb3..4f1054d38e 100644 --- a/spec/ruby/library/bigdecimal/to_s_spec.rb +++ b/spec/ruby/library/bigdecimal/to_s_spec.rb @@ -39,25 +39,20 @@ describe "BigDecimal#to_s" do @bigneg.to_s("+").should_not =~ /^\+.*/ end - it "inserts a space every n chars to fraction part, if integer n is supplied" do + it "inserts a space every n chars, if integer n is supplied" do re =\ - /\A0\.314 159 265 358 979 323 846 264 338 327 950 288 419 716 939 937E1\z/i + /\A0\.314 159 265 358 979 323 846 264 338 327 950 288 419 716 939 937E1\z/i @bigdec.to_s(3).should =~ re str1 = '-123.45678 90123 45678 9' BigDecimal("-123.45678901234567890").to_s('5F').should == str1 + BigDecimal('1000010').to_s('5F').should == "10000 10.0" # trailing zeroes removed BigDecimal("1.00000000000").to_s('1F').should == "1.0" # 0 is treated as no spaces BigDecimal("1.2345").to_s('0F').should == "1.2345" end - version_is BigDecimal::VERSION, "3.1.5" do #ruby_version_is '3.3' do - it "inserts a space every n chars to integer part, if integer n is supplied" do - BigDecimal('1000010').to_s('5F').should == "10 00010.0" - end - end - it "can return a leading space for values > 0" do @bigdec.to_s(" F").should =~ /\ .*/ @bigneg.to_s(" F").should_not =~ /\ .*/ @@ -88,13 +83,15 @@ describe "BigDecimal#to_s" do end end - it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do - Encoding.default_internal = nil - BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII) - end + ruby_version_is "3.0" do + it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do + Encoding.default_internal = nil + BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII) + end - it "returns a String in US-ASCII encoding when Encoding.default_internal is not nil" do - Encoding.default_internal = Encoding::IBM437 - BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII) + it "returns a String in US-ASCII encoding when Encoding.default_internal is not nil" do + Encoding.default_internal = Encoding::IBM437 + BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII) + end end end diff --git a/spec/ruby/library/cgi/escapeURIComponent_spec.rb b/spec/ruby/library/cgi/escapeURIComponent_spec.rb deleted file mode 100644 index 2cf283c778..0000000000 --- a/spec/ruby/library/cgi/escapeURIComponent_spec.rb +++ /dev/null @@ -1,57 +0,0 @@ -require_relative '../../spec_helper' -require 'cgi' - -ruby_version_is "3.2" do - describe "CGI.escapeURIComponent" do - it "escapes whitespace" do - string = "&<>\" \xE3\x82\x86\xE3\x82\x93\xE3\x82\x86\xE3\x82\x93" - CGI.escapeURIComponent(string).should == '%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93' - end - - it "does not escape with unreserved characters" do - string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~" - CGI.escapeURIComponent(string).should == "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~" - end - - it "supports String with invalid encoding" do - string = "\xC0\<\<".force_encoding("UTF-8") - CGI.escapeURIComponent(string).should == "%C0%3C%3C" - end - - it "processes String bytes one by one, not characters" do - CGI.escapeURIComponent("β").should == "%CE%B2" # "β" bytes representation is CE B2 - end - - it "raises a TypeError with nil" do - -> { - CGI.escapeURIComponent(nil) - }.should raise_error(TypeError, 'no implicit conversion of nil into String') - end - - it "encodes empty string" do - CGI.escapeURIComponent("").should == "" - end - - it "encodes single whitespace" do - CGI.escapeURIComponent(" ").should == "%20" - end - - it "encodes double whitespace" do - CGI.escapeURIComponent(" ").should == "%20%20" - end - - it "preserves encoding" do - string = "whatever".encode("ASCII-8BIT") - CGI.escapeURIComponent(string).encoding.should == Encoding::ASCII_8BIT - end - - it "uses implicit type conversion to String" do - object = Object.new - def object.to_str - "a b" - end - - CGI.escapeURIComponent(object).should == "a%20b" - end - end -end diff --git a/spec/ruby/library/cgi/initialize_spec.rb b/spec/ruby/library/cgi/initialize_spec.rb index 61bc971d49..f794f157f0 100644 --- a/spec/ruby/library/cgi/initialize_spec.rb +++ b/spec/ruby/library/cgi/initialize_spec.rb @@ -29,8 +29,8 @@ describe "CGI#initialize when passed no arguments" do it "does not extend self with any of the other HTML modules" do @cgi.send(:initialize) - @cgi.should_not be_kind_of(CGI::HtmlExtension) @cgi.should_not be_kind_of(CGI::Html3) + @cgi.should_not be_kind_of(CGI::HtmlExtension) @cgi.should_not be_kind_of(CGI::Html4) @cgi.should_not be_kind_of(CGI::Html4Tr) @cgi.should_not be_kind_of(CGI::Html4Fr) diff --git a/spec/ruby/library/cmath/math/acos_spec.rb b/spec/ruby/library/cmath/math/acos_spec.rb new file mode 100644 index 0000000000..2e9104f835 --- /dev/null +++ b/spec/ruby/library/cmath/math/acos_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/acos' + + describe "Math#acos" do + it_behaves_like :complex_math_acos, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:acos) + end + end + + describe "Math.acos" do + it_behaves_like :complex_math_acos, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/acosh_spec.rb b/spec/ruby/library/cmath/math/acosh_spec.rb new file mode 100644 index 0000000000..809112f6c0 --- /dev/null +++ b/spec/ruby/library/cmath/math/acosh_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/acosh' + + describe "Math#acosh" do + it_behaves_like :complex_math_acosh, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:acosh) + end + end + + describe "Math.acosh" do + it_behaves_like :complex_math_acosh, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/asin_spec.rb b/spec/ruby/library/cmath/math/asin_spec.rb new file mode 100644 index 0000000000..4ac588ebd2 --- /dev/null +++ b/spec/ruby/library/cmath/math/asin_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/asin' + + describe "Math#asin" do + it_behaves_like :complex_math_asin, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:asin) + end + end + + describe "Math.asin" do + it_behaves_like :complex_math_asin, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/asinh_spec.rb b/spec/ruby/library/cmath/math/asinh_spec.rb new file mode 100644 index 0000000000..7d8b397a04 --- /dev/null +++ b/spec/ruby/library/cmath/math/asinh_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/asinh' + + describe "Math#asinh" do + it_behaves_like :complex_math_asinh, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:asinh) + end + end + + describe "Math.asinh" do + it_behaves_like :complex_math_asinh, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/atan2_spec.rb b/spec/ruby/library/cmath/math/atan2_spec.rb new file mode 100644 index 0000000000..1a9b7d7607 --- /dev/null +++ b/spec/ruby/library/cmath/math/atan2_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/atan2' + + describe "Math#atan2" do + it_behaves_like :complex_math_atan2, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:atan2) + end + end + + describe "Math.atan2" do + it_behaves_like :complex_math_atan2, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/atan_spec.rb b/spec/ruby/library/cmath/math/atan_spec.rb new file mode 100644 index 0000000000..b0171081a6 --- /dev/null +++ b/spec/ruby/library/cmath/math/atan_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/atan' + + describe "Math#atan" do + it_behaves_like :complex_math_atan, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:atan) + end + end + + describe "Math.atan" do + it_behaves_like :complex_math_atan, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/atanh_spec.rb b/spec/ruby/library/cmath/math/atanh_spec.rb new file mode 100644 index 0000000000..6b22c6c9e4 --- /dev/null +++ b/spec/ruby/library/cmath/math/atanh_spec.rb @@ -0,0 +1,20 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative '../../../fixtures/math/common' + require_relative '../../../shared/math/atanh' + require_relative 'shared/atanh' + + describe "Math#atanh" do + it_behaves_like :math_atanh_base, :atanh, IncludesMath.new + it_behaves_like :complex_math_atanh_complex, :atanh, IncludesMath.new + + it_behaves_like :math_atanh_private, :atanh, IncludesMath.new + end + + describe "Math.atanh" do + it_behaves_like :math_atanh_base, :atanh, CMath + it_behaves_like :complex_math_atanh_complex, :atanh, CMath + end +end diff --git a/spec/ruby/library/cmath/math/cos_spec.rb b/spec/ruby/library/cmath/math/cos_spec.rb new file mode 100644 index 0000000000..3f097bcb3b --- /dev/null +++ b/spec/ruby/library/cmath/math/cos_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/cos' + + describe "Math#cos" do + it_behaves_like :complex_math_cos, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:cos) + end + end + + describe "Math.cos" do + it_behaves_like :complex_math_cos, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/cosh_spec.rb b/spec/ruby/library/cmath/math/cosh_spec.rb new file mode 100644 index 0000000000..197f899981 --- /dev/null +++ b/spec/ruby/library/cmath/math/cosh_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/cosh' + + describe "Math#cosh" do + it_behaves_like :complex_math_cosh, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:cosh) + end + end + + describe "Math.cosh" do + it_behaves_like :complex_math_cosh, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/exp_spec.rb b/spec/ruby/library/cmath/math/exp_spec.rb new file mode 100644 index 0000000000..eef2ec3129 --- /dev/null +++ b/spec/ruby/library/cmath/math/exp_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/exp' + + describe "Math#exp" do + it_behaves_like :complex_math_exp, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:exp) + end + end + + describe "Math.exp" do + it_behaves_like :complex_math_exp, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/fixtures/classes.rb b/spec/ruby/library/cmath/math/fixtures/classes.rb new file mode 100644 index 0000000000..443c1a9ace --- /dev/null +++ b/spec/ruby/library/cmath/math/fixtures/classes.rb @@ -0,0 +1,4 @@ +require 'cmath' +class IncludesMath + include CMath +end diff --git a/spec/ruby/library/cmath/math/log10_spec.rb b/spec/ruby/library/cmath/math/log10_spec.rb new file mode 100644 index 0000000000..603bbb1457 --- /dev/null +++ b/spec/ruby/library/cmath/math/log10_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/log10' + + describe "Math#log10" do + it_behaves_like :complex_math_log10, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:log10) + end + end + + describe "Math.log10" do + it_behaves_like :complex_math_log10, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/log_spec.rb b/spec/ruby/library/cmath/math/log_spec.rb new file mode 100644 index 0000000000..b4da781323 --- /dev/null +++ b/spec/ruby/library/cmath/math/log_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/log' + + describe "Math#log" do + it_behaves_like :complex_math_log, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:log) + end + end + + describe "Math.log" do + it_behaves_like :complex_math_log, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/shared/acos.rb b/spec/ruby/library/cmath/math/shared/acos.rb new file mode 100644 index 0000000000..65637fa838 --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/acos.rb @@ -0,0 +1,41 @@ +require_relative '../fixtures/classes' + +describe :complex_math_acos, shared: true do + it "returns the arccosine of the passed argument" do + @object.send(:acos, 1).should be_close(0.0, TOLERANCE) + @object.send(:acos, 0).should be_close(1.5707963267949, TOLERANCE) + @object.send(:acos, -1).should be_close(Math::PI,TOLERANCE) + end + + it "returns the arccosine for Complex numbers" do + @object.send(:acos, Complex(3, 4)).should be_close(Complex(0.93681246115572, -2.30550903124348), TOLERANCE) + end + + it "returns the arccosine for numbers greater than 1.0 as a Complex number" do + @object.send(:acos, 1.0001).should be_close(Complex(0.0, 0.0141420177752494), TOLERANCE) + end + + it "returns the arccosine for numbers less than -1.0 as a Complex number" do + @object.send(:acos, -1.0001).should be_close(Complex(3.14159265358979, -0.0141420177752495), TOLERANCE) + end +end + +describe :complex_math_acos_bang, shared: true do + it "returns the arccosine of the argument" do + @object.send(:acos!, 1).should be_close(0.0, TOLERANCE) + @object.send(:acos!, 0).should be_close(1.5707963267949, TOLERANCE) + @object.send(:acos!, -1).should be_close(Math::PI,TOLERANCE) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:acos!, Complex(4, 5)) }.should raise_error(TypeError) + end + + it "raises an Errno::EDOM for numbers greater than 1.0" do + -> { @object.send(:acos!, 1.0001) }.should raise_error(Errno::EDOM) + end + + it "raises an Errno::EDOM for numbers less than -1.0" do + -> { @object.send(:acos!, -1.0001) }.should raise_error(Errno::EDOM) + end +end diff --git a/spec/ruby/library/cmath/math/shared/acosh.rb b/spec/ruby/library/cmath/math/shared/acosh.rb new file mode 100644 index 0000000000..285b0b823f --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/acosh.rb @@ -0,0 +1,37 @@ +require_relative '../fixtures/classes' + +describe :complex_math_acosh, shared: true do + it "returns the principle value of the inverse hyperbolic cosine of the argument" do + @object.send(:acosh, 14.2).should be_close(3.345146999647, TOLERANCE) + @object.send(:acosh, 1.0).should be_close(0.0, TOLERANCE) + end + + it "returns the principle value of the inverse hyperbolic cosine for numbers less than 1.0 as a Complex number" do + @object.send(:acosh, 1.0 - TOLERANCE).should be_close(Complex(0.0, 0.00774598605746135), TOLERANCE) + @object.send(:acosh, 0).should be_close(Complex(0.0, 1.5707963267949), TOLERANCE) + @object.send(:acosh, -1.0).should be_close(Complex(0.0, 3.14159265358979), TOLERANCE) + end + + it "returns the principle value of the inverse hyperbolic cosine for Complex numbers" do + @object.send(:acosh, Complex(3, 4)) + @object.send(:acosh, Complex(3, 4)).imaginary.should be_close(0.93681246115572, TOLERANCE) + @object.send(:acosh, Complex(3, 4)).real.should be_close(2.305509031243477, TOLERANCE) + end +end + +describe :complex_math_acosh_bang, shared: true do + it "returns the principle value of the inverse hyperbolic cosine of the argument" do + @object.send(:acosh!, 14.2).should be_close(3.345146999647, TOLERANCE) + @object.send(:acosh!, 1.0).should be_close(0.0, TOLERANCE) + end + + it "raises Errno::EDOM for numbers less than 1.0" do + -> { @object.send(:acosh!, 1.0 - TOLERANCE) }.should raise_error(Errno::EDOM) + -> { @object.send(:acosh!, 0) }.should raise_error(Errno::EDOM) + -> { @object.send(:acosh!, -1.0) }.should raise_error(Errno::EDOM) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:acosh!, Complex(4, 5)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/asin.rb b/spec/ruby/library/cmath/math/shared/asin.rb new file mode 100644 index 0000000000..91fed7aa06 --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/asin.rb @@ -0,0 +1,47 @@ +require_relative '../fixtures/classes' + +describe :complex_math_asin, shared: true do + it "returns the arcsine of the argument" do + @object.send(:asin, 1).should be_close(Math::PI/2, TOLERANCE) + @object.send(:asin, 0).should be_close(0.0, TOLERANCE) + @object.send(:asin, -1).should be_close(-Math::PI/2, TOLERANCE) + @object.send(:asin, 0.25).should be_close(0.252680255142079, TOLERANCE) + @object.send(:asin, 0.50).should be_close(0.523598775598299, TOLERANCE) + @object.send(:asin, 0.75).should be_close(0.8480620789814816,TOLERANCE) + end + + it "returns the arcsine for Complex numbers" do + @object.send(:asin, Complex(3, 4)).should be_close(Complex(0.633983865639174, 2.30550903124347), TOLERANCE) + end + + it "returns a Complex number when the argument is greater than 1.0" do + @object.send(:asin, 1.0001).should be_close(Complex(1.5707963267949, -0.0141420177752494), TOLERANCE) + end + + it "returns a Complex number when the argument is less than -1.0" do + @object.send(:asin, -1.0001).should be_close(Complex(-1.5707963267949, 0.0141420177752494), TOLERANCE) + end +end + +describe :complex_math_asin_bang, shared: true do + it "returns the arcsine of the argument" do + @object.send(:asin!, 1).should be_close(Math::PI/2, TOLERANCE) + @object.send(:asin!, 0).should be_close(0.0, TOLERANCE) + @object.send(:asin!, -1).should be_close(-Math::PI/2, TOLERANCE) + @object.send(:asin!, 0.25).should be_close(0.252680255142079, TOLERANCE) + @object.send(:asin!, 0.50).should be_close(0.523598775598299, TOLERANCE) + @object.send(:asin!, 0.75).should be_close(0.8480620789814816,TOLERANCE) + end + + it "raises an Errno::EDOM if the argument is greater than 1.0" do + -> { @object.send(:asin!, 1.0001) }.should raise_error( Errno::EDOM) + end + + it "raises an Errno::EDOM if the argument is less than -1.0" do + -> { @object.send(:asin!, -1.0001) }.should raise_error( Errno::EDOM) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:asin!, Complex(4, 5)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/asinh.rb b/spec/ruby/library/cmath/math/shared/asinh.rb new file mode 100644 index 0000000000..b4ddd3a22e --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/asinh.rb @@ -0,0 +1,32 @@ +require_relative '../fixtures/classes' + +describe :complex_math_asinh, shared: true do + it "returns the inverse hyperbolic sin of the argument" do + @object.send(:asinh, 1.5).should be_close(1.19476321728711, TOLERANCE) + @object.send(:asinh, -2.97).should be_close(-1.8089166921397, TOLERANCE) + @object.send(:asinh, 0.0).should == 0.0 + @object.send(:asinh, -0.0).should == -0.0 + @object.send(:asinh, 1.05367e-08).should be_close(1.05367e-08, TOLERANCE) + @object.send(:asinh, -1.05367e-08).should be_close(-1.05367e-08, TOLERANCE) + end + + it "returns the inverse hyperbolic sin for Complex numbers" do + @object.send(:asinh, Complex(3, 4)).should be_close(Complex(2.29991404087927, 0.917616853351479), TOLERANCE) + @object.send(:asinh, Complex(3.5, -4)).should be_close(Complex(2.36263337274419, -0.843166327537659), TOLERANCE) + end +end + +describe :complex_math_asinh_bang, shared: true do + it "returns the inverse hyperbolic sin of the argument" do + @object.send(:asinh!, 1.5).should be_close(1.19476321728711, TOLERANCE) + @object.send(:asinh!, -2.97).should be_close(-1.8089166921397, TOLERANCE) + @object.send(:asinh!, 0.0).should == 0.0 + @object.send(:asinh!, -0.0).should == -0.0 + @object.send(:asinh!, 1.05367e-08).should be_close(1.05367e-08, TOLERANCE) + @object.send(:asinh!, -1.05367e-08).should be_close(-1.05367e-08, TOLERANCE) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:asinh!, Complex(4, 5)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/atan.rb b/spec/ruby/library/cmath/math/shared/atan.rb new file mode 100644 index 0000000000..63a496e841 --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/atan.rb @@ -0,0 +1,32 @@ +require_relative '../fixtures/classes' + +describe :complex_math_atan, shared: true do + it "returns the arctangent of the argument" do + @object.send(:atan, 1).should be_close(Math::PI/4, TOLERANCE) + @object.send(:atan, 0).should be_close(0.0, TOLERANCE) + @object.send(:atan, -1).should be_close(-Math::PI/4, TOLERANCE) + @object.send(:atan, 0.25).should be_close(0.244978663126864, TOLERANCE) + @object.send(:atan, 0.50).should be_close(0.463647609000806, TOLERANCE) + @object.send(:atan, 0.75).should be_close(0.643501108793284, TOLERANCE) + end + + it "returns the arctangent for Complex numbers" do + @object.send(:atan, Complex(3, 4)).should be_close(Complex(1.44830699523146, 0.158997191679999), TOLERANCE) + @object.send(:atan, Complex(3.5, -4)).should be_close(Complex(1.44507428165589, -0.140323762363786), TOLERANCE) + end +end + +describe :complex_math_atan_bang, shared: true do + it "returns the arctangent of the argument" do + @object.send(:atan!, 1).should be_close(Math::PI/4, TOLERANCE) + @object.send(:atan!, 0).should be_close(0.0, TOLERANCE) + @object.send(:atan!, -1).should be_close(-Math::PI/4, TOLERANCE) + @object.send(:atan!, 0.25).should be_close(0.244978663126864, TOLERANCE) + @object.send(:atan!, 0.50).should be_close(0.463647609000806, TOLERANCE) + @object.send(:atan!, 0.75).should be_close(0.643501108793284, TOLERANCE) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:atan!, Complex(4, 5)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/atan2.rb b/spec/ruby/library/cmath/math/shared/atan2.rb new file mode 100644 index 0000000000..6d89423924 --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/atan2.rb @@ -0,0 +1,34 @@ +require_relative '../fixtures/classes' + +describe :complex_math_atan2, shared: true do + it "returns the arc tangent of the passed arguments" do + @object.send(:atan2, 4.2, 0.3).should be_close(1.49948886200961, TOLERANCE) + @object.send(:atan2, 0.0, 1.0).should be_close(0.0, TOLERANCE) + @object.send(:atan2, -9.1, 3.2).should be_close(-1.23265379809025, TOLERANCE) + @object.send(:atan2, 7.22, -3.3).should be_close(1.99950888779256, TOLERANCE) + end + + it "returns the arc tangent for two Complex numbers" do + CMath.atan2(Complex(3, 4), Complex(3.5, -4)).should be_close(Complex(-0.641757436698881, 1.10829873031207), TOLERANCE) + end + + it "returns the arc tangent for Complex and real numbers" do + CMath.atan2(Complex(3, 4), -7).should be_close(Complex(2.61576754731561, -0.494290673139855), TOLERANCE) + CMath.atan2(5, Complex(3.5, -4)).should be_close(Complex(0.739102348493673, 0.487821626522923), TOLERANCE) + end +end + +describe :complex_math_atan2_bang, shared: true do + it "returns the arc tangent of the passed arguments" do + @object.send(:atan2!, 4.2, 0.3).should be_close(1.49948886200961, TOLERANCE) + @object.send(:atan2!, 0.0, 1.0).should be_close(0.0, TOLERANCE) + @object.send(:atan2!, -9.1, 3.2).should be_close(-1.23265379809025, TOLERANCE) + @object.send(:atan2!, 7.22, -3.3).should be_close(1.99950888779256, TOLERANCE) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:atan2!, Complex(4, 5), Complex(4, 5)) }.should raise_error(TypeError) + -> { @object.send(:atan2!, 4, Complex(4, 5)) }.should raise_error(TypeError) + -> { @object.send(:atan2!, Complex(4, 5), 5) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/atanh.rb b/spec/ruby/library/cmath/math/shared/atanh.rb new file mode 100644 index 0000000000..ae80e61bec --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/atanh.rb @@ -0,0 +1,30 @@ +require_relative '../fixtures/classes' + +describe :complex_math_atanh_complex, shared: true do + it "returns the inverse hyperbolic tangent as a Complex number for arguments greater than 1.0" do + value = Complex(18.36840028483855, 1.5707963267948966) + @object.send(@method, 1.0 + Float::EPSILON).should be_close(value, TOLERANCE) + + value = Complex(0.100335347731076, 1.5707963267949) + @object.send(@method, 10).should be_close(value, TOLERANCE) + end + + it "returns the inverse hyperbolic tangent as a Complex number for arguments greater than 1.0" do + value = Complex(-18.36840028483855, 1.5707963267948966) + @object.send(@method, -1.0 - Float::EPSILON).should be_close(value, TOLERANCE) + + value = Complex(0.100335347731076, 1.5707963267949) + @object.send(@method, 10).should be_close(value, TOLERANCE) + end + + it "returns the inverse hyperbolic tangent for Complex numbers" do + value = Complex(0.117500907311434, 1.40992104959658) + @object.send(@method, Complex(3, 4)).should be_close(value, TOLERANCE) + end +end + +describe :complex_math_atanh_no_complex, shared: true do + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:atanh!, Complex(4, 5)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/cos.rb b/spec/ruby/library/cmath/math/shared/cos.rb new file mode 100644 index 0000000000..31cb5ab1e5 --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/cos.rb @@ -0,0 +1,30 @@ +require_relative '../fixtures/classes' + +describe :complex_math_cos, shared: true do + it "returns the cosine of the argument expressed in radians" do + @object.send(:cos, CMath::PI).should be_close(-1.0, TOLERANCE) + @object.send(:cos, 0).should be_close(1.0, TOLERANCE) + @object.send(:cos, CMath::PI/2).should be_close(0.0, TOLERANCE) + @object.send(:cos, 3*Math::PI/2).should be_close(0.0, TOLERANCE) + @object.send(:cos, 2*Math::PI).should be_close(1.0, TOLERANCE) + end + + it "returns the cosine for Complex numbers" do + @object.send(:cos, Complex(0, CMath::PI)).should be_close(Complex(11.5919532755215, 0.0), TOLERANCE) + @object.send(:cos, Complex(3, 4)).should be_close(Complex(-27.0349456030742, -3.85115333481178), TOLERANCE) + end +end + +describe :complex_math_cos_bang, shared: true do + it "returns the cosine of the argument expressed in radians" do + @object.send(:cos!, CMath::PI).should be_close(-1.0, TOLERANCE) + @object.send(:cos!, 0).should be_close(1.0, TOLERANCE) + @object.send(:cos!, CMath::PI/2).should be_close(0.0, TOLERANCE) + @object.send(:cos!, 3*Math::PI/2).should be_close(0.0, TOLERANCE) + @object.send(:cos!, 2*Math::PI).should be_close(1.0, TOLERANCE) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:cos!, Complex(3, 4)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/cosh.rb b/spec/ruby/library/cmath/math/shared/cosh.rb new file mode 100644 index 0000000000..7cf561c985 --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/cosh.rb @@ -0,0 +1,28 @@ +require_relative '../fixtures/classes' + +describe :complex_math_cosh, shared: true do + it "returns the hyperbolic cosine of the passed argument" do + @object.send(:cosh, 0.0).should == 1.0 + @object.send(:cosh, -0.0).should == 1.0 + @object.send(:cosh, 1.5).should be_close(2.35240961524325, TOLERANCE) + @object.send(:cosh, -2.99).should be_close(9.96798496414416, TOLERANCE) + end + + it "returns the hyperbolic cosine for Complex numbers" do + @object.send(:cosh, Complex(0, CMath::PI)).should be_close(Complex(-1.0, 0.0), TOLERANCE) + @object.send(:cosh, Complex(3, 4)).should be_close(Complex(-6.58066304055116, -7.58155274274654), TOLERANCE) + end +end + +describe :complex_math_cosh_bang, shared: true do + it "returns the hyperbolic cosine of the passed argument" do + @object.send(:cosh!, 0.0).should == 1.0 + @object.send(:cosh!, -0.0).should == 1.0 + @object.send(:cosh!, 1.5).should be_close(2.35240961524325, TOLERANCE) + @object.send(:cosh!, -2.99).should be_close(9.96798496414416, TOLERANCE) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:cosh!, Complex(4, 5)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/exp.rb b/spec/ruby/library/cmath/math/shared/exp.rb new file mode 100644 index 0000000000..6715ac63d3 --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/exp.rb @@ -0,0 +1,28 @@ +require_relative '../fixtures/classes' + +describe :complex_math_exp, shared: true do + it "returns the base-e exponential of the passed argument" do + @object.send(:exp, 0.0).should == 1.0 + @object.send(:exp, -0.0).should == 1.0 + @object.send(:exp, -1.8).should be_close(0.165298888221587, TOLERANCE) + @object.send(:exp, 1.25).should be_close(3.49034295746184, TOLERANCE) + end + + it "returns the base-e exponential for Complex numbers" do + @object.send(:exp, Complex(0, 0)).should == Complex(1.0, 0.0) + @object.send(:exp, Complex(1, 3)).should be_close(Complex(-2.69107861381979, 0.383603953541131), TOLERANCE) + end +end + +describe :complex_math_exp_bang, shared: true do + it "returns the base-e exponential of the passed argument" do + @object.send(:exp!, 0.0).should == 1.0 + @object.send(:exp!, -0.0).should == 1.0 + @object.send(:exp!, -1.8).should be_close(0.165298888221587, TOLERANCE) + @object.send(:exp!, 1.25).should be_close(3.49034295746184, TOLERANCE) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:exp!, Complex(1, 3)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/log.rb b/spec/ruby/library/cmath/math/shared/log.rb new file mode 100644 index 0000000000..4b23e8c5f2 --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/log.rb @@ -0,0 +1,39 @@ +require_relative '../fixtures/classes' + +describe :complex_math_log, shared: true do + it "returns the natural logarithm of the passed argument" do + @object.send(:log, 0.0001).should be_close(-9.21034037197618, TOLERANCE) + @object.send(:log, 0.000000000001e-15).should be_close(-62.1697975108392, TOLERANCE) + @object.send(:log, 1).should be_close(0.0, TOLERANCE) + @object.send(:log, 10).should be_close( 2.30258509299405, TOLERANCE) + @object.send(:log, 10e15).should be_close(36.8413614879047, TOLERANCE) + end + + it "returns the natural logarithm for Complex numbers" do + @object.send(:log, Complex(3, 4)).should be_close(Complex(1.6094379124341, 0.927295218001612), TOLERANCE) + @object.send(:log, Complex(-3, 4)).should be_close(Complex(1.6094379124341, 2.21429743558818), TOLERANCE) + end + + it "returns the natural logarithm for negative numbers as a Complex number" do + @object.send(:log, -10).should be_close(Complex(2.30258509299405, 3.14159265358979), TOLERANCE) + @object.send(:log, -20).should be_close(Complex(2.99573227355399, 3.14159265358979), TOLERANCE) + end +end + +describe :complex_math_log_bang, shared: true do + it "returns the natural logarithm of the argument" do + @object.send(:log!, 0.0001).should be_close(-9.21034037197618, TOLERANCE) + @object.send(:log!, 0.000000000001e-15).should be_close(-62.1697975108392, TOLERANCE) + @object.send(:log!, 1).should be_close(0.0, TOLERANCE) + @object.send(:log!, 10).should be_close( 2.30258509299405, TOLERANCE) + @object.send(:log!, 10e15).should be_close(36.8413614879047, TOLERANCE) + end + + it "raises an Errno::EDOM if the argument is less than 0" do + -> { @object.send(:log!, -10) }.should raise_error(Errno::EDOM) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:log!, Complex(4, 5)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/log10.rb b/spec/ruby/library/cmath/math/shared/log10.rb new file mode 100644 index 0000000000..f49934d958 --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/log10.rb @@ -0,0 +1,41 @@ +require_relative '../fixtures/classes' + +describe :complex_math_log10, shared: true do + it "returns the base-10 logarithm of the passed argument" do + @object.send(:log10, 0.0001).should be_close(-4.0, TOLERANCE) + @object.send(:log10, 0.000000000001e-15).should be_close(-27.0, TOLERANCE) + @object.send(:log10, 1).should be_close(0.0, TOLERANCE) + @object.send(:log10, 10).should be_close(1.0, TOLERANCE) + @object.send(:log10, 10e15).should be_close(16.0, TOLERANCE) + end + + it "returns the base-10 logarithm for Complex numbers" do + @object.send(:log10, Complex(3, 4)).should be_close(Complex(0.698970004336019, 0.402719196273373), TOLERANCE) + @object.send(:log10, Complex(-3, 4)).should be_close(Complex(0.698970004336019, 0.961657157568468), TOLERANCE) + end + + # BUG: does not work correctly, because Math#log10 + # does not check for negative values + #it "returns the base-10 logarithm for negative numbers as a Complex number" do + # @object.send(:log10, -10).should be_close(Complex(2.30258509299405, 3.14159265358979), TOLERANCE) + # @object.send(:log10, -20).should be_close(Complex(2.99573227355399, 3.14159265358979), TOLERANCE) + #end +end + +describe :complex_math_log10_bang, shared: true do + it "returns the base-10 logarithm of the argument" do + @object.send(:log10!, 0.0001).should be_close(-4.0, TOLERANCE) + @object.send(:log10!, 0.000000000001e-15).should be_close(-27.0, TOLERANCE) + @object.send(:log10!, 1).should be_close(0.0, TOLERANCE) + @object.send(:log10!, 10).should be_close(1.0, TOLERANCE) + @object.send(:log10!, 10e15).should be_close(16.0, TOLERANCE) + end + + it "raises an Errno::EDOM when the passed argument is negative" do + -> { @object.send(:log10!, -10) }.should raise_error(Errno::EDOM) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:log10!, Complex(4, 5)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/sin.rb b/spec/ruby/library/cmath/math/shared/sin.rb new file mode 100644 index 0000000000..1cb1b29cda --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/sin.rb @@ -0,0 +1,30 @@ +require_relative '../fixtures/classes' + +describe :complex_math_sin, shared: true do + it "returns the sine of the passed argument expressed in radians" do + @object.send(:sin, CMath::PI).should be_close(0.0, TOLERANCE) + @object.send(:sin, 0).should be_close(0.0, TOLERANCE) + @object.send(:sin, CMath::PI/2).should be_close(1.0, TOLERANCE) + @object.send(:sin, 3*Math::PI/2).should be_close(-1.0, TOLERANCE) + @object.send(:sin, 2*Math::PI).should be_close(0.0, TOLERANCE) + end + + it "returns the sine for Complex numbers" do + @object.send(:sin, Complex(0, CMath::PI)).should be_close(Complex(0.0, 11.5487393572577), TOLERANCE) + @object.send(:sin, Complex(3, 4)).should be_close(Complex(3.85373803791938, -27.0168132580039), TOLERANCE) + end +end + +describe :complex_math_sin_bang, shared: true do + it "returns the sine of the passed argument expressed in radians" do + @object.send(:sin!, CMath::PI).should be_close(0.0, TOLERANCE) + @object.send(:sin!, 0).should be_close(0.0, TOLERANCE) + @object.send(:sin!, CMath::PI/2).should be_close(1.0, TOLERANCE) + @object.send(:sin!, 3*Math::PI/2).should be_close(-1.0, TOLERANCE) + @object.send(:sin!, 2*Math::PI).should be_close(0.0, TOLERANCE) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:sin!, Complex(4, 5)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/sinh.rb b/spec/ruby/library/cmath/math/shared/sinh.rb new file mode 100644 index 0000000000..de80a376da --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/sinh.rb @@ -0,0 +1,28 @@ +require_relative '../fixtures/classes' + +describe :complex_math_sinh, shared: true do + it "returns the hyperbolic sin of the argument" do + @object.send(:sinh, 0.0).should == 0.0 + @object.send(:sinh, -0.0).should == 0.0 + @object.send(:sinh, 1.5).should be_close(2.12927945509482, TOLERANCE) + @object.send(:sinh, -2.8).should be_close(-8.19191835423591, TOLERANCE) + end + + it "returns the hyperbolic sin for Complex numbers" do + @object.send(:sinh, Complex(0, CMath::PI)).should be_close(Complex(-0.0, 1.22464679914735e-16), TOLERANCE) + @object.send(:sinh, Complex(3, 4)).should be_close(Complex(-6.548120040911, -7.61923172032141), TOLERANCE) + end +end + +describe :complex_math_sinh_bang, shared: true do + it "returns the hyperbolic sin of the argument" do + @object.send(:sinh!, 0.0).should == 0.0 + @object.send(:sinh!, -0.0).should == 0.0 + @object.send(:sinh!, 1.5).should be_close(2.12927945509482, TOLERANCE) + @object.send(:sinh!, -2.8).should be_close(-8.19191835423591, TOLERANCE) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:sinh!, Complex(4, 5)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/sqrt.rb b/spec/ruby/library/cmath/math/shared/sqrt.rb new file mode 100644 index 0000000000..23b1ba48ff --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/sqrt.rb @@ -0,0 +1,34 @@ +require_relative '../fixtures/classes' + +describe :complex_math_sqrt, shared: true do + it "returns the square root for positive numbers" do + @object.send(:sqrt, 4).should == 2 + @object.send(:sqrt, 19.36).should == 4.4 + end + + it "returns the square root for negative numbers" do + @object.send(:sqrt, -4).should == Complex(0, 2.0) + @object.send(:sqrt, -19.36).should == Complex(0, 4.4) + end + + it "returns the square root for Complex numbers" do + @object.send(:sqrt, Complex(4, 5)).should be_close(Complex(2.2806933416653, 1.09615788950152), TOLERANCE) + @object.send(:sqrt, Complex(4, -5)).should be_close(Complex(2.2806933416653, -1.09615788950152), TOLERANCE) + end +end + +describe :complex_math_sqrt_bang, shared: true do + it "returns the square root for positive numbers" do + @object.send(:sqrt!, 4).should == 2 + @object.send(:sqrt!, 19.36).should == 4.4 + end + + it "raises Errno::EDOM when the passed argument is negative" do + -> { @object.send(:sqrt!, -4) }.should raise_error(Errno::EDOM) + -> { @object.send(:sqrt!, -19.36) }.should raise_error(Errno::EDOM) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:sqrt!, Complex(4, 5)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/tan.rb b/spec/ruby/library/cmath/math/shared/tan.rb new file mode 100644 index 0000000000..9022c84fc9 --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/tan.rb @@ -0,0 +1,28 @@ +require_relative '../fixtures/classes' + +describe :complex_math_tan, shared: true do + it "returns the tangent of the argument" do + @object.send(:tan, 0.0).should == 0.0 + @object.send(:tan, -0.0).should == -0.0 + @object.send(:tan, 4.22).should be_close(1.86406937682395, TOLERANCE) + @object.send(:tan, -9.65).should be_close(-0.229109052606441, TOLERANCE) + end + + it "returns the tangent for Complex numbers" do + @object.send(:tan, Complex(0, CMath::PI)).should be_close(Complex(0.0, 0.99627207622075), TOLERANCE) + @object.send(:tan, Complex(3, 4)).should be_close(Complex(-0.000187346204629452, 0.999355987381473), TOLERANCE) + end +end + +describe :complex_math_tan_bang, shared: true do + it "returns the tangent of the argument" do + @object.send(:tan!, 0.0).should == 0.0 + @object.send(:tan!, -0.0).should == -0.0 + @object.send(:tan!, 4.22).should be_close(1.86406937682395, TOLERANCE) + @object.send(:tan!, -9.65).should be_close(-0.229109052606441, TOLERANCE) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:tan!, Complex(4, 5)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/shared/tanh.rb b/spec/ruby/library/cmath/math/shared/tanh.rb new file mode 100644 index 0000000000..f2c9a5abb1 --- /dev/null +++ b/spec/ruby/library/cmath/math/shared/tanh.rb @@ -0,0 +1,32 @@ +require_relative '../fixtures/classes' + +describe :complex_math_tanh, shared: true do + it "returns the hyperbolic tangent of the argument" do + @object.send(:tanh, 0.0).should == 0.0 + @object.send(:tanh, -0.0).should == -0.0 + @object.send(:tanh, infinity_value).should == 1.0 + @object.send(:tanh, -infinity_value).should == -1.0 + @object.send(:tanh, 2.5).should be_close(0.98661429815143, TOLERANCE) + @object.send(:tanh, -4.892).should be_close(-0.999887314427707, TOLERANCE) + end + + it "returns the hyperbolic tangent for Complex numbers" do + @object.send(:tanh, Complex(0, CMath::PI)).should be_close(Complex(0.0, -1.22464679914735e-16), TOLERANCE) + @object.send(:tanh, Complex(3, 4)).should be_close(Complex(1.00070953606723, 0.00490825806749599), TOLERANCE) + end +end + +describe :complex_math_tanh_bang, shared: true do + it "returns the hyperbolic tangent of the argument" do + @object.send(:tanh!, 0.0).should == 0.0 + @object.send(:tanh!, -0.0).should == -0.0 + @object.send(:tanh!, infinity_value).should == 1.0 + @object.send(:tanh!, -infinity_value).should == -1.0 + @object.send(:tanh!, 2.5).should be_close(0.98661429815143, TOLERANCE) + @object.send(:tanh!, -4.892).should be_close(-0.999887314427707, TOLERANCE) + end + + it "raises a TypeError when passed a Complex number" do + -> { @object.send(:tanh!, Complex(4, 5)) }.should raise_error(TypeError) + end +end diff --git a/spec/ruby/library/cmath/math/sin_spec.rb b/spec/ruby/library/cmath/math/sin_spec.rb new file mode 100644 index 0000000000..b7a219fbbd --- /dev/null +++ b/spec/ruby/library/cmath/math/sin_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/sin' + + describe "Math#sin" do + it_behaves_like :complex_math_sin, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:sin) + end + end + + describe "Math.sin" do + it_behaves_like :complex_math_sin, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/sinh_spec.rb b/spec/ruby/library/cmath/math/sinh_spec.rb new file mode 100644 index 0000000000..c6e6a3baf4 --- /dev/null +++ b/spec/ruby/library/cmath/math/sinh_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/sinh' + + describe "Math#sinh" do + it_behaves_like :complex_math_sinh, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:sinh) + end + end + + describe "Math.sinh" do + it_behaves_like :complex_math_sinh, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/sqrt_spec.rb b/spec/ruby/library/cmath/math/sqrt_spec.rb new file mode 100644 index 0000000000..421824f99c --- /dev/null +++ b/spec/ruby/library/cmath/math/sqrt_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/sqrt' + + describe "Math#sqrt" do + it_behaves_like :complex_math_sqrt, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:sqrt) + end + end + + describe "Math.sqrt" do + it_behaves_like :complex_math_sqrt, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/tan_spec.rb b/spec/ruby/library/cmath/math/tan_spec.rb new file mode 100644 index 0000000000..e2acdd8091 --- /dev/null +++ b/spec/ruby/library/cmath/math/tan_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/tan' + + describe "Math#tan" do + it_behaves_like :complex_math_tan, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:tan) + end + end + + describe "Math.tan" do + it_behaves_like :complex_math_tan, :_, CMath + end +end diff --git a/spec/ruby/library/cmath/math/tanh_spec.rb b/spec/ruby/library/cmath/math/tanh_spec.rb new file mode 100644 index 0000000000..94da20cd51 --- /dev/null +++ b/spec/ruby/library/cmath/math/tanh_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require 'complex' + require_relative 'shared/tanh' + + describe "Math#tanh" do + it_behaves_like :complex_math_tanh, :_, IncludesMath.new + + it "is a private instance method" do + IncludesMath.should have_private_instance_method(:tanh) + end + end + + describe "Math.tanh" do + it_behaves_like :complex_math_tanh, :_, CMath + end +end diff --git a/spec/ruby/library/coverage/result_spec.rb b/spec/ruby/library/coverage/result_spec.rb index 4bcce00cd7..4cc43e8462 100644 --- a/spec/ruby/library/coverage/result_spec.rb +++ b/spec/ruby/library/coverage/result_spec.rb @@ -91,51 +91,15 @@ describe 'Coverage.result' do Coverage.result.should_not include(@config_file) end - ruby_version_is '3.1'...'3.2' do - it 'returns the correct results when eval is used' do - Coverage.start - require @eval_code_file.chomp('.rb') - result = Coverage.result - - result.should == { - @eval_code_file => [ - 1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1 - ] - } - end - end - - ruby_version_is '3.2' do - it 'indicates support for different features' do - Coverage.supported?(:lines).should == true - end - - it 'returns the correct results when eval coverage is enabled' do - Coverage.supported?(:eval).should == true - - Coverage.start(lines: true, eval: true) - require @eval_code_file.chomp('.rb') - result = Coverage.result - - result.should == { - @eval_code_file => { - lines: [1, nil, 1, nil, 1, 1, nil, nil, nil, nil, 1] - } - } - end - - it 'returns the correct results when eval coverage is enabled' do - Coverage.supported?(:eval).should == true - - Coverage.start(lines: true, eval: false) - require @eval_code_file.chomp('.rb') - result = Coverage.result + it 'returns the correct results when eval is used' do + Coverage.start + require @eval_code_file.chomp('.rb') + result = Coverage.result - result.should == { - @eval_code_file => { - lines: [1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1] - } - } - end + result.should == { + @eval_code_file => [ + 1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1 + ] + } end end diff --git a/spec/ruby/library/coverage/running_spec.rb b/spec/ruby/library/coverage/running_spec.rb deleted file mode 100644 index e9cc7ada5a..0000000000 --- a/spec/ruby/library/coverage/running_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require_relative '../../spec_helper' -require 'coverage' - -describe 'Coverage.running?' do - it "returns false if coverage is not started" do - Coverage.running?.should == false - end - - it "returns true if coverage is started" do - Coverage.start - Coverage.running?.should == true - Coverage.result - end - - it "returns false if coverage was started and stopped" do - Coverage.start - Coverage.result - Coverage.running?.should == false - end -end diff --git a/spec/ruby/library/coverage/start_spec.rb b/spec/ruby/library/coverage/start_spec.rb index a993abbf4e..ddfad8b47c 100644 --- a/spec/ruby/library/coverage/start_spec.rb +++ b/spec/ruby/library/coverage/start_spec.rb @@ -2,11 +2,5 @@ require_relative '../../spec_helper' require 'coverage' describe 'Coverage.start' do - ruby_version_is '3.2' do - it "can measure coverage within eval" do - Coverage.start(lines: true, eval: true) - eval("Object.new\n"*3, binding, "test.rb", 1) - Coverage.result["test.rb"].should == {lines: [1, 1, 1]} - end - end + it 'needs to be reviewed for spec completeness' end diff --git a/spec/ruby/library/coverage/supported_spec.rb b/spec/ruby/library/coverage/supported_spec.rb deleted file mode 100644 index 78b3784ee0..0000000000 --- a/spec/ruby/library/coverage/supported_spec.rb +++ /dev/null @@ -1,32 +0,0 @@ -require_relative '../../spec_helper' -require 'coverage' - -describe "Coverage.supported?" do - ruby_version_is "3.2" do - it "returns true or false if coverage measurement is supported for the given mode" do - [true, false].should.include?(Coverage.supported?(:lines)) - [true, false].should.include?(Coverage.supported?(:branches)) - [true, false].should.include?(Coverage.supported?(:methods)) - [true, false].should.include?(Coverage.supported?(:eval)) - end - - it "returns false for not existing modes" do - Coverage.supported?(:foo).should == false - Coverage.supported?(:bar).should == false - end - - it "raise TypeError if argument is not Symbol" do - -> { - Coverage.supported?("lines") - }.should raise_error(TypeError, "wrong argument type String (expected Symbol)") - - -> { - Coverage.supported?([]) - }.should raise_error(TypeError, "wrong argument type Array (expected Symbol)") - - -> { - Coverage.supported?(1) - }.should raise_error(TypeError, "wrong argument type Integer (expected Symbol)") - end - end -end diff --git a/spec/ruby/library/date/civil_spec.rb b/spec/ruby/library/date/civil_spec.rb index 1c780fce56..f3537c2f84 100644 --- a/spec/ruby/library/date/civil_spec.rb +++ b/spec/ruby/library/date/civil_spec.rb @@ -2,6 +2,11 @@ require_relative '../../spec_helper' require_relative 'shared/civil' require 'date' -describe "Date.civil" do +describe "Date#civil" do it_behaves_like :date_civil, :civil end + + +describe "Date.civil" do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/library/date/deconstruct_keys_spec.rb b/spec/ruby/library/date/deconstruct_keys_spec.rb deleted file mode 100644 index 92579e35c7..0000000000 --- a/spec/ruby/library/date/deconstruct_keys_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -require_relative '../../spec_helper' -require 'date' -date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0' - -version_is date_version, "3.3" do #ruby_version_is "3.2" do - describe "Date#deconstruct_keys" do - it "returns whole hash for nil as an argument" do - d = Date.new(2022, 10, 5) - d.deconstruct_keys(nil).should == { year: 2022, month: 10, day: 5, yday: 278, wday: 3 } - end - - it "returns only specified keys" do - d = Date.new(2022, 10, 5) - d.deconstruct_keys([:year, :month]).should == { year: 2022, month: 10 } - end - - it "requires one argument" do - -> { - Date.new(2022, 10, 5).deconstruct_keys - }.should raise_error(ArgumentError) - end - - it "it raises error when argument is neither nil nor array" do - d = Date.new(2022, 10, 5) - - -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)") - -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)") - -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)") - -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)") - end - - it "returns {} when passed []" do - Date.new(2022, 10, 5).deconstruct_keys([]).should == {} - end - - it "ignores non-Symbol keys" do - Date.new(2022, 10, 5).deconstruct_keys(['year', []]).should == {} - end - - it "ignores not existing Symbol keys" do - Date.new(2022, 10, 5).deconstruct_keys([:year, :a]).should == { year: 2022 } - end - end -end diff --git a/spec/ruby/library/date/iso8601_spec.rb b/spec/ruby/library/date/iso8601_spec.rb index af66845a6b..2c698db514 100644 --- a/spec/ruby/library/date/iso8601_spec.rb +++ b/spec/ruby/library/date/iso8601_spec.rb @@ -17,21 +17,18 @@ describe "Date.iso8601" do d.should == Date.civil(-4712, 1, 1) end + it "parses a Symbol into a Date object" do + d = Date.iso8601(:'2015-10-15') + d.should == Date.civil(2015, 10, 15) + end + it "parses a StringSubclass into a Date object" do d = Date.iso8601(Class.new(String).new("-4712-01-01")) d.should == Date.civil(-4712, 1, 1) end - it "raises a Date::Error if the argument is a invalid Date" do - -> { - Date.iso8601('invalid') - }.should raise_error(Date::Error, "invalid date") - end - - it "raises a Date::Error when passed a nil" do - -> { - Date.iso8601(nil) - }.should raise_error(Date::Error, "invalid date") + it "raises an ArgumentError when passed a Symbol without a valid Date" do + -> { Date.iso8601(:test) }.should raise_error(ArgumentError) end it "raises a TypeError when passed an Object" do @@ -44,13 +41,4 @@ describe "Date._iso8601" do h = Date._iso8601('invalid') h.should == {} end - - it "returns an empty hash if the argument is nil" do - h = Date._iso8601(nil) - h.should == {} - end - - it "raises a TypeError when passed an Object" do - -> { Date._iso8601(Object.new) }.should raise_error(TypeError) - end end diff --git a/spec/ruby/library/date/new_spec.rb b/spec/ruby/library/date/new_spec.rb index cb64cabce6..18120118c0 100644 --- a/spec/ruby/library/date/new_spec.rb +++ b/spec/ruby/library/date/new_spec.rb @@ -1,6 +1,7 @@ require 'date' require_relative '../../spec_helper' require_relative 'shared/civil' +require_relative 'shared/new_bang' describe "Date.new" do it_behaves_like :date_civil, :new diff --git a/spec/ruby/library/date/parse_spec.rb b/spec/ruby/library/date/parse_spec.rb index 5ef4f6e9b5..ef72ba3f4e 100644 --- a/spec/ruby/library/date/parse_spec.rb +++ b/spec/ruby/library/date/parse_spec.rb @@ -67,7 +67,7 @@ describe "Date#parse" do it "raises a TypeError trying to parse non-String-like object" do -> { Date.parse(1) }.should raise_error(TypeError) - -> { Date.parse([]) }.should raise_error(TypeError) + -> { Date.parse(:invalid) }.should raise_error(TypeError) end it "coerces using to_str" do @@ -93,7 +93,7 @@ describe "Date#parse with '.' separator" do @sep = '.' end - it_should_behave_like :date_parse + it_should_behave_like "date_parse" end describe "Date#parse with '/' separator" do @@ -101,7 +101,7 @@ describe "Date#parse with '/' separator" do @sep = '/' end - it_should_behave_like :date_parse + it_should_behave_like "date_parse" end describe "Date#parse with ' ' separator" do @@ -109,7 +109,7 @@ describe "Date#parse with ' ' separator" do @sep = ' ' end - it_should_behave_like :date_parse + it_should_behave_like "date_parse" end describe "Date#parse with '/' separator US-style" do @@ -117,7 +117,7 @@ describe "Date#parse with '/' separator US-style" do @sep = '/' end - it_should_behave_like :date_parse_us + it_should_behave_like "date_parse_us" end describe "Date#parse with '-' separator EU-style" do @@ -125,7 +125,7 @@ describe "Date#parse with '-' separator EU-style" do @sep = '-' end - it_should_behave_like :date_parse_eu + it_should_behave_like "date_parse_eu" end describe "Date#parse(.)" do diff --git a/spec/ruby/library/date/shared/new_bang.rb b/spec/ruby/library/date/shared/new_bang.rb new file mode 100644 index 0000000000..90f1b432f0 --- /dev/null +++ b/spec/ruby/library/date/shared/new_bang.rb @@ -0,0 +1,14 @@ +describe :date_new_bang, shared: true do + + it "returns a new Date object set to Astronomical Julian Day 0 if no arguments passed" do + d = Date.send(@method) + d.ajd.should == 0 + end + + it "accepts astronomical julian day number, offset as a fraction of a day and returns a new Date object" do + d = Date.send(@method, 10, 0.5) + d.ajd.should == 10 + d.jd.should == 11 + end + +end diff --git a/spec/ruby/library/date/shared/parse.rb b/spec/ruby/library/date/shared/parse.rb index 40af908386..1015285e04 100644 --- a/spec/ruby/library/date/shared/parse.rb +++ b/spec/ruby/library/date/shared/parse.rb @@ -13,7 +13,7 @@ describe :date_parse, shared: true do d.day.should == 23 end - it "can parse a 'DD mmm YYYY' string into a Date object" do + it "can parse a 'mmm DD YYYY' string into a Date object" do d = Date.parse("23#{@sep}feb#{@sep}2008") d.year.should == 2008 d.month.should == 2 @@ -42,7 +42,7 @@ describe :date_parse, shared: true do d.should == Date.civil(2005, 11, 5) end - it "can parse a day, month name and year into a Date object" do + it "can parse a year, day and month name into a Date object" do d = Date.parse("5th#{@sep}november#{@sep}2005") d.should == Date.civil(2005, 11, 5) end diff --git a/spec/ruby/library/date/shared/parse_eu.rb b/spec/ruby/library/date/shared/parse_eu.rb index 3819524a57..ecb15e3c0e 100644 --- a/spec/ruby/library/date/shared/parse_eu.rb +++ b/spec/ruby/library/date/shared/parse_eu.rb @@ -7,28 +7,28 @@ describe :date_parse_eu, shared: true do d.day.should == 1 end - it "can parse a DD-MM-YYYY string into a Date object" do + it "can parse a MM-DD-YYYY string into a Date object" do d = Date.parse("10#{@sep}01#{@sep}2007") d.year.should == 2007 d.month.should == 1 d.day.should == 10 end - it "can parse a YY-MM-DD string into a Date object" do + it "can parse a MM-DD-YY string into a Date object" do d = Date.parse("10#{@sep}01#{@sep}07") d.year.should == 2010 d.month.should == 1 d.day.should == 7 end - it "can parse a YY-MM-DD string into a Date object NOT using the year digits as 20XX" do + it "can parse a MM-DD-YY string into a Date object NOT using the year digits as 20XX" do d = Date.parse("10#{@sep}01#{@sep}07", false) d.year.should == 10 d.month.should == 1 d.day.should == 7 end - it "can parse a YY-MM-DD string into a Date object using the year digits as 20XX" do + it "can parse a MM-DD-YY string into a Date object using the year digits as 20XX" do d = Date.parse("10#{@sep}01#{@sep}07", true) d.year.should == 2010 d.month.should == 1 diff --git a/spec/ruby/library/date/shared/parse_us.rb b/spec/ruby/library/date/shared/parse_us.rb index 17e2fc96c1..7be62b1af1 100644 --- a/spec/ruby/library/date/shared/parse_us.rb +++ b/spec/ruby/library/date/shared/parse_us.rb @@ -6,28 +6,28 @@ describe :date_parse_us, shared: true do d.day.should == 1 end - it "parses a DD#{@sep}MM#{@sep}YYYY string into a Date object" do + it "parses a MM#{@sep}DD#{@sep}YYYY string into a Date object" do d = Date.parse("10#{@sep}01#{@sep}2007") d.year.should == 2007 d.month.should == 1 d.day.should == 10 end - it "parses a YY#{@sep}MM#{@sep}DD string into a Date object" do + it "parses a MM#{@sep}DD#{@sep}YY string into a Date object" do d = Date.parse("10#{@sep}01#{@sep}07") d.year.should == 2010 d.month.should == 1 d.day.should == 7 end - it "parses a YY#{@sep}MM#{@sep}DD string into a Date object NOT using the year digits as 20XX" do + it "parses a MM#{@sep}DD#{@sep}YY string into a Date object NOT using the year digits as 20XX" do d = Date.parse("10#{@sep}01#{@sep}07", false) d.year.should == 10 d.month.should == 1 d.day.should == 7 end - it "parses a YY#{@sep}MM#{@sep}DD string into a Date object using the year digits as 20XX" do + it "parses a MM#{@sep}DD#{@sep}YY string into a Date object using the year digits as 20XX" do d = Date.parse("10#{@sep}01#{@sep}07", true) d.year.should == 2010 d.month.should == 1 diff --git a/spec/ruby/library/date/shared/valid_jd.rb b/spec/ruby/library/date/shared/valid_jd.rb index e474dfb450..f6ca3f579d 100644 --- a/spec/ruby/library/date/shared/valid_jd.rb +++ b/spec/ruby/library/date/shared/valid_jd.rb @@ -10,11 +10,23 @@ describe :date_valid_jd?, shared: true do Date.send(@method, nil).should be_false end - it "returns false if passed symbol" do - Date.send(@method, :number).should be_false + ruby_version_is ''...'2.7' do + it "returns true if passed symbol" do + Date.send(@method, :number).should be_true + end + + it "returns true if passed false" do + Date.send(@method, false).should be_true + end end - it "returns false if passed false" do - Date.send(@method, false).should be_false + ruby_version_is '2.7' do + it "returns false if passed symbol" do + Date.send(@method, :number).should be_false + end + + it "returns false if passed false" do + Date.send(@method, false).should be_false + end end end diff --git a/spec/ruby/library/date/strftime_spec.rb b/spec/ruby/library/date/strftime_spec.rb index b5232a2073..8b1ebe061c 100644 --- a/spec/ruby/library/date/strftime_spec.rb +++ b/spec/ruby/library/date/strftime_spec.rb @@ -1,7 +1,5 @@ -require_relative "../../spec_helper" require 'date' require_relative '../../shared/time/strftime_for_date' -date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0' describe "Date#strftime" do before :all do @@ -24,14 +22,14 @@ describe "Date#strftime" do end # %v is %e-%b-%Y for Date/DateTime - version_is date_version, ""..."3.2" do #ruby_version_is ""..."3.1" do + ruby_version_is ""..."3.1" do it "should be able to show the commercial week" do @date.strftime("%v").should == " 9-Apr-2000" @date.strftime("%v").should == @date.strftime('%e-%b-%Y') end end - version_is date_version, "3.2" do #ruby_version_is "3.1" do + ruby_version_is "3.1" do it "should be able to show the commercial week" do @date.strftime("%v").should == " 9-APR-2000" @date.strftime("%v").should != @date.strftime('%e-%b-%Y') diff --git a/spec/ruby/library/datetime/deconstruct_keys_spec.rb b/spec/ruby/library/datetime/deconstruct_keys_spec.rb deleted file mode 100644 index 77ceaa51c4..0000000000 --- a/spec/ruby/library/datetime/deconstruct_keys_spec.rb +++ /dev/null @@ -1,46 +0,0 @@ -require_relative '../../spec_helper' -require 'date' -date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0' - -version_is date_version, "3.3" do #ruby_version_is "3.2" do - describe "DateTime#deconstruct_keys" do - it "returns whole hash for nil as an argument" do - d = DateTime.new(2022, 10, 5, 13, 30) - res = { year: 2022, month: 10, day: 5, yday: 278, wday: 3, hour: 13, - min: 30, sec: 0, sec_fraction: (0/1), zone: "+00:00" } - d.deconstruct_keys(nil).should == res - end - - it "returns only specified keys" do - d = DateTime.new(2022, 10, 5, 13, 39) - d.deconstruct_keys([:zone, :hour]).should == { zone: "+00:00", hour: 13 } - end - - it "requires one argument" do - -> { - DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys - }.should raise_error(ArgumentError) - end - - it "it raises error when argument is neither nil nor array" do - d = DateTime.new(2022, 10, 5, 13, 30) - - -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)") - -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)") - -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)") - -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)") - end - - it "returns {} when passed []" do - DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys([]).should == {} - end - - it "ignores non-Symbol keys" do - DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys(['year', []]).should == {} - end - - it "ignores not existing Symbol keys" do - DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys([:year, :a]).should == { year: 2022 } - end - end -end diff --git a/spec/ruby/library/datetime/rfc2822_spec.rb b/spec/ruby/library/datetime/rfc2822_spec.rb index 83f7fa8d5b..70bfca60b4 100644 --- a/spec/ruby/library/datetime/rfc2822_spec.rb +++ b/spec/ruby/library/datetime/rfc2822_spec.rb @@ -3,8 +3,4 @@ require 'date' describe "DateTime.rfc2822" do it "needs to be reviewed for spec completeness" - - it "raises DateError if passed nil" do - -> { DateTime.rfc2822(nil) }.should raise_error(Date::Error, "invalid date") - end end diff --git a/spec/ruby/library/datetime/strftime_spec.rb b/spec/ruby/library/datetime/strftime_spec.rb index abb0838e8e..725bcafb0d 100644 --- a/spec/ruby/library/datetime/strftime_spec.rb +++ b/spec/ruby/library/datetime/strftime_spec.rb @@ -2,7 +2,6 @@ require_relative '../../spec_helper' require 'date' require_relative '../../shared/time/strftime_for_date' require_relative '../../shared/time/strftime_for_time' -date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0' describe "DateTime#strftime" do before :all do @@ -34,14 +33,14 @@ describe "DateTime#strftime" do end # %v is %e-%b-%Y for Date/DateTime - version_is date_version, ""..."3.2" do #ruby_version_is ""..."3.1" do + ruby_version_is ""..."3.1" do it "should be able to show the commercial week" do @time.strftime("%v").should == " 3-Feb-2001" @time.strftime("%v").should == @time.strftime('%e-%b-%Y') end end - version_is date_version, "3.2" do #ruby_version_is "3.1" do + ruby_version_is "3.1" do it "should be able to show the commercial week" do @time.strftime("%v").should == " 3-FEB-2001" @time.strftime("%v").should != @time.strftime('%e-%b-%Y') diff --git a/spec/ruby/library/datetime/to_time_spec.rb b/spec/ruby/library/datetime/to_time_spec.rb index 09e6192e7f..a11b6e30e1 100644 --- a/spec/ruby/library/datetime/to_time_spec.rb +++ b/spec/ruby/library/datetime/to_time_spec.rb @@ -1,6 +1,5 @@ require_relative '../../spec_helper' require 'date' -date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0' describe "DateTime#to_time" do it "yields a new Time object" do @@ -8,10 +7,10 @@ describe "DateTime#to_time" do end it "returns a Time representing the same instant" do - datetime = DateTime.civil(2012, 12, 31, 23, 58, 59) + datetime = DateTime.civil(3, 12, 31, 23, 58, 59) time = datetime.to_time.utc - time.year.should == 2012 + time.year.should == 3 time.month.should == 12 time.day.should == 31 time.hour.should == 23 @@ -19,19 +18,6 @@ describe "DateTime#to_time" do time.sec.should == 59 end - version_is date_version, '3.2.3' do #ruby_version_is "3.2" do - it "returns a Time representing the same instant before Gregorian" do - datetime = DateTime.civil(1582, 10, 4, 23, 58, 59) - time = datetime.to_time.utc - time.year.should == 1582 - time.month.should == 10 - time.day.should == 14 - time.hour.should == 23 - time.min.should == 58 - time.sec.should == 59 - end - end - it "preserves the same time regardless of local time or zone" do date = DateTime.new(2012, 12, 24, 12, 23, 00, '+03:00') diff --git a/spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb b/spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb index 3975e5208b..729cfc96c6 100644 --- a/spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb +++ b/spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require 'delegate' describe "DelegateClass#respond_to_missing?" do diff --git a/spec/ruby/library/delegate/delegator/taint_spec.rb b/spec/ruby/library/delegate/delegator/taint_spec.rb index 6bf13bb73d..b875b5a6b8 100644 --- a/spec/ruby/library/delegate/delegator/taint_spec.rb +++ b/spec/ruby/library/delegate/delegator/taint_spec.rb @@ -5,4 +5,21 @@ describe "Delegator#taint" do before :each do @delegate = DelegateSpecs::Delegator.new("") end + + ruby_version_is ''...'2.7' do + it "returns self" do + @delegate.taint.equal?(@delegate).should be_true + end + + it "taints the delegator" do + @delegate.__setobj__(nil) + @delegate.taint + @delegate.tainted?.should be_true + end + + it "taints the delegated object" do + @delegate.taint + @delegate.__getobj__.tainted?.should be_true + end + end end diff --git a/spec/ruby/library/delegate/delegator/trust_spec.rb b/spec/ruby/library/delegate/delegator/trust_spec.rb index f1b81814c5..492f02e27f 100644 --- a/spec/ruby/library/delegate/delegator/trust_spec.rb +++ b/spec/ruby/library/delegate/delegator/trust_spec.rb @@ -5,4 +5,20 @@ describe "Delegator#trust" do before :each do @delegate = DelegateSpecs::Delegator.new([]) end + + ruby_version_is ''...'2.7' do + it "returns self" do + @delegate.trust.equal?(@delegate).should be_true + end + + it "trusts the delegator" do + @delegate.trust + @delegate.untrusted?.should be_false + end + + it "trusts the delegated object" do + @delegate.trust + @delegate.__getobj__.untrusted?.should be_false + end + end end diff --git a/spec/ruby/library/delegate/delegator/untaint_spec.rb b/spec/ruby/library/delegate/delegator/untaint_spec.rb index 4051fd2629..3f8f7721a9 100644 --- a/spec/ruby/library/delegate/delegator/untaint_spec.rb +++ b/spec/ruby/library/delegate/delegator/untaint_spec.rb @@ -5,4 +5,22 @@ describe "Delegator#untaint" do before :each do @delegate = -> { DelegateSpecs::Delegator.new("") }.call end + + ruby_version_is ''...'2.7' do + it "returns self" do + @delegate.untaint.equal?(@delegate).should be_true + end + + it "untaints the delegator" do + @delegate.untaint + @delegate.tainted?.should be_false + # No additional meaningful test; that it does or not taint + # "for real" the delegator has no consequence + end + + it "untaints the delegated object" do + @delegate.untaint + @delegate.__getobj__.tainted?.should be_false + end + end end diff --git a/spec/ruby/library/delegate/delegator/untrust_spec.rb b/spec/ruby/library/delegate/delegator/untrust_spec.rb index 4f7fa1e582..acc91b099a 100644 --- a/spec/ruby/library/delegate/delegator/untrust_spec.rb +++ b/spec/ruby/library/delegate/delegator/untrust_spec.rb @@ -5,4 +5,21 @@ describe "Delegator#untrust" do before :each do @delegate = DelegateSpecs::Delegator.new("") end + + ruby_version_is ''...'2.7' do + it "returns self" do + @delegate.untrust.equal?(@delegate).should be_true + end + + it "untrusts the delegator" do + @delegate.__setobj__(nil) + @delegate.untrust + @delegate.untrusted?.should be_true + end + + it "untrusts the delegated object" do + @delegate.untrust + @delegate.__getobj__.untrusted?.should be_true + end + end end diff --git a/spec/ruby/library/digest/instance/shared/update.rb b/spec/ruby/library/digest/instance/shared/update.rb index 17779e54a4..dccc8f80df 100644 --- a/spec/ruby/library/digest/instance/shared/update.rb +++ b/spec/ruby/library/digest/instance/shared/update.rb @@ -3,6 +3,6 @@ describe :digest_instance_update, shared: true do c = Class.new do include Digest::Instance end - -> { c.new.send(@method, "test") }.should raise_error(RuntimeError) + -> { c.new.update("test") }.should raise_error(RuntimeError) end end diff --git a/spec/ruby/library/digest/md5/shared/sample.rb b/spec/ruby/library/digest/md5/shared/sample.rb new file mode 100644 index 0000000000..2bb4f658b1 --- /dev/null +++ b/spec/ruby/library/digest/md5/shared/sample.rb @@ -0,0 +1,17 @@ +# -*- encoding: binary -*- + +require 'digest/md5' + +module MD5Constants + + Contents = "Ipsum is simply dummy text of the printing and typesetting industry. \nLorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. \nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. \nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum." + + Klass = ::Digest::MD5 + BlockLength = 64 + DigestLength = 16 + BlankDigest = "\324\035\214\331\217\000\262\004\351\200\t\230\354\370B~" + Digest = "\2473\267qw\276\364\343\345\320\304\350\313\314\217n" + BlankHexdigest = "d41d8cd98f00b204e9800998ecf8427e" + Hexdigest = "a733b77177bef4e3e5d0c4e8cbcc8f6e" + +end diff --git a/spec/ruby/library/erb/new_spec.rb b/spec/ruby/library/erb/new_spec.rb index a5aeeaeed1..f18e25939e 100644 --- a/spec/ruby/library/erb/new_spec.rb +++ b/spec/ruby/library/erb/new_spec.rb @@ -138,20 +138,4 @@ END ERB.new(@eruby_str).result ->{ ERB.new("<%= list %>").result }.should raise_error(NameError) end - - describe "warning about arguments" do - version_is ERB.version, "2.2.1" do #ruby_version_is "3.1" do - it "warns when passed safe_level and later arguments" do - -> { - ERB.new(@eruby_str, nil, '%') - }.should complain(/warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments./) - end - - it "does not warn when passed arguments as keyword argument" do - -> { - ERB.new(@eruby_str, trim_mode: '%') - }.should_not complain(/warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments./) - end - end - end end diff --git a/spec/ruby/library/etc/confstr_spec.rb b/spec/ruby/library/etc/confstr_spec.rb index 5b43461150..41a970a918 100644 --- a/spec/ruby/library/etc/confstr_spec.rb +++ b/spec/ruby/library/etc/confstr_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../spec_helper' +require File.expand_path('../../../spec_helper', __FILE__) require 'etc' platform_is_not :windows, :android do diff --git a/spec/ruby/library/etc/passwd_spec.rb b/spec/ruby/library/etc/passwd_spec.rb index 7157fd3f2e..d61dada451 100644 --- a/spec/ruby/library/etc/passwd_spec.rb +++ b/spec/ruby/library/etc/passwd_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../spec_helper' +require File.expand_path('../../../spec_helper', __FILE__) require 'etc' platform_is_not :windows do diff --git a/spec/ruby/library/etc/sysconf_spec.rb b/spec/ruby/library/etc/sysconf_spec.rb index 1f2c7a770f..e7d59d1b22 100644 --- a/spec/ruby/library/etc/sysconf_spec.rb +++ b/spec/ruby/library/etc/sysconf_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../spec_helper' +require File.expand_path('../../../spec_helper', __FILE__) require 'etc' platform_is_not :windows do diff --git a/spec/ruby/library/etc/sysconfdir_spec.rb b/spec/ruby/library/etc/sysconfdir_spec.rb index 8538faa65b..d54299c513 100644 --- a/spec/ruby/library/etc/sysconfdir_spec.rb +++ b/spec/ruby/library/etc/sysconfdir_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../spec_helper' +require File.expand_path('../../../spec_helper', __FILE__) require 'etc' describe "Etc.sysconfdir" do diff --git a/spec/ruby/library/etc/systmpdir_spec.rb b/spec/ruby/library/etc/systmpdir_spec.rb index 5b007aa9f9..99c82903f8 100644 --- a/spec/ruby/library/etc/systmpdir_spec.rb +++ b/spec/ruby/library/etc/systmpdir_spec.rb @@ -1,4 +1,4 @@ -require_relative '../../spec_helper' +require File.expand_path('../../../spec_helper', __FILE__) require 'etc' describe "Etc.systmpdir" do diff --git a/spec/ruby/library/etc/uname_spec.rb b/spec/ruby/library/etc/uname_spec.rb deleted file mode 100644 index a42558f593..0000000000 --- a/spec/ruby/library/etc/uname_spec.rb +++ /dev/null @@ -1,14 +0,0 @@ -require_relative '../../spec_helper' -require 'etc' - -describe "Etc.uname" do - it "returns a Hash with the documented keys" do - uname = Etc.uname - uname.should be_kind_of(Hash) - uname.should.key?(:sysname) - uname.should.key?(:nodename) - uname.should.key?(:release) - uname.should.key?(:version) - uname.should.key?(:machine) - end -end diff --git a/spec/ruby/library/expect/expect_spec.rb b/spec/ruby/library/expect/expect_spec.rb index 76ea3d5451..a7041d42ee 100644 --- a/spec/ruby/library/expect/expect_spec.rb +++ b/spec/ruby/library/expect/expect_spec.rb @@ -1,6 +1,5 @@ -require_relative '../../spec_helper' - platform_is_not :windows do + require_relative '../../spec_helper' require 'expect' describe "IO#expect" do diff --git a/spec/ruby/library/fiber/current_spec.rb b/spec/ruby/library/fiber/current_spec.rb index 1467a88d0d..e67d7d050a 100644 --- a/spec/ruby/library/fiber/current_spec.rb +++ b/spec/ruby/library/fiber/current_spec.rb @@ -3,12 +3,6 @@ require_relative '../../spec_helper' require 'fiber' describe "Fiber.current" do - ruby_version_is "3.1" do - it "is available without an extra require" do - ruby_exe("print Fiber.current.class", options: '--disable-gems --disable-did-you-mean').should == "Fiber" - end - end - it "returns the root Fiber when called outside of a Fiber" do root = Fiber.current root.should be_an_instance_of(Fiber) @@ -48,11 +42,22 @@ describe "Fiber.current" do fiber3 = Fiber.new do states << :fiber3 fiber2.transfer - states << :fiber3_terminated + ruby_version_is '3.0' do + states << :fiber3_terminated + end + ruby_version_is '' ... '3.0' do + flunk + end end fiber3.resume - states.should == [:fiber3, :fiber2, :fiber, :fiber3_terminated] + ruby_version_is "" ... "3.0" do + states.should == [:fiber3, :fiber2, :fiber] + end + + ruby_version_is "3.0" do + states.should == [:fiber3, :fiber2, :fiber, :fiber3_terminated] + end end end diff --git a/spec/ruby/library/fiber/resume_spec.rb b/spec/ruby/library/fiber/resume_spec.rb index fd69d3ba99..8b7c104a6f 100644 --- a/spec/ruby/library/fiber/resume_spec.rb +++ b/spec/ruby/library/fiber/resume_spec.rb @@ -3,16 +3,33 @@ require_relative '../../spec_helper' require 'fiber' describe "Fiber#resume" do - it "can work with Fiber#transfer" do - fiber1 = Fiber.new { true } - fiber2 = Fiber.new { fiber1.transfer; Fiber.yield 10 ; Fiber.yield 20; raise } - fiber2.resume.should == 10 - fiber2.resume.should == 20 + ruby_version_is '' ... '3.0' do + it "raises a FiberError if the Fiber has transferred control to another Fiber" do + fiber1 = Fiber.new { true } + fiber2 = Fiber.new { fiber1.transfer; Fiber.yield } + fiber2.resume + -> { fiber2.resume }.should raise_error(FiberError) + end + + it "raises a FiberError if the Fiber attempts to resume a resuming fiber" do + root_fiber = Fiber.current + fiber1 = Fiber.new { root_fiber.resume } + -> { fiber1.resume }.should raise_error(FiberError, /double resume/) + end end - it "raises a FiberError if the Fiber attempts to resume a resuming fiber" do - root_fiber = Fiber.current - fiber1 = Fiber.new { root_fiber.resume } - -> { fiber1.resume }.should raise_error(FiberError, /attempt to resume a resuming fiber/) + ruby_version_is '3.0' do + it "can work with Fiber#transfer" do + fiber1 = Fiber.new { true } + fiber2 = Fiber.new { fiber1.transfer; Fiber.yield 10 ; Fiber.yield 20; raise } + fiber2.resume.should == 10 + fiber2.resume.should == 20 + end + + it "raises a FiberError if the Fiber attempts to resume a resuming fiber" do + root_fiber = Fiber.current + fiber1 = Fiber.new { root_fiber.resume } + -> { fiber1.resume }.should raise_error(FiberError, /attempt to resume a resuming fiber/) + end end end diff --git a/spec/ruby/library/fiber/transfer_spec.rb b/spec/ruby/library/fiber/transfer_spec.rb index e20d51352e..7af548da1a 100644 --- a/spec/ruby/library/fiber/transfer_spec.rb +++ b/spec/ruby/library/fiber/transfer_spec.rb @@ -11,7 +11,13 @@ describe "Fiber#transfer" do it "transfers control from one Fiber to another when called from a Fiber" do fiber1 = Fiber.new { :fiber1 } fiber2 = Fiber.new { fiber1.transfer; :fiber2 } - fiber2.resume.should == :fiber2 + + ruby_version_is '' ... '3.0' do + fiber2.resume.should == :fiber1 + end + ruby_version_is '3.0' do + fiber2.resume.should == :fiber2 + end end it "returns to the root Fiber when finished" do @@ -34,12 +40,24 @@ describe "Fiber#transfer" do states.should == [:start, :end] end - it "can not transfer control to a Fiber that has suspended by Fiber.yield" do - states = [] - fiber1 = Fiber.new { states << :fiber1 } - fiber2 = Fiber.new { states << :fiber2_start; Fiber.yield fiber1.transfer; states << :fiber2_end} - fiber2.resume.should == [:fiber2_start, :fiber1] - -> { fiber2.transfer }.should raise_error(FiberError) + ruby_version_is '' ... '3.0' do + it "can transfer control to a Fiber that has transferred to another Fiber" do + states = [] + fiber1 = Fiber.new { states << :fiber1 } + fiber2 = Fiber.new { states << :fiber2_start; fiber1.transfer; states << :fiber2_end} + fiber2.resume.should == [:fiber2_start, :fiber1] + fiber2.transfer.should == [:fiber2_start, :fiber1, :fiber2_end] + end + end + + ruby_version_is '3.0' do + it "can not transfer control to a Fiber that has suspended by Fiber.yield" do + states = [] + fiber1 = Fiber.new { states << :fiber1 } + fiber2 = Fiber.new { states << :fiber2_start; Fiber.yield fiber1.transfer; states << :fiber2_end} + fiber2.resume.should == [:fiber2_start, :fiber1] + -> { fiber2.transfer }.should raise_error(FiberError) + end end it "raises a FiberError when transferring to a Fiber which resumes itself" do @@ -83,4 +101,28 @@ describe "Fiber#transfer" do thread.join states.should == [0, 1, 2, 3] end + + ruby_version_is "" ... "3.0" do + it "runs until Fiber.yield" do + obj = mock('obj') + obj.should_not_receive(:do) + fiber = Fiber.new { 1 + 2; Fiber.yield; obj.do } + fiber.transfer + end + + it "resumes from the last call to Fiber.yield on subsequent invocations" do + fiber = Fiber.new { Fiber.yield :first; :second } + fiber.transfer.should == :first + fiber.transfer.should == :second + end + + it "sets the block parameters to its arguments on the first invocation" do + first = mock('first') + first.should_receive(:arg).with(:first).twice + + fiber = Fiber.new { |arg| first.arg arg; Fiber.yield; first.arg arg; } + fiber.transfer :first + fiber.transfer :second + end + end end diff --git a/spec/ruby/library/fiddle/handle/initialize_spec.rb b/spec/ruby/library/fiddle/handle/initialize_spec.rb deleted file mode 100644 index 51c2470efd..0000000000 --- a/spec/ruby/library/fiddle/handle/initialize_spec.rb +++ /dev/null @@ -1,10 +0,0 @@ -require_relative '../../../spec_helper' -require 'fiddle' - -describe "Fiddle::Handle#initialize" do - it "raises Fiddle::DLError if the library cannot be found" do - -> { - Fiddle::Handle.new("doesnotexist.doesnotexist") - }.should raise_error(Fiddle::DLError) - end -end diff --git a/spec/ruby/library/io-wait/fixtures/classes.rb b/spec/ruby/library/io-wait/fixtures/classes.rb deleted file mode 100644 index 837c7edd06..0000000000 --- a/spec/ruby/library/io-wait/fixtures/classes.rb +++ /dev/null @@ -1,12 +0,0 @@ -module IOWaitSpec - def self.exhaust_write_buffer(io) - written = 0 - buf = " " * 4096 - - begin - written += io.write_nonblock(buf) - rescue Errno::EAGAIN, Errno::EWOULDBLOCK - return written - end while true - end -end diff --git a/spec/ruby/library/io-wait/wait_readable_spec.rb b/spec/ruby/library/io-wait/wait_readable_spec.rb deleted file mode 100644 index 06ffbda5c8..0000000000 --- a/spec/ruby/library/io-wait/wait_readable_spec.rb +++ /dev/null @@ -1,27 +0,0 @@ -require_relative '../../spec_helper' - -ruby_version_is ''...'3.2' do - require 'io/wait' -end - -describe "IO#wait_readable" do - before :each do - @io = File.new(__FILE__ ) - end - - after :each do - @io.close - end - - it "waits for the IO to become readable with no timeout" do - @io.wait_readable.should == @io - end - - it "waits for the IO to become readable with the given timeout" do - @io.wait_readable(1).should == @io - end - - it "waits for the IO to become readable with the given large timeout" do - @io.wait_readable(365 * 24 * 60 * 60).should == @io - end -end diff --git a/spec/ruby/library/io-wait/wait_spec.rb b/spec/ruby/library/io-wait/wait_spec.rb deleted file mode 100644 index 3861281277..0000000000 --- a/spec/ruby/library/io-wait/wait_spec.rb +++ /dev/null @@ -1,144 +0,0 @@ -require_relative '../../spec_helper' -require_relative 'fixtures/classes' - -ruby_version_is ''...'3.2' do - require 'io/wait' -end - -describe "IO#wait" do - before :each do - @io = File.new(__FILE__ ) - - if /mswin|mingw/ =~ RUBY_PLATFORM - require 'socket' - @r, @w = Socket.pair(Socket::AF_INET, Socket::SOCK_STREAM, 0) - else - @r, @w = IO.pipe - end - end - - after :each do - @io.close unless @io.closed? - - @r.close unless @r.closed? - @w.close unless @w.closed? - end - - context "[events, timeout] passed" do - ruby_version_is ""..."3.2" do - it "returns self when the READABLE event is ready during the timeout" do - @w.write('data to read') - @r.wait(IO::READABLE, 2).should.equal?(@r) - end - - it "returns self when the WRITABLE event is ready during the timeout" do - @w.wait(IO::WRITABLE, 0).should.equal?(@w) - end - end - - ruby_version_is "3.2" do - it "returns events mask when the READABLE event is ready during the timeout" do - @w.write('data to read') - @r.wait(IO::READABLE, 2).should == IO::READABLE - end - - it "returns events mask when the WRITABLE event is ready during the timeout" do - @w.wait(IO::WRITABLE, 0).should == IO::WRITABLE - end - end - - it "waits for the READABLE event to be ready" do - queue = Queue.new - thread = Thread.new { queue.pop; sleep 1; @w.write('data to read') }; - - queue.push('signal'); - @r.wait(IO::READABLE, 2).should_not == nil - - thread.join - end - - it "waits for the WRITABLE event to be ready" do - written_bytes = IOWaitSpec.exhaust_write_buffer(@w) - - queue = Queue.new - thread = Thread.new { queue.pop; sleep 1; @r.read(written_bytes) }; - - queue.push('signal'); - @w.wait(IO::WRITABLE, 2).should_not == nil - - thread.join - end - - it "returns nil when the READABLE event is not ready during the timeout" do - @w.wait(IO::READABLE, 0).should == nil - end - - it "returns nil when the WRITABLE event is not ready during the timeout" do - IOWaitSpec.exhaust_write_buffer(@w) - @w.wait(IO::WRITABLE, 0).should == nil - end - - it "raises IOError when io is closed (closed stream (IOError))" do - @io.close - -> { @io.wait(IO::READABLE, 0) }.should raise_error(IOError, "closed stream") - end - - ruby_version_is "3.2" do - it "raises ArgumentError when events is not positive" do - -> { @w.wait(0, 0) }.should raise_error(ArgumentError, "Events must be positive integer!") - -> { @w.wait(-1, 0) }.should raise_error(ArgumentError, "Events must be positive integer!") - end - end - end - - context "[timeout, mode] passed" do - it "accepts :r, :read, :readable mode to check READABLE event" do - @io.wait(0, :r).should == @io - @io.wait(0, :read).should == @io - @io.wait(0, :readable).should == @io - end - - it "accepts :w, :write, :writable mode to check WRITABLE event" do - @io.wait(0, :w).should == @io - @io.wait(0, :write).should == @io - @io.wait(0, :writable).should == @io - end - - it "accepts :rw, :read_write, :readable_writable mode to check READABLE and WRITABLE events" do - @io.wait(0, :rw).should == @io - @io.wait(0, :read_write).should == @io - @io.wait(0, :readable_writable).should == @io - end - - it "accepts a list of modes" do - @io.wait(0, :r, :w, :rw).should == @io - end - - # It works at least since 2.7 but by some reason may fail on 3.1 - ruby_version_is "3.2" do - it "accepts timeout and mode in any order" do - @io.wait(0, :r).should == @io - @io.wait(:r, 0).should == @io - @io.wait(:r, 0, :w).should == @io - end - end - - it "raises ArgumentError when passed wrong Symbol value as mode argument" do - -> { @io.wait(0, :wrong) }.should raise_error(ArgumentError, "unsupported mode: wrong") - end - - # It works since 3.0 but by some reason may fail on 3.1 - ruby_version_is "3.2" do - it "raises ArgumentError when several Integer arguments passed" do - -> { @w.wait(0, 10, :r) }.should raise_error(ArgumentError, "timeout given more than once") - end - end - - ruby_version_is "3.2" do - it "raises IOError when io is closed (closed stream (IOError))" do - @io.close - -> { @io.wait(0, :r) }.should raise_error(IOError, "closed stream") - end - end - end -end diff --git a/spec/ruby/library/io-wait/wait_writable_spec.rb b/spec/ruby/library/io-wait/wait_writable_spec.rb deleted file mode 100644 index 8c44780d39..0000000000 --- a/spec/ruby/library/io-wait/wait_writable_spec.rb +++ /dev/null @@ -1,20 +0,0 @@ -require_relative '../../spec_helper' - -ruby_version_is ''...'3.2' do - require 'io/wait' -end - -describe "IO#wait_writable" do - it "waits for the IO to become writable with no timeout" do - STDOUT.wait_writable.should == STDOUT - end - - it "waits for the IO to become writable with the given timeout" do - STDOUT.wait_writable(1).should == STDOUT - end - - it "waits for the IO to become writable with the given large timeout" do - # Represents one year and is larger than a 32-bit int - STDOUT.wait_writable(365 * 24 * 60 * 60).should == STDOUT - end -end diff --git a/spec/ruby/library/ipaddr/new_spec.rb b/spec/ruby/library/ipaddr/new_spec.rb index 714c1e2f1a..053928c3cf 100644 --- a/spec/ruby/library/ipaddr/new_spec.rb +++ b/spec/ruby/library/ipaddr/new_spec.rb @@ -77,13 +77,7 @@ describe "IPAddr#new" do a.family.should == Socket::AF_INET6 end - ipaddr_version = if defined?(IPAddr::VERSION) #ruby_version_is ""..."3.1" do - IPAddr::VERSION - else - "1.2.2" - end - - version_is ipaddr_version, ""..."1.2.3" do #ruby_version_is ""..."3.1" do + ruby_version_is ""..."3.1" do it "raises on incorrect IPAddr strings" do [ ["fe80::1%fxp0"], @@ -99,7 +93,7 @@ describe "IPAddr#new" do end end - version_is ipaddr_version, "1.2.3" do #ruby_version_is "3.1" do + ruby_version_is "3.1" do it "raises on incorrect IPAddr strings" do [ ["::1/255.255.255.0"], diff --git a/spec/ruby/library/logger/device/close_spec.rb b/spec/ruby/library/logger/device/close_spec.rb index 1db5d582a7..d7d107fcce 100644 --- a/spec/ruby/library/logger/device/close_spec.rb +++ b/spec/ruby/library/logger/device/close_spec.rb @@ -15,8 +15,17 @@ describe "Logger::LogDevice#close" do rm_r @file_path end - it "closes the LogDevice's stream" do - @device.close - -> { @device.write("Test") }.should complain(/\Alog shifting failed\./) + ruby_version_is ""..."2.7" do + it "closes the LogDevice's stream" do + @device.close + -> { @device.write("Test") }.should complain(/\Alog writing failed\./) + end + end + + ruby_version_is "2.7" do + it "closes the LogDevice's stream" do + @device.close + -> { @device.write("Test") }.should complain(/\Alog shifting failed\./) + end end end diff --git a/spec/ruby/library/logger/device/write_spec.rb b/spec/ruby/library/logger/device/write_spec.rb index 87ecf2ad6a..5506bb2c38 100644 --- a/spec/ruby/library/logger/device/write_spec.rb +++ b/spec/ruby/library/logger/device/write_spec.rb @@ -35,8 +35,17 @@ describe "Logger::LogDevice#write" do rm_r path end - it "fails if the device is already closed" do - @device.close - -> { @device.write "foo" }.should complain(/\Alog shifting failed\./) + ruby_version_is ""..."2.7" do + it "fails if the device is already closed" do + @device.close + -> { @device.write "foo" }.should complain(/\Alog writing failed\./) + end + end + + ruby_version_is "2.7" do + it "fails if the device is already closed" do + @device.close + -> { @device.write "foo" }.should complain(/\Alog shifting failed\./) + end end end diff --git a/spec/ruby/library/matrix/multiply_spec.rb b/spec/ruby/library/matrix/multiply_spec.rb index a63fcf4020..841d9d95b7 100644 --- a/spec/ruby/library/matrix/multiply_spec.rb +++ b/spec/ruby/library/matrix/multiply_spec.rb @@ -24,8 +24,8 @@ ruby_version_is ""..."3.1" do it "returns the result of multiplying the elements of self and a Bignum" do (@a * bignum_value).should == Matrix[ - [18446744073709551616, 36893488147419103232], - [55340232221128654848, 73786976294838206464] + [9223372036854775808, 18446744073709551616], + [27670116110564327424, 36893488147419103232] ] end diff --git a/spec/ruby/library/matrix/unitary_spec.rb b/spec/ruby/library/matrix/unitary_spec.rb index 04e6df8be0..b579cb244d 100644 --- a/spec/ruby/library/matrix/unitary_spec.rb +++ b/spec/ruby/library/matrix/unitary_spec.rb @@ -14,8 +14,10 @@ ruby_version_is ""..."3.1" do Matrix[[0, Complex(0, 1)], [Complex(0, 1), 0]].should.unitary? end - it "returns true for unitary matrices with a Complex and a negative #imag" do - Matrix[[0, Complex(0, 1)], [Complex(0, -1), 0]].should.unitary? + version_is((Matrix::const_defined?(:VERSION) ? Matrix::VERSION : "0.1.0"), "0.3.0") do + it "returns true for unitary matrices with a Complex and a negative #imag" do + Matrix[[0, Complex(0, 1)], [Complex(0, -1), 0]].should.unitary? + end end it "raises an error for rectangular matrices" do diff --git a/spec/ruby/library/monitor/exit_spec.rb b/spec/ruby/library/monitor/exit_spec.rb deleted file mode 100644 index 952ad9525d..0000000000 --- a/spec/ruby/library/monitor/exit_spec.rb +++ /dev/null @@ -1,10 +0,0 @@ -require_relative '../../spec_helper' -require 'monitor' - -describe "Monitor#exit" do - it "raises ThreadError when monitor is not entered" do - m = Monitor.new - - -> { m.exit }.should raise_error(ThreadError) - end -end diff --git a/spec/ruby/library/net/ftp/shared/getbinaryfile.rb b/spec/ruby/library/net/ftp/shared/getbinaryfile.rb index ceec8e7cd5..f324f5b85d 100644 --- a/spec/ruby/library/net/ftp/shared/getbinaryfile.rb +++ b/spec/ruby/library/net/ftp/shared/getbinaryfile.rb @@ -1,6 +1,6 @@ -describe :net_ftp_getbinaryfile, shared: true do +describe :net_ftp_getbinaryfile, shared: :true do before :each do - @fixture_file = __dir__ + "/../fixtures/getbinaryfile" + @fixture_file = File.dirname(__FILE__) + "/../fixtures/getbinaryfile" @tmp_file = tmp("getbinaryfile") @server = NetFTPSpecs::DummyFTP.new diff --git a/spec/ruby/library/net/ftp/shared/gettextfile.rb b/spec/ruby/library/net/ftp/shared/gettextfile.rb index 7fe14f7dfb..82bec2a4a7 100644 --- a/spec/ruby/library/net/ftp/shared/gettextfile.rb +++ b/spec/ruby/library/net/ftp/shared/gettextfile.rb @@ -1,4 +1,4 @@ -describe :net_ftp_gettextfile, shared: true do +describe :net_ftp_gettextfile, shared: :true do before :each do @tmp_file = tmp("gettextfile") diff --git a/spec/ruby/library/net/ftp/shared/putbinaryfile.rb b/spec/ruby/library/net/ftp/shared/putbinaryfile.rb index 45f53adc2a..1163a1cfea 100644 --- a/spec/ruby/library/net/ftp/shared/putbinaryfile.rb +++ b/spec/ruby/library/net/ftp/shared/putbinaryfile.rb @@ -1,9 +1,9 @@ -describe :net_ftp_putbinaryfile, shared: true do +describe :net_ftp_putbinaryfile, shared: :true do before :each do @server = NetFTPSpecs::DummyFTP.new @server.serve_once - @local_fixture_file = __dir__ + "/../fixtures/putbinaryfile" + @local_fixture_file = File.dirname(__FILE__) + "/../fixtures/putbinaryfile" @remote_tmp_file = tmp("binaryfile", false) @ftp = Net::FTP.new diff --git a/spec/ruby/library/net/ftp/shared/puttextfile.rb b/spec/ruby/library/net/ftp/shared/puttextfile.rb index 3836e954b8..50e8de28e6 100644 --- a/spec/ruby/library/net/ftp/shared/puttextfile.rb +++ b/spec/ruby/library/net/ftp/shared/puttextfile.rb @@ -3,7 +3,7 @@ describe :net_ftp_puttextfile, shared: true do @server = NetFTPSpecs::DummyFTP.new @server.serve_once - @local_fixture_file = __dir__ + "/../fixtures/puttextfile" + @local_fixture_file = File.dirname(__FILE__) + "/../fixtures/puttextfile" @remote_tmp_file = tmp("textfile", false) @ftp = Net::FTP.new diff --git a/spec/ruby/library/net/ftp/storbinary_spec.rb b/spec/ruby/library/net/ftp/storbinary_spec.rb index 6f73344612..64c9090760 100644 --- a/spec/ruby/library/net/ftp/storbinary_spec.rb +++ b/spec/ruby/library/net/ftp/storbinary_spec.rb @@ -9,7 +9,7 @@ ruby_version_is ""..."3.1" do @server = NetFTPSpecs::DummyFTP.new @server.serve_once - @local_fixture_file = __dir__ + "/fixtures/putbinaryfile" + @local_fixture_file = File.dirname(__FILE__) + "/fixtures/putbinaryfile" @tmp_file = tmp("binaryfile", false) @ftp = Net::FTP.new diff --git a/spec/ruby/library/net/ftp/storlines_spec.rb b/spec/ruby/library/net/ftp/storlines_spec.rb index 32b9448732..a4bb7af799 100644 --- a/spec/ruby/library/net/ftp/storlines_spec.rb +++ b/spec/ruby/library/net/ftp/storlines_spec.rb @@ -9,7 +9,7 @@ ruby_version_is ""..."3.1" do @server = NetFTPSpecs::DummyFTP.new @server.serve_once - @local_fixture_file = __dir__ + "/fixtures/puttextfile" + @local_fixture_file = File.dirname(__FILE__) + "/fixtures/puttextfile" @tmp_file = tmp("textfile", false) @ftp = Net::FTP.new diff --git a/spec/ruby/library/net/http/http/get_spec.rb b/spec/ruby/library/net/http/http/get_spec.rb index a3b62e3754..9f6c45f26b 100644 --- a/spec/ruby/library/net/http/http/get_spec.rb +++ b/spec/ruby/library/net/http/http/get_spec.rb @@ -80,13 +80,15 @@ describe "Net::HTTP.get" do end end - it "lets the kill Thread exception goes through and does not replace it with Zlib::BufError" do - socket, client_thread = start_threads - begin - client_thread.kill - client_thread.value.should == nil - ensure - socket.close + ruby_version_is "3.0" do # https://bugs.ruby-lang.org/issues/13882#note-6 + it "lets the kill Thread exception goes through and does not replace it with Zlib::BufError" do + socket, client_thread = start_threads + begin + client_thread.kill + client_thread.value.should == nil + ensure + socket.close + end end end end diff --git a/spec/ruby/library/objectspace/dump_all_spec.rb b/spec/ruby/library/objectspace/dump_all_spec.rb deleted file mode 100644 index e9b449a905..0000000000 --- a/spec/ruby/library/objectspace/dump_all_spec.rb +++ /dev/null @@ -1,112 +0,0 @@ -require_relative '../../spec_helper' -require 'objspace' - -describe "ObjectSpace.dump_all" do - it "dumps Ruby heap to string when passed output: :string" do - stdout = ruby_exe(<<~RUBY, options: "-robjspace") - string = "abc" - dump = ObjectSpace.dump_all(output: :string) - puts dump.class - puts dump.include?('"value":"abc"') - RUBY - - stdout.should == "String\ntrue\n" - end - - it "dumps Ruby heap to a temporary file when passed output: :file" do - stdout = ruby_exe(<<~RUBY, options: "-robjspace") - string = "abc" - file = ObjectSpace.dump_all(output: :file) - - begin - file.flush - file.rewind - content = file.read - - puts file.class - puts content.include?('"value":"abc"') - ensure - file.close - File.unlink file.path - end - RUBY - - stdout.should == "File\ntrue\n" - end - - it "dumps Ruby heap to a temporary file when :output not specified" do - stdout = ruby_exe(<<~RUBY, options: "-robjspace") - string = "abc" - file = ObjectSpace.dump_all - - begin - file.flush - file.rewind - content = file.read - - puts file.class - puts content.include?('"value":"abc"') - ensure - file.close - File.unlink file.path - end - RUBY - - stdout.should == "File\ntrue\n" - end - - it "dumps Ruby heap to a temporary file when passed output: :nil" do - stdout = ruby_exe(<<~RUBY, options: "-robjspace") - string = "abc" - file = ObjectSpace.dump_all(output: nil) - - begin - file.flush - file.rewind - content = file.read - - puts file.class - puts content.include?('"value":"abc"') - ensure - file.close - File.unlink file.path - end - RUBY - - stdout.should == "File\ntrue\n" - end - - it "dumps Ruby heap to stdout when passed output: :stdout" do - stdout = ruby_exe(<<~RUBY, options: "-robjspace") - string = "abc" - ObjectSpace.dump_all(output: :stdout) - RUBY - - stdout.should include('"value":"abc"') - end - - it "dumps Ruby heap to provided IO when passed output: IO" do - stdout = ruby_exe(<<~RUBY, options: "-robjspace -rtempfile") - string = "abc" - io = Tempfile.create("object_space_dump_all") - - begin - result = ObjectSpace.dump_all(output: io) - io.rewind - content = io.read - - puts result.equal?(io) - puts content.include?('"value":"abc"') - ensure - io.close - File.unlink io.path - end - RUBY - - stdout.should == "true\ntrue\n" - end - - it "raises ArgumentError when passed not supported :output value" do - -> { ObjectSpace.dump_all(output: Object.new) }.should raise_error(ArgumentError, /wrong output option/) - end -end diff --git a/spec/ruby/library/objectspace/dump_spec.rb b/spec/ruby/library/objectspace/dump_spec.rb deleted file mode 100644 index e22ee3df1e..0000000000 --- a/spec/ruby/library/objectspace/dump_spec.rb +++ /dev/null @@ -1,70 +0,0 @@ -require_relative '../../spec_helper' -require 'objspace' - -describe "ObjectSpace.dump" do - it "dumps the content of object as JSON" do - require 'json' - string = ObjectSpace.dump("abc") - dump = JSON.parse(string) - - dump['type'].should == "STRING" - dump['value'].should == "abc" - end - - it "dumps to string when passed output: :string" do - string = ObjectSpace.dump("abc", output: :string) - string.should be_kind_of(String) - string.should include('"value":"abc"') - end - - it "dumps to string when :output not specified" do - string = ObjectSpace.dump("abc") - string.should be_kind_of(String) - string.should include('"value":"abc"') - end - - it "dumps to a temporary file when passed output: :file" do - file = ObjectSpace.dump("abc", output: :file) - file.should be_kind_of(File) - - file.rewind - content = file.read - content.should include('"value":"abc"') - ensure - file.close - File.unlink file.path - end - - it "dumps to a temporary file when passed output: :nil" do - file = ObjectSpace.dump("abc", output: nil) - file.should be_kind_of(File) - - file.rewind - file.read.should include('"value":"abc"') - ensure - file.close - File.unlink file.path - end - - it "dumps to stdout when passed output: :stdout" do - stdout = ruby_exe('ObjectSpace.dump("abc", output: :stdout)', options: "-robjspace").chomp - stdout.should include('"value":"abc"') - end - - it "dumps to provided IO when passed output: IO" do - filename = tmp("io_read.txt") - io = File.open(filename, "w+") - result = ObjectSpace.dump("abc", output: io) - result.should.equal? io - - io.rewind - io.read.should include('"value":"abc"') - ensure - io.close - rm_r filename - end - - it "raises ArgumentError when passed not supported :output value" do - -> { ObjectSpace.dump("abc", output: Object.new) }.should raise_error(ArgumentError, /wrong output option/) - end -end diff --git a/spec/ruby/library/objectspace/fixtures/trace.rb b/spec/ruby/library/objectspace/fixtures/trace.rb deleted file mode 100644 index fd4524b0ba..0000000000 --- a/spec/ruby/library/objectspace/fixtures/trace.rb +++ /dev/null @@ -1,5 +0,0 @@ -require "objspace/trace" -a = "foo" -b = "b" + "a" + "r" -c = 42 -p a, b, c diff --git a/spec/ruby/library/objectspace/trace_object_allocations_spec.rb b/spec/ruby/library/objectspace/trace_object_allocations_spec.rb index 612430e067..3100511dc9 100644 --- a/spec/ruby/library/objectspace/trace_object_allocations_spec.rb +++ b/spec/ruby/library/objectspace/trace_object_allocations_spec.rb @@ -128,22 +128,4 @@ describe "ObjectSpace.trace_object_allocations" do ObjectSpace.trace_object_allocations_stop end end - - it "returns nil for class_path, generation, method_id, sourcefile, and sourceline for immutable objects" do - ObjectSpace.trace_object_allocations_start - begin - one = nil - two = 42 - three = :foo - [one, two, three].each do |i| - ObjectSpace.allocation_class_path(i).should == nil - ObjectSpace.allocation_generation(i).should == nil - ObjectSpace.allocation_method_id(i).should == nil - ObjectSpace.allocation_sourcefile(i).should == nil - ObjectSpace.allocation_sourceline(i).should == nil - end - ensure - ObjectSpace.trace_object_allocations_stop - end - end end diff --git a/spec/ruby/library/objectspace/trace_spec.rb b/spec/ruby/library/objectspace/trace_spec.rb deleted file mode 100644 index 59952a006c..0000000000 --- a/spec/ruby/library/objectspace/trace_spec.rb +++ /dev/null @@ -1,15 +0,0 @@ -require_relative '../../spec_helper' - -ruby_version_is "3.1" do - describe 'require "objspace/trace"' do - it "shows object allocation sites" do - file = fixture(__FILE__ , "trace.rb") - ruby_exe(file, args: "2>&1").lines(chomp: true).should == [ - "objspace/trace is enabled", - "\"foo\" @ #{file}:2", - "\"bar\" @ #{file}:3", - "42" - ] - end - end -end diff --git a/spec/ruby/library/openssl/config/freeze_spec.rb b/spec/ruby/library/openssl/config/freeze_spec.rb new file mode 100644 index 0000000000..c814341b86 --- /dev/null +++ b/spec/ruby/library/openssl/config/freeze_spec.rb @@ -0,0 +1,22 @@ +require_relative '../../../spec_helper' +require_relative '../shared/constants' + +require 'openssl' + +version_is(OpenSSL::VERSION, ""..."2.2") do + describe "OpenSSL::Config#freeze" do + it "needs to be reviewed for completeness" + + it "freezes" do + c = OpenSSL::Config.new + -> { + c['foo'] = [ ['key', 'value'] ] + }.should_not raise_error + c.freeze + c.frozen?.should be_true + -> { + c['foo'] = [ ['key', 'value'] ] + }.should raise_error(TypeError) + end + end +end diff --git a/spec/ruby/library/openssl/digest/append_spec.rb b/spec/ruby/library/openssl/digest/append_spec.rb deleted file mode 100644 index 08802b7253..0000000000 --- a/spec/ruby/library/openssl/digest/append_spec.rb +++ /dev/null @@ -1,6 +0,0 @@ -require_relative '../../../spec_helper' -require_relative 'shared/update' - -describe "OpenSSL::Digest#<<" do - it_behaves_like :openssl_digest_update, :<< -end diff --git a/spec/ruby/library/openssl/digest/block_length_spec.rb b/spec/ruby/library/openssl/digest/block_length_spec.rb deleted file mode 100644 index 444ed9d20d..0000000000 --- a/spec/ruby/library/openssl/digest/block_length_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -require_relative '../../../spec_helper' -require_relative '../../../library/digest/sha1/shared/constants' -require_relative '../../../library/digest/sha256/shared/constants' -require_relative '../../../library/digest/sha384/shared/constants' -require_relative '../../../library/digest/sha512/shared/constants' -require 'openssl' - -describe "OpenSSL::Digest#block_length" do - context "when the digest object is created via a name argument" do - it "returns a SHA1 block length" do - OpenSSL::Digest.new('sha1').block_length.should == SHA1Constants::BlockLength - end - - it "returns a SHA256 block length" do - OpenSSL::Digest.new('sha256').block_length.should == SHA256Constants::BlockLength - end - - it "returns a SHA384 block length" do - OpenSSL::Digest.new('sha384').block_length.should == SHA384Constants::BlockLength - end - - it "returns a SHA512 block length" do - OpenSSL::Digest.new('sha512').block_length.should == SHA512Constants::BlockLength - end - end - - context "when the digest object is created via a subclass" do - it "returns a SHA1 block length" do - OpenSSL::Digest::SHA1.new.block_length.should == SHA1Constants::BlockLength - end - - it "returns a SHA256 block length" do - OpenSSL::Digest::SHA256.new.block_length.should == SHA256Constants::BlockLength - end - - it "returns a SHA384 block length" do - OpenSSL::Digest::SHA384.new.block_length.should == SHA384Constants::BlockLength - end - - it "returns a SHA512 block length" do - OpenSSL::Digest::SHA512.new.block_length.should == SHA512Constants::BlockLength - end - end -end diff --git a/spec/ruby/library/openssl/digest/digest_length_spec.rb b/spec/ruby/library/openssl/digest/digest_length_spec.rb deleted file mode 100644 index 37d1cba9a7..0000000000 --- a/spec/ruby/library/openssl/digest/digest_length_spec.rb +++ /dev/null @@ -1,44 +0,0 @@ -require_relative '../../../spec_helper' -require_relative '../../../library/digest/sha1/shared/constants' -require_relative '../../../library/digest/sha256/shared/constants' -require_relative '../../../library/digest/sha384/shared/constants' -require_relative '../../../library/digest/sha512/shared/constants' -require 'openssl' - -describe "OpenSSL::Digest#digest_length" do - context "when the digest object is created via a name argument" do - it "returns a SHA1 digest length" do - OpenSSL::Digest.new('sha1').digest_length.should == SHA1Constants::DigestLength - end - - it "returns a SHA256 digest length" do - OpenSSL::Digest.new('sha256').digest_length.should == SHA256Constants::DigestLength - end - - it "returns a SHA384 digest length" do - OpenSSL::Digest.new('sha384').digest_length.should == SHA384Constants::DigestLength - end - - it "returns a SHA512 digest length" do - OpenSSL::Digest.new('sha512').digest_length.should == SHA512Constants::DigestLength - end - end - - context "when the digest object is created via a subclass" do - it "returns a SHA1 digest length" do - OpenSSL::Digest::SHA1.new.digest_length.should == SHA1Constants::DigestLength - end - - it "returns a SHA256 digest length" do - OpenSSL::Digest::SHA256.new.digest_length.should == SHA256Constants::DigestLength - end - - it "returns a SHA384 digest length" do - OpenSSL::Digest::SHA384.new.digest_length.should == SHA384Constants::DigestLength - end - - it "returns a SHA512 digest length" do - OpenSSL::Digest::SHA512.new.digest_length.should == SHA512Constants::DigestLength - end - end -end diff --git a/spec/ruby/library/openssl/digest/initialize_spec.rb b/spec/ruby/library/openssl/digest/initialize_spec.rb deleted file mode 100644 index 1cd0409c4d..0000000000 --- a/spec/ruby/library/openssl/digest/initialize_spec.rb +++ /dev/null @@ -1,141 +0,0 @@ -require_relative '../../../spec_helper' -require_relative '../../../library/digest/sha1/shared/constants' -require_relative '../../../library/digest/sha256/shared/constants' -require_relative '../../../library/digest/sha384/shared/constants' -require_relative '../../../library/digest/sha512/shared/constants' -require 'openssl' - -describe "OpenSSL::Digest#initialize" do - describe "can be called with a digest name" do - it "returns a SHA1 object" do - OpenSSL::Digest.new("sha1").name.should == "SHA1" - end - - it "returns a SHA256 object" do - OpenSSL::Digest.new("sha256").name.should == "SHA256" - end - - it "returns a SHA384 object" do - OpenSSL::Digest.new("sha384").name.should == "SHA384" - end - - it "returns a SHA512 object" do - OpenSSL::Digest.new("sha512").name.should == "SHA512" - end - - it "throws an error when called with an unknown digest" do - -> { OpenSSL::Digest.new("wd40") }.should raise_error(RuntimeError, /Unsupported digest algorithm \(wd40\)/) - end - - it "cannot be called with a symbol" do - -> { OpenSSL::Digest.new(:SHA1) }.should raise_error(TypeError, /wrong argument type Symbol/) - end - - it "does not call #to_str on the argument" do - name = mock("digest name") - name.should_not_receive(:to_str) - -> { OpenSSL::Digest.new(name) }.should raise_error(TypeError, /wrong argument type/) - end - end - - describe "can be called with a digest object" do - it "returns a SHA1 object" do - OpenSSL::Digest.new(OpenSSL::Digest::SHA1.new).name.should == "SHA1" - end - - it "returns a SHA256 object" do - OpenSSL::Digest.new(OpenSSL::Digest::SHA256.new).name.should == "SHA256" - end - - it "returns a SHA384 object" do - OpenSSL::Digest.new(OpenSSL::Digest::SHA384.new).name.should == "SHA384" - end - - it "returns a SHA512 object" do - OpenSSL::Digest.new(OpenSSL::Digest::SHA512.new).name.should == "SHA512" - end - - it "ignores the state of the digest object" do - sha1 = OpenSSL::Digest.new('sha1', SHA1Constants::Contents) - OpenSSL::Digest.new(sha1).digest.should == SHA1Constants::BlankDigest - end - end - - it "cannot be called with a digest class" do - -> { OpenSSL::Digest.new(OpenSSL::Digest::SHA1) }.should raise_error(TypeError, /wrong argument type Class/) - end - - context "when called without an initial String argument" do - it "returns a SHA1 digest" do - OpenSSL::Digest.new("sha1").digest.should == SHA1Constants::BlankDigest - end - - it "returns a SHA256 digest" do - OpenSSL::Digest.new("sha256").digest.should == SHA256Constants::BlankDigest - end - - it "returns a SHA384 digest" do - OpenSSL::Digest.new("sha384").digest.should == SHA384Constants::BlankDigest - end - - it "returns a SHA512 digest" do - OpenSSL::Digest.new("sha512").digest.should == SHA512Constants::BlankDigest - end - end - - context "when called with an initial String argument" do - it "returns a SHA1 digest of that argument" do - OpenSSL::Digest.new("sha1", SHA1Constants::Contents).digest.should == SHA1Constants::Digest - end - - it "returns a SHA256 digest of that argument" do - OpenSSL::Digest.new("sha256", SHA256Constants::Contents).digest.should == SHA256Constants::Digest - end - - it "returns a SHA384 digest of that argument" do - OpenSSL::Digest.new("sha384", SHA384Constants::Contents).digest.should == SHA384Constants::Digest - end - - it "returns a SHA512 digest of that argument" do - OpenSSL::Digest.new("sha512", SHA512Constants::Contents).digest.should == SHA512Constants::Digest - end - end - - context "can be called on subclasses" do - describe "can be called without an initial String argument on subclasses" do - it "returns a SHA1 digest" do - OpenSSL::Digest::SHA1.new.digest.should == SHA1Constants::BlankDigest - end - - it "returns a SHA256 digest" do - OpenSSL::Digest::SHA256.new.digest.should == SHA256Constants::BlankDigest - end - - it "returns a SHA384 digest" do - OpenSSL::Digest::SHA384.new.digest.should == SHA384Constants::BlankDigest - end - - it "returns a SHA512 digest" do - OpenSSL::Digest::SHA512.new.digest.should == SHA512Constants::BlankDigest - end - end - - describe "can be called with an initial String argument on subclasses" do - it "returns a SHA1 digest" do - OpenSSL::Digest::SHA1.new(SHA1Constants::Contents).digest.should == SHA1Constants::Digest - end - - it "returns a SHA256 digest" do - OpenSSL::Digest::SHA256.new(SHA256Constants::Contents).digest.should == SHA256Constants::Digest - end - - it "returns a SHA384 digest" do - OpenSSL::Digest::SHA384.new(SHA384Constants::Contents).digest.should == SHA384Constants::Digest - end - - it "returns a SHA512 digest" do - OpenSSL::Digest::SHA512.new(SHA512Constants::Contents).digest.should == SHA512Constants::Digest - end - end - end -end diff --git a/spec/ruby/library/openssl/digest/name_spec.rb b/spec/ruby/library/openssl/digest/name_spec.rb deleted file mode 100644 index b379f35c1c..0000000000 --- a/spec/ruby/library/openssl/digest/name_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -require_relative '../../../spec_helper' -require 'openssl' - -describe "OpenSSL::Digest#name" do - it "returns the name of digest" do - OpenSSL::Digest.new('SHA1').name.should == 'SHA1' - end - - it "converts the name to the internal representation of OpenSSL" do - OpenSSL::Digest.new('sha1').name.should == 'SHA1' - end - - it "works on subclasses too" do - OpenSSL::Digest::SHA1.new.name.should == 'SHA1' - end -end diff --git a/spec/ruby/library/openssl/digest/reset_spec.rb b/spec/ruby/library/openssl/digest/reset_spec.rb deleted file mode 100644 index c19bf46633..0000000000 --- a/spec/ruby/library/openssl/digest/reset_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -require_relative '../../../spec_helper' -require_relative '../../../library/digest/sha1/shared/constants' -require_relative '../../../library/digest/sha256/shared/constants' -require_relative '../../../library/digest/sha384/shared/constants' -require_relative '../../../library/digest/sha512/shared/constants' -require 'openssl' - -describe "OpenSSL::Digest#reset" do - it "works for a SHA1 digest" do - digest = OpenSSL::Digest.new('sha1', SHA1Constants::Contents) - digest.reset - digest.update(SHA1Constants::Contents) - digest.digest.should == SHA1Constants::Digest - end - - it "works for a SHA256 digest" do - digest = OpenSSL::Digest.new('sha256', SHA256Constants::Contents) - digest.reset - digest.update(SHA256Constants::Contents) - digest.digest.should == SHA256Constants::Digest - end - - it "works for a SHA384 digest" do - digest = OpenSSL::Digest.new('sha384', SHA384Constants::Contents) - digest.reset - digest.update(SHA384Constants::Contents) - digest.digest.should == SHA384Constants::Digest - end - - it "works for a SHA512 digest" do - digest = OpenSSL::Digest.new('sha512', SHA512Constants::Contents) - digest.reset - digest.update(SHA512Constants::Contents) - digest.digest.should == SHA512Constants::Digest - end -end diff --git a/spec/ruby/library/openssl/digest/shared/update.rb b/spec/ruby/library/openssl/digest/shared/update.rb deleted file mode 100644 index e5ff9dcb16..0000000000 --- a/spec/ruby/library/openssl/digest/shared/update.rb +++ /dev/null @@ -1,123 +0,0 @@ -require_relative '../../../../library/digest/sha1/shared/constants' -require_relative '../../../../library/digest/sha256/shared/constants' -require_relative '../../../../library/digest/sha384/shared/constants' -require_relative '../../../../library/digest/sha512/shared/constants' -require 'openssl' - -describe :openssl_digest_update, shared: true do - context "when given input as a single string" do - it "returns a SHA1 digest" do - digest = OpenSSL::Digest.new('sha1') - digest.send(@method, SHA1Constants::Contents) - digest.digest.should == SHA1Constants::Digest - end - - it "returns a SHA256 digest" do - digest = OpenSSL::Digest.new('sha256') - digest.send(@method, SHA256Constants::Contents) - digest.digest.should == SHA256Constants::Digest - end - - it "returns a SHA384 digest" do - digest = OpenSSL::Digest.new('sha384') - digest.send(@method, SHA384Constants::Contents) - digest.digest.should == SHA384Constants::Digest - end - - it "returns a SHA512 digest" do - digest = OpenSSL::Digest.new('sha512') - digest.send(@method, SHA512Constants::Contents) - digest.digest.should == SHA512Constants::Digest - end - end - - context "when given input as multiple smaller substrings" do - it "returns a SHA1 digest" do - digest = OpenSSL::Digest.new('sha1') - SHA1Constants::Contents.each_char { |b| digest.send(@method, b) } - digest.digest.should == SHA1Constants::Digest - end - - it "returns a SHA256 digest" do - digest = OpenSSL::Digest.new('sha256') - SHA256Constants::Contents.each_char { |b| digest.send(@method, b) } - digest.digest.should == SHA256Constants::Digest - end - - it "returns a SHA384 digest" do - digest = OpenSSL::Digest.new('sha384') - SHA384Constants::Contents.each_char { |b| digest.send(@method, b) } - digest.digest.should == SHA384Constants::Digest - end - - it "returns a SHA512 digest" do - digest = OpenSSL::Digest.new('sha512') - SHA512Constants::Contents.each_char { |b| digest.send(@method, b) } - digest.digest.should == SHA512Constants::Digest - end - end - - context "when input is not a String and responds to #to_str" do - it "returns a SHA1 digest" do - str = mock('str') - str.should_receive(:to_str).and_return(SHA1Constants::Contents) - digest = OpenSSL::Digest.new('sha1') - digest.send(@method, str) - digest.digest.should == SHA1Constants::Digest - end - - it "returns a SHA256 digest" do - str = mock('str') - str.should_receive(:to_str).and_return(SHA256Constants::Contents) - digest = OpenSSL::Digest.new('sha256') - digest.send(@method, str) - digest.digest.should == SHA256Constants::Digest - end - - it "returns a SHA384 digest" do - str = mock('str') - str.should_receive(:to_str).and_return(SHA384Constants::Contents) - digest = OpenSSL::Digest.new('sha384') - digest.send(@method, str) - digest.digest.should == SHA384Constants::Digest - end - - it "returns a SHA512 digest" do - str = mock('str') - str.should_receive(:to_str).and_return(SHA512Constants::Contents) - digest = OpenSSL::Digest.new('sha512') - digest.send(@method, str) - digest.digest.should == SHA512Constants::Digest - end - end - - context "when input is not a String and does not respond to #to_str" do - it "raises a TypeError with SHA1" do - digest = OpenSSL::Digest.new('sha1') - -> { - digest.send(@method, Object.new) - }.should raise_error(TypeError, 'no implicit conversion of Object into String') - end - - it "raises a TypeError with SHA256" do - digest = OpenSSL::Digest.new('sha256') - -> { - digest.send(@method, Object.new) - }.should raise_error(TypeError, 'no implicit conversion of Object into String') - end - - it "raises a TypeError with SHA384" do - digest = OpenSSL::Digest.new('sha384') - -> { - digest.send(@method, Object.new) - }.should raise_error(TypeError, 'no implicit conversion of Object into String') - end - - it "raises a TypeError with SHA512" do - digest = OpenSSL::Digest.new('sha512') - -> { - digest.send(@method, Object.new) - }.should raise_error(TypeError, 'no implicit conversion of Object into String') - end - end -end diff --git a/spec/ruby/library/openssl/digest/update_spec.rb b/spec/ruby/library/openssl/digest/update_spec.rb deleted file mode 100644 index 3a90b06c6b..0000000000 --- a/spec/ruby/library/openssl/digest/update_spec.rb +++ /dev/null @@ -1,6 +0,0 @@ -require_relative '../../../spec_helper' -require_relative 'shared/update' - -describe "OpenSSL::Digest#update" do - it_behaves_like :openssl_digest_update, :update -end diff --git a/spec/ruby/library/openssl/digest/digest_spec.rb b/spec/ruby/library/openssl/digest_spec.rb index cf27d01b6d..b8e82d073f 100644 --- a/spec/ruby/library/openssl/digest/digest_spec.rb +++ b/spec/ruby/library/openssl/digest_spec.rb @@ -1,11 +1,12 @@ -require_relative '../../../spec_helper' -require_relative '../../../library/digest/sha1/shared/constants' -require_relative '../../../library/digest/sha256/shared/constants' -require_relative '../../../library/digest/sha384/shared/constants' -require_relative '../../../library/digest/sha512/shared/constants' +require_relative '../../spec_helper' +require_relative '../../library/digest/sha1/shared/constants' +require_relative '../../library/digest/sha256/shared/constants' +require_relative '../../library/digest/sha384/shared/constants' +require_relative '../../library/digest/sha512/shared/constants' require 'openssl' -describe "OpenSSL::Digest class methods" do +describe "OpenSSL::Digest" do + describe ".digest" do it "returns a SHA1 digest" do OpenSSL::Digest.digest('sha1', SHA1Constants::Contents).should == SHA1Constants::Digest diff --git a/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb b/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb deleted file mode 100644 index 5a2ca168b5..0000000000 --- a/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb +++ /dev/null @@ -1,42 +0,0 @@ -require_relative '../../spec_helper' -require 'openssl' - -describe "OpenSSL.fixed_length_secure_compare" do - it "returns true for two strings with the same content" do - input1 = "the quick brown fox jumps over the lazy dog" - input2 = "the quick brown fox jumps over the lazy dog" - OpenSSL.fixed_length_secure_compare(input1, input2).should be_true - end - - it "returns false for two strings of equal size with different content" do - input1 = "the quick brown fox jumps over the lazy dog" - input2 = "the lazy dog jumps over the quick brown fox" - OpenSSL.fixed_length_secure_compare(input1, input2).should be_false - end - - it "converts both arguments to strings using #to_str" do - input1 = mock("input1") - input1.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog") - input2 = mock("input2") - input2.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog") - OpenSSL.fixed_length_secure_compare(input1, input2).should be_true - end - - it "does not accept arguments that are not string and cannot be coerced into strings" do - -> { - OpenSSL.fixed_length_secure_compare("input1", :input2) - }.should raise_error(TypeError, 'no implicit conversion of Symbol into String') - - -> { - OpenSSL.fixed_length_secure_compare(Object.new, "input2") - }.should raise_error(TypeError, 'no implicit conversion of Object into String') - end - - it "raises an ArgumentError for two strings of different size" do - input1 = "the quick brown fox jumps over the lazy dog" - input2 = "the quick brown fox" - -> { - OpenSSL.fixed_length_secure_compare(input1, input2) - }.should raise_error(ArgumentError, 'inputs must be of equal length') - end -end diff --git a/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb b/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb deleted file mode 100644 index 40f8597275..0000000000 --- a/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb +++ /dev/null @@ -1,168 +0,0 @@ -require_relative '../../../spec_helper' -require 'openssl' - -describe "OpenSSL::KDF.pbkdf2_hmac" do - before :each do - @defaults = { - salt: "\x00".b * 16, - iterations: 20_000, - length: 16, - hash: "sha1" - } - end - - it "creates the same value with the same input" do - key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults) - key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b - end - - it "supports nullbytes embedded in the password" do - key = OpenSSL::KDF.pbkdf2_hmac("sec\x00ret".b, **@defaults) - key.should == "\xB9\x7F\xB0\xC2\th\xC8<\x86\xF3\x94Ij7\xEF\xF1".b - end - - it "coerces the password into a String using #to_str" do - pass = mock("pass") - pass.should_receive(:to_str).and_return("secret") - key = OpenSSL::KDF.pbkdf2_hmac(pass, **@defaults) - key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b - end - - it "coerces the salt into a String using #to_str" do - salt = mock("salt") - salt.should_receive(:to_str).and_return("\x00".b * 16) - key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, salt: salt) - key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b - end - - it "coerces the iterations into an Integer using #to_int" do - iterations = mock("iterations") - iterations.should_receive(:to_int).and_return(20_000) - key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: iterations) - key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b - end - - it "coerces the length into an Integer using #to_int" do - length = mock("length") - length.should_receive(:to_int).and_return(16) - key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: length) - key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b - end - - it "accepts a OpenSSL::Digest object as hash" do - hash = OpenSSL::Digest.new("sha1") - key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: hash) - key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b - end - - it "accepts an empty password" do - key = OpenSSL::KDF.pbkdf2_hmac("", **@defaults) - key.should == "k\x9F-\xB1\xF7\x9A\v\xA1(C\xF9\x85!P\xEF\x8C".b - end - - it "accepts an empty salt" do - key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, salt: "") - key.should == "\xD5f\xE5\xEA\xF91\x1D\xD3evD\xED\xDB\xE80\x80".b - end - - it "accepts an empty length" do - key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: 0) - key.should.empty? - end - - it "accepts an arbitrary length" do - key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: 19) - key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0\xCF\xBB\x7F".b - end - - it "accepts any hash function known to OpenSSL" do - key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: "sha512") - key.should == "N\x12}D\xCE\x99\xDBC\x8E\xEC\xAAr\xEA1\xDF\xFF".b - end - - it "raises a TypeError when password is not a String and does not respond to #to_str" do - -> { - OpenSSL::KDF.pbkdf2_hmac(Object.new, **@defaults) - }.should raise_error(TypeError, "no implicit conversion of Object into String") - end - - it "raises a TypeError when salt is not a String and does not respond to #to_str" do - -> { - OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, salt: Object.new) - }.should raise_error(TypeError, "no implicit conversion of Object into String") - end - - it "raises a TypeError when iterations is not an Integer and does not respond to #to_int" do - -> { - OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: Object.new) - }.should raise_error(TypeError, "no implicit conversion of Object into Integer") - end - - it "raises a TypeError when length is not an Integer and does not respond to #to_int" do - -> { - OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: Object.new) - }.should raise_error(TypeError, "no implicit conversion of Object into Integer") - end - - it "raises a TypeError when hash is neither a String nor an OpenSSL::Digest" do - -> { - OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: Object.new) - }.should raise_error(TypeError, "wrong argument type Object (expected OpenSSL/Digest)") - end - - it "raises a TypeError when hash is neither a String nor an OpenSSL::Digest, it does not try to call #to_str" do - hash = mock("hash") - hash.should_not_receive(:to_str) - -> { - OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: hash) - }.should raise_error(TypeError, "wrong argument type MockObject (expected OpenSSL/Digest)") - end - - it "raises a RuntimeError for unknown digest algorithms" do - -> { - OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: "wd40") - }.should raise_error(RuntimeError, /Unsupported digest algorithm \(wd40\)/) - end - - it "treats salt as a required keyword" do - -> { - OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:salt)) - }.should raise_error(ArgumentError, 'missing keyword: :salt') - end - - it "treats iterations as a required keyword" do - -> { - OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:iterations)) - }.should raise_error(ArgumentError, 'missing keyword: :iterations') - end - - it "treats length as a required keyword" do - -> { - OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:length)) - }.should raise_error(ArgumentError, 'missing keyword: :length') - end - - it "treats hash as a required keyword" do - -> { - OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:hash)) - }.should raise_error(ArgumentError, 'missing keyword: :hash') - end - - it "treats all keywords as required" do - -> { - OpenSSL::KDF.pbkdf2_hmac("secret") - }.should raise_error(ArgumentError, 'missing keywords: :salt, :iterations, :length, :hash') - end - - guard -> { OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000 } do - it "raises an OpenSSL::KDF::KDFError for 0 or less iterations" do - -> { - OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: 0) - }.should raise_error(OpenSSL::KDF::KDFError, "PKCS5_PBKDF2_HMAC: invalid iteration count") - - -> { - OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: -1) - }.should raise_error(OpenSSL::KDF::KDFError, /PKCS5_PBKDF2_HMAC/) - end - end -end diff --git a/spec/ruby/library/openssl/kdf/scrypt_spec.rb b/spec/ruby/library/openssl/kdf/scrypt_spec.rb deleted file mode 100644 index 5dc9f2f281..0000000000 --- a/spec/ruby/library/openssl/kdf/scrypt_spec.rb +++ /dev/null @@ -1,209 +0,0 @@ -require_relative '../../../spec_helper' -require 'openssl' - -guard -> { OpenSSL::KDF.respond_to?(:scrypt) } do - describe "OpenSSL::KDF.scrypt" do - before :each do - @defaults = { - salt: "\x00".b * 16, - N: 2**14, - r: 8, - p: 1, - length: 32 - } - end - - it "creates the same value with the same input" do - key = OpenSSL::KDF.scrypt("secret", **@defaults) - key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b - end - - it "supports nullbytes embedded into the password" do - key = OpenSSL::KDF.scrypt("sec\x00ret".b, **@defaults) - key.should == "\xF9\xA4\xA0\xF1p\xF4\xF0\xCAT\xB4v\xEB\r7\x88N\xF7\x15]Ns\xFCwt4a\xC9\xC6\xA7\x13\x81&".b - end - - it "coerces the password into a String using #to_str" do - pass = mock("pass") - pass.should_receive(:to_str).and_return("secret") - key = OpenSSL::KDF.scrypt(pass, **@defaults) - key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b - end - - it "coerces the salt into a String using #to_str" do - salt = mock("salt") - salt.should_receive(:to_str).and_return("\x00".b * 16) - key = OpenSSL::KDF.scrypt("secret", **@defaults, salt: salt) - key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b - end - - it "coerces the N into an Integer using #to_int" do - n = mock("N") - n.should_receive(:to_int).and_return(2**14) - key = OpenSSL::KDF.scrypt("secret", **@defaults, N: n) - key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b - end - - it "coerces the r into an Integer using #to_int" do - r = mock("r") - r.should_receive(:to_int).and_return(8) - key = OpenSSL::KDF.scrypt("secret", **@defaults, r: r) - key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b - end - - it "coerces the p into an Integer using #to_int" do - p = mock("p") - p.should_receive(:to_int).and_return(1) - key = OpenSSL::KDF.scrypt("secret", **@defaults, p: p) - key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b - end - - it "coerces the length into an Integer using #to_int" do - length = mock("length") - length.should_receive(:to_int).and_return(32) - key = OpenSSL::KDF.scrypt("secret", **@defaults, length: length) - key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b - end - - it "accepts an empty password" do - key = OpenSSL::KDF.scrypt("", **@defaults) - key.should == "\xAA\xFC\xF5^E\x94v\xFFk\xE6\xF0vR\xE7\x13\xA7\xF5\x15'\x9A\xE4C\x9Dn\x18F_E\xD2\v\e\xB3".b - end - - it "accepts an empty salt" do - key = OpenSSL::KDF.scrypt("secret", **@defaults, salt: "") - key.should == "\x96\xACDl\xCB3/aN\xB0F\x8A#\xD7\x92\xD2O\x1E\v\xBB\xCE\xC0\xAA\xB9\x0F]\xB09\xEA8\xDD\e".b - end - - it "accepts a zero length" do - key = OpenSSL::KDF.scrypt("secret", **@defaults, length: 0) - key.should.empty? - end - - it "accepts an arbitrary length" do - key = OpenSSL::KDF.scrypt("secret", **@defaults, length: 19) - key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D".b - end - - it "raises a TypeError when password is not a String and does not respond to #to_str" do - -> { - OpenSSL::KDF.scrypt(Object.new, **@defaults) - }.should raise_error(TypeError, "no implicit conversion of Object into String") - end - - it "raises a TypeError when salt is not a String and does not respond to #to_str" do - -> { - OpenSSL::KDF.scrypt("secret", **@defaults, salt: Object.new) - }.should raise_error(TypeError, "no implicit conversion of Object into String") - end - - it "raises a TypeError when N is not an Integer and does not respond to #to_int" do - -> { - OpenSSL::KDF.scrypt("secret", **@defaults, N: Object.new) - }.should raise_error(TypeError, "no implicit conversion of Object into Integer") - end - - it "raises a TypeError when r is not an Integer and does not respond to #to_int" do - -> { - OpenSSL::KDF.scrypt("secret", **@defaults, r: Object.new) - }.should raise_error(TypeError, "no implicit conversion of Object into Integer") - end - - it "raises a TypeError when p is not an Integer and does not respond to #to_int" do - -> { - OpenSSL::KDF.scrypt("secret", **@defaults, p: Object.new) - }.should raise_error(TypeError, "no implicit conversion of Object into Integer") - end - - it "raises a TypeError when length is not an Integer and does not respond to #to_int" do - -> { - OpenSSL::KDF.scrypt("secret", **@defaults, length: Object.new) - }.should raise_error(TypeError, "no implicit conversion of Object into Integer") - end - - it "treats salt as a required keyword" do - -> { - OpenSSL::KDF.scrypt("secret", **@defaults.except(:salt)) - }.should raise_error(ArgumentError, 'missing keyword: :salt') - end - - it "treats N as a required keyword" do - -> { - OpenSSL::KDF.scrypt("secret", **@defaults.except(:N)) - }.should raise_error(ArgumentError, 'missing keyword: :N') - end - - it "treats r as a required keyword" do - -> { - OpenSSL::KDF.scrypt("secret", **@defaults.except(:r)) - }.should raise_error(ArgumentError, 'missing keyword: :r') - end - - it "treats p as a required keyword" do - -> { - OpenSSL::KDF.scrypt("secret", **@defaults.except(:p)) - }.should raise_error(ArgumentError, 'missing keyword: :p') - end - - it "treats length as a required keyword" do - -> { - OpenSSL::KDF.scrypt("secret", **@defaults.except(:length)) - }.should raise_error(ArgumentError, 'missing keyword: :length') - end - - it "treats all keywords as required" do - -> { - OpenSSL::KDF.scrypt("secret") - }.should raise_error(ArgumentError, 'missing keywords: :salt, :N, :r, :p, :length') - end - - it "requires N to be a power of 2" do - -> { - OpenSSL::KDF.scrypt("secret", **@defaults, N: 2**14 - 1) - }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/) - end - - it "requires N to be at least 2" do - key = OpenSSL::KDF.scrypt("secret", **@defaults, N: 2) - key.should == "\x06A$a\xA9!\xBE\x01\x85\xA7\x18\xBCEa\x82\xC5\xFEl\x93\xAB\xBD\xF7\x8B\x84\v\xFC\eN\xEBQ\xE6\xD2".b - - -> { - OpenSSL::KDF.scrypt("secret", **@defaults, N: 1) - }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/) - - -> { - OpenSSL::KDF.scrypt("secret", **@defaults, N: 0) - }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/) - - -> { - OpenSSL::KDF.scrypt("secret", **@defaults, N: -1) - }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/) - end - - it "requires r to be positive" do - -> { - OpenSSL::KDF.scrypt("secret", **@defaults, r: 0) - }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/) - - -> { - OpenSSL::KDF.scrypt("secret", **@defaults, r: -1) - }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/) - end - - it "requires p to be positive" do - -> { - OpenSSL::KDF.scrypt("secret", **@defaults, p: 0) - }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/) - - -> { - OpenSSL::KDF.scrypt("secret", **@defaults, p: -1) - }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/) - end - - it "requires length to be not negative" do - -> { - OpenSSL::KDF.scrypt("secret", **@defaults, length: -1) - }.should raise_error(ArgumentError, "negative string size (or size too big)") - end - end -end diff --git a/spec/ruby/library/openssl/random/shared/random_bytes.rb b/spec/ruby/library/openssl/random/shared/random_bytes.rb index f97ccd9974..037f10d409 100644 --- a/spec/ruby/library/openssl/random/shared/random_bytes.rb +++ b/spec/ruby/library/openssl/random/shared/random_bytes.rb @@ -1,7 +1,7 @@ require_relative '../../../../spec_helper' require 'openssl' -describe :openssl_random_bytes, shared: true do +describe :openssl_random_bytes, shared: true do |cmd| it "generates a random binary string of specified length" do (1..64).each do |idx| bytes = OpenSSL::Random.send(@method, idx) diff --git a/spec/ruby/library/openssl/secure_compare_spec.rb b/spec/ruby/library/openssl/secure_compare_spec.rb deleted file mode 100644 index cec48e01e7..0000000000 --- a/spec/ruby/library/openssl/secure_compare_spec.rb +++ /dev/null @@ -1,38 +0,0 @@ -require_relative '../../spec_helper' -require 'openssl' - -describe "OpenSSL.secure_compare" do - it "returns true for two strings with the same content" do - input1 = "the quick brown fox jumps over the lazy dog" - input2 = "the quick brown fox jumps over the lazy dog" - OpenSSL.secure_compare(input1, input2).should be_true - end - - it "returns false for two strings with different content" do - input1 = "the quick brown fox jumps over the lazy dog" - input2 = "the lazy dog jumps over the quick brown fox" - OpenSSL.secure_compare(input1, input2).should be_false - end - - it "converts both arguments to strings using #to_str, but adds equality check for the original objects" do - input1 = mock("input1") - input1.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog") - input2 = mock("input2") - input2.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog") - OpenSSL.secure_compare(input1, input2).should be_false - - input = mock("input") - input.should_receive(:to_str).twice.and_return("the quick brown fox jumps over the lazy dog") - OpenSSL.secure_compare(input, input).should be_true - end - - it "does not accept arguments that are not string and cannot be coerced into strings" do - -> { - OpenSSL.secure_compare("input1", :input2) - }.should raise_error(TypeError, 'no implicit conversion of Symbol into String') - - -> { - OpenSSL.secure_compare(Object.new, "input2") - }.should raise_error(TypeError, 'no implicit conversion of Object into String') - end -end diff --git a/spec/ruby/library/openssl/x509/store/verify_spec.rb b/spec/ruby/library/openssl/x509/store/verify_spec.rb deleted file mode 100644 index 6a6a53d992..0000000000 --- a/spec/ruby/library/openssl/x509/store/verify_spec.rb +++ /dev/null @@ -1,78 +0,0 @@ -require_relative '../../../../spec_helper' -require 'openssl' - -describe "OpenSSL::X509::Store#verify" do - it "returns true for valid certificate" do - key = OpenSSL::PKey::RSA.new 2048 - cert = OpenSSL::X509::Certificate.new - cert.version = 2 - cert.serial = 1 - cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA" - cert.issuer = cert.subject - cert.public_key = key.public_key - cert.not_before = Time.now - 10 - cert.not_after = cert.not_before + 365 * 24 * 60 * 60 - cert.sign key, OpenSSL::Digest.new('SHA256') - store = OpenSSL::X509::Store.new - store.add_cert(cert) - [store.verify(cert), store.error, store.error_string].should == [true, 0, "ok"] - end - - it "returns false for an expired certificate" do - key = OpenSSL::PKey::RSA.new 2048 - cert = OpenSSL::X509::Certificate.new - cert.version = 2 - cert.serial = 1 - cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA" - cert.issuer = cert.subject - cert.public_key = key.public_key - cert.not_before = Time.now - 10 - cert.not_after = Time.now - 5 - cert.sign key, OpenSSL::Digest.new('SHA256') - store = OpenSSL::X509::Store.new - store.add_cert(cert) - store.verify(cert).should == false - end - - it "returns false for an expired root certificate" do - root_key = OpenSSL::PKey::RSA.new 2048 - root_cert = OpenSSL::X509::Certificate.new - root_cert.version = 2 - root_cert.serial = 1 - root_cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA" - root_cert.issuer = root_cert.subject - root_cert.public_key = root_key.public_key - root_cert.not_before = Time.now - 10 - root_cert.not_after = Time.now - 5 - ef = OpenSSL::X509::ExtensionFactory.new - ef.subject_certificate = root_cert - ef.issuer_certificate = root_cert - root_cert.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true)) - root_cert.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true)) - root_cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false)) - root_cert.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false)) - root_cert.sign(root_key, OpenSSL::Digest.new('SHA256')) - - - key = OpenSSL::PKey::RSA.new 2048 - cert = OpenSSL::X509::Certificate.new - cert.version = 2 - cert.serial = 2 - cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby certificate" - cert.issuer = root_cert.subject - cert.public_key = key.public_key - cert.not_before = Time.now - cert.not_after = cert.not_before + 1 * 365 * 24 * 60 * 60 - ef = OpenSSL::X509::ExtensionFactory.new - ef.subject_certificate = cert - ef.issuer_certificate = root_cert - cert.add_extension(ef.create_extension("keyUsage","digitalSignature", true)) - cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false)) - cert.sign(root_key, OpenSSL::Digest.new('SHA256')) - - store = OpenSSL::X509::Store.new - store.add_cert(root_cert) - store.add_cert(cert) - store.verify(cert).should == false - end -end diff --git a/spec/ruby/library/openstruct/method_missing_spec.rb b/spec/ruby/library/openstruct/method_missing_spec.rb index 89f83d07b3..212db015a9 100644 --- a/spec/ruby/library/openstruct/method_missing_spec.rb +++ b/spec/ruby/library/openstruct/method_missing_spec.rb @@ -17,8 +17,10 @@ describe "OpenStruct#method_missing when passed additional arguments" do -> { os.test(1, 2, 3) }.should raise_error(NoMethodError) end - it "raises an ArgumentError when the key exists" do - os = OpenStruct.new(test: 20) - -> { os.test(1, 2, 3) }.should raise_error(ArgumentError) + ruby_version_is "2.7" do + it "raises an ArgumentError when the key exists" do + os = OpenStruct.new(test: 20) + -> { os.test(1, 2, 3) }.should raise_error(ArgumentError) + end end end diff --git a/spec/ruby/library/pathname/birthtime_spec.rb b/spec/ruby/library/pathname/birthtime_spec.rb deleted file mode 100644 index 109c112303..0000000000 --- a/spec/ruby/library/pathname/birthtime_spec.rb +++ /dev/null @@ -1,16 +0,0 @@ -require_relative '../../spec_helper' -require 'pathname' - -describe "Pathname#birthtime" do - platform_is :windows, :darwin, :freebsd, :netbsd do - it "returns the birth time for self" do - Pathname.new(__FILE__).birthtime.should be_kind_of(Time) - end - end - - platform_is :openbsd do - it "raises an NotImplementedError" do - -> { Pathname.new(__FILE__).birthtime }.should raise_error(NotImplementedError) - end - end -end diff --git a/spec/ruby/library/pathname/glob_spec.rb b/spec/ruby/library/pathname/glob_spec.rb index ced810fa90..f6dfd6cd58 100644 --- a/spec/ruby/library/pathname/glob_spec.rb +++ b/spec/ruby/library/pathname/glob_spec.rb @@ -40,45 +40,18 @@ describe 'Pathname.glob' do }.should raise_error(ArgumentError, /unknown keyword: :?foo/) end - it "does not raise an ArgumentError when supplied a flag and :base keyword argument" do - expected = [Pathname.new('ipaddr.rb'), Pathname.new('irb.rb'), Pathname.new('.hidden.rb')].sort - Pathname.glob('*i*.rb', File::FNM_DOTMATCH, base: @dir + 'lib').sort.should == expected - end -end - - -describe 'Pathname#glob' do - before :all do - @dir = tmp('pathname_glob') + '/' - @file_1 = @dir + 'lib/ipaddr.rb' - @file_2 = @dir + 'lib/irb.rb' - @file_3 = @dir + 'lib/.hidden.rb' - - touch @file_1 - touch @file_2 - touch @file_3 - end - - after :all do - rm_r @dir[0...-1] - end - - it 'returns [] for no match' do - Pathname.new(@dir).glob('lib/*.js').should == [] - end - - it 'returns matching file paths' do - Pathname.new(@dir).glob('lib/*i*.rb').sort.should == [Pathname.new(@file_1), Pathname.new(@file_2)].sort - end - - it 'yields matching file paths to block' do - ary = [] - Pathname.new(@dir).glob('lib/*i*.rb') { |p| ary << p }.should be_nil - ary.sort.should == [Pathname.new(@file_1), Pathname.new(@file_2)].sort - end - - it 'returns matching file paths when a flag is provided' do - expected = [Pathname.new(@file_1), Pathname.new(@file_2), Pathname.new(@file_3)].sort - Pathname.new(@dir).glob('lib/*i*.rb', File::FNM_DOTMATCH).sort.should == expected + ruby_version_is ''...'2.7' do + it 'raises an ArgumentError when supplied a flag and :base keyword argument' do + -> { + Pathname.glob(@dir + 'lib/*i*.rb', File::FNM_DOTMATCH, base: 'lib') + }.should raise_error(ArgumentError, 'wrong number of arguments (given 3, expected 1..2)') + end + end + + ruby_version_is "2.7" do + it "does not raise an ArgumentError when supplied a flag and :base keyword argument" do + expected = [Pathname.new('ipaddr.rb'), Pathname.new('irb.rb'), Pathname.new('.hidden.rb')].sort + Pathname.glob('*i*.rb', File::FNM_DOTMATCH, base: @dir + 'lib').sort.should == expected + end end end diff --git a/spec/ruby/library/pathname/new_spec.rb b/spec/ruby/library/pathname/new_spec.rb index 36226ed515..760fd8638f 100644 --- a/spec/ruby/library/pathname/new_spec.rb +++ b/spec/ruby/library/pathname/new_spec.rb @@ -10,6 +10,13 @@ describe "Pathname.new" do -> { Pathname.new("\0")}.should raise_error(ArgumentError) end + ruby_version_is ''...'2.7' do + it "is tainted if path is tainted" do + path = '/usr/local/bin'.taint + Pathname.new(path).should.tainted? + end + end + it "raises a TypeError if not passed a String type" do -> { Pathname.new(nil) }.should raise_error(TypeError) -> { Pathname.new(0) }.should raise_error(TypeError) diff --git a/spec/ruby/library/pathname/pathname_spec.rb b/spec/ruby/library/pathname/pathname_spec.rb index 0fb2881468..7d63fe86e3 100644 --- a/spec/ruby/library/pathname/pathname_spec.rb +++ b/spec/ruby/library/pathname/pathname_spec.rb @@ -10,10 +10,21 @@ describe "Kernel#Pathname" do Kernel.should have_method(:Pathname) end - it "returns same argument when called with a pathname argument" do - path = Pathname('foo') - new_path = Pathname(path) + ruby_version_is ''...'2.7' do + it "returns a new pathname when called with a pathname argument" do + path = Pathname('foo') + new_path = Pathname(path) - path.should.equal?(new_path) + path.should_not.equal?(new_path) + end + end + + ruby_version_is '2.7' do + it "returns same argument when called with a pathname argument" do + path = Pathname('foo') + new_path = Pathname(path) + + path.should.equal?(new_path) + end end end diff --git a/spec/ruby/library/pathname/relative_path_from_spec.rb b/spec/ruby/library/pathname/relative_path_from_spec.rb index 133a149849..abe9c80a45 100644 --- a/spec/ruby/library/pathname/relative_path_from_spec.rb +++ b/spec/ruby/library/pathname/relative_path_from_spec.rb @@ -48,8 +48,4 @@ describe "Pathname#relative_path_from" do relative_path_str('..', '..').should == '.' relative_path_str('..', '.').should == '..' end - - it 'converts string argument to Pathname' do - Pathname.new('/usr/bin/ls').relative_path_from('/usr').to_s.should == 'bin/ls' - end end diff --git a/spec/ruby/library/pp/pp_spec.rb b/spec/ruby/library/pp/pp_spec.rb index 243478efd9..06b22601d8 100644 --- a/spec/ruby/library/pp/pp_spec.rb +++ b/spec/ruby/library/pp/pp_spec.rb @@ -20,11 +20,4 @@ describe "PP.pp" do other_out.to_s.should == "[1, 2, 3]\n" end - - it 'correctly prints a Hash' do - hash = { 'key' => 42 } - -> { - PP.pp hash - }.should output('{"key"=>42}' + "\n") - end end diff --git a/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb b/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb index 3dc9900127..b7d9c7a8e4 100644 --- a/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb +++ b/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb @@ -2,22 +2,27 @@ require_relative '../../spec_helper' require 'rbconfig' describe "RbConfig::CONFIG['UNICODE_EMOJI_VERSION']" do - ruby_version_is ""..."3.1" do - it "is 12.1" do - RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "12.1" + ruby_version_is "2.6"..."2.6.2" do + it "is 11.0 for Ruby 2.6.0 and 2.6.1" do + RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "11.0" end end - ruby_version_is "3.1"..."3.2" do - it "is 13.1" do - RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "13.1" + ruby_version_is "2.6.2"..."2.7" do + it "is 12.0 for Ruby 2.6.2+" do + RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "12.0" end end - # Caution: ruby_version_is means is_or_later - ruby_version_is "3.2" do - it "is 15.0" do - RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "15.0" + ruby_version_is "2.7"..."3.1" do + it "is 12.1 for Ruby 2.7 and 3.0" do + RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "12.1" + end + end + + ruby_version_is "3.1" do + it "is 13.1 for Ruby 3.1" do + RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "13.1" end end end diff --git a/spec/ruby/library/rbconfig/unicode_version_spec.rb b/spec/ruby/library/rbconfig/unicode_version_spec.rb index 458f13bf03..fe19b10293 100644 --- a/spec/ruby/library/rbconfig/unicode_version_spec.rb +++ b/spec/ruby/library/rbconfig/unicode_version_spec.rb @@ -2,22 +2,27 @@ require_relative '../../spec_helper' require 'rbconfig' describe "RbConfig::CONFIG['UNICODE_VERSION']" do - ruby_version_is ""..."3.1" do - it "is 12.1.0" do - RbConfig::CONFIG['UNICODE_VERSION'].should == "12.1.0" + ruby_version_is "2.6"..."2.6.2" do + it "is 11.0.0 for Ruby 2.6.0 and 2.6.1" do + RbConfig::CONFIG['UNICODE_VERSION'].should == "11.0.0" end end - ruby_version_is "3.1"..."3.2" do - it "is 13.0.0" do - RbConfig::CONFIG['UNICODE_VERSION'].should == "13.0.0" + ruby_version_is "2.6.2"..."2.6.3" do + it "is 12.0.0 for Ruby 2.6.2" do + RbConfig::CONFIG['UNICODE_VERSION'].should == "12.0.0" end end - # Caution: ruby_version_is means is_or_later - ruby_version_is "3.2" do - it "is 15.0.0" do - RbConfig::CONFIG['UNICODE_VERSION'].should == "15.0.0" + ruby_version_is "2.6.3"..."3.1" do + it "is 12.1.0 for Ruby 2.6.3+, Ruby 2.7, and Ruby 3.0" do + RbConfig::CONFIG['UNICODE_VERSION'].should == "12.1.0" + end + end + + ruby_version_is "3.1" do + it "is 13.0.0 for Ruby 3.1" do + RbConfig::CONFIG['UNICODE_VERSION'].should == "13.0.0" end end end diff --git a/spec/ruby/library/readline/history/delete_at_spec.rb b/spec/ruby/library/readline/history/delete_at_spec.rb index 3bd577e75c..c95a6a865e 100644 --- a/spec/ruby/library/readline/history/delete_at_spec.rb +++ b/spec/ruby/library/readline/history/delete_at_spec.rb @@ -34,5 +34,14 @@ with_feature :readline do -> { Readline::HISTORY.delete_at(10) }.should raise_error(IndexError) -> { Readline::HISTORY.delete_at(-10) }.should raise_error(IndexError) end + + ruby_version_is ''...'2.7' do + it "taints the returned strings" do + Readline::HISTORY.push("1", "2", "3") + Readline::HISTORY.delete_at(0).tainted?.should be_true + Readline::HISTORY.delete_at(0).tainted?.should be_true + Readline::HISTORY.delete_at(0).tainted?.should be_true + end + end end end diff --git a/spec/ruby/library/readline/history/each_spec.rb b/spec/ruby/library/readline/history/each_spec.rb index aa48dd46df..23387bfc98 100644 --- a/spec/ruby/library/readline/history/each_spec.rb +++ b/spec/ruby/library/readline/history/each_spec.rb @@ -19,5 +19,13 @@ with_feature :readline do end result.should == ["1", "2", "3"] end + + ruby_version_is ''...'2.7' do + it "yields tainted Objects" do + Readline::HISTORY.each do |x| + x.tainted?.should be_true + end + end + end end end diff --git a/spec/ruby/library/readline/history/element_reference_spec.rb b/spec/ruby/library/readline/history/element_reference_spec.rb index 0a74f3d62d..dfa5367cad 100644 --- a/spec/ruby/library/readline/history/element_reference_spec.rb +++ b/spec/ruby/library/readline/history/element_reference_spec.rb @@ -12,6 +12,13 @@ with_feature :readline do Readline::HISTORY.pop end + ruby_version_is ''...'2.7' do + it "returns tainted objects" do + Readline::HISTORY[0].tainted?.should be_true + Readline::HISTORY[1].tainted?.should be_true + end + end + it "returns the history item at the passed index" do Readline::HISTORY[0].should == "1" Readline::HISTORY[1].should == "2" diff --git a/spec/ruby/library/readline/history/pop_spec.rb b/spec/ruby/library/readline/history/pop_spec.rb index 156a8a06f8..e17be666d8 100644 --- a/spec/ruby/library/readline/history/pop_spec.rb +++ b/spec/ruby/library/readline/history/pop_spec.rb @@ -19,5 +19,14 @@ with_feature :readline do Readline::HISTORY.pop.should == "1" Readline::HISTORY.size.should == 0 end + + ruby_version_is ''...'2.7' do + it "taints the returned strings" do + Readline::HISTORY.push("1", "2", "3") + Readline::HISTORY.pop.tainted?.should be_true + Readline::HISTORY.pop.tainted?.should be_true + Readline::HISTORY.pop.tainted?.should be_true + end + end end end diff --git a/spec/ruby/library/readline/history/shift_spec.rb b/spec/ruby/library/readline/history/shift_spec.rb index 9aad7d5399..ccd90193fd 100644 --- a/spec/ruby/library/readline/history/shift_spec.rb +++ b/spec/ruby/library/readline/history/shift_spec.rb @@ -19,5 +19,14 @@ with_feature :readline do Readline::HISTORY.shift.should == "3" Readline::HISTORY.size.should == 0 end + + ruby_version_is ''...'2.7' do + it "taints the returned strings" do + Readline::HISTORY.push("1", "2", "3") + Readline::HISTORY.shift.tainted?.should be_true + Readline::HISTORY.shift.tainted?.should be_true + Readline::HISTORY.shift.tainted?.should be_true + end + end end end diff --git a/spec/ruby/library/readline/readline_spec.rb b/spec/ruby/library/readline/readline_spec.rb index 6e349ad543..24d2cbbe86 100644 --- a/spec/ruby/library/readline/readline_spec.rb +++ b/spec/ruby/library/readline/readline_spec.rb @@ -21,6 +21,13 @@ with_feature :readline do ruby_exe('File.write ARGV[0], Readline.readline', @options) File.read(@out).should == "test" end + + ruby_version_is ''...'2.7' do + it "taints the returned strings" do + ruby_exe('File.write ARGV[0], Readline.readline.tainted?', @options) + File.read(@out).should == "true" + end + end end end end diff --git a/spec/ruby/library/rexml/attribute/clone_spec.rb b/spec/ruby/library/rexml/attribute/clone_spec.rb new file mode 100644 index 0000000000..5c86468d45 --- /dev/null +++ b/spec/ruby/library/rexml/attribute/clone_spec.rb @@ -0,0 +1,14 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#clone" do + it "returns a copy of this Attribute" do + orig = REXML::Attribute.new("name", "value&&") + orig.should == orig.clone + orig.clone.to_s.should == orig.to_s + orig.clone.to_string.should == orig.to_string + end + end +end diff --git a/spec/ruby/library/rexml/attribute/element_spec.rb b/spec/ruby/library/rexml/attribute/element_spec.rb new file mode 100644 index 0000000000..0e4ce46a4f --- /dev/null +++ b/spec/ruby/library/rexml/attribute/element_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#element" do + it "returns the parent element" do + e = REXML::Element.new "root" + + REXML::Attribute.new("name", "value", e).element.should == e + REXML::Attribute.new("name", "default_constructor").element.should == nil + end + end + + describe "REXML::Attribute#element=" do + it "sets the parent element" do + e = REXML::Element.new "root" + f = REXML::Element.new "temp" + a = REXML::Attribute.new("name", "value", e) + a.element.should == e + + a.element = f + a.element.should == f + end + end +end diff --git a/spec/ruby/library/rexml/attribute/equal_value_spec.rb b/spec/ruby/library/rexml/attribute/equal_value_spec.rb new file mode 100644 index 0000000000..1498bae624 --- /dev/null +++ b/spec/ruby/library/rexml/attribute/equal_value_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#==" do + it "returns true if other has equal name and value" do + a1 = REXML::Attribute.new("foo", "bar") + a1.should == a1.clone + + a2 = REXML::Attribute.new("foo", "bar") + a1.should == a2 + + a3 = REXML::Attribute.new("foo", "bla") + a1.should_not == a3 + + a4 = REXML::Attribute.new("baz", "bar") + a1.should_not == a4 + end + end +end diff --git a/spec/ruby/library/rexml/attribute/hash_spec.rb b/spec/ruby/library/rexml/attribute/hash_spec.rb new file mode 100644 index 0000000000..7e0cbcc1ea --- /dev/null +++ b/spec/ruby/library/rexml/attribute/hash_spec.rb @@ -0,0 +1,16 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#hash" do + # These are not really complete, any idea on how to make them more + # "testable" will be appreciated. + it "returns a hashcode made of the name and value of self" do + a = REXML::Attribute.new("name", "value") + a.hash.should be_kind_of(Numeric) + b = REXML::Attribute.new(a) + a.hash.should == b.hash + end + end +end diff --git a/spec/ruby/library/rexml/attribute/initialize_spec.rb b/spec/ruby/library/rexml/attribute/initialize_spec.rb new file mode 100644 index 0000000000..35b87b0733 --- /dev/null +++ b/spec/ruby/library/rexml/attribute/initialize_spec.rb @@ -0,0 +1,32 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#initialize" do + before :each do + @e = REXML::Element.new "root" + @name = REXML::Attribute.new("name", "Nicko") + @e.add_attribute @name + end + + it "receives two strings for name and value" do + @e.attributes["name"].should == "Nicko" + @e.add_attribute REXML::Attribute.new("last_name", nil) + @e.attributes["last_name"].should == "" + end + + it "receives an Attribute and clones it" do + copy = REXML::Attribute.new(@name) + copy.should == @name + end + + it "receives a parent node" do + last_name = REXML::Attribute.new("last_name", "McBrain", @e) + last_name.element.should == @e + + last_name = REXML::Attribute.new(@name, @e) + last_name.element.should == @e + end + end +end diff --git a/spec/ruby/library/rexml/attribute/inspect_spec.rb b/spec/ruby/library/rexml/attribute/inspect_spec.rb new file mode 100644 index 0000000000..ee5236b98e --- /dev/null +++ b/spec/ruby/library/rexml/attribute/inspect_spec.rb @@ -0,0 +1,22 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#inspect" do + it "returns the name and value as a string" do + a = REXML::Attribute.new("my_name", "my_value") + a.inspect.should == "my_name='my_value'" + end + + it "accepts attributes with no value" do + a = REXML::Attribute.new("my_name") + a.inspect.should == "my_name=''" + end + + it "does not escape text" do + a = REXML::Attribute.new("name", "<>") + a.inspect.should == "name='<>'" + end + end +end diff --git a/spec/ruby/library/rexml/attribute/namespace_spec.rb b/spec/ruby/library/rexml/attribute/namespace_spec.rb new file mode 100644 index 0000000000..645b3cd1b1 --- /dev/null +++ b/spec/ruby/library/rexml/attribute/namespace_spec.rb @@ -0,0 +1,27 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#namespace" do + it "returns the namespace url" do + e = REXML::Element.new("root") + e.add_attribute REXML::Attribute.new("xmlns:ns", "http://some_uri") + e.namespace("ns").should == "http://some_uri" + end + + it "returns nil if namespace is not defined" do + e = REXML::Element.new("root") + e.add_attribute REXML::Attribute.new("test", "value") + e.namespace("test").should == nil + e.namespace("ns").should == nil + end + + it "defaults arg to nil" do + e = REXML::Element.new("root") + e.add_attribute REXML::Attribute.new("xmlns:ns", "http://some_uri") + e.namespace.should == "" + e.namespace("ns").should == "http://some_uri" + end + end +end diff --git a/spec/ruby/library/rexml/attribute/node_type_spec.rb b/spec/ruby/library/rexml/attribute/node_type_spec.rb new file mode 100644 index 0000000000..da055ae8f0 --- /dev/null +++ b/spec/ruby/library/rexml/attribute/node_type_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#node_type" do + it "always returns :attribute" do + attr = REXML::Attribute.new("foo", "bar") + attr.node_type.should == :attribute + REXML::Attribute.new(attr).node_type.should == :attribute + end + end +end diff --git a/spec/ruby/library/rexml/attribute/prefix_spec.rb b/spec/ruby/library/rexml/attribute/prefix_spec.rb new file mode 100644 index 0000000000..87bff4822b --- /dev/null +++ b/spec/ruby/library/rexml/attribute/prefix_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#prefix" do + it "returns the namespace of the Attribute" do + ans = REXML::Attribute.new("ns:someattr", "some_value") + out = REXML::Attribute.new("out:something", "some_other_value") + + ans.prefix.should == "ns" + out.prefix.should == "out" + end + + it "returns an empty string for Attributes with no prefixes" do + attr = REXML::Attribute.new("foo", "bar") + + attr.prefix.should == "" + end + end +end diff --git a/spec/ruby/library/rexml/attribute/remove_spec.rb b/spec/ruby/library/rexml/attribute/remove_spec.rb new file mode 100644 index 0000000000..5f928b1286 --- /dev/null +++ b/spec/ruby/library/rexml/attribute/remove_spec.rb @@ -0,0 +1,23 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#remove" do + before :each do + @e = REXML::Element.new "Root" + @attr = REXML::Attribute.new("foo", "bar") + end + + it "deletes this Attribute from parent" do + @e.add_attribute(@attr) + @e.attributes["foo"].should_not == nil + @attr.remove + @e.attributes["foo"].should == nil + end + + it "does not anything if element has no parent" do + -> {@attr.remove}.should_not raise_error(Exception) + end + end +end diff --git a/spec/ruby/library/rexml/attribute/to_s_spec.rb b/spec/ruby/library/rexml/attribute/to_s_spec.rb new file mode 100644 index 0000000000..e362cee8f1 --- /dev/null +++ b/spec/ruby/library/rexml/attribute/to_s_spec.rb @@ -0,0 +1,17 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#to_s" do + it "returns the value of the Attribute" do + REXML::Attribute.new("name", "some_value").to_s.should == "some_value" + end + + it "returns the escaped value if it was created from Attribute" do + orig = REXML::Attribute.new("name", "<&>") + copy = REXML::Attribute.new(orig) + copy.to_s.should == "<&>" + end + end +end diff --git a/spec/ruby/library/rexml/attribute/to_string_spec.rb b/spec/ruby/library/rexml/attribute/to_string_spec.rb new file mode 100644 index 0000000000..a9d249f5bb --- /dev/null +++ b/spec/ruby/library/rexml/attribute/to_string_spec.rb @@ -0,0 +1,17 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#to_string" do + it "returns the attribute as XML" do + attr = REXML::Attribute.new("name", "value") + attr_empty = REXML::Attribute.new("name") + attr_ns = REXML::Attribute.new("xmlns:ns", "http://uri") + + attr.to_string.should == "name='value'" + attr_empty.to_string.should == "name=''" + attr_ns.to_string.should == "xmlns:ns='http://uri'" + end + end +end diff --git a/spec/ruby/library/rexml/attribute/value_spec.rb b/spec/ruby/library/rexml/attribute/value_spec.rb new file mode 100644 index 0000000000..77071f6f70 --- /dev/null +++ b/spec/ruby/library/rexml/attribute/value_spec.rb @@ -0,0 +1,17 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#value" do + it "returns the value of the Attribute unnormalized" do + attr = REXML::Attribute.new("name", "value") + attr_ents = REXML::Attribute.new("name", "<&>") + attr_empty = REXML::Attribute.new("name") + + attr.value.should == "value" + attr_ents.value.should == "<&>" + attr_empty.value.should == "" + end + end +end diff --git a/spec/ruby/library/rexml/attribute/write_spec.rb b/spec/ruby/library/rexml/attribute/write_spec.rb new file mode 100644 index 0000000000..0012b3cc77 --- /dev/null +++ b/spec/ruby/library/rexml/attribute/write_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#write" do + before :each do + @attr = REXML::Attribute.new("name", "Charlotte") + @s = "" + end + + it "writes the name and value to output" do + @attr.write(@s) + @s.should == "name='Charlotte'" + end + + it "currently ignores the second argument" do + @attr.write(@s, 3) + @s.should == "name='Charlotte'" + + @s = "" + @attr.write(@s, "foo") + @s.should == "name='Charlotte'" + end + end +end diff --git a/spec/ruby/library/rexml/attribute/xpath_spec.rb b/spec/ruby/library/rexml/attribute/xpath_spec.rb new file mode 100644 index 0000000000..0a09046b01 --- /dev/null +++ b/spec/ruby/library/rexml/attribute/xpath_spec.rb @@ -0,0 +1,22 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attribute#xpath" do + + before :each do + @e = REXML::Element.new "root" + @attr = REXML::Attribute.new("year", "1989") + end + + it "returns the path for Attribute" do + @e.add_attribute @attr + @attr.xpath.should == "root/@year" + end + + it "raises an error if attribute has no parent" do + -> { @attr.xpath }.should raise_error(Exception) + end + end +end diff --git a/spec/ruby/library/rexml/attributes/add_spec.rb b/spec/ruby/library/rexml/attributes/add_spec.rb new file mode 100644 index 0000000000..e24e9fabbc --- /dev/null +++ b/spec/ruby/library/rexml/attributes/add_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require_relative 'shared/add' + require 'rexml/document' + + describe "REXML::Attributes#add" do + it_behaves_like :rexml_attribute_add, :add + end +end diff --git a/spec/ruby/library/rexml/attributes/append_spec.rb b/spec/ruby/library/rexml/attributes/append_spec.rb new file mode 100644 index 0000000000..f96a727f47 --- /dev/null +++ b/spec/ruby/library/rexml/attributes/append_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require_relative 'shared/add' + require 'rexml/document' + + describe "REXML::Attributes#<<" do + it_behaves_like :rexml_attribute_add, :<< + end +end diff --git a/spec/ruby/library/rexml/attributes/delete_all_spec.rb b/spec/ruby/library/rexml/attributes/delete_all_spec.rb new file mode 100644 index 0000000000..707baa235b --- /dev/null +++ b/spec/ruby/library/rexml/attributes/delete_all_spec.rb @@ -0,0 +1,34 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attributes#delete_all" do + before :each do + @e = REXML::Element.new("root") + end + + it "deletes all attributes that match name" do + uri = REXML::Attribute.new("uri", "http://something") + @e.attributes << uri + @e.attributes.delete_all("uri") + @e.attributes.should be_empty + @e.attributes["uri"].should == nil + end + + it "deletes all attributes that match name with a namespace" do + ns_uri = REXML::Attribute.new("xmlns:uri", "http://something_here_too") + @e.attributes << ns_uri + @e.attributes.delete_all("xmlns:uri") + @e.attributes.should be_empty + @e.attributes["xmlns:uri"].should == nil + end + + it "returns the removed attribute" do + uri = REXML::Attribute.new("uri", "http://something_here_too") + @e.attributes << uri + attrs = @e.attributes.delete_all("uri") + attrs.first.should == uri + end + end +end diff --git a/spec/ruby/library/rexml/attributes/delete_spec.rb b/spec/ruby/library/rexml/attributes/delete_spec.rb new file mode 100644 index 0000000000..723fa70751 --- /dev/null +++ b/spec/ruby/library/rexml/attributes/delete_spec.rb @@ -0,0 +1,30 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attributes#delete" do + before :each do + @e = REXML::Element.new("root") + @name = REXML::Attribute.new("name", "Pepe") + end + + it "takes an attribute name and deletes the attribute" do + @e.attributes.delete("name") + @e.attributes["name"].should be_nil + @e.attributes.should be_empty + end + + it "takes an Attribute and deletes it" do + @e.attributes.delete(@name) + @e.attributes["name"].should be_nil + @e.attributes.should be_empty + end + + it "returns the element with the attribute removed" do + ret_val = @e.attributes.delete(@name) + ret_val.should == @e + ret_val.attributes.should be_empty + end + end +end diff --git a/spec/ruby/library/rexml/attributes/each_attribute_spec.rb b/spec/ruby/library/rexml/attributes/each_attribute_spec.rb new file mode 100644 index 0000000000..692cf4f943 --- /dev/null +++ b/spec/ruby/library/rexml/attributes/each_attribute_spec.rb @@ -0,0 +1,25 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attributes#each_attribute" do + it "iterates over the attributes yielding actual Attribute objects" do + e = REXML::Element.new("root") + name = REXML::Attribute.new("name", "Joe") + ns_uri = REXML::Attribute.new("xmlns:ns", "http://some_uri") + e.add_attribute name + e.add_attribute ns_uri + + attributes = [] + + e.attributes.each_attribute do |attr| + attributes << attr + end + + attributes = attributes.sort_by {|a| a.name } + attributes.first.should == name + attributes.last.should == ns_uri + end + end +end diff --git a/spec/ruby/library/rexml/attributes/each_spec.rb b/spec/ruby/library/rexml/attributes/each_spec.rb new file mode 100644 index 0000000000..49add3b77b --- /dev/null +++ b/spec/ruby/library/rexml/attributes/each_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attributes#each" do + before :each do + @e = REXML::Element.new("root") + @name = REXML::Attribute.new("name", "Joe") + @ns_uri = REXML::Attribute.new("xmlns:ns", "http://some_uri") + @e.add_attribute @name + @e.add_attribute @ns_uri + end + + it "iterates over the attributes yielding expanded-name/value" do + attributes = [] + @e.attributes.each do |attr| + attr.should be_kind_of(Array) + attributes << attr + end + attributes = attributes.sort_by {|a| a.first } + attributes.first.should == ["name", "Joe"] + attributes.last.should == ["xmlns:ns", "http://some_uri"] + end + end +end diff --git a/spec/ruby/library/rexml/attributes/element_reference_spec.rb b/spec/ruby/library/rexml/attributes/element_reference_spec.rb new file mode 100644 index 0000000000..0d089eaab2 --- /dev/null +++ b/spec/ruby/library/rexml/attributes/element_reference_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attributes#[]" do + before :each do + @e = REXML::Element.new("root") + @lang = REXML::Attribute.new("language", "english") + @e.attributes << @lang + end + + it "returns the value of an attribute" do + @e.attributes["language"].should == "english" + end + + it "returns nil if the attribute does not exist" do + @e.attributes["chunky bacon"].should == nil + end + end +end diff --git a/spec/ruby/library/rexml/attributes/element_set_spec.rb b/spec/ruby/library/rexml/attributes/element_set_spec.rb new file mode 100644 index 0000000000..834ad682a6 --- /dev/null +++ b/spec/ruby/library/rexml/attributes/element_set_spec.rb @@ -0,0 +1,28 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attributes#[]=" do + before :each do + @e = REXML::Element.new("song") + @name = REXML::Attribute.new("name", "Holy Smoke!") + @e.attributes << @name + end + + it "sets an attribute" do + @e.attributes["author"] = "_why's foxes" + @e.attributes["author"].should == "_why's foxes" + end + + it "overwrites an existing attribute" do + @e.attributes["name"] = "Chunky Bacon" + @e.attributes["name"].should == "Chunky Bacon" + end + + it "deletes an attribute is value is nil" do + @e.attributes["name"] = nil + @e.attributes.length.should == 0 + end + end +end diff --git a/spec/ruby/library/rexml/attributes/get_attribute_ns_spec.rb b/spec/ruby/library/rexml/attributes/get_attribute_ns_spec.rb new file mode 100644 index 0000000000..1109ff519c --- /dev/null +++ b/spec/ruby/library/rexml/attributes/get_attribute_ns_spec.rb @@ -0,0 +1,17 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attributes#get_attribute_ns" do + it "returns an attribute by name and namespace" do + e = REXML::Element.new("root") + attr = REXML::Attribute.new("xmlns:ns", "http://some_url") + e.attributes << attr + attr.prefix.should == "xmlns" + # This might be a bug in Attribute, commenting until those specs + # are ready + # e.attributes.get_attribute_ns(attr.prefix, "name").should == "http://some_url" + end + end +end diff --git a/spec/ruby/library/rexml/attributes/get_attribute_spec.rb b/spec/ruby/library/rexml/attributes/get_attribute_spec.rb new file mode 100644 index 0000000000..cc94191729 --- /dev/null +++ b/spec/ruby/library/rexml/attributes/get_attribute_spec.rb @@ -0,0 +1,32 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attributes#get_attribute" do + before :each do + @e = REXML::Element.new("root") + @name = REXML::Attribute.new("name", "Dave") + @e.attributes << @name + end + + it "fetches an attributes" do + @e.attributes.get_attribute("name").should == @name + end + + it "fetches an namespaced attribute" do + ns_name = REXML::Attribute.new("im:name", "Murray") + @e.attributes << ns_name + @e.attributes.get_attribute("name").should == @name + @e.attributes.get_attribute("im:name").should == ns_name + end + + it "returns an Attribute" do + @e.attributes.get_attribute("name").should be_kind_of(REXML::Attribute) + end + + it "returns nil if it attribute does not exist" do + @e.attributes.get_attribute("fake").should be_nil + end + end +end diff --git a/spec/ruby/library/rexml/attributes/initialize_spec.rb b/spec/ruby/library/rexml/attributes/initialize_spec.rb new file mode 100644 index 0000000000..42ec742e60 --- /dev/null +++ b/spec/ruby/library/rexml/attributes/initialize_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attributes#initialize" do + it "is auto initialized by Element" do + e = REXML::Element.new "root" + e.attributes.should be_kind_of(REXML::Attributes) + + e.attributes << REXML::Attribute.new("name", "Paul") + e.attributes["name"].should == "Paul" + end + + it "receives a parent node" do + e = REXML::Element.new "root" + e.attributes << REXML::Attribute.new("name", "Vic") + e.attributes["name"].should == "Vic" + end + end +end diff --git a/spec/ruby/library/rexml/attributes/length_spec.rb b/spec/ruby/library/rexml/attributes/length_spec.rb new file mode 100644 index 0000000000..81733b4a96 --- /dev/null +++ b/spec/ruby/library/rexml/attributes/length_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require_relative 'shared/length' + require 'rexml/document' + + describe "REXML::Attributes#length" do + it_behaves_like :rexml_attribute_length, :length + end +end diff --git a/spec/ruby/library/rexml/attributes/namespaces_spec.rb b/spec/ruby/library/rexml/attributes/namespaces_spec.rb new file mode 100644 index 0000000000..b88346854f --- /dev/null +++ b/spec/ruby/library/rexml/attributes/namespaces_spec.rb @@ -0,0 +1,9 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attributes#namespaces" do + it "needs to be reviewed for spec completeness" + end +end diff --git a/spec/ruby/library/rexml/attributes/prefixes_spec.rb b/spec/ruby/library/rexml/attributes/prefixes_spec.rb new file mode 100644 index 0000000000..574b7ffbaf --- /dev/null +++ b/spec/ruby/library/rexml/attributes/prefixes_spec.rb @@ -0,0 +1,27 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attributes#prefixes" do + before :each do + @e = REXML::Element.new("root") + a1 = REXML::Attribute.new("xmlns:a", "bar") + a2 = REXML::Attribute.new("xmlns:b", "bla") + a3 = REXML::Attribute.new("xmlns:c", "baz") + @e.attributes << a1 + @e.attributes << a2 + @e.attributes << a3 + + @e.attributes << REXML::Attribute.new("xmlns", "foo") + end + + it "returns an array with the prefixes of each attribute" do + @e.attributes.prefixes.sort.should == ["a", "b", "c"] + end + + it "does not include the default namespace" do + @e.attributes.prefixes.include?("xmlns").should == false + end + end +end diff --git a/spec/ruby/library/rexml/attributes/shared/add.rb b/spec/ruby/library/rexml/attributes/shared/add.rb new file mode 100644 index 0000000000..872f149f45 --- /dev/null +++ b/spec/ruby/library/rexml/attributes/shared/add.rb @@ -0,0 +1,17 @@ +describe :rexml_attribute_add, shared: true do + before :each do + @e = REXML::Element.new("root") + @attr = REXML::Attributes.new(@e) + @name = REXML::Attribute.new("name", "Joe") + end + + it "adds an attribute" do + @attr.send(@method, @name) + @attr["name"].should == "Joe" + end + + it "replaces an existing attribute" do + @attr.send(@method, REXML::Attribute.new("name", "Bruce")) + @attr["name"].should == "Bruce" + end +end diff --git a/spec/ruby/library/rexml/attributes/shared/length.rb b/spec/ruby/library/rexml/attributes/shared/length.rb new file mode 100644 index 0000000000..7848f9bf33 --- /dev/null +++ b/spec/ruby/library/rexml/attributes/shared/length.rb @@ -0,0 +1,13 @@ +require_relative '../../../../spec_helper' +require 'rexml/document' + +describe :rexml_attribute_length, shared: true do + it "returns the number of attributes" do + e = REXML::Element.new("root") + e.attributes.send(@method).should == 0 + + e.attributes << REXML::Attribute.new("name", "John") + e.attributes << REXML::Attribute.new("another_name", "Leo") + e.attributes.send(@method).should == 2 + end +end diff --git a/spec/ruby/library/rexml/attributes/size_spec.rb b/spec/ruby/library/rexml/attributes/size_spec.rb new file mode 100644 index 0000000000..13ef08f644 --- /dev/null +++ b/spec/ruby/library/rexml/attributes/size_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require_relative 'shared/length' + require 'rexml/document' + + describe "REXML::Attributes#size" do + it_behaves_like :rexml_attribute_length, :size + end +end diff --git a/spec/ruby/library/rexml/attributes/to_a_spec.rb b/spec/ruby/library/rexml/attributes/to_a_spec.rb new file mode 100644 index 0000000000..902cd86a29 --- /dev/null +++ b/spec/ruby/library/rexml/attributes/to_a_spec.rb @@ -0,0 +1,22 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Attributes#to_a" do + it "returns an array with the attributes" do + e = REXML::Element.new("root") + name = REXML::Attribute.new("name", "Dave") + last = REXML::Attribute.new("last_name", "Murray") + + e.attributes << name + e.attributes << last + + e.attributes.to_a.sort{|a,b|a.to_s<=>b.to_s}.should == [name, last] + end + + it "returns an empty array if it has no attributes" do + REXML::Element.new("root").attributes.to_a.should == [] + end + end +end diff --git a/spec/ruby/library/rexml/cdata/clone_spec.rb b/spec/ruby/library/rexml/cdata/clone_spec.rb new file mode 100644 index 0000000000..abe1a0b062 --- /dev/null +++ b/spec/ruby/library/rexml/cdata/clone_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::CData#clone" do + it "makes a copy of itself" do + c = REXML::CData.new("some text") + c.clone.to_s.should == c.to_s + c.clone.should == c + end + end +end diff --git a/spec/ruby/library/rexml/cdata/initialize_spec.rb b/spec/ruby/library/rexml/cdata/initialize_spec.rb new file mode 100644 index 0000000000..1393d97f4a --- /dev/null +++ b/spec/ruby/library/rexml/cdata/initialize_spec.rb @@ -0,0 +1,27 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::CData#initialize" do + it "creates a new CData object" do + c = REXML::CData.new("some text") + c.should be_kind_of(REXML::CData) + c.should be_kind_of(REXML::Text) + end + + it "respects whitespace if whitespace is true" do + c = REXML::CData.new("whitespace test", true) + c1 = REXML::CData.new("whitespace test", false) + + c.to_s.should == "whitespace test" + c1.to_s.should == "whitespace test" + end + + it "receives parent as third argument" do + e = REXML::Element.new("root") + REXML::CData.new("test", true, e) + e.to_s.should == "<root><![CDATA[test]]></root>" + end + end +end diff --git a/spec/ruby/library/rexml/cdata/shared/to_s.rb b/spec/ruby/library/rexml/cdata/shared/to_s.rb new file mode 100644 index 0000000000..f8c4951c95 --- /dev/null +++ b/spec/ruby/library/rexml/cdata/shared/to_s.rb @@ -0,0 +1,11 @@ +describe :rexml_cdata_to_s, shared: true do + it "returns the contents of the CData" do + c = REXML::CData.new("some text") + c.send(@method).should == "some text" + end + + it "does not escape text" do + c1 = REXML::CData.new("some& text\n") + c1.send(@method).should == "some& text\n" + end +end diff --git a/spec/ruby/library/rexml/cdata/to_s_spec.rb b/spec/ruby/library/rexml/cdata/to_s_spec.rb new file mode 100644 index 0000000000..a5c061f116 --- /dev/null +++ b/spec/ruby/library/rexml/cdata/to_s_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require_relative 'shared/to_s' + require 'rexml/document' + + describe "REXML::CData#to_s" do + it_behaves_like :rexml_cdata_to_s, :to_s + end +end diff --git a/spec/ruby/library/rexml/cdata/value_spec.rb b/spec/ruby/library/rexml/cdata/value_spec.rb new file mode 100644 index 0000000000..9f36226976 --- /dev/null +++ b/spec/ruby/library/rexml/cdata/value_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require_relative 'shared/to_s' + require 'rexml/document' + + describe "REXML::CData#value" do + it_behaves_like :rexml_cdata_to_s, :value + end +end diff --git a/spec/ruby/library/rexml/document/add_element_spec.rb b/spec/ruby/library/rexml/document/add_element_spec.rb new file mode 100644 index 0000000000..29dec0b24e --- /dev/null +++ b/spec/ruby/library/rexml/document/add_element_spec.rb @@ -0,0 +1,34 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Document#add_element" do + it "adds arg1 with attributes arg2 as root node" do + d = REXML::Document.new + e = REXML::Element.new("root") + d.add_element e + d.root.should == e + end + + it "sets arg2 as arg1's attributes" do + d = REXML::Document.new + e = REXML::Element.new("root") + attr = {"foo" => "bar"} + d.add_element(e,attr) + d.root.attributes["foo"].should == attr["foo"] + end + + it "accepts a node name as arg1 and adds it as root" do + d = REXML::Document.new + d.add_element "foo" + d.root.name.should == "foo" + end + + it "sets arg1's context to the root's context" do + d = REXML::Document.new("", {"foo" => "bar"}) + d.add_element "foo" + d.root.context.should == d.context + end + end +end diff --git a/spec/ruby/library/rexml/document/add_spec.rb b/spec/ruby/library/rexml/document/add_spec.rb new file mode 100644 index 0000000000..8666d3dbf9 --- /dev/null +++ b/spec/ruby/library/rexml/document/add_spec.rb @@ -0,0 +1,60 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + # This spec defines Document#add and Document#<< + + describe :rexml_document_add, shared: true do + before :each do + @doc = REXML::Document.new("<root/>") + @decl = REXML::XMLDecl.new("1.0") + end + + it "sets document's XML declaration" do + @doc.send(@method, @decl) + @doc.xml_decl.should == @decl + end + + it "inserts XML declaration as first node" do + @doc.send(@method, @decl) + @doc.children[0].version.should == "1.0" + end + + it "overwrites existing XML declaration" do + @doc.send(@method, @decl) + @doc.send(@method, REXML::XMLDecl.new("2.0")) + @doc.xml_decl.version.should == "2.0" + end + + it "sets document DocType" do + @doc.send(@method, REXML::DocType.new("transitional")) + @doc.doctype.name.should == "transitional" + end + + it "overwrites existing DocType" do + @doc.send(@method, REXML::DocType.new("transitional")) + @doc.send(@method, REXML::DocType.new("strict")) + @doc.doctype.name.should == "strict" + end + + it "adds root node unless it exists" do + d = REXML::Document.new("") + elem = REXML::Element.new "root" + d.send(@method, elem) + d.root.should == elem + end + + it "refuses to add second root" do + -> { @doc.send(@method, REXML::Element.new("foo")) }.should raise_error(RuntimeError) + end + end + + describe "REXML::Document#add" do + it_behaves_like :rexml_document_add, :add + end + + describe "REXML::Document#<<" do + it_behaves_like :rexml_document_add, :<< + end +end diff --git a/spec/ruby/library/rexml/document/clone_spec.rb b/spec/ruby/library/rexml/document/clone_spec.rb new file mode 100644 index 0000000000..137fe8a073 --- /dev/null +++ b/spec/ruby/library/rexml/document/clone_spec.rb @@ -0,0 +1,23 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + # According to the MRI documentation (http://www.ruby-doc.org/stdlib/libdoc/rexml/rdoc/index.html), + # clone's behavior "should be obvious". Apparently "obvious" means cloning + # only the attributes and the context of the document, not its children. + describe "REXML::Document#clone" do + it "clones document attributes" do + d = REXML::Document.new("foo") + d.attributes["foo"] = "bar" + e = d.clone + e.attributes.should == d.attributes + end + + it "clones document context" do + d = REXML::Document.new("foo", {"foo" => "bar"}) + e = d.clone + e.context.should == d.context + end + end +end diff --git a/spec/ruby/library/rexml/document/doctype_spec.rb b/spec/ruby/library/rexml/document/doctype_spec.rb new file mode 100644 index 0000000000..e1b7ba4916 --- /dev/null +++ b/spec/ruby/library/rexml/document/doctype_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Document#doctype" do + it "returns the doctype" do + d = REXML::Document.new + dt = REXML::DocType.new("foo") + d.add dt + d.doctype.should == dt + end + + it "returns nil if there's no doctype" do + REXML::Document.new.doctype.should == nil + end + end +end diff --git a/spec/ruby/library/rexml/document/encoding_spec.rb b/spec/ruby/library/rexml/document/encoding_spec.rb new file mode 100644 index 0000000000..2cc947f06a --- /dev/null +++ b/spec/ruby/library/rexml/document/encoding_spec.rb @@ -0,0 +1,25 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Document#encoding" do + before :each do + @doc = REXML::Document.new + end + + it "returns encoding from XML declaration" do + @doc.add REXML::XMLDecl.new(nil, "UTF-16", nil) + @doc.encoding.should == "UTF-16" + end + + it "returns encoding from XML declaration (for UTF-16 as well)" do + @doc.add REXML::XMLDecl.new("1.0", "UTF-8", nil) + @doc.encoding.should == "UTF-8" + end + + it "uses UTF-8 as default encoding" do + @doc.encoding.should == "UTF-8" + end + end +end diff --git a/spec/ruby/library/rexml/document/expanded_name_spec.rb b/spec/ruby/library/rexml/document/expanded_name_spec.rb new file mode 100644 index 0000000000..9d1025b5e0 --- /dev/null +++ b/spec/ruby/library/rexml/document/expanded_name_spec.rb @@ -0,0 +1,19 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe :document_expanded_name, shared: true do + it "returns an empty string for root" do # root nodes have no expanded name + REXML::Document.new.send(@method).should == "" + end + end + + describe "REXML::Document#expanded_name" do + it_behaves_like :document_expanded_name, :expanded_name + end + + describe "REXML::Document#name" do + it_behaves_like :document_expanded_name, :name + end +end diff --git a/spec/ruby/library/rexml/document/new_spec.rb b/spec/ruby/library/rexml/document/new_spec.rb new file mode 100644 index 0000000000..4e24b6f5a1 --- /dev/null +++ b/spec/ruby/library/rexml/document/new_spec.rb @@ -0,0 +1,39 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Document#new" do + + it "initializes context of {} unless specified" do + d = REXML::Document.new("<foo />") + d.context.should == {} + end + + it "has empty attributes if source is nil" do + d = REXML::Document.new(nil) + d.elements.should be_empty + end + + it "can use other document context" do + s = REXML::Document.new("") + d = REXML::Document.new(s) + d.context.should == s.context + end + + it "clones source attributes" do + s = REXML::Document.new("<root />") + s.attributes["some_attr"] = "some_val" + d = REXML::Document.new(s) + d.attributes.should == s.attributes + end + + it "raises an error if source is not a Document, String or IO" do + -> {REXML::Document.new(3)}.should raise_error(RuntimeError) + end + + it "does not perform XML validation" do + REXML::Document.new("Invalid document").should be_kind_of(REXML::Document) + end + end +end diff --git a/spec/ruby/library/rexml/document/node_type_spec.rb b/spec/ruby/library/rexml/document/node_type_spec.rb new file mode 100644 index 0000000000..b6d7e7a7da --- /dev/null +++ b/spec/ruby/library/rexml/document/node_type_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Document#node_type" do + it "returns :document" do + REXML::Document.new.node_type.should == :document + end + end +end diff --git a/spec/ruby/library/rexml/document/root_spec.rb b/spec/ruby/library/rexml/document/root_spec.rb new file mode 100644 index 0000000000..1a584a720b --- /dev/null +++ b/spec/ruby/library/rexml/document/root_spec.rb @@ -0,0 +1,15 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Document#root" do + it "returns document root tag name" do + REXML::Document.new("<foo/>").root.name.should == "foo" + end + + it "returns nil if there is not root" do + REXML::Document.new.root.should == nil + end + end +end diff --git a/spec/ruby/library/rexml/document/stand_alone_spec.rb b/spec/ruby/library/rexml/document/stand_alone_spec.rb new file mode 100644 index 0000000000..e1c721e782 --- /dev/null +++ b/spec/ruby/library/rexml/document/stand_alone_spec.rb @@ -0,0 +1,22 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Document#stand_alone?" do + it "returns the XMLDecl standalone value" do + d = REXML::Document.new + decl = REXML::XMLDecl.new("1.0", "UTF-8", "yes") + d.add decl + d.stand_alone?.should == "yes" + end + + # According to the docs this should return the default XMLDecl but that + # will carry some more problems when printing the document. Currently, it + # returns nil. See http://www.ruby-forum.com/topic/146812#650061 + it "returns the default value when no XML declaration present" do + REXML::Document.new.stand_alone?.should == nil + end + + end +end diff --git a/spec/ruby/library/rexml/document/version_spec.rb b/spec/ruby/library/rexml/document/version_spec.rb new file mode 100644 index 0000000000..4f6b40551b --- /dev/null +++ b/spec/ruby/library/rexml/document/version_spec.rb @@ -0,0 +1,17 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Document#version" do + it "returns XML version from declaration" do + d = REXML::Document.new + d.add REXML::XMLDecl.new("1.1") + d.version.should == "1.1" + end + + it "returns the default version when declaration is not present" do + REXML::Document.new.version.should == REXML::XMLDecl::DEFAULT_VERSION + end + end +end diff --git a/spec/ruby/library/rexml/document/write_spec.rb b/spec/ruby/library/rexml/document/write_spec.rb new file mode 100644 index 0000000000..00c22141b3 --- /dev/null +++ b/spec/ruby/library/rexml/document/write_spec.rb @@ -0,0 +1,38 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + require 'rexml/formatters/transitive' + + # Maybe this can be cleaned + describe "REXML::Document#write" do + before :each do + @d = REXML::Document.new + city = REXML::Element.new "Springfield" + street = REXML::Element.new "EvergreenTerrace" + address = REXML::Element.new "House742" + @d << city << street << address + @str = "" + end + + it "returns document source as string" do + @d.write(@str) + @str.should == "<Springfield><EvergreenTerrace><House742/></EvergreenTerrace></Springfield>" + end + + it "returns document indented" do + @d.write(@str, 2) + @str.should =~ /\s*<Springfield>\s*<EvergreenTerrace>\s*<House742\/>\s*<\/EvergreenTerrace>\s*<\/Springfield>/ + end + + it "returns document with transitive support" do + @d.write(@str, 2, true) + @str.should =~ /\s*<Springfield\s*><EvergreenTerrace\s*><House742\s*\/><\/EvergreenTerrace\s*><\/Springfield\s*>/ + end + + it "returns document with support for IE" do + @d.write(@str, -1, false, true) + @str.should == "<Springfield><EvergreenTerrace><House742 /></EvergreenTerrace></Springfield>" + end + end +end diff --git a/spec/ruby/library/rexml/document/xml_decl_spec.rb b/spec/ruby/library/rexml/document/xml_decl_spec.rb new file mode 100644 index 0000000000..8ac47510b0 --- /dev/null +++ b/spec/ruby/library/rexml/document/xml_decl_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Document#xml_decl" do + it "returns XML declaration of the document" do + d = REXML::Document.new + decl = REXML::XMLDecl.new("1.0", "UTF-16", "yes") + d.add decl + d.xml_decl.should == decl + end + + it "returns default XML declaration unless present" do + REXML::Document.new.xml_decl.should == REXML::XMLDecl.new + end + end +end diff --git a/spec/ruby/library/rexml/element/add_attribute_spec.rb b/spec/ruby/library/rexml/element/add_attribute_spec.rb new file mode 100644 index 0000000000..64f2ec84a3 --- /dev/null +++ b/spec/ruby/library/rexml/element/add_attribute_spec.rb @@ -0,0 +1,44 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#add_attribute" do + before :each do + @person = REXML::Element.new "person" + @person.attributes["name"] = "Bill" + end + + it "adds a new attribute" do + @person.add_attribute("age", "17") + @person.attributes["age"].should == "17" + end + + it "overwrites an existing attribute" do + @person.add_attribute("name", "Bill") + @person.attributes["name"].should == "Bill" + end + + it "accepts a pair of strings" do + @person.add_attribute("male", "true") + @person.attributes["male"].should == "true" + end + + it "accepts an Attribute for key" do + attr = REXML::Attribute.new("male", "true") + @person.add_attribute attr + @person.attributes["male"].should == "true" + end + + it "ignores value if key is an Attribute" do + attr = REXML::Attribute.new("male", "true") + @person.add_attribute(attr, "false") + @person.attributes["male"].should == "true" + end + + it "returns the attribute added" do + attr = REXML::Attribute.new("name", "Tony") + @person.add_attribute(attr).should == attr + end + end +end diff --git a/spec/ruby/library/rexml/element/add_attributes_spec.rb b/spec/ruby/library/rexml/element/add_attributes_spec.rb new file mode 100644 index 0000000000..f331803dd8 --- /dev/null +++ b/spec/ruby/library/rexml/element/add_attributes_spec.rb @@ -0,0 +1,25 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#add_attributes" do + before :each do + @person = REXML::Element.new "person" + @person.attributes["name"] = "Bill" + end + + it "adds multiple attributes from a hash" do + @person.add_attributes({"name" => "Joe", "age" => "27"}) + @person.attributes["name"].should == "Joe" + @person.attributes["age"].should == "27" + end + + it "adds multiple attributes from an array" do + attrs = { "name" => "Joe", "age" => "27"} + @person.add_attributes attrs.to_a + @person.attributes["name"].should == "Joe" + @person.attributes["age"].should == "27" + end + end +end diff --git a/spec/ruby/library/rexml/element/add_element_spec.rb b/spec/ruby/library/rexml/element/add_element_spec.rb new file mode 100644 index 0000000000..8ba023f2c7 --- /dev/null +++ b/spec/ruby/library/rexml/element/add_element_spec.rb @@ -0,0 +1,41 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#add_element" do + before :each do + @root = REXML::Element.new("root") + end + + it "adds a child without attributes" do + name = REXML::Element.new("name") + @root.add_element name + @root.elements["name"].name.should == name.name + @root.elements["name"].attributes.should == name.attributes + @root.elements["name"].context.should == name.context + end + + it "adds a child with attributes" do + person = REXML::Element.new("person") + @root.add_element(person, {"name" => "Madonna"}) + @root.elements["person"].name.should == person.name + @root.elements["person"].attributes.should == person.attributes + @root.elements["person"].context.should == person.context + end + + it "adds a child with name" do + @root.add_element "name" + @root.elements["name"].name.should == "name" + @root.elements["name"].attributes.should == {} + @root.elements["name"].context.should == nil + end + + it "returns the added child" do + name = @root.add_element "name" + @root.elements["name"].name.should == name.name + @root.elements["name"].attributes.should == name.attributes + @root.elements["name"].context.should == name.context + end + end +end diff --git a/spec/ruby/library/rexml/element/add_namespace_spec.rb b/spec/ruby/library/rexml/element/add_namespace_spec.rb new file mode 100644 index 0000000000..44b074bac7 --- /dev/null +++ b/spec/ruby/library/rexml/element/add_namespace_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#add_namespace" do + before :each do + @elem = REXML::Element.new("person") + end + + it "adds a namespace to element" do + @elem.add_namespace("foo", "bar") + @elem.namespace("foo").should == "bar" + end + + it "accepts a prefix string as prefix" do + @elem.add_namespace("xmlns:foo", "bar") + @elem.namespace("foo").should == "bar" + end + + it "uses prefix as URI if uri is nil" do + @elem.add_namespace("some_uri", nil) + @elem.namespace.should == "some_uri" + end + end +end diff --git a/spec/ruby/library/rexml/element/add_text_spec.rb b/spec/ruby/library/rexml/element/add_text_spec.rb new file mode 100644 index 0000000000..3a0531ad42 --- /dev/null +++ b/spec/ruby/library/rexml/element/add_text_spec.rb @@ -0,0 +1,27 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#add_text" do + before :each do + @name = REXML::Element.new "Name" + end + + it "adds text to an element" do + @name.add_text "Ringo" + @name.to_s.should == "<Name>Ringo</Name>" + end + + it "accepts a Text" do + @name.add_text(REXML::Text.new("Ringo")) + @name.to_s.should == "<Name>Ringo</Name>" + end + + it "joins the new text with the old one" do + @name.add_text "Ringo" + @name.add_text " Starr" + @name.to_s.should == "<Name>Ringo Starr</Name>" + end + end +end diff --git a/spec/ruby/library/rexml/element/attribute_spec.rb b/spec/ruby/library/rexml/element/attribute_spec.rb new file mode 100644 index 0000000000..b223d3440c --- /dev/null +++ b/spec/ruby/library/rexml/element/attribute_spec.rb @@ -0,0 +1,20 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#attribute" do + it "returns an attribute by name" do + person = REXML::Element.new "Person" + attribute = REXML::Attribute.new("drink", "coffee") + person.add_attribute(attribute) + person.attribute("drink").should == attribute + end + + it "supports attributes inside namespaces" do + e = REXML::Element.new("element") + e.add_attributes({"xmlns:ns" => "http://some_uri"}) + e.attribute("ns", "ns").to_s.should == "http://some_uri" + end + end +end diff --git a/spec/ruby/library/rexml/element/attributes_spec.rb b/spec/ruby/library/rexml/element/attributes_spec.rb new file mode 100644 index 0000000000..92bcecc40a --- /dev/null +++ b/spec/ruby/library/rexml/element/attributes_spec.rb @@ -0,0 +1,22 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#attributes" do + it "returns element's Attributes" do + p = REXML::Element.new "Person" + + name = REXML::Attribute.new("name", "John") + attrs = REXML::Attributes.new(p) + attrs.add name + + p.add_attribute name + p.attributes.should == attrs + end + + it "returns an empty hash if element has no attributes" do + REXML::Element.new("Person").attributes.should == {} + end + end +end diff --git a/spec/ruby/library/rexml/element/cdatas_spec.rb b/spec/ruby/library/rexml/element/cdatas_spec.rb new file mode 100644 index 0000000000..988b2cb422 --- /dev/null +++ b/spec/ruby/library/rexml/element/cdatas_spec.rb @@ -0,0 +1,27 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#cdatas" do + before :each do + @e = REXML::Element.new("Root") + end + + it "returns the array of children cdatas" do + c = REXML::CData.new("Primary") + d = REXML::CData.new("Secondary") + @e << c + @e << d + @e.cdatas.should == [c, d] + end + + it "freezes the returned array" do + @e.cdatas.should.frozen? + end + + it "returns an empty array if element has no cdata" do + @e.cdatas.should == [] + end + end +end diff --git a/spec/ruby/library/rexml/element/clone_spec.rb b/spec/ruby/library/rexml/element/clone_spec.rb new file mode 100644 index 0000000000..490e43181f --- /dev/null +++ b/spec/ruby/library/rexml/element/clone_spec.rb @@ -0,0 +1,32 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#clone" do + before :each do + @e = REXML::Element.new "a" + end + it "creates a copy of element" do + @e.clone.to_s.should == @e.to_s + end + + it "copies the attributes" do + @e.add_attribute("foo", "bar") + @e.clone.to_s.should == @e.to_s + end + + it "does not copy the text" do + @e.add_text "some text..." + @e.clone.to_s.should_not == @e + @e.clone.to_s.should == "<a/>" + end + + it "does not copy the child elements" do + b = REXML::Element.new "b" + @e << b + @e.clone.should_not == @e + @e.clone.to_s.should == "<a/>" + end + end +end diff --git a/spec/ruby/library/rexml/element/comments_spec.rb b/spec/ruby/library/rexml/element/comments_spec.rb new file mode 100644 index 0000000000..84ab9a7469 --- /dev/null +++ b/spec/ruby/library/rexml/element/comments_spec.rb @@ -0,0 +1,23 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#comments" do + before :each do + @e = REXML::Element.new "root" + @c1 = REXML::Comment.new "this is a comment" + @c2 = REXML::Comment.new "this is another comment" + @e << @c1 + @e << @c2 + end + + it "returns the array of comments" do + @e.comments.should == [@c1, @c2] + end + + it "returns a frozen object" do + @e.comments.should.frozen? + end + end +end diff --git a/spec/ruby/library/rexml/element/delete_attribute_spec.rb b/spec/ruby/library/rexml/element/delete_attribute_spec.rb new file mode 100644 index 0000000000..e2ba81eb0d --- /dev/null +++ b/spec/ruby/library/rexml/element/delete_attribute_spec.rb @@ -0,0 +1,42 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#delete_attribute" do + before :each do + @e = REXML::Element.new("Person") + @attr = REXML::Attribute.new("name", "Sean") + @e.add_attribute(@attr) + end + + it "deletes an attribute from the element" do + @e.delete_attribute("name") + @e.attributes["name"].should be_nil + end + + # Bug was filled with a patch in Ruby's tracker #20298 + quarantine! do + it "receives an Attribute" do + @e.add_attribute(@attr) + @e.delete_attribute(@attr) + @e.attributes["name"].should be_nil + end + end + + # Docs say that it returns the removed attribute but then examples + # show it returns the element with the attribute removed. + # Also fixed in #20298 + it "returns the element with the attribute removed" do + elem = @e.delete_attribute("name") + elem.attributes.should be_empty + elem.to_s.should eql("<Person/>") + end + + it "returns nil if the attribute does not exist" do + @e.delete_attribute("name") + at = @e.delete_attribute("name") + at.should be_nil + end + end +end diff --git a/spec/ruby/library/rexml/element/delete_element_spec.rb b/spec/ruby/library/rexml/element/delete_element_spec.rb new file mode 100644 index 0000000000..c0b486a6f7 --- /dev/null +++ b/spec/ruby/library/rexml/element/delete_element_spec.rb @@ -0,0 +1,52 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#delete_element" do + before :each do + @root = REXML::Element.new("root") + end + + it "deletes the child element" do + node = REXML::Element.new("some_node") + @root.add_element node + @root.delete_element node + @root.elements.size.should == 0 + end + + it "deletes a child via XPath" do + @root.add_element "some_node" + @root.delete_element "some_node" + @root.elements.size.should == 0 + end + + it "deletes the child at index" do + @root.add_element "some_node" + @root.delete_element 1 + @root.elements.size.should == 0 + end + + # According to the docs this should return the deleted element + # but it won't if it's an Element. + it "deletes Element and returns it" do + node = REXML::Element.new("some_node") + @root.add_element node + del_node = @root.delete_element node + del_node.should == node + end + + # Note how passing the string will return the removed element + # but passing the Element as above won't. + it "deletes an element and returns it" do + node = REXML::Element.new("some_node") + @root.add_element node + del_node = @root.delete_element "some_node" + del_node.should == node + end + + it "returns nil unless element exists" do + @root.delete_element("something").should == nil + end + end +end diff --git a/spec/ruby/library/rexml/element/delete_namespace_spec.rb b/spec/ruby/library/rexml/element/delete_namespace_spec.rb new file mode 100644 index 0000000000..a7763d51e8 --- /dev/null +++ b/spec/ruby/library/rexml/element/delete_namespace_spec.rb @@ -0,0 +1,28 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#delete_namespace" do + + before :each do + @doc = REXML::Document.new "<a xmlns:foo='bar' xmlns='twiddle'/>" + end + + it "deletes a namespace from the element" do + @doc.root.delete_namespace 'foo' + @doc.root.namespace("foo").should be_nil + @doc.root.to_s.should == "<a xmlns='twiddle'/>" + end + + it "deletes default namespace when called with no args" do + @doc.root.delete_namespace + @doc.root.namespace.should be_empty + @doc.root.to_s.should == "<a xmlns:foo='bar'/>" + end + + it "returns the element" do + @doc.root.delete_namespace.should == @doc.root + end + end +end diff --git a/spec/ruby/library/rexml/element/document_spec.rb b/spec/ruby/library/rexml/element/document_spec.rb new file mode 100644 index 0000000000..754f27d8a0 --- /dev/null +++ b/spec/ruby/library/rexml/element/document_spec.rb @@ -0,0 +1,19 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#document" do + + it "returns the element's document" do + d = REXML::Document.new("<root><elem/></root>") + d << REXML::XMLDecl.new + d.root.document.should == d + d.root.document.to_s.should == d.to_s + end + + it "returns nil if it belongs to no document" do + REXML::Element.new("standalone").document.should be_nil + end + end +end diff --git a/spec/ruby/library/rexml/element/each_element_with_attribute_spec.rb b/spec/ruby/library/rexml/element/each_element_with_attribute_spec.rb new file mode 100644 index 0000000000..dcc6dbbf17 --- /dev/null +++ b/spec/ruby/library/rexml/element/each_element_with_attribute_spec.rb @@ -0,0 +1,38 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#each_element_with_attributes" do + before :each do + @document = REXML::Element.new("people") + @father = REXML::Element.new("Person") + @father.attributes["name"] = "Joe" + @son = REXML::Element.new("Child") + @son.attributes["name"] = "Fred" + @document.root << @father + @document.root << @son + @children = [] + end + + it "returns children with attribute" do + @document.each_element_with_attribute("name") { |elem| @children << elem } + @children[0].should == @father + @children[1].should == @son + end + + it "takes attribute value as second argument" do + @document.each_element_with_attribute("name", "Fred"){ |elem| elem.should == @son } + end + + it "takes max number of children as third argument" do + @document.each_element_with_attribute("name", nil, 1) { |elem| @children << elem } + @children.size.should == 1 + @children[0].should == @father + end + + it "takes XPath filter as fourth argument" do + @document.each_element_with_attribute("name", nil, 0, "Child"){ |elem| elem.should == @son} + end + end +end diff --git a/spec/ruby/library/rexml/element/each_element_with_text_spec.rb b/spec/ruby/library/rexml/element/each_element_with_text_spec.rb new file mode 100644 index 0000000000..a4a200d237 --- /dev/null +++ b/spec/ruby/library/rexml/element/each_element_with_text_spec.rb @@ -0,0 +1,34 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#each_element_with_text" do + before :each do + @document = REXML::Element.new("people") + + @joe = REXML::Element.new("Person") + @joe.text = "Joe" + @fred = REXML::Element.new("Person") + @fred.text = "Fred" + @another = REXML::Element.new("AnotherPerson") + @another.text = "Fred" + @document.root << @joe + @document.root << @fred + @document.root << @another + @children = [] + end + + it "returns children with text" do + @document.each_element_with_text("Joe"){|c| c.should == @joe} + end + + it "takes max as second argument" do + @document.each_element_with_text("Fred", 1){ |c| c.should == @fred} + end + + it "takes XPath filter as third argument" do + @document.each_element_with_text("Fred", 0, "Person"){ |c| c.should == @fred} + end + end +end diff --git a/spec/ruby/library/rexml/element/element_reference_spec.rb b/spec/ruby/library/rexml/element/element_reference_spec.rb new file mode 100644 index 0000000000..9e5d371ce4 --- /dev/null +++ b/spec/ruby/library/rexml/element/element_reference_spec.rb @@ -0,0 +1,23 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#[]" do + + before :each do + @doc = REXML::Document.new("<root foo='bar'></root>") + @child = REXML::Element.new("child") + @doc.root.add_element @child + end + + it "return attribute value if argument is string or symbol" do + @doc.root[:foo].should == 'bar' + @doc.root['foo'].should == 'bar' + end + + it "return nth element if argument is int" do + @doc.root[0].should == @child + end + end +end diff --git a/spec/ruby/library/rexml/element/get_text_spec.rb b/spec/ruby/library/rexml/element/get_text_spec.rb new file mode 100644 index 0000000000..0fa8d7cb3f --- /dev/null +++ b/spec/ruby/library/rexml/element/get_text_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#get_text" do + before :each do + @doc = REXML::Document.new "<p>some text<b>this is bold!</b> more text</p>" + end + + it "returns the first text child node" do + @doc.root.get_text.value.should == "some text" + @doc.root.get_text.should be_kind_of(REXML::Text) + end + + it "returns text from an element matching path" do + @doc.root.get_text("b").value.should == "this is bold!" + @doc.root.get_text("b").should be_kind_of(REXML::Text) + end + end +end diff --git a/spec/ruby/library/rexml/element/has_attributes_spec.rb b/spec/ruby/library/rexml/element/has_attributes_spec.rb new file mode 100644 index 0000000000..af3ce8ce1b --- /dev/null +++ b/spec/ruby/library/rexml/element/has_attributes_spec.rb @@ -0,0 +1,20 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#has_attributes?" do + before :each do + @e = REXML::Element.new("test_elem") + end + + it "returns true when element has any attributes" do + @e.add_attribute("name", "Joe") + @e.has_attributes?.should be_true + end + + it "returns false if element has no attributes" do + @e.has_attributes?.should be_false + end + end +end diff --git a/spec/ruby/library/rexml/element/has_elements_spec.rb b/spec/ruby/library/rexml/element/has_elements_spec.rb new file mode 100644 index 0000000000..04c7fe01a5 --- /dev/null +++ b/spec/ruby/library/rexml/element/has_elements_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#has_elements?" do + before :each do + @e = REXML::Element.new("root") + end + + it "returns true if element has child elements" do + child = REXML::Element.new("child") + @e << child + @e.has_elements?.should be_true + end + + it "returns false if element doesn't have child elements" do + @e.has_elements?.should be_false + end + end +end diff --git a/spec/ruby/library/rexml/element/has_text_spec.rb b/spec/ruby/library/rexml/element/has_text_spec.rb new file mode 100644 index 0000000000..206c167ae6 --- /dev/null +++ b/spec/ruby/library/rexml/element/has_text_spec.rb @@ -0,0 +1,19 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#has_text?" do + + it "returns true if element has a Text child" do + e = REXML::Element.new("Person") + e.text = "My text" + e.has_text?.should be_true + end + + it "returns false if it has no Text children" do + e = REXML::Element.new("Person") + e.has_text?.should be_false + end + end +end diff --git a/spec/ruby/library/rexml/element/inspect_spec.rb b/spec/ruby/library/rexml/element/inspect_spec.rb new file mode 100644 index 0000000000..ec16c136ee --- /dev/null +++ b/spec/ruby/library/rexml/element/inspect_spec.rb @@ -0,0 +1,30 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#inspect" do + + before :each do + @name = REXML::Element.new "name" + end + + it "returns the node as a string" do + @name.inspect.should == "<name/>" + end + + it "inserts '...' if the node has children" do + e = REXML::Element.new "last_name" + @name << e + @name.inspect.should == "<name> ... </>" + # This might make more sense but differs from MRI's default behavior + # @name.inspect.should == "<name> ... </name>" + end + + it "inserts the attributes in the string" do + @name.add_attribute "language" + @name.attributes["language"] = "english" + @name.inspect.should == "<name language='english'/>" + end + end +end diff --git a/spec/ruby/library/rexml/element/instructions_spec.rb b/spec/ruby/library/rexml/element/instructions_spec.rb new file mode 100644 index 0000000000..11f1396df0 --- /dev/null +++ b/spec/ruby/library/rexml/element/instructions_spec.rb @@ -0,0 +1,24 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#instructions" do + before :each do + @elem = REXML::Element.new("root") + end + it "returns the Instruction children nodes" do + inst = REXML::Instruction.new("xml-stylesheet", "href='headlines.css'") + @elem << inst + @elem.instructions.first.should == inst + end + + it "returns an empty array if it has no Instruction children" do + @elem.instructions.should be_empty + end + + it "freezes the returned array" do + @elem.instructions.frozen?.should be_true + end + end +end diff --git a/spec/ruby/library/rexml/element/namespace_spec.rb b/spec/ruby/library/rexml/element/namespace_spec.rb new file mode 100644 index 0000000000..28966289c5 --- /dev/null +++ b/spec/ruby/library/rexml/element/namespace_spec.rb @@ -0,0 +1,30 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#namespace" do + before :each do + @doc = REXML::Document.new("<a xmlns='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>") + @elem = @doc.elements["//b"] + end + + it "returns the default namespace" do + @elem.namespace.should == "1" + end + + it "accepts a namespace prefix" do + @elem.namespace("y").should == "2" + @doc.elements["//c"].namespace("z").should == "3" + end + + it "returns an empty String if default namespace is not defined" do + e = REXML::Document.new("<a/>") + e.root.namespace.should be_empty + end + + it "returns nil if namespace is not defined" do + @elem.namespace("z").should be_nil + end + end +end diff --git a/spec/ruby/library/rexml/element/namespaces_spec.rb b/spec/ruby/library/rexml/element/namespaces_spec.rb new file mode 100644 index 0000000000..4544540173 --- /dev/null +++ b/spec/ruby/library/rexml/element/namespaces_spec.rb @@ -0,0 +1,35 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#namespaces" do + before :each do + doc = REXML::Document.new("<a xmlns='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>") + @elem = doc.elements["//c"] + end + + it "returns a hash of the namespaces" do + ns = {"y"=>"2", "z"=>"3", "xmlns"=>"1"} + @elem.namespaces.keys.sort.should == ns.keys.sort + @elem.namespaces.values.sort.should == ns.values.sort + end + + it "returns an empty hash if no namespaces exist" do + e = REXML::Element.new "element" + e.namespaces.kind_of?(Hash).should == true + e.namespaces.should be_empty + end + + it "uses namespace prefixes as keys" do + prefixes = ["y", "z", "xmlns"] + @elem.namespaces.keys.sort.should == prefixes.sort + end + + it "uses namespace values as the hash values" do + values = ["2", "3", "1"] + @elem.namespaces.values.sort.should == values.sort + end + + end +end diff --git a/spec/ruby/library/rexml/element/new_spec.rb b/spec/ruby/library/rexml/element/new_spec.rb new file mode 100644 index 0000000000..c6ab289476 --- /dev/null +++ b/spec/ruby/library/rexml/element/new_spec.rb @@ -0,0 +1,38 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#new" do + + it "creates element from tag name" do + REXML::Element.new("foo").name.should == "foo" + end + + it "creates element with default attributes" do + e = REXML::Element.new + e.name.should == REXML::Element::UNDEFINED + e.context.should == nil + e.parent.should == nil + end + + it "creates element from another element" do + e = REXML::Element.new "foo" + f = REXML::Element.new e + e.name.should == f.name + e.context.should == f.context + e.parent.should == f.parent + end + + it "takes parent as second argument" do + parent = REXML::Element.new "foo" + child = REXML::Element.new "bar", parent + child.parent.should == parent + end + + it "takes context as third argument" do + context = {"some_key" => "some_value"} + REXML::Element.new("foo", nil, context).context.should == context + end + end +end diff --git a/spec/ruby/library/rexml/element/next_element_spec.rb b/spec/ruby/library/rexml/element/next_element_spec.rb new file mode 100644 index 0000000000..46d8f74760 --- /dev/null +++ b/spec/ruby/library/rexml/element/next_element_spec.rb @@ -0,0 +1,22 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#next_element" do + before :each do + @a = REXML::Element.new "a" + @b = REXML::Element.new "b" + @c = REXML::Element.new "c" + @a.root << @b + @a.root << @c + end + it "returns next existing element" do + @a.elements["b"].next_element.should == @c + end + + it "returns nil on last element" do + @a.elements["c"].next_element.should == nil + end + end +end diff --git a/spec/ruby/library/rexml/element/node_type_spec.rb b/spec/ruby/library/rexml/element/node_type_spec.rb new file mode 100644 index 0000000000..a39c2deca5 --- /dev/null +++ b/spec/ruby/library/rexml/element/node_type_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#node_type" do + it "returns :element" do + REXML::Element.new("MyElem").node_type.should == :element + end + end +end diff --git a/spec/ruby/library/rexml/element/prefixes_spec.rb b/spec/ruby/library/rexml/element/prefixes_spec.rb new file mode 100644 index 0000000000..ea4caab4bc --- /dev/null +++ b/spec/ruby/library/rexml/element/prefixes_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#prefixes" do + before :each do + doc = REXML::Document.new("<a xmlns='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>") + @elem = doc.elements["//c"] + end + + it "returns an array of the prefixes of the namespaces" do + @elem.prefixes.should == ["y", "z"] + end + + it "does not include the default namespace" do + @elem.prefixes.include?("xmlns").should == false + end + + it "returns an empty array if no namespace was defined" do + doc = REXML::Document.new "<root><something/></root>" + root = doc.elements["//root"] + root.prefixes.should == [] + end + end +end diff --git a/spec/ruby/library/rexml/element/previous_element_spec.rb b/spec/ruby/library/rexml/element/previous_element_spec.rb new file mode 100644 index 0000000000..a43b1ddd10 --- /dev/null +++ b/spec/ruby/library/rexml/element/previous_element_spec.rb @@ -0,0 +1,23 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#previous_element" do + before :each do + @a = REXML::Element.new "a" + @b = REXML::Element.new "b" + @c = REXML::Element.new "c" + @a.root << @b + @a.root << @c + end + + it "returns previous element" do + @a.elements["c"].previous_element.should == @b + end + + it "returns nil on first element" do + @a.elements["b"].previous_element.should == nil + end + end +end diff --git a/spec/ruby/library/rexml/element/raw_spec.rb b/spec/ruby/library/rexml/element/raw_spec.rb new file mode 100644 index 0000000000..200a99d194 --- /dev/null +++ b/spec/ruby/library/rexml/element/raw_spec.rb @@ -0,0 +1,27 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#raw" do + it "returns true if raw mode is set to all" do + REXML::Element.new("MyElem", nil, {raw: :all}).raw.should == true + end + + it "returns true if raw mode is set to expanded_name" do + REXML::Element.new("MyElem", nil, {raw: "MyElem"}).raw.should == true + end + + it "returns false if raw mode is not set" do + REXML::Element.new("MyElem", nil, {raw: ""}).raw.should == false + end + + it "returns false if raw is not :all or expanded_name" do + REXML::Element.new("MyElem", nil, {raw: "Something"}).raw.should == false + end + + it "returns nil if context is not set" do + REXML::Element.new("MyElem").raw.should == nil + end + end +end diff --git a/spec/ruby/library/rexml/element/root_spec.rb b/spec/ruby/library/rexml/element/root_spec.rb new file mode 100644 index 0000000000..52aa4571b9 --- /dev/null +++ b/spec/ruby/library/rexml/element/root_spec.rb @@ -0,0 +1,31 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#root" do + before :each do + @doc = REXML::Document.new + @root = REXML::Element.new "root" + @node = REXML::Element.new "node" + @doc << @root << @node + end + + it "returns first child on documents" do + @doc.root.should == @root + end + + it "returns self on root nodes" do + @root.root.should == @root + end + + it "returns parent's root on child nodes" do + @node.root.should == @root + end + + it "returns self on standalone nodes" do + e = REXML::Element.new "Elem" # Note that it doesn't have a parent node + e.root.should == e + end + end +end diff --git a/spec/ruby/library/rexml/element/text_spec.rb b/spec/ruby/library/rexml/element/text_spec.rb new file mode 100644 index 0000000000..3234bba153 --- /dev/null +++ b/spec/ruby/library/rexml/element/text_spec.rb @@ -0,0 +1,49 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#text" do + before :each do + @e = REXML::Element.new "name" + @e.text = "John" + end + + it "returns the text node of element" do + @e.text.should == "John" + end + + it "returns the text node value" do + t = REXML::Text.new "Joe" + @e.text = t + @e.text.should == "Joe" + @e.text.should_not == t + end + + it "returns nil if no text is attached" do + elem = REXML::Element.new "name" + elem.text.should == nil + end + end + + describe "REXML::Element#text=" do + before :each do + @e = REXML::Element.new "name" + @e.text = "John" + end + + it "sets the text node" do + @e.to_s.should == "<name>John</name>" + end + + it "replaces existing text" do + @e.text = "Joe" + @e.to_s.should == "<name>Joe</name>" + end + + it "receives nil as an argument" do + @e.text = nil + @e.to_s.should == "<name/>" + end + end +end diff --git a/spec/ruby/library/rexml/element/texts_spec.rb b/spec/ruby/library/rexml/element/texts_spec.rb new file mode 100644 index 0000000000..2d374d5e66 --- /dev/null +++ b/spec/ruby/library/rexml/element/texts_spec.rb @@ -0,0 +1,19 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#texts" do + + it "returns an array of the Text children" do + e = REXML::Element.new("root") + e.add_text "First" + e.add_text "Second" + e.texts.should == ["FirstSecond"] + end + + it "returns an empty array if it has no Text children" do + REXML::Element.new("root").texts.should == [] + end + end +end diff --git a/spec/ruby/library/rexml/element/whitespace_spec.rb b/spec/ruby/library/rexml/element/whitespace_spec.rb new file mode 100644 index 0000000000..f455067922 --- /dev/null +++ b/spec/ruby/library/rexml/element/whitespace_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Element#whitespace" do + it "returns true if whitespace is respected in the element" do + e = REXML::Element.new("root") + e.whitespace.should be_true + + e = REXML::Element.new("root", nil, respect_whitespace: :all) + e.whitespace.should be_true + + e = REXML::Element.new("root", nil, respect_whitespace: ["root"]) + e.whitespace.should be_true + end + + it "returns false if whitespace is ignored inside element" do + e = REXML::Element.new("root", nil, compress_whitespace: :all) + e.whitespace.should be_false + + e = REXML::Element.new("root", nil, compress_whitespace: ["root"]) + e.whitespace.should be_false + end + end +end diff --git a/spec/ruby/library/rexml/node/each_recursive_spec.rb b/spec/ruby/library/rexml/node/each_recursive_spec.rb new file mode 100644 index 0000000000..da347b1389 --- /dev/null +++ b/spec/ruby/library/rexml/node/each_recursive_spec.rb @@ -0,0 +1,24 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Node#each_recursive" do + before :each do + @doc = REXML::Document.new + @doc << REXML::XMLDecl.new + @root = REXML::Element.new "root" + @child1 = REXML::Element.new "child1" + @child2 = REXML::Element.new "child2" + @root << @child1 + @root << @child2 + @doc << @root + end + + it "visits all subnodes of self" do + nodes = [] + @doc.each_recursive { |node| nodes << node} + nodes.should == [@root, @child1, @child2] + end + end +end diff --git a/spec/ruby/library/rexml/node/find_first_recursive_spec.rb b/spec/ruby/library/rexml/node/find_first_recursive_spec.rb new file mode 100644 index 0000000000..2a4f1097ae --- /dev/null +++ b/spec/ruby/library/rexml/node/find_first_recursive_spec.rb @@ -0,0 +1,28 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Node#find_first_recursive" do + before :each do + @e = REXML::Element.new("root") + @node1 = REXML::Element.new("node") + @node2 = REXML::Element.new("another node") + @subnode = REXML::Element.new("another node") + @node1 << @subnode + @e << @node1 + @e << @node2 + end + + it "finds the first element that matches block" do + found = @e.find_first_recursive { |n| n.to_s == "<node><another node/></node>"} + found.should == @node1 + end + + it "visits the nodes in preorder" do + found = @e.find_first_recursive { |n| n.to_s == "<another node/>"} + found.should == @subnode + found.should_not == @node2 + end + end +end diff --git a/spec/ruby/library/rexml/node/index_in_parent_spec.rb b/spec/ruby/library/rexml/node/index_in_parent_spec.rb new file mode 100644 index 0000000000..55909f86d6 --- /dev/null +++ b/spec/ruby/library/rexml/node/index_in_parent_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Node#index_in_parent" do + it "returns the index (starting from 1) of self in parent" do + e = REXML::Element.new("root") + node1 = REXML::Element.new("node") + node2 = REXML::Element.new("another node") + e << node1 + e << node2 + + node1.index_in_parent.should == 1 + node2.index_in_parent.should == 2 + end + end +end diff --git a/spec/ruby/library/rexml/node/next_sibling_node_spec.rb b/spec/ruby/library/rexml/node/next_sibling_node_spec.rb new file mode 100644 index 0000000000..7aae861d75 --- /dev/null +++ b/spec/ruby/library/rexml/node/next_sibling_node_spec.rb @@ -0,0 +1,24 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Node#next_sibling_node" do + before :each do + @e = REXML::Element.new("root") + @node1 = REXML::Element.new("node") + @node2 = REXML::Element.new("another node") + @e << @node1 + @e << @node2 + end + + it "returns the next child node in parent" do + @node1.next_sibling_node.should == @node2 + end + + it "returns nil if there are no more child nodes next" do + @node2.next_sibling_node.should == nil + @e.next_sibling_node.should == nil + end + end +end diff --git a/spec/ruby/library/rexml/node/parent_spec.rb b/spec/ruby/library/rexml/node/parent_spec.rb new file mode 100644 index 0000000000..43c3a747e0 --- /dev/null +++ b/spec/ruby/library/rexml/node/parent_spec.rb @@ -0,0 +1,23 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Node#parent?" do + it "returns true for Elements" do + e = REXML::Element.new("foo") + e.should.parent? + end + + it "returns true for Documents" do + e = REXML::Document.new + e.should.parent? + end + + # This includes attributes, CData and declarations. + it "returns false for Texts" do + e = REXML::Text.new("foo") + e.should_not.parent? + end + end +end diff --git a/spec/ruby/library/rexml/node/previous_sibling_node_spec.rb b/spec/ruby/library/rexml/node/previous_sibling_node_spec.rb new file mode 100644 index 0000000000..11263968a7 --- /dev/null +++ b/spec/ruby/library/rexml/node/previous_sibling_node_spec.rb @@ -0,0 +1,24 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Node#previous_sibling_node" do + before :each do + @e = REXML::Element.new("root") + @node1 = REXML::Element.new("node") + @node2 = REXML::Element.new("another node") + @e << @node1 + @e << @node2 + end + + it "returns the previous child node in parent" do + @node2.previous_sibling_node.should == @node1 + end + + it "returns nil if there are no more child nodes before" do + @node1.previous_sibling_node.should == nil + @e.previous_sibling_node.should == nil + end + end +end diff --git a/spec/ruby/library/rexml/shared/each_element.rb b/spec/ruby/library/rexml/shared/each_element.rb new file mode 100644 index 0000000000..2e0871161d --- /dev/null +++ b/spec/ruby/library/rexml/shared/each_element.rb @@ -0,0 +1,36 @@ +require 'rexml/document' +require_relative '../../../spec_helper' + +describe :rexml_each_element, shared: true do + before :each do + @e = REXML::Element.new "root" + s1 = REXML::Element.new "node1" + s2 = REXML::Element.new "node2" + s3 = REXML::Element.new "node3" + s4 = REXML::Element.new "sub_node" + @e << s1 + @e << s2 + @e << s3 + @e << s4 + end + + it "iterates through element" do + str = "" + @e.send(@method) { |elem| str << elem.name << " " } + str.should == "node1 node2 node3 sub_node " + end + + it "iterates through element filtering with XPath" do + str = "" + @e.send(@method, "/*"){ |e| str << e.name << " "} + str.should == "node1 node2 node3 sub_node " + end +end + +describe "REXML::Element#each_element" do + it_behaves_like :rexml_each_element, :each_element +end + +describe "REXML::Elements#each" do + it_behaves_like :rexml_each_element, :each +end diff --git a/spec/ruby/library/rexml/shared/elements_to_a.rb b/spec/ruby/library/rexml/shared/elements_to_a.rb new file mode 100644 index 0000000000..b7169f0b2e --- /dev/null +++ b/spec/ruby/library/rexml/shared/elements_to_a.rb @@ -0,0 +1,34 @@ +require 'rexml/document' +require_relative '../../../spec_helper' + +describe :rexml_elements_to_a, shared: true do + before :each do + @e = REXML::Element.new "root" + @first = REXML::Element.new("FirstChild") + @second = REXML::Element.new("SecondChild") + @e << @first + @e << @second + end + + it "returns elements that match xpath" do + @e.elements.send(@method, "FirstChild").first.should == @first + end + + # According to the docs REXML::Element#get_elements is an alias for + # REXML::Elements.to_a. Implementation wise there's a difference, get_elements + # always needs the first param (even if it's nil). + # A patch was submitted: + # http://rubyforge.org/tracker/index.php?func=detail&aid=19354&group_id=426&atid=1698 + it "returns all children if xpath is nil" do + @e.elements.send(@method).should == [@first, @second] + end + +end + +describe "REXML::REXML::Elements#to_a" do + it_behaves_like :rexml_elements_to_a, :to_a +end + +describe "REXML::REXML::Element#get_elements" do + it_behaves_like :rexml_elements_to_a, :get_elements +end diff --git a/spec/ruby/library/rexml/text/append_spec.rb b/spec/ruby/library/rexml/text/append_spec.rb new file mode 100644 index 0000000000..5e7a5bae7c --- /dev/null +++ b/spec/ruby/library/rexml/text/append_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text#<<" do + it "appends a string to this text node" do + text = REXML::Text.new("foo") + text << "bar" + text.should == "foobar" + end + end +end diff --git a/spec/ruby/library/rexml/text/clone_spec.rb b/spec/ruby/library/rexml/text/clone_spec.rb new file mode 100644 index 0000000000..7801782ff5 --- /dev/null +++ b/spec/ruby/library/rexml/text/clone_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text#clone" do + it "creates a copy of this node" do + text = REXML::Text.new("foo") + text.clone.should == "foo" + text.clone.should == text + end + end +end diff --git a/spec/ruby/library/rexml/text/comparison_spec.rb b/spec/ruby/library/rexml/text/comparison_spec.rb new file mode 100644 index 0000000000..119dd050a6 --- /dev/null +++ b/spec/ruby/library/rexml/text/comparison_spec.rb @@ -0,0 +1,28 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text#<=>" do + before :each do + @first = REXML::Text.new("abc") + @last = REXML::Text.new("def") + end + + it "returns -1 if lvalue is less than rvalue" do + val = @first <=> @last + val.should == -1 + end + + it "returns -1 if lvalue is greater than rvalue" do + val = @last <=> @first + val.should == 1 + end + + it "returns 0 if both values are equal" do + tmp = REXML::Text.new("tmp") + val = tmp <=> tmp + val.should == 0 + end + end +end diff --git a/spec/ruby/library/rexml/text/empty_spec.rb b/spec/ruby/library/rexml/text/empty_spec.rb new file mode 100644 index 0000000000..4c9c899bcb --- /dev/null +++ b/spec/ruby/library/rexml/text/empty_spec.rb @@ -0,0 +1,15 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text#empty?" do + it "returns true if the text is empty" do + REXML::Text.new("").should.empty? + end + + it "returns false if the text is not empty" do + REXML::Text.new("some_text").should_not.empty? + end + end +end diff --git a/spec/ruby/library/rexml/text/indent_text_spec.rb b/spec/ruby/library/rexml/text/indent_text_spec.rb new file mode 100644 index 0000000000..73065c37da --- /dev/null +++ b/spec/ruby/library/rexml/text/indent_text_spec.rb @@ -0,0 +1,26 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text#indent_text" do + before :each do + @t = REXML::Text.new("") + end + it "indents a string with default parameters" do + @t.indent_text("foo").should == "\tfoo" + end + + it "accepts a custom indentation level as second argument" do + @t.indent_text("foo", 2, "\t", true).should == "\t\tfoo" + end + + it "accepts a custom separator as third argument" do + @t.indent_text("foo", 1, "\n", true).should == "\nfoo" + end + + it "accepts a fourth parameter to skip the first line" do + @t.indent_text("foo", 1, "\t", false).should == "foo" + end + end +end diff --git a/spec/ruby/library/rexml/text/inspect_spec.rb b/spec/ruby/library/rexml/text/inspect_spec.rb new file mode 100644 index 0000000000..af389890ee --- /dev/null +++ b/spec/ruby/library/rexml/text/inspect_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text#inspect" do + it "inspects the string attribute as a string" do + REXML::Text.new("a text").inspect.should == "a text".inspect + end + end +end diff --git a/spec/ruby/library/rexml/text/new_spec.rb b/spec/ruby/library/rexml/text/new_spec.rb new file mode 100644 index 0000000000..8b33da9294 --- /dev/null +++ b/spec/ruby/library/rexml/text/new_spec.rb @@ -0,0 +1,51 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text.new" do + + it "creates a Text child node with no parent" do + t = REXML::Text.new("test") + t.should be_kind_of(REXML::Child) + t.should == "test" + t.parent.should == nil + end + + it "respects whitespace if second argument is true" do + t = REXML::Text.new("testing whitespace", true) + t.should == "testing whitespace" + t = REXML::Text.new(" ", true) + t.should == " " + end + + it "receives a parent as third argument" do + e = REXML::Element.new("root") + t = REXML::Text.new("test", false, e) + t.parent.should == e + e.to_s.should == "<root>test</root>" + end + + it "expects escaped text if raw is true" do + t = REXML::Text.new("<&>", false, nil, true) + t.should == "<&>" + + ->{ REXML::Text.new("<&>", false, nil, true)}.should raise_error(Exception) + end + + it "uses raw value of the parent if raw is nil" do + e1 = REXML::Element.new("root", nil, { raw: :all}) + -> {REXML::Text.new("<&>", false, e1)}.should raise_error(Exception) + + e2 = REXML::Element.new("root", nil, { raw: []}) + e2.raw.should be_false + t1 = REXML::Text.new("<&>", false, e2) + t1.should == "<&>" + end + + it "escapes the values if raw is false" do + t = REXML::Text.new("<&>", false, nil, false) + t.should == "<&>" + end + end +end diff --git a/spec/ruby/library/rexml/text/node_type_spec.rb b/spec/ruby/library/rexml/text/node_type_spec.rb new file mode 100644 index 0000000000..f44a1ede3e --- /dev/null +++ b/spec/ruby/library/rexml/text/node_type_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text#node_type" do + it "returns :text" do + REXML::Text.new("test").node_type.should == :text + end + end +end diff --git a/spec/ruby/library/rexml/text/normalize_spec.rb b/spec/ruby/library/rexml/text/normalize_spec.rb new file mode 100644 index 0000000000..cde11ec3c9 --- /dev/null +++ b/spec/ruby/library/rexml/text/normalize_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text.normalize" do + it "escapes a string with <, >, &, ' and \" " do + REXML::Text.normalize("< > & \" '").should == "< > & " '" + end + end +end diff --git a/spec/ruby/library/rexml/text/read_with_substitution_spec.rb b/spec/ruby/library/rexml/text/read_with_substitution_spec.rb new file mode 100644 index 0000000000..7ff26f4d53 --- /dev/null +++ b/spec/ruby/library/rexml/text/read_with_substitution_spec.rb @@ -0,0 +1,15 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text.read_with_substitution" do + it "reads a text and escapes entities" do + REXML::Text.read_with_substitution("< > & " '").should == "< > & \" '" + end + + it "accepts an regex for invalid expressions and raises an error if text matches" do + -> {REXML::Text.read_with_substitution("this is illegal", /illegal/)}.should raise_error(Exception) + end + end +end diff --git a/spec/ruby/library/rexml/text/to_s_spec.rb b/spec/ruby/library/rexml/text/to_s_spec.rb new file mode 100644 index 0000000000..e67632c9a1 --- /dev/null +++ b/spec/ruby/library/rexml/text/to_s_spec.rb @@ -0,0 +1,20 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text#to_s" do + it "returns the string of this Text node" do + u = REXML::Text.new("sean russell", false, nil, true) + u.to_s.should == "sean russell" + + t = REXML::Text.new("some test text") + t.to_s.should == "some test text" + end + + it "escapes the text" do + t = REXML::Text.new("& < >") + t.to_s.should == "& < >" + end + end +end diff --git a/spec/ruby/library/rexml/text/unnormalize_spec.rb b/spec/ruby/library/rexml/text/unnormalize_spec.rb new file mode 100644 index 0000000000..7b507194d0 --- /dev/null +++ b/spec/ruby/library/rexml/text/unnormalize_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text.unnormalize" do + it "unescapes a string with the values defined in SETUTITSBUS" do + REXML::Text.unnormalize("< > & " '").should == "< > & \" '" + end + end +end diff --git a/spec/ruby/library/rexml/text/value_spec.rb b/spec/ruby/library/rexml/text/value_spec.rb new file mode 100644 index 0000000000..53d40c765f --- /dev/null +++ b/spec/ruby/library/rexml/text/value_spec.rb @@ -0,0 +1,40 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text#value" do + it "returns the text value of this node" do + REXML::Text.new("test").value.should == "test" + end + + it "does not escape entities" do + REXML::Text.new("& \"").value.should == "& \"" + end + + it "follows the respect_whitespace attribute" do + REXML::Text.new("test bar", false).value.should == "test bar" + REXML::Text.new("test bar", true).value.should == "test bar" + end + + it "ignores the raw attribute" do + REXML::Text.new("sean russell", false, nil, true).value.should == "sean russell" + end + end + + describe "REXML::Text#value=" do + before :each do + @t = REXML::Text.new("new") + end + + it "sets the text of the node" do + @t.value = "another text" + @t.to_s.should == "another text" + end + + it "escapes entities" do + @t.value = "<a>" + @t.to_s.should == "<a>" + end + end +end diff --git a/spec/ruby/library/rexml/text/wrap_spec.rb b/spec/ruby/library/rexml/text/wrap_spec.rb new file mode 100644 index 0000000000..331a8439e2 --- /dev/null +++ b/spec/ruby/library/rexml/text/wrap_spec.rb @@ -0,0 +1,23 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text#wrap" do + before :each do + @t = REXML::Text.new("abc def") + end + + it "wraps the text at width" do + @t.wrap("abc def", 3, false).should == "abc\ndef" + end + + it "returns the string if width is greater than the size of the string" do + @t.wrap("abc def", 10, false).should == "abc def" + end + + it "takes a newline at the beginning option as the third parameter" do + @t.wrap("abc def", 3, true).should == "\nabc\ndef" + end + end +end diff --git a/spec/ruby/library/rexml/text/write_with_substitution_spec.rb b/spec/ruby/library/rexml/text/write_with_substitution_spec.rb new file mode 100644 index 0000000000..840f141e3d --- /dev/null +++ b/spec/ruby/library/rexml/text/write_with_substitution_spec.rb @@ -0,0 +1,36 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Text#write_with_substitution" do + before :each do + @t = REXML::Text.new("test") + @f = tmp("rexml_spec") + @file = File.open(@f, "w+") + end + + after :each do + @file.close + rm_r @f + end + + it "writes out the input to a String" do + s = "" + @t.write_with_substitution(s, "some text") + s.should == "some text" + end + + it "writes out the input to an IO" do + @t.write_with_substitution(@file, "some text") + @file.rewind + @file.gets.should == "some text" + end + + it "escapes characters" do + @t.write_with_substitution(@file, "& < >") + @file.rewind + @file.gets.should == "& < >" + end + end +end diff --git a/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb b/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb index 9b37eaa43c..58913cddab 100644 --- a/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb +++ b/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb @@ -3,7 +3,7 @@ require 'rubygems' describe "Gem.load_path_insert_index" do guard -> { RbConfig::TOPDIR } do - it "is set for an installed Ruby" do + it "is set for an installed an installed Ruby" do Gem.load_path_insert_index.should be_kind_of Integer end end diff --git a/spec/ruby/library/scanf/io/block_scanf_spec.rb b/spec/ruby/library/scanf/io/block_scanf_spec.rb new file mode 100644 index 0000000000..b9cc1b507e --- /dev/null +++ b/spec/ruby/library/scanf/io/block_scanf_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require_relative 'shared/block_scanf' + require 'scanf' + + describe "IO#block_scanf" do + it_behaves_like :scanf_io_block_scanf, :block_scanf + end +end diff --git a/spec/ruby/library/scanf/io/fixtures/date.txt b/spec/ruby/library/scanf/io/fixtures/date.txt new file mode 100644 index 0000000000..a1bd635c0c --- /dev/null +++ b/spec/ruby/library/scanf/io/fixtures/date.txt @@ -0,0 +1,4 @@ +Beethoven 1770 +Bach 1685 +Handel 1685 + diff --git a/spec/ruby/library/scanf/io/fixtures/helloworld.txt b/spec/ruby/library/scanf/io/fixtures/helloworld.txt new file mode 100644 index 0000000000..3b18e512db --- /dev/null +++ b/spec/ruby/library/scanf/io/fixtures/helloworld.txt @@ -0,0 +1 @@ +hello world diff --git a/spec/ruby/library/scanf/io/scanf_spec.rb b/spec/ruby/library/scanf/io/scanf_spec.rb new file mode 100644 index 0000000000..6a3e6d0d1a --- /dev/null +++ b/spec/ruby/library/scanf/io/scanf_spec.rb @@ -0,0 +1,38 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require_relative 'shared/block_scanf' + require 'scanf' + + describe "IO#scanf" do + before :each do + @hw = File.open(fixture(__FILE__, 'helloworld.txt'), 'rb') + @data = File.open(fixture(__FILE__, 'date.txt'), 'rb') + end + + after :each do + @hw.close unless @hw.closed? + @data.close unless @data.closed? + end + + it "returns an array containing the input converted in the specified type" do + @hw.scanf("%s%s").should == ["hello", "world"] + @data.scanf("%s%d").should == ["Beethoven", 1770] + end + + it "returns an array containing the input converted in the specified type with given maximum field width" do + @hw.scanf("%2s").should == ["he"] + @data.scanf("%2c").should == ["Be"] + end + + it "returns an empty array when a wrong specifier is passed" do + @hw.scanf("%a").should == [] + @hw.scanf("%1").should == [] + @data.scanf("abc").should == [] + end + end + + describe "IO#scanf with block" do + it_behaves_like :scanf_io_block_scanf, :scanf + end +end diff --git a/spec/ruby/library/scanf/io/shared/block_scanf.rb b/spec/ruby/library/scanf/io/shared/block_scanf.rb new file mode 100644 index 0000000000..d938f43734 --- /dev/null +++ b/spec/ruby/library/scanf/io/shared/block_scanf.rb @@ -0,0 +1,28 @@ +require 'scanf' + +describe :scanf_io_block_scanf, shared: true do + before :each do + @data = File.open(fixture(__FILE__, 'date.txt'), 'rb') + end + + after :each do + @data.close unless @data.closed? + end + + it "passes each match to the block as an array" do + res = @data.send(@method, "%s%d") { |name, year| "#{name} was born in #{year}." } + res.should == ["Beethoven was born in 1770.", "Bach was born in 1685.", "Handel was born in 1685."] + end + + it "keeps scanning the input and cycling back to the beginning of the input string" do + a = [] + @data.send(@method, "%s"){|w| a << w} + a.should == [["Beethoven"], ["1770"], ["Bach"], ["1685"], ["Handel"], ["1685"]] + end + + it "returns an empty array when a wrong specifier is passed" do + a = [] + @data.send(@method, "%z"){|w| a << w} + a.empty?.should be_true + end +end diff --git a/spec/ruby/library/scanf/string/block_scanf_spec.rb b/spec/ruby/library/scanf/string/block_scanf_spec.rb new file mode 100644 index 0000000000..277e1fa1d7 --- /dev/null +++ b/spec/ruby/library/scanf/string/block_scanf_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require_relative 'shared/block_scanf' + require 'scanf' + + describe "String#block_scanf" do + it_behaves_like :scanf_string_block_scanf, :block_scanf + end +end diff --git a/spec/ruby/library/scanf/string/scanf_spec.rb b/spec/ruby/library/scanf/string/scanf_spec.rb new file mode 100644 index 0000000000..c8897db675 --- /dev/null +++ b/spec/ruby/library/scanf/string/scanf_spec.rb @@ -0,0 +1,56 @@ +require_relative '../../../spec_helper' + +ruby_version_is ''...'2.7' do + require_relative 'shared/block_scanf' + require 'scanf' + + describe "String#scanf" do + it "returns an array containing the input converted in the specified type" do + "hello world".scanf("%s").should == ["hello"] + "hello world".scanf("%s%d").should == ["hello"] + "hello world".scanf("%s%c").should == ["hello", " "] + "hello world".scanf("%c%s").should == ["h", "ello"] + "hello world".scanf("%s%s").should == ["hello", "world"] + "hello world".scanf("%c").should == ["h"] + "123".scanf("%s").should == ["123"] + "123".scanf("%c").should == ["1"] + "123".scanf("%d").should == [123] + "123".scanf("%u").should == [123] + "123".scanf("%o").should == [83] + "123".scanf("%x").should == [291] + "123".scanf("%i").should == [123] + "0123".scanf("%i").should == [83] + "123".scanf("%f").should == [123.0] + "0X123".scanf("%i").should == [291] + "0x123".scanf("%i").should == [291] + end + + it "returns an array containing the input converted in the specified type with given maximum field width" do + "hello world".scanf("%2s").should == ["he"] + "hello world".scanf("%2c").should == ["he"] + "123".scanf("%2s").should == ["12"] + "123".scanf("%2c").should == ["12"] + "123".scanf("%2d").should == [12] + "123".scanf("%2u").should == [12] + "123".scanf("%2o").should == [10] + "123".scanf("%2x").should == [18] + "123".scanf("%2i").should == [12] + "0123".scanf("%2i").should == [1] + "123".scanf("%2f").should == [12.0] + "0X123".scanf("%2i").should == [0] + "0X123".scanf("%3i").should == [1] + "0X123".scanf("%4i").should == [18] + end + + it "returns an empty array when a wrong specifier is passed" do + "hello world".scanf("%a").should == [] + "123".scanf("%1").should == [] + "123".scanf("abc").should == [] + "123".scanf(:d).should == [] + end + end + + describe "String#scanf with block" do + it_behaves_like :scanf_string_block_scanf, :scanf + end +end diff --git a/spec/ruby/library/scanf/string/shared/block_scanf.rb b/spec/ruby/library/scanf/string/shared/block_scanf.rb new file mode 100644 index 0000000000..25ab3f442a --- /dev/null +++ b/spec/ruby/library/scanf/string/shared/block_scanf.rb @@ -0,0 +1,25 @@ +require 'scanf' + +describe :scanf_string_block_scanf, shared: true do + it "passes each match to the block as an array" do + a = [] + "hello world".send(@method, "%s%s"){|w| a << w} + a.should == [["hello", "world"]] + end + + it "keeps scanning the input and cycling back to the beginning of the input string" do + a = [] + "hello world".send(@method, "%s"){|w| a << w} + a.should == [["hello"], ["world"]] + + string = "123 abc 456 def 789 ghi" + s = string.send(@method, "%d%s"){|num,str| [num * 2, str.upcase]} + s.should == [[246, "ABC"], [912, "DEF"], [1578, "GHI"]] + end + + it "returns an empty array when a wrong specifier is passed" do + a = [] + "hello world".send(@method, "%z"){|w| a << w} + a.empty?.should be_true + end +end diff --git a/spec/ruby/library/set/comparison_spec.rb b/spec/ruby/library/set/comparison_spec.rb index ddcfbae0af..b851ea3d57 100644 --- a/spec/ruby/library/set/comparison_spec.rb +++ b/spec/ruby/library/set/comparison_spec.rb @@ -1,27 +1,29 @@ -require_relative '../../spec_helper' -require 'set' - -describe "Set#<=>" do - it "returns 0 if the sets are equal" do - (Set[] <=> Set[]).should == 0 - (Set[:a, :b, :c] <=> Set[:a, :b, :c]).should == 0 - end - - it "returns -1 if the set is a proper subset of the other set" do - (Set[] <=> Set[1]).should == -1 - (Set[1, 2] <=> Set[1, 2, 3]).should == -1 - end - - it "returns +1 if the set is a proper superset of other set" do - (Set[1] <=> Set[]).should == +1 - (Set[1, 2, 3] <=> Set[1, 2]).should == +1 - end - - it "returns nil if the set has unique elements" do - (Set[1, 2, 3] <=> Set[:a, :b, :c]).should be_nil - end - - it "returns nil when the argument is not set-like" do - (Set[] <=> false).should be_nil - end -end +require_relative '../../spec_helper'
+require 'set'
+
+ruby_version_is "3.0" do
+ describe "Set#<=>" do
+ it "returns 0 if the sets are equal" do
+ (Set[] <=> Set[]).should == 0
+ (Set[:a, :b, :c] <=> Set[:a, :b, :c]).should == 0
+ end
+
+ it "returns -1 if the set is a proper subset of the other set" do
+ (Set[] <=> Set[1]).should == -1
+ (Set[1, 2] <=> Set[1, 2, 3]).should == -1
+ end
+
+ it "returns +1 if the set is a proper superset of other set" do
+ (Set[1] <=> Set[]).should == +1
+ (Set[1, 2, 3] <=> Set[1, 2]).should == +1
+ end
+
+ it "returns nil if the set has unique elements" do
+ (Set[1, 2, 3] <=> Set[:a, :b, :c]).should be_nil
+ end
+
+ it "returns nil when the argument is not set-like" do
+ (Set[] <=> false).should be_nil
+ end
+ end
+end
diff --git a/spec/ruby/library/set/divide_spec.rb b/spec/ruby/library/set/divide_spec.rb index 998a1b292c..fdd8cd9622 100644 --- a/spec/ruby/library/set/divide_spec.rb +++ b/spec/ruby/library/set/divide_spec.rb @@ -13,11 +13,11 @@ describe "Set#divide" do ret.sort.should == ["five", "four", "one", "three", "two"] end - it "returns an enumerator when not passed a block" do - ret = Set[1, 2, 3, 4].divide - ret.should be_kind_of(Enumerator) - ret.each(&:even?).should == Set[Set[1, 3], Set[2, 4]] - end + # BUG: Does not raise a LocalJumpError, but a NoMethodError + # + # it "raises a LocalJumpError when not passed a block" do + # lambda { Set[1].divide }.should raise_error(LocalJumpError) + # end end describe "Set#divide when passed a block with an arity of 2" do @@ -31,29 +31,4 @@ describe "Set#divide when passed a block with an arity of 2" do Set[1, 2].divide { |x, y| ret << [x, y] } ret.sort.should == [[1, 1], [1, 2], [2, 1], [2, 2]] end - - it "returns an enumerator when not passed a block" do - ret = Set[1, 2, 3, 4].divide - ret.should be_kind_of(Enumerator) - ret.each { |a, b| (a + b).even? }.should == Set[Set[1, 3], Set[2, 4]] - end -end - -describe "Set#divide when passed a block with an arity of > 2" do - it "only uses the first element if the arity > 2" do - set = Set["one", "two", "three", "four", "five"].divide do |x, y, z| - y.should be_nil - z.should be_nil - x.length - end - set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]] - end - - it "only uses the first element if the arity = -1" do - set = Set["one", "two", "three", "four", "five"].divide do |*xs| - xs.size.should == 1 - xs.first.length - end - set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]] - end end diff --git a/spec/ruby/library/set/each_spec.rb b/spec/ruby/library/set/each_spec.rb index 44e185a4da..9bb5ead03a 100644 --- a/spec/ruby/library/set/each_spec.rb +++ b/spec/ruby/library/set/each_spec.rb @@ -18,7 +18,6 @@ describe "Set#each" do it "returns an Enumerator when not passed a block" do enum = @set.each - enum.should be_an_instance_of(Enumerator) ret = [] enum.each { |x| ret << x } diff --git a/spec/ruby/library/set/enumerable/to_set_spec.rb b/spec/ruby/library/set/enumerable/to_set_spec.rb index b2d850515b..3790d8deee 100644 --- a/spec/ruby/library/set/enumerable/to_set_spec.rb +++ b/spec/ruby/library/set/enumerable/to_set_spec.rb @@ -7,6 +7,14 @@ describe "Enumerable#to_set" do {a: 1, b: 2}.to_set.should == Set[[:b, 2], [:a, 1]] end + ruby_version_is ''...'3.0' do + it "allows passing an alternate class for Set" do + sorted_set = [1, 2, 3].to_set(SortedSet) + sorted_set.should == SortedSet[1, 2, 3] + sorted_set.instance_of?(SortedSet).should == true + end + end + it "passes down passed blocks" do [1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9] end diff --git a/spec/ruby/library/set/flatten_spec.rb b/spec/ruby/library/set/flatten_spec.rb index 51b58d6439..4ac83ea825 100644 --- a/spec/ruby/library/set/flatten_spec.rb +++ b/spec/ruby/library/set/flatten_spec.rb @@ -1,7 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/set_like' require 'set' -set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0' describe "Set#flatten" do it "returns a copy of self with each included Set flattened" do @@ -46,11 +45,9 @@ describe "Set#flatten!" do -> { set.flatten! }.should raise_error(ArgumentError) end - version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do - context "when Set contains a Set-like object" do - it "flattens self, including Set-like objects" do - Set[SetSpecs::SetLike.new([1])].flatten!.should == Set[1] - end + context "when Set contains a Set-like object" do + it "flattens self, including Set-like objects" do + Set[SetSpecs::SetLike.new([1])].flatten!.should == Set[1] end end end diff --git a/spec/ruby/library/set/initialize_clone_spec.rb b/spec/ruby/library/set/initialize_clone_spec.rb index bda42cd6e8..62985987fa 100644 --- a/spec/ruby/library/set/initialize_clone_spec.rb +++ b/spec/ruby/library/set/initialize_clone_spec.rb @@ -2,15 +2,17 @@ require_relative '../../spec_helper' require 'set' describe "Set#initialize_clone" do - # See https://bugs.ruby-lang.org/issues/14266 - it "does not freeze the new Set when called from clone(freeze: false)" do - set1 = Set[1, 2] - set1.freeze - set2 = set1.clone(freeze: false) - set1.frozen?.should == true - set2.frozen?.should == false - set2.add 3 - set1.should == Set[1, 2] - set2.should == Set[1, 2, 3] + ruby_version_is "3.0" do + # See https://bugs.ruby-lang.org/issues/14266 + it "does not freeze the new Set when called from clone(freeze: false)" do + set1 = Set[1, 2] + set1.freeze + set2 = set1.clone(freeze: false) + set1.frozen?.should == true + set2.frozen?.should == false + set2.add 3 + set1.should == Set[1, 2] + set2.should == Set[1, 2, 3] + end end end diff --git a/spec/ruby/library/set/join_spec.rb b/spec/ruby/library/set/join_spec.rb index 3f511a84e4..7498a91d98 100644 --- a/spec/ruby/library/set/join_spec.rb +++ b/spec/ruby/library/set/join_spec.rb @@ -1,29 +1,31 @@ require_relative '../../spec_helper' require 'set' -describe "Set#join" do - it "returns an empty string if the Set is empty" do - Set[].join.should == '' - end +ruby_version_is "3.0" do + describe "Set#join" do + it "returns an empty string if the Set is empty" do + Set[].join.should == '' + end - it "returns a new string formed by joining elements after conversion" do - set = Set[:a, :b, :c] - set.join.should == "abc" - end + it "returns a new string formed by joining elements after conversion" do + set = Set[:a, :b, :c] + set.join.should == "abc" + end - it "does not separate elements when the passed separator is nil" do - set = Set[:a, :b, :c] - set.join(nil).should == "abc" - end + it "does not separate elements when the passed separator is nil" do + set = Set[:a, :b, :c] + set.join(nil).should == "abc" + end - it "returns a string formed by concatenating each element separated by the separator" do - set = Set[:a, :b, :c] - set.join(' | ').should == "a | b | c" - end + it "returns a string formed by concatenating each element separated by the separator" do + set = Set[:a, :b, :c] + set.join(' | ').should == "a | b | c" + end - it "calls #to_a to convert the Set in to an Array" do - set = Set[:a, :b, :c] - set.should_receive(:to_a).and_return([:a, :b, :c]) - set.join.should == "abc" + it "calls #to_a to convert the Set in to an Array" do + set = Set[:a, :b, :c] + set.should_receive(:to_a).and_return([:a, :b, :c]) + set.join.should == "abc" + end end end diff --git a/spec/ruby/library/set/proper_subset_spec.rb b/spec/ruby/library/set/proper_subset_spec.rb index 6b51dedc9f..1f496a6199 100644 --- a/spec/ruby/library/set/proper_subset_spec.rb +++ b/spec/ruby/library/set/proper_subset_spec.rb @@ -1,7 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/set_like' require 'set' -set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0' describe "Set#proper_subset?" do before :each do @@ -34,11 +33,9 @@ describe "Set#proper_subset?" do -> { Set[].proper_subset?(Object.new) }.should raise_error(ArgumentError) end - version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do - context "when comparing to a Set-like object" do - it "returns true if passed a Set-like object that self is a proper subset of" do - Set[1, 2, 3].proper_subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true - end + context "when comparing to a Set-like object" do + it "returns true if passed a Set-like object that self is a proper subset of" do + Set[1, 2, 3].proper_subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true end end end diff --git a/spec/ruby/library/set/shared/inspect.rb b/spec/ruby/library/set/shared/inspect.rb index adb6ddb4c9..69fbdd12f6 100644 --- a/spec/ruby/library/set/shared/inspect.rb +++ b/spec/ruby/library/set/shared/inspect.rb @@ -1,4 +1,4 @@ -describe :set_inspect, shared: true do +describe "set_inspect", shared: true do it "returns a String representation of self" do Set[].send(@method).should be_kind_of(String) Set[nil, false, true].send(@method).should be_kind_of(String) @@ -7,19 +7,9 @@ describe :set_inspect, shared: true do Set[:a, "b", Set[?c]].send(@method).should be_kind_of(String) end - it "does include the elements of the set" do - Set["1"].send(@method).should == '#<Set: {"1"}>' - end - - it "puts spaces between the elements" do - Set["1", "2"].send(@method).should include('", "') - end - - it "correctly handles cyclic-references" do - set1 = Set[] - set2 = Set[set1] - set1 << set2 - set1.send(@method).should be_kind_of(String) - set1.send(@method).should include("#<Set: {...}>") + it "correctly handles self-references" do + (set = Set[]) << set + set.send(@method).should be_kind_of(String) + set.send(@method).should include("#<Set: {...}>") end end diff --git a/spec/ruby/library/set/sortedset/add_spec.rb b/spec/ruby/library/set/sortedset/add_spec.rb new file mode 100644 index 0000000000..4f3bb252e1 --- /dev/null +++ b/spec/ruby/library/set/sortedset/add_spec.rb @@ -0,0 +1,42 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + require_relative 'shared/add' + + describe "SortedSet#add" do + it_behaves_like :sorted_set_add, :add + + it "takes only values which responds <=>" do + obj = mock('no_comparison_operator') + obj.stub!(:respond_to?).with(:<=>).and_return(false) + -> { SortedSet["hello"].add(obj) }.should raise_error(ArgumentError) + end + + it "raises on incompatible <=> comparison" do + # Use #to_a here as elements are sorted only when needed. + # Therefore the <=> incompatibility is only noticed on sorting. + -> { SortedSet['1', '2'].add(3).to_a }.should raise_error(ArgumentError) + end + end + + describe "SortedSet#add?" do + before :each do + @set = SortedSet.new + end + + it "adds the passed Object to self" do + @set.add?("cat") + @set.should include("cat") + end + + it "returns self when the Object has not yet been added to self" do + @set.add?("cat").should equal(@set) + end + + it "returns nil when the Object has already been added to self" do + @set.add?("cat") + @set.add?("cat").should be_nil + end + end +end diff --git a/spec/ruby/library/set/sortedset/append_spec.rb b/spec/ruby/library/set/sortedset/append_spec.rb new file mode 100644 index 0000000000..d72d70b21f --- /dev/null +++ b/spec/ruby/library/set/sortedset/append_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + require_relative 'shared/add' + + describe "SortedSet#<<" do + it_behaves_like :sorted_set_add, :<< + end +end diff --git a/spec/ruby/library/set/sortedset/case_equality_spec.rb b/spec/ruby/library/set/sortedset/case_equality_spec.rb new file mode 100644 index 0000000000..d7c296b626 --- /dev/null +++ b/spec/ruby/library/set/sortedset/case_equality_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require_relative 'shared/include' + require 'set' + + describe "SortedSet#===" do + it_behaves_like :sorted_set_include, :=== + end +end diff --git a/spec/ruby/library/set/sortedset/classify_spec.rb b/spec/ruby/library/set/sortedset/classify_spec.rb new file mode 100644 index 0000000000..4011e58b82 --- /dev/null +++ b/spec/ruby/library/set/sortedset/classify_spec.rb @@ -0,0 +1,30 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#classify" do + before :each do + @set = SortedSet["one", "two", "three", "four"] + end + + it "yields each Object in self in sorted order" do + res = [] + @set.classify { |x| res << x } + res.should == ["one", "two", "three", "four"].sort + end + + it "returns an Enumerator when passed no block" do + enum = @set.classify + enum.should be_an_instance_of(Enumerator) + + classified = enum.each { |x| x.length } + classified.should == { 3 => SortedSet["one", "two"], 4 => SortedSet["four"], 5 => SortedSet["three"] } + end + + it "classifies the Objects in self based on the block's return value" do + classified = @set.classify { |x| x.length } + classified.should == { 3 => SortedSet["one", "two"], 4 => SortedSet["four"], 5 => SortedSet["three"] } + end + end +end diff --git a/spec/ruby/library/set/sortedset/clear_spec.rb b/spec/ruby/library/set/sortedset/clear_spec.rb new file mode 100644 index 0000000000..879aa824d8 --- /dev/null +++ b/spec/ruby/library/set/sortedset/clear_spec.rb @@ -0,0 +1,20 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#clear" do + before :each do + @set = SortedSet["one", "two", "three", "four"] + end + + it "removes all elements from self" do + @set.clear + @set.should be_empty + end + + it "returns self" do + @set.clear.should equal(@set) + end + end +end diff --git a/spec/ruby/library/set/sortedset/collect_spec.rb b/spec/ruby/library/set/sortedset/collect_spec.rb new file mode 100644 index 0000000000..0674f0d130 --- /dev/null +++ b/spec/ruby/library/set/sortedset/collect_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + require_relative 'shared/collect' + + describe "SortedSet#collect!" do + it_behaves_like :sorted_set_collect_bang, :collect! + end +end diff --git a/spec/ruby/library/set/sortedset/constructor_spec.rb b/spec/ruby/library/set/sortedset/constructor_spec.rb new file mode 100644 index 0000000000..31f30fd892 --- /dev/null +++ b/spec/ruby/library/set/sortedset/constructor_spec.rb @@ -0,0 +1,18 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet[]" do + it "returns a new SortedSet populated with the passed Objects" do + set = SortedSet[1, 2, 3] + + set.instance_of?(SortedSet).should be_true + set.size.should eql(3) + + set.should include(1) + set.should include(2) + set.should include(3) + end + end +end diff --git a/spec/ruby/library/set/sortedset/delete_if_spec.rb b/spec/ruby/library/set/sortedset/delete_if_spec.rb new file mode 100644 index 0000000000..787639ae12 --- /dev/null +++ b/spec/ruby/library/set/sortedset/delete_if_spec.rb @@ -0,0 +1,41 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#delete_if" do + before :each do + @set = SortedSet["one", "two", "three"] + end + + it "yields each Object in self in sorted order" do + ret = [] + @set.delete_if { |x| ret << x } + ret.should == ["one", "two", "three"].sort + end + + it "deletes every element from self for which the passed block returns true" do + @set.delete_if { |x| x.size == 3 } + @set.size.should eql(1) + + @set.should_not include("one") + @set.should_not include("two") + @set.should include("three") + end + + it "returns self" do + @set.delete_if { |x| x }.should equal(@set) + end + + it "returns an Enumerator when passed no block" do + enum = @set.delete_if + enum.should be_an_instance_of(Enumerator) + + enum.each { |x| x.size == 3 } + + @set.should_not include("one") + @set.should_not include("two") + @set.should include("three") + end + end +end diff --git a/spec/ruby/library/set/sortedset/delete_spec.rb b/spec/ruby/library/set/sortedset/delete_spec.rb new file mode 100644 index 0000000000..0e2a6accf3 --- /dev/null +++ b/spec/ruby/library/set/sortedset/delete_spec.rb @@ -0,0 +1,40 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#delete" do + before :each do + @set = SortedSet["a", "b", "c"] + end + + it "deletes the passed Object from self" do + @set.delete("a") + @set.should_not include("a") + end + + it "returns self" do + @set.delete("a").should equal(@set) + @set.delete("x").should equal(@set) + end + end + + describe "SortedSet#delete?" do + before :each do + @set = SortedSet["a", "b", "c"] + end + + it "deletes the passed Object from self" do + @set.delete?("a") + @set.should_not include("a") + end + + it "returns self when the passed Object is in self" do + @set.delete?("a").should equal(@set) + end + + it "returns nil when the passed Object is not in self" do + @set.delete?("x").should be_nil + end + end +end diff --git a/spec/ruby/library/set/sortedset/difference_spec.rb b/spec/ruby/library/set/sortedset/difference_spec.rb new file mode 100644 index 0000000000..fb064bdff9 --- /dev/null +++ b/spec/ruby/library/set/sortedset/difference_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + require_relative 'shared/difference' + + describe "SortedSet#difference" do + it_behaves_like :sorted_set_difference, :difference + end +end diff --git a/spec/ruby/library/set/sortedset/divide_spec.rb b/spec/ruby/library/set/sortedset/divide_spec.rb new file mode 100644 index 0000000000..31ab6037e4 --- /dev/null +++ b/spec/ruby/library/set/sortedset/divide_spec.rb @@ -0,0 +1,37 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#divide" do + it "divides self into a set of subsets based on the blocks return values" do + set = SortedSet["one", "two", "three", "four", "five"].divide { |x| x.length } + set.map { |x| x.to_a }.to_a.sort.should == [["five", "four"], ["one", "two"], ["three"]] + end + + it "yields each Object in self in sorted order" do + ret = [] + SortedSet["one", "two", "three", "four", "five"].divide { |x| ret << x } + ret.should == ["one", "two", "three", "four", "five"].sort + end + + # BUG: Does not raise a LocalJumpError, but a NoMethodError + # + # it "raises a LocalJumpError when not passed a block" do + # lambda { SortedSet[1].divide }.should raise_error(LocalJumpError) + # end + end + + describe "SortedSet#divide when passed a block with an arity of 2" do + it "divides self into a set of subsets based on the blocks return values" do + set = SortedSet[1, 3, 4, 6, 9, 10, 11].divide { |x, y| (x - y).abs == 1 } + set.map { |x| x.to_a }.to_a.sort.should == [[1], [3, 4], [6], [9, 10, 11]] + end + + it "yields each two Objects to the block" do + ret = [] + SortedSet[1, 2].divide { |x, y| ret << [x, y] } + ret.should == [[1, 1], [1, 2], [2, 1], [2, 2]] + end + end +end diff --git a/spec/ruby/library/set/sortedset/each_spec.rb b/spec/ruby/library/set/sortedset/each_spec.rb new file mode 100644 index 0000000000..79d8aee223 --- /dev/null +++ b/spec/ruby/library/set/sortedset/each_spec.rb @@ -0,0 +1,29 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#each" do + before :each do + @set = SortedSet[1, 2, 3] + end + + it "yields each Object in self in sorted order" do + ret = [] + SortedSet["one", "two", "three"].each { |x| ret << x } + ret.should == ["one", "two", "three"].sort + end + + it "returns self" do + @set.each { |x| x }.should equal(@set) + end + + it "returns an Enumerator when not passed a block" do + enum = @set.each + + ret = [] + enum.each { |x| ret << x } + ret.sort.should == [1, 2, 3] + end + end +end diff --git a/spec/ruby/library/set/sortedset/empty_spec.rb b/spec/ruby/library/set/sortedset/empty_spec.rb new file mode 100644 index 0000000000..2e52c3e81a --- /dev/null +++ b/spec/ruby/library/set/sortedset/empty_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#empty?" do + it "returns true if self is empty" do + SortedSet[].empty?.should be_true + SortedSet[1].empty?.should be_false + SortedSet[1,2,3].empty?.should be_false + end + end +end diff --git a/spec/ruby/library/set/sortedset/eql_spec.rb b/spec/ruby/library/set/sortedset/eql_spec.rb new file mode 100644 index 0000000000..050464994b --- /dev/null +++ b/spec/ruby/library/set/sortedset/eql_spec.rb @@ -0,0 +1,19 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#eql?" do + it "returns true when the passed argument is a SortedSet and contains the same elements" do + SortedSet[].should eql(SortedSet[]) + SortedSet[1, 2, 3].should eql(SortedSet[1, 2, 3]) + SortedSet[1, 2, 3].should eql(SortedSet[3, 2, 1]) + + # SortedSet["a", :b, ?c].should eql(SortedSet[?c, :b, "a"]) + + SortedSet[1, 2, 3].should_not eql(SortedSet[1.0, 2, 3]) + SortedSet[1, 2, 3].should_not eql(SortedSet[2, 3]) + SortedSet[1, 2, 3].should_not eql(SortedSet[]) + end + end +end diff --git a/spec/ruby/library/set/sortedset/equal_value_spec.rb b/spec/ruby/library/set/sortedset/equal_value_spec.rb new file mode 100644 index 0000000000..30422f5b95 --- /dev/null +++ b/spec/ruby/library/set/sortedset/equal_value_spec.rb @@ -0,0 +1,16 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#==" do + it "returns true when the passed Object is a SortedSet and self and the Object contain the same elements" do + SortedSet[].should == SortedSet[] + SortedSet[1, 2, 3].should == SortedSet[1, 2, 3] + SortedSet["1", "2", "3"].should == SortedSet["1", "2", "3"] + + SortedSet[1, 2, 3].should_not == SortedSet[1.0, 2, 3] + SortedSet[1, 2, 3].should_not == [1, 2, 3] + end + end +end diff --git a/spec/ruby/library/set/sortedset/exclusion_spec.rb b/spec/ruby/library/set/sortedset/exclusion_spec.rb new file mode 100644 index 0000000000..1967dfbfa6 --- /dev/null +++ b/spec/ruby/library/set/sortedset/exclusion_spec.rb @@ -0,0 +1,21 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#^" do + before :each do + @set = SortedSet[1, 2, 3, 4] + end + + it "returns a new SortedSet containing elements that are not in both self and the passed Enumerable" do + (@set ^ SortedSet[3, 4, 5]).should == SortedSet[1, 2, 5] + (@set ^ [3, 4, 5]).should == SortedSet[1, 2, 5] + end + + it "raises an ArgumentError when passed a non-Enumerable" do + -> { @set ^ 3 }.should raise_error(ArgumentError) + -> { @set ^ Object.new }.should raise_error(ArgumentError) + end + end +end diff --git a/spec/ruby/library/set/sortedset/filter_spec.rb b/spec/ruby/library/set/sortedset/filter_spec.rb new file mode 100644 index 0000000000..3b9dcb63c9 --- /dev/null +++ b/spec/ruby/library/set/sortedset/filter_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require_relative 'shared/select' + require 'set' + + describe "SortedSet#filter!" do + it_behaves_like :sorted_set_select_bang, :filter! + end +end diff --git a/spec/ruby/library/set/sortedset/flatten_merge_spec.rb b/spec/ruby/library/set/sortedset/flatten_merge_spec.rb new file mode 100644 index 0000000000..0d67cb331e --- /dev/null +++ b/spec/ruby/library/set/sortedset/flatten_merge_spec.rb @@ -0,0 +1,11 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#flatten_merge" do + it "is protected" do + SortedSet.should have_protected_instance_method("flatten_merge") + end + end +end diff --git a/spec/ruby/library/set/sortedset/flatten_spec.rb b/spec/ruby/library/set/sortedset/flatten_spec.rb new file mode 100644 index 0000000000..e83ad1044a --- /dev/null +++ b/spec/ruby/library/set/sortedset/flatten_spec.rb @@ -0,0 +1,47 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + # Note: Flatten make little sens on sorted sets, because SortedSets are not (by default) + # comparable. For a SortedSet to be both valid and nested, we need to define a comparison operator: + module SortedSet_FlattenSpecs + class ComparableSortedSet < SortedSet + def <=>(other) + return puts "#{other} vs #{self}" unless other.is_a?(ComparableSortedSet) + to_a <=> other.to_a + end + end + end + + describe "SortedSet#flatten" do + it "returns a copy of self with each included SortedSet flattened" do + klass = SortedSet_FlattenSpecs::ComparableSortedSet + set = klass[klass[1,2], klass[3,4], klass[5,6,7], klass[8]] + flattened_set = set.flatten + + flattened_set.should_not equal(set) + flattened_set.should == klass[1, 2, 3, 4, 5, 6, 7, 8] + end + end + + describe "SortedSet#flatten!" do + it "flattens self" do + klass = SortedSet_FlattenSpecs::ComparableSortedSet + set = klass[klass[1,2], klass[3,4], klass[5,6,7], klass[8]] + set.flatten! + set.should == klass[1, 2, 3, 4, 5, 6, 7, 8] + end + + it "returns self when self was modified" do + klass = SortedSet_FlattenSpecs::ComparableSortedSet + set = klass[klass[1,2], klass[3,4]] + set.flatten!.should equal(set) + end + + it "returns nil when self was not modified" do + set = SortedSet[1, 2, 3, 4] + set.flatten!.should be_nil + end + end +end diff --git a/spec/ruby/library/set/sortedset/hash_spec.rb b/spec/ruby/library/set/sortedset/hash_spec.rb new file mode 100644 index 0000000000..40676de7fc --- /dev/null +++ b/spec/ruby/library/set/sortedset/hash_spec.rb @@ -0,0 +1,16 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#hash" do + it "is static" do + SortedSet[].hash.should == SortedSet[].hash + SortedSet[1, 2, 3].hash.should == SortedSet[1, 2, 3].hash + SortedSet["a", "b", "c"].hash.should == SortedSet["c", "b", "a"].hash + + SortedSet[].hash.should_not == SortedSet[1, 2, 3].hash + SortedSet[1, 2, 3].hash.should_not == SortedSet["a", "b", "c"].hash + end + end +end diff --git a/spec/ruby/library/set/sortedset/include_spec.rb b/spec/ruby/library/set/sortedset/include_spec.rb new file mode 100644 index 0000000000..ec2ad987d5 --- /dev/null +++ b/spec/ruby/library/set/sortedset/include_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require_relative 'shared/include' + require 'set' + + describe "SortedSet#include?" do + it_behaves_like :sorted_set_include, :include? + end +end diff --git a/spec/ruby/library/set/sortedset/initialize_spec.rb b/spec/ruby/library/set/sortedset/initialize_spec.rb new file mode 100644 index 0000000000..4d1707b72a --- /dev/null +++ b/spec/ruby/library/set/sortedset/initialize_spec.rb @@ -0,0 +1,33 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#initialize" do + it "is private" do + SortedSet.should have_private_instance_method("initialize") + end + + it "adds all elements of the passed Enumerable to self" do + s = SortedSet.new([1, 2, 3]) + s.size.should eql(3) + s.should include(1) + s.should include(2) + s.should include(3) + end + + it "preprocesses all elements by a passed block before adding to self" do + s = SortedSet.new([1, 2, 3]) { |x| x * x } + s.size.should eql(3) + s.should include(1) + s.should include(4) + s.should include(9) + end + + it "raises on incompatible <=> comparison" do + # Use #to_a here as elements are sorted only when needed. + # Therefore the <=> incompatibility is only noticed on sorting. + -> { SortedSet.new(['00', nil]).to_a }.should raise_error(ArgumentError) + end + end +end diff --git a/spec/ruby/library/set/sortedset/inspect_spec.rb b/spec/ruby/library/set/sortedset/inspect_spec.rb new file mode 100644 index 0000000000..1c4dd9e6e2 --- /dev/null +++ b/spec/ruby/library/set/sortedset/inspect_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#inspect" do + it "returns a String representation of self" do + SortedSet[].inspect.should be_kind_of(String) + SortedSet[1, 2, 3].inspect.should be_kind_of(String) + SortedSet["1", "2", "3"].inspect.should be_kind_of(String) + end + end +end diff --git a/spec/ruby/library/set/sortedset/intersection_spec.rb b/spec/ruby/library/set/sortedset/intersection_spec.rb new file mode 100644 index 0000000000..6daa271b73 --- /dev/null +++ b/spec/ruby/library/set/sortedset/intersection_spec.rb @@ -0,0 +1,14 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require_relative 'shared/intersection' + require 'set' + + describe "SortedSet#intersection" do + it_behaves_like :sorted_set_intersection, :intersection + end + + describe "SortedSet#&" do + it_behaves_like :sorted_set_intersection, :& + end +end diff --git a/spec/ruby/library/set/sortedset/keep_if_spec.rb b/spec/ruby/library/set/sortedset/keep_if_spec.rb new file mode 100644 index 0000000000..3e5f3bbc47 --- /dev/null +++ b/spec/ruby/library/set/sortedset/keep_if_spec.rb @@ -0,0 +1,34 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#keep_if" do + before :each do + @set = SortedSet["one", "two", "three"] + end + + it "yields each Object in self in sorted order" do + ret = [] + @set.keep_if { |x| ret << x } + ret.should == ["one", "two", "three"].sort + end + + it "keeps every element from self for which the passed block returns true" do + @set.keep_if { |x| x.size != 3 } + @set.to_a.should == ["three"] + end + + it "returns self" do + @set.keep_if {}.should equal(@set) + end + + it "returns an Enumerator when passed no block" do + enum = @set.keep_if + enum.should be_an_instance_of(Enumerator) + + enum.each { |x| x.size != 3 } + @set.to_a.should == ["three"] + end + end +end diff --git a/spec/ruby/library/set/sortedset/length_spec.rb b/spec/ruby/library/set/sortedset/length_spec.rb new file mode 100644 index 0000000000..de6791f6bb --- /dev/null +++ b/spec/ruby/library/set/sortedset/length_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require_relative 'shared/length' + require 'set' + + describe "SortedSet#length" do + it_behaves_like :sorted_set_length, :length + end +end diff --git a/spec/ruby/library/set/sortedset/map_spec.rb b/spec/ruby/library/set/sortedset/map_spec.rb new file mode 100644 index 0000000000..4971b9529b --- /dev/null +++ b/spec/ruby/library/set/sortedset/map_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + require_relative 'shared/collect' + + describe "SortedSet#map!" do + it_behaves_like :sorted_set_collect_bang, :map! + end +end diff --git a/spec/ruby/library/set/sortedset/member_spec.rb b/spec/ruby/library/set/sortedset/member_spec.rb new file mode 100644 index 0000000000..142b09b651 --- /dev/null +++ b/spec/ruby/library/set/sortedset/member_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require_relative 'shared/include' + require 'set' + + describe "SortedSet#member?" do + it_behaves_like :sorted_set_include, :member? + end +end diff --git a/spec/ruby/library/set/sortedset/merge_spec.rb b/spec/ruby/library/set/sortedset/merge_spec.rb new file mode 100644 index 0000000000..c4cbc6d2b4 --- /dev/null +++ b/spec/ruby/library/set/sortedset/merge_spec.rb @@ -0,0 +1,22 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#merge" do + it "adds the elements of the passed Enumerable to self" do + SortedSet["a", "b"].merge(SortedSet["b", "c", "d"]).should == SortedSet["a", "b", "c", "d"] + SortedSet[1, 2].merge([3, 4]).should == SortedSet[1, 2, 3, 4] + end + + it "returns self" do + set = SortedSet[1, 2] + set.merge([3, 4]).should equal(set) + end + + it "raises an ArgumentError when passed a non-Enumerable" do + -> { SortedSet[1, 2].merge(1) }.should raise_error(ArgumentError) + -> { SortedSet[1, 2].merge(Object.new) }.should raise_error(ArgumentError) + end + end +end diff --git a/spec/ruby/library/set/sortedset/minus_spec.rb b/spec/ruby/library/set/sortedset/minus_spec.rb new file mode 100644 index 0000000000..d6abc5e204 --- /dev/null +++ b/spec/ruby/library/set/sortedset/minus_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + require_relative 'shared/difference' + + describe "SortedSet#-" do + it_behaves_like :sorted_set_difference, :- + end +end diff --git a/spec/ruby/library/set/sortedset/plus_spec.rb b/spec/ruby/library/set/sortedset/plus_spec.rb new file mode 100644 index 0000000000..13fc873ad1 --- /dev/null +++ b/spec/ruby/library/set/sortedset/plus_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require_relative 'shared/union' + require 'set' + + describe "SortedSet#+" do + it_behaves_like :sorted_set_union, :+ + end +end diff --git a/spec/ruby/library/set/sortedset/pretty_print_cycle_spec.rb b/spec/ruby/library/set/sortedset/pretty_print_cycle_spec.rb new file mode 100644 index 0000000000..e97f509406 --- /dev/null +++ b/spec/ruby/library/set/sortedset/pretty_print_cycle_spec.rb @@ -0,0 +1,13 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#pretty_print_cycle" do + it "passes the 'pretty print' representation of a self-referencing SortedSet to the pretty print writer" do + pp = mock("PrettyPrint") + pp.should_receive(:text).with("#<SortedSet: {...}>") + SortedSet[1, 2, 3].pretty_print_cycle(pp) + end + end +end diff --git a/spec/ruby/library/set/sortedset/pretty_print_spec.rb b/spec/ruby/library/set/sortedset/pretty_print_spec.rb new file mode 100644 index 0000000000..a8088bf797 --- /dev/null +++ b/spec/ruby/library/set/sortedset/pretty_print_spec.rb @@ -0,0 +1,20 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#pretty_print" do + it "passes the 'pretty print' representation of self to the pretty print writer" do + pp = mock("PrettyPrint") + set = SortedSet[1, 2, 3] + + pp.should_receive(:text).with("#<SortedSet: {") + pp.should_receive(:text).with("}>") + + pp.should_receive(:nest).with(1).and_yield + pp.should_receive(:seplist).with(set) + + set.pretty_print(pp) + end + end +end diff --git a/spec/ruby/library/set/sortedset/proper_subset_spec.rb b/spec/ruby/library/set/sortedset/proper_subset_spec.rb new file mode 100644 index 0000000000..34fb89d13d --- /dev/null +++ b/spec/ruby/library/set/sortedset/proper_subset_spec.rb @@ -0,0 +1,36 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#proper_subset?" do + before :each do + @set = SortedSet[1, 2, 3, 4] + end + + it "returns true if passed a SortedSet that self is a proper subset of" do + SortedSet[].proper_subset?(@set).should be_true + SortedSet[].proper_subset?(SortedSet[1, 2, 3]).should be_true + SortedSet[].proper_subset?(SortedSet["a", "b", "c"]).should be_true + + SortedSet[1, 2, 3].proper_subset?(@set).should be_true + SortedSet[1, 3].proper_subset?(@set).should be_true + SortedSet[1, 2].proper_subset?(@set).should be_true + SortedSet[1].proper_subset?(@set).should be_true + + SortedSet[5].proper_subset?(@set).should be_false + SortedSet[1, 5].proper_subset?(@set).should be_false + SortedSet["test"].proper_subset?(@set).should be_false + + @set.proper_subset?(@set).should be_false + SortedSet[].proper_subset?(SortedSet[]).should be_false + end + + it "raises an ArgumentError when passed a non-SortedSet" do + -> { SortedSet[].proper_subset?([]) }.should raise_error(ArgumentError) + -> { SortedSet[].proper_subset?(1) }.should raise_error(ArgumentError) + -> { SortedSet[].proper_subset?("test") }.should raise_error(ArgumentError) + -> { SortedSet[].proper_subset?(Object.new) }.should raise_error(ArgumentError) + end + end +end diff --git a/spec/ruby/library/set/sortedset/proper_superset_spec.rb b/spec/ruby/library/set/sortedset/proper_superset_spec.rb new file mode 100644 index 0000000000..8b92444f72 --- /dev/null +++ b/spec/ruby/library/set/sortedset/proper_superset_spec.rb @@ -0,0 +1,36 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#proper_superset?" do + before :each do + @set = SortedSet[1, 2, 3, 4] + end + + it "returns true if passed a SortedSet that self is a proper superset of" do + @set.proper_superset?(SortedSet[]).should be_true + SortedSet[1, 2, 3].proper_superset?(SortedSet[]).should be_true + SortedSet["a", "b", "c"].proper_superset?(SortedSet[]).should be_true + + @set.proper_superset?(SortedSet[1, 2, 3]).should be_true + @set.proper_superset?(SortedSet[1, 3]).should be_true + @set.proper_superset?(SortedSet[1, 2]).should be_true + @set.proper_superset?(SortedSet[1]).should be_true + + @set.proper_superset?(SortedSet[5]).should be_false + @set.proper_superset?(SortedSet[1, 5]).should be_false + @set.proper_superset?(SortedSet["test"]).should be_false + + @set.proper_superset?(@set).should be_false + SortedSet[].proper_superset?(SortedSet[]).should be_false + end + + it "raises an ArgumentError when passed a non-SortedSet" do + -> { SortedSet[].proper_superset?([]) }.should raise_error(ArgumentError) + -> { SortedSet[].proper_superset?(1) }.should raise_error(ArgumentError) + -> { SortedSet[].proper_superset?("test") }.should raise_error(ArgumentError) + -> { SortedSet[].proper_superset?(Object.new) }.should raise_error(ArgumentError) + end + end +end diff --git a/spec/ruby/library/set/sortedset/reject_spec.rb b/spec/ruby/library/set/sortedset/reject_spec.rb new file mode 100644 index 0000000000..396b864cc5 --- /dev/null +++ b/spec/ruby/library/set/sortedset/reject_spec.rb @@ -0,0 +1,45 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#reject!" do + before :each do + @set = SortedSet["one", "two", "three"] + end + + it "yields each Object in self in sorted order" do + res = [] + @set.reject! { |x| res << x } + res.should == ["one", "two", "three"].sort + end + + it "deletes every element from self for which the passed block returns true" do + @set.reject! { |x| x.size == 3 } + @set.size.should eql(1) + + @set.should_not include("one") + @set.should_not include("two") + @set.should include("three") + end + + it "returns self when self was modified" do + @set.reject! { |x| true }.should equal(@set) + end + + it "returns nil when self was not modified" do + @set.reject! { |x| false }.should be_nil + end + + it "returns an Enumerator when passed no block" do + enum = @set.reject! + enum.should be_an_instance_of(Enumerator) + + enum.each { |x| x.size == 3 } + + @set.should_not include("one") + @set.should_not include("two") + @set.should include("three") + end + end +end diff --git a/spec/ruby/library/set/sortedset/replace_spec.rb b/spec/ruby/library/set/sortedset/replace_spec.rb new file mode 100644 index 0000000000..2900221c01 --- /dev/null +++ b/spec/ruby/library/set/sortedset/replace_spec.rb @@ -0,0 +1,20 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#replace" do + before :each do + @set = SortedSet["a", "b", "c"] + end + + it "replaces the contents with other and returns self" do + @set.replace(SortedSet[1, 2, 3]).should == @set + @set.should == SortedSet[1, 2, 3] + end + + it "accepts any enumerable as other" do + @set.replace([1, 2, 3]).should == SortedSet[1, 2, 3] + end + end +end diff --git a/spec/ruby/library/set/sortedset/select_spec.rb b/spec/ruby/library/set/sortedset/select_spec.rb new file mode 100644 index 0000000000..fc4c15ee4d --- /dev/null +++ b/spec/ruby/library/set/sortedset/select_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require_relative 'shared/select' + require 'set' + + describe "SortedSet#select!" do + it_behaves_like :sorted_set_select_bang, :select! + end +end diff --git a/spec/ruby/library/set/sortedset/shared/add.rb b/spec/ruby/library/set/sortedset/shared/add.rb new file mode 100644 index 0000000000..95ef1b090e --- /dev/null +++ b/spec/ruby/library/set/sortedset/shared/add.rb @@ -0,0 +1,14 @@ +describe :sorted_set_add, shared: true do + before :each do + @set = SortedSet.new + end + + it "adds the passed Object to self" do + @set.send(@method, "dog") + @set.should include("dog") + end + + it "returns self" do + @set.send(@method, "dog").should equal(@set) + end +end diff --git a/spec/ruby/library/set/sortedset/shared/collect.rb b/spec/ruby/library/set/sortedset/shared/collect.rb new file mode 100644 index 0000000000..e53304d427 --- /dev/null +++ b/spec/ruby/library/set/sortedset/shared/collect.rb @@ -0,0 +1,20 @@ +describe :sorted_set_collect_bang, shared: true do + before :each do + @set = SortedSet[1, 2, 3, 4, 5] + end + + it "yields each Object in self in sorted order" do + res = [] + SortedSet["one", "two", "three"].send(@method) { |x| res << x; x } + res.should == ["one", "two", "three"].sort + end + + it "returns self" do + @set.send(@method) { |x| x }.should equal(@set) + end + + it "replaces self with the return values of the block" do + @set.send(@method) { |x| x * 2 } + @set.should == SortedSet[2, 4, 6, 8, 10] + end +end diff --git a/spec/ruby/library/set/sortedset/shared/difference.rb b/spec/ruby/library/set/sortedset/shared/difference.rb new file mode 100644 index 0000000000..688e23a7a7 --- /dev/null +++ b/spec/ruby/library/set/sortedset/shared/difference.rb @@ -0,0 +1,15 @@ +describe :sorted_set_difference, shared: true do + before :each do + @set = SortedSet["a", "b", "c"] + end + + it "returns a new SortedSet containing self's elements excluding the elements in the passed Enumerable" do + @set.send(@method, SortedSet["a", "b"]).should == SortedSet["c"] + @set.send(@method, ["b", "c"]).should == SortedSet["a"] + end + + it "raises an ArgumentError when passed a non-Enumerable" do + -> { @set.send(@method, 1) }.should raise_error(ArgumentError) + -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError) + end +end diff --git a/spec/ruby/library/set/sortedset/shared/include.rb b/spec/ruby/library/set/sortedset/shared/include.rb new file mode 100644 index 0000000000..cd1758819d --- /dev/null +++ b/spec/ruby/library/set/sortedset/shared/include.rb @@ -0,0 +1,7 @@ +describe :sorted_set_include, shared: true do + it "returns true when self contains the passed Object" do + set = SortedSet["a", "b", "c"] + set.send(@method, "a").should be_true + set.send(@method, "e").should be_false + end +end diff --git a/spec/ruby/library/set/sortedset/shared/intersection.rb b/spec/ruby/library/set/sortedset/shared/intersection.rb new file mode 100644 index 0000000000..045716ad05 --- /dev/null +++ b/spec/ruby/library/set/sortedset/shared/intersection.rb @@ -0,0 +1,15 @@ +describe :sorted_set_intersection, shared: true do + before :each do + @set = SortedSet["a", "b", "c"] + end + + it "returns a new SortedSet containing only elements shared by self and the passed Enumerable" do + @set.send(@method, SortedSet["b", "c", "d", "e"]).should == SortedSet["b", "c"] + @set.send(@method, ["b", "c", "d"]).should == SortedSet["b", "c"] + end + + it "raises an ArgumentError when passed a non-Enumerable" do + -> { @set.send(@method, 1) }.should raise_error(ArgumentError) + -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError) + end +end diff --git a/spec/ruby/library/set/sortedset/shared/length.rb b/spec/ruby/library/set/sortedset/shared/length.rb new file mode 100644 index 0000000000..d1dfee1cff --- /dev/null +++ b/spec/ruby/library/set/sortedset/shared/length.rb @@ -0,0 +1,6 @@ +describe :sorted_set_length, shared: true do + it "returns the number of elements in the set" do + set = SortedSet["a", "b", "c"] + set.send(@method).should == 3 + end +end diff --git a/spec/ruby/library/set/sortedset/shared/select.rb b/spec/ruby/library/set/sortedset/shared/select.rb new file mode 100644 index 0000000000..e13311eda5 --- /dev/null +++ b/spec/ruby/library/set/sortedset/shared/select.rb @@ -0,0 +1,35 @@ +require_relative '../../../../spec_helper' +require 'set' + +describe :sorted_set_select_bang, shared: true do + before :each do + @set = SortedSet["one", "two", "three"] + end + + it "yields each Object in self in sorted order" do + res = [] + @set.send(@method) { |x| res << x } + res.should == ["one", "two", "three"].sort + end + + it "keeps every element from self for which the passed block returns true" do + @set.send(@method) { |x| x.size != 3 } + @set.to_a.should == ["three"] + end + + it "returns self when self was modified" do + @set.send(@method) { false }.should equal(@set) + end + + it "returns nil when self was not modified" do + @set.send(@method) { true }.should be_nil + end + + it "returns an Enumerator when passed no block" do + enum = @set.send(@method) + enum.should be_an_instance_of(Enumerator) + + enum.each { |x| x.size != 3 } + @set.to_a.should == ["three"] + end +end diff --git a/spec/ruby/library/set/sortedset/shared/union.rb b/spec/ruby/library/set/sortedset/shared/union.rb new file mode 100644 index 0000000000..9015bdc8e3 --- /dev/null +++ b/spec/ruby/library/set/sortedset/shared/union.rb @@ -0,0 +1,15 @@ +describe :sorted_set_union, shared: true do + before :each do + @set = SortedSet["a", "b", "c"] + end + + it "returns a new SortedSet containing all elements of self and the passed Enumerable" do + @set.send(@method, SortedSet["b", "d", "e"]).should == SortedSet["a", "b", "c", "d", "e"] + @set.send(@method, ["b", "e"]).should == SortedSet["a", "b", "c", "e"] + end + + it "raises an ArgumentError when passed a non-Enumerable" do + -> { @set.send(@method, 1) }.should raise_error(ArgumentError) + -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError) + end +end diff --git a/spec/ruby/library/set/sortedset/size_spec.rb b/spec/ruby/library/set/sortedset/size_spec.rb new file mode 100644 index 0000000000..d908b33b53 --- /dev/null +++ b/spec/ruby/library/set/sortedset/size_spec.rb @@ -0,0 +1,10 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require_relative 'shared/length' + require 'set' + + describe "SortedSet#size" do + it_behaves_like :sorted_set_length, :size + end +end diff --git a/spec/ruby/library/set/sortedset/sortedset_spec.rb b/spec/ruby/library/set/sortedset/sortedset_spec.rb index 67993dee29..3ead5495fc 100644 --- a/spec/ruby/library/set/sortedset/sortedset_spec.rb +++ b/spec/ruby/library/set/sortedset/sortedset_spec.rb @@ -1,12 +1,22 @@ require_relative '../../../spec_helper' require 'set' -describe "SortedSet" do - it "raises error including message that it has been extracted from the set stdlib" do - -> { - SortedSet - }.should raise_error(RuntimeError) { |e| - e.message.should.include?("The `SortedSet` class has been extracted from the `set` library") - } +ruby_version_is "3.0" do + describe "SortedSet" do + it "raises error including message that it has been extracted from the set stdlib" do + -> { + SortedSet + }.should raise_error(RuntimeError) { |e| + e.message.should.include?("The `SortedSet` class has been extracted from the `set` library") + } + end + end +end + +ruby_version_is ""..."3.0" do + describe "SortedSet" do + it "is part of the set stdlib" do + SortedSet.superclass.should == Set + end end end diff --git a/spec/ruby/library/set/sortedset/subset_spec.rb b/spec/ruby/library/set/sortedset/subset_spec.rb new file mode 100644 index 0000000000..272e3f985e --- /dev/null +++ b/spec/ruby/library/set/sortedset/subset_spec.rb @@ -0,0 +1,36 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#subset?" do + before :each do + @set = SortedSet[1, 2, 3, 4] + end + + it "returns true if passed a SortedSet that is equal to self or self is a subset of" do + @set.subset?(@set).should be_true + SortedSet[].subset?(SortedSet[]).should be_true + + SortedSet[].subset?(@set).should be_true + SortedSet[].subset?(SortedSet[1, 2, 3]).should be_true + SortedSet[].subset?(SortedSet["a", "b", "c"]).should be_true + + SortedSet[1, 2, 3].subset?(@set).should be_true + SortedSet[1, 3].subset?(@set).should be_true + SortedSet[1, 2].subset?(@set).should be_true + SortedSet[1].subset?(@set).should be_true + + SortedSet[5].subset?(@set).should be_false + SortedSet[1, 5].subset?(@set).should be_false + SortedSet["test"].subset?(@set).should be_false + end + + it "raises an ArgumentError when passed a non-SortedSet" do + -> { SortedSet[].subset?([]) }.should raise_error(ArgumentError) + -> { SortedSet[].subset?(1) }.should raise_error(ArgumentError) + -> { SortedSet[].subset?("test") }.should raise_error(ArgumentError) + -> { SortedSet[].subset?(Object.new) }.should raise_error(ArgumentError) + end + end +end diff --git a/spec/ruby/library/set/sortedset/subtract_spec.rb b/spec/ruby/library/set/sortedset/subtract_spec.rb new file mode 100644 index 0000000000..b2af127f89 --- /dev/null +++ b/spec/ruby/library/set/sortedset/subtract_spec.rb @@ -0,0 +1,20 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#subtract" do + before :each do + @set = SortedSet["a", "b", "c"] + end + + it "deletes any elements contained in other and returns self" do + @set.subtract(SortedSet["b", "c"]).should == @set + @set.should == SortedSet["a"] + end + + it "accepts any enumerable as other" do + @set.subtract(["c"]).should == SortedSet["a", "b"] + end + end +end diff --git a/spec/ruby/library/set/sortedset/superset_spec.rb b/spec/ruby/library/set/sortedset/superset_spec.rb new file mode 100644 index 0000000000..a1bbacb966 --- /dev/null +++ b/spec/ruby/library/set/sortedset/superset_spec.rb @@ -0,0 +1,36 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#superset?" do + before :each do + @set = SortedSet[1, 2, 3, 4] + end + + it "returns true if passed a SortedSet that equals self or self is a proper superset of" do + @set.superset?(@set).should be_true + SortedSet[].superset?(SortedSet[]).should be_true + + @set.superset?(SortedSet[]).should be_true + SortedSet[1, 2, 3].superset?(SortedSet[]).should be_true + SortedSet["a", "b", "c"].superset?(SortedSet[]).should be_true + + @set.superset?(SortedSet[1, 2, 3]).should be_true + @set.superset?(SortedSet[1, 3]).should be_true + @set.superset?(SortedSet[1, 2]).should be_true + @set.superset?(SortedSet[1]).should be_true + + @set.superset?(SortedSet[5]).should be_false + @set.superset?(SortedSet[1, 5]).should be_false + @set.superset?(SortedSet["test"]).should be_false + end + + it "raises an ArgumentError when passed a non-SortedSet" do + -> { SortedSet[].superset?([]) }.should raise_error(ArgumentError) + -> { SortedSet[].superset?(1) }.should raise_error(ArgumentError) + -> { SortedSet[].superset?("test") }.should raise_error(ArgumentError) + -> { SortedSet[].superset?(Object.new) }.should raise_error(ArgumentError) + end + end +end diff --git a/spec/ruby/library/set/sortedset/to_a_spec.rb b/spec/ruby/library/set/sortedset/to_a_spec.rb new file mode 100644 index 0000000000..bb54cd7cdb --- /dev/null +++ b/spec/ruby/library/set/sortedset/to_a_spec.rb @@ -0,0 +1,20 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require 'set' + + describe "SortedSet#to_a" do + it "returns an array containing elements" do + set = SortedSet.new [1, 2, 3] + set.to_a.should == [1, 2, 3] + end + + it "returns a sorted array containing elements" do + set = SortedSet[2, 3, 1] + set.to_a.should == [1, 2, 3] + + set = SortedSet.new [5, 6, 4, 4] + set.to_a.should == [4, 5, 6] + end + end +end diff --git a/spec/ruby/library/set/sortedset/union_spec.rb b/spec/ruby/library/set/sortedset/union_spec.rb new file mode 100644 index 0000000000..c942f20d3e --- /dev/null +++ b/spec/ruby/library/set/sortedset/union_spec.rb @@ -0,0 +1,14 @@ +require_relative '../../../spec_helper' + +ruby_version_is ""..."3.0" do + require_relative 'shared/union' + require 'set' + + describe "SortedSet#union" do + it_behaves_like :sorted_set_union, :union + end + + describe "SortedSet#|" do + it_behaves_like :sorted_set_union, :| + end +end diff --git a/spec/ruby/library/set/subset_spec.rb b/spec/ruby/library/set/subset_spec.rb index 85666d633f..f375efa6df 100644 --- a/spec/ruby/library/set/subset_spec.rb +++ b/spec/ruby/library/set/subset_spec.rb @@ -1,7 +1,6 @@ require_relative '../../spec_helper' require_relative 'fixtures/set_like' require 'set' -set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0' describe "Set#subset?" do before :each do @@ -34,11 +33,9 @@ describe "Set#subset?" do -> { Set[].subset?(Object.new) }.should raise_error(ArgumentError) end - version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do - context "when comparing to a Set-like object" do - it "returns true if passed a Set-like object that self is a subset of" do - Set[1, 2, 3].subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true - end + context "when comparing to a Set-like object" do + it "returns true if passed a Set-like object that self is a subset of" do + Set[1, 2, 3].subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true end end end diff --git a/spec/ruby/library/set/to_s_spec.rb b/spec/ruby/library/set/to_s_spec.rb index 3c26ae9346..7b9f7b6603 100644 --- a/spec/ruby/library/set/to_s_spec.rb +++ b/spec/ruby/library/set/to_s_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../spec_helper" require_relative 'shared/inspect' require 'set' diff --git a/spec/ruby/library/socket/addrinfo/initialize_spec.rb b/spec/ruby/library/socket/addrinfo/initialize_spec.rb index 83b204b575..00250439fd 100644 --- a/spec/ruby/library/socket/addrinfo/initialize_spec.rb +++ b/spec/ruby/library/socket/addrinfo/initialize_spec.rb @@ -91,7 +91,7 @@ describe "Addrinfo#initialize" do @addrinfo.afamily.should == Socket::AF_INET6 end - it "returns the specified socket type" do + it "returns the 0 socket type" do @addrinfo.socktype.should == Socket::SOCK_STREAM end diff --git a/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb b/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb index 4f7cf439a0..c32da5986d 100644 --- a/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb +++ b/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb @@ -1,4 +1,5 @@ -describe :socket_addrinfo_to_sockaddr, shared: true do +describe :socket_addrinfo_to_sockaddr, :shared => true do + describe "for an ipv4 socket" do before :each do @addrinfo = Addrinfo.tcp("127.0.0.1", 80) @@ -46,4 +47,5 @@ describe :socket_addrinfo_to_sockaddr, shared: true do addr.send(@method).should == Socket.sockaddr_in(0, '') end end + end diff --git a/spec/ruby/library/socket/basicsocket/recv_spec.rb b/spec/ruby/library/socket/basicsocket/recv_spec.rb index a56114f4ab..b6ccda5d00 100644 --- a/spec/ruby/library/socket/basicsocket/recv_spec.rb +++ b/spec/ruby/library/socket/basicsocket/recv_spec.rb @@ -32,25 +32,6 @@ describe "BasicSocket#recv" do ScratchPad.recorded.should == 'hello' end - ruby_version_is "3.3" do - it "returns nil on a closed stream socket" do - t = Thread.new do - client = @server.accept - packet = client.recv(10) - client.close - packet - end - - Thread.pass while t.status and t.status != "sleep" - t.status.should_not be_nil - - socket = TCPSocket.new('127.0.0.1', @port) - socket.close - - t.value.should be_nil - end - end - platform_is_not :solaris do it "accepts flags to specify unusual receiving behaviour" do t = Thread.new do diff --git a/spec/ruby/library/socket/basicsocket/send_spec.rb b/spec/ruby/library/socket/basicsocket/send_spec.rb index 041ce03d72..868801df30 100644 --- a/spec/ruby/library/socket/basicsocket/send_spec.rb +++ b/spec/ruby/library/socket/basicsocket/send_spec.rb @@ -22,7 +22,7 @@ describe "BasicSocket#send" do client = @server.accept loop do got = client.recv(5) - break if got.nil? || got.empty? + break if got.empty? data << got end client.close @@ -67,7 +67,7 @@ describe "BasicSocket#send" do client = @server.accept loop do got = client.recv(5) - break if got.nil? || got.empty? + break if got.empty? data << got end client.close diff --git a/spec/ruby/library/socket/basicsocket/shutdown_spec.rb b/spec/ruby/library/socket/basicsocket/shutdown_spec.rb index c78b32de38..41d9581bde 100644 --- a/spec/ruby/library/socket/basicsocket/shutdown_spec.rb +++ b/spec/ruby/library/socket/basicsocket/shutdown_spec.rb @@ -23,7 +23,7 @@ platform_is_not :windows do # hangs it 'shuts down a socket for reading' do @client.shutdown(Socket::SHUT_RD) - @client.recv(1).to_s.should be_empty + @client.recv(1).should be_empty end it 'shuts down a socket for writing' do @@ -35,7 +35,7 @@ platform_is_not :windows do # hangs it 'shuts down a socket for reading and writing' do @client.shutdown(Socket::SHUT_RDWR) - @client.recv(1).to_s.should be_empty + @client.recv(1).should be_empty -> { @client.write('hello') }.should raise_error(Errno::EPIPE) end @@ -49,13 +49,13 @@ platform_is_not :windows do # hangs it 'shuts down a socket for reading using :RD' do @client.shutdown(:RD) - @client.recv(1).to_s.should be_empty + @client.recv(1).should be_empty end it 'shuts down a socket for reading using :SHUT_RD' do @client.shutdown(:SHUT_RD) - @client.recv(1).to_s.should be_empty + @client.recv(1).should be_empty end it 'shuts down a socket for writing using :WR' do @@ -73,7 +73,7 @@ platform_is_not :windows do # hangs it 'shuts down a socket for reading and writing' do @client.shutdown(:RDWR) - @client.recv(1).to_s.should be_empty + @client.recv(1).should be_empty -> { @client.write('hello') }.should raise_error(Errno::EPIPE) end @@ -87,13 +87,13 @@ platform_is_not :windows do # hangs it 'shuts down a socket for reading using "RD"' do @client.shutdown('RD') - @client.recv(1).to_s.should be_empty + @client.recv(1).should be_empty end it 'shuts down a socket for reading using "SHUT_RD"' do @client.shutdown('SHUT_RD') - @client.recv(1).to_s.should be_empty + @client.recv(1).should be_empty end it 'shuts down a socket for writing using "WR"' do @@ -123,7 +123,7 @@ platform_is_not :windows do # hangs @client.shutdown(@dummy) - @client.recv(1).to_s.should be_empty + @client.recv(1).should be_empty end it 'shuts down a socket for reading using "SHUT_RD"' do @@ -131,7 +131,7 @@ platform_is_not :windows do # hangs @client.shutdown(@dummy) - @client.recv(1).to_s.should be_empty + @client.recv(1).should be_empty end it 'shuts down a socket for reading and writing' do @@ -139,7 +139,7 @@ platform_is_not :windows do # hangs @client.shutdown(@dummy) - @client.recv(1).to_s.should be_empty + @client.recv(1).should be_empty -> { @client.write('hello') }.should raise_error(Errno::EPIPE) end diff --git a/spec/ruby/library/socket/fixtures/classes.rb b/spec/ruby/library/socket/fixtures/classes.rb index 786629d2ef..4a590502ca 100644 --- a/spec/ruby/library/socket/fixtures/classes.rb +++ b/spec/ruby/library/socket/fixtures/classes.rb @@ -37,9 +37,7 @@ module SocketSpecs # Check for too long unix socket path (max 104 bytes on macOS) # Note that Linux accepts not null-terminated paths but the man page advises against it. if path.bytesize > 104 - # rm_r in spec/mspec/lib/mspec/helpers/fs.rb fails against - # "/tmp/unix_server_spec.socket" - skip "too long unix socket path: #{path}" + path = "/tmp/unix_server_spec.socket" end rm_socket(path) path @@ -113,7 +111,7 @@ module SocketSpecs begin data = socket.recv(1024) - return if data.nil? || data.empty? + return if data.empty? log "SpecTCPServer received: #{data.inspect}" return if data == "QUIT" diff --git a/spec/ruby/library/socket/ipsocket/getaddress_spec.rb b/spec/ruby/library/socket/ipsocket/getaddress_spec.rb index 96324982e5..746d2ab86b 100644 --- a/spec/ruby/library/socket/ipsocket/getaddress_spec.rb +++ b/spec/ruby/library/socket/ipsocket/getaddress_spec.rb @@ -19,7 +19,7 @@ describe "Socket::IPSocket#getaddress" do # traditionally invalidly named ones. it "raises an error on unknown hostnames" do -> { - IPSocket.getaddress("rubyspecdoesntexist.ruby-lang.org") + IPSocket.getaddress("rubyspecdoesntexist.fallingsnow.net") }.should raise_error(SocketError) end end diff --git a/spec/ruby/library/socket/shared/pack_sockaddr.rb b/spec/ruby/library/socket/shared/pack_sockaddr.rb index 9f6238e7bc..2df09027c9 100644 --- a/spec/ruby/library/socket/shared/pack_sockaddr.rb +++ b/spec/ruby/library/socket/shared/pack_sockaddr.rb @@ -19,13 +19,6 @@ describe :socket_pack_sockaddr_in, shared: true do Socket.unpack_sockaddr_in(sockaddr_in).should == [0, '127.0.0.1'] end - platform_is_not :solaris do - it 'resolves the service name to a port' do - sockaddr_in = Socket.public_send(@method, 'http', '127.0.0.1') - Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '127.0.0.1'] - end - end - describe 'using an IPv4 address' do it 'returns a String of 16 bytes' do str = Socket.public_send(@method, 80, '127.0.0.1') diff --git a/spec/ruby/library/socket/shared/partially_closable_sockets.rb b/spec/ruby/library/socket/shared/partially_closable_sockets.rb index b1c2ebabe1..1bdff08bf6 100644 --- a/spec/ruby/library/socket/shared/partially_closable_sockets.rb +++ b/spec/ruby/library/socket/shared/partially_closable_sockets.rb @@ -1,4 +1,4 @@ -describe :partially_closable_sockets, shared: true do +describe "partially closable sockets", shared: true do it "if the write end is closed then the other side can read past EOF without blocking" do @s1.write("foo") @s1.close_write diff --git a/spec/ruby/library/socket/socket/getnameinfo_spec.rb b/spec/ruby/library/socket/socket/getnameinfo_spec.rb index 4f13bf484d..b406348aa8 100644 --- a/spec/ruby/library/socket/socket/getnameinfo_spec.rb +++ b/spec/ruby/library/socket/socket/getnameinfo_spec.rb @@ -70,7 +70,7 @@ describe 'Socket.getnameinfo' do it 'raises SocketError or TypeError when using an invalid String' do -> { Socket.getnameinfo('cats') }.should raise_error(Exception) { |e| - (e.is_a?(SocketError) || e.is_a?(TypeError)).should == true + [SocketError, TypeError].should include(e.class) } end diff --git a/spec/ruby/library/socket/socket/new_spec.rb b/spec/ruby/library/socket/socket/new_spec.rb new file mode 100644 index 0000000000..b2ec607f6a --- /dev/null +++ b/spec/ruby/library/socket/socket/new_spec.rb @@ -0,0 +1,2 @@ +require_relative '../spec_helper' +require_relative '../fixtures/classes' diff --git a/spec/ruby/library/socket/tcpserver/new_spec.rb b/spec/ruby/library/socket/tcpserver/new_spec.rb index dd1ba676bd..8d9696c9d8 100644 --- a/spec/ruby/library/socket/tcpserver/new_spec.rb +++ b/spec/ruby/library/socket/tcpserver/new_spec.rb @@ -97,12 +97,6 @@ describe "TCPServer.new" do addr[1].should be_kind_of(Integer) end - it "does not use the given block and warns to use TCPServer::open" do - -> { - @server = TCPServer.new(0) { raise } - }.should complain(/warning: TCPServer::new\(\) does not take block; use TCPServer::open\(\) instead/) - end - it "raises Errno::EADDRNOTAVAIL when the address is unknown" do -> { TCPServer.new("1.2.3.4", 0) }.should raise_error(Errno::EADDRNOTAVAIL) end diff --git a/spec/ruby/library/socket/tcpsocket/initialize_spec.rb b/spec/ruby/library/socket/tcpsocket/initialize_spec.rb index 3bec06c697..065c8f4190 100644 --- a/spec/ruby/library/socket/tcpsocket/initialize_spec.rb +++ b/spec/ruby/library/socket/tcpsocket/initialize_spec.rb @@ -4,27 +4,6 @@ require_relative 'shared/new' describe 'TCPSocket#initialize' do it_behaves_like :tcpsocket_new, :new - - describe "with a running server" do - before :each do - @server = SocketSpecs::SpecTCPServer.new - @hostname = @server.hostname - end - - after :each do - if @socket - @socket.write "QUIT" - @socket.close - end - @server.shutdown - end - - it "does not use the given block and warns to use TCPSocket::open" do - -> { - @socket = TCPSocket.new(@hostname, @server.port, nil) { raise } - }.should complain(/warning: TCPSocket::new\(\) does not take block; use TCPSocket::open\(\) instead/) - end - end end describe 'TCPSocket#initialize' do diff --git a/spec/ruby/library/socket/tcpsocket/open_spec.rb b/spec/ruby/library/socket/tcpsocket/open_spec.rb index 0c0b579064..31b630a23b 100644 --- a/spec/ruby/library/socket/tcpsocket/open_spec.rb +++ b/spec/ruby/library/socket/tcpsocket/open_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative 'shared/new' describe "TCPSocket.open" do diff --git a/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb b/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb index d365ecd335..a381627a39 100644 --- a/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb +++ b/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb @@ -16,6 +16,6 @@ describe "TCPSocket partial closability" do @s2.close end - it_should_behave_like :partially_closable_sockets + it_should_behave_like "partially closable sockets" end diff --git a/spec/ruby/library/socket/tcpsocket/shared/new.rb b/spec/ruby/library/socket/tcpsocket/shared/new.rb index 90f8d7e6a2..4189acc2f8 100644 --- a/spec/ruby/library/socket/tcpsocket/shared/new.rb +++ b/spec/ruby/library/socket/tcpsocket/shared/new.rb @@ -14,25 +14,11 @@ describe :tcpsocket_new, shared: true do } end - ruby_version_is ""..."3.2" do + ruby_version_is "3.0" do it 'raises Errno::ETIMEDOUT with :connect_timeout when no server is listening on the given address' do -> { TCPSocket.send(@method, "192.0.2.1", 80, connect_timeout: 0) }.should raise_error(Errno::ETIMEDOUT) - rescue Errno::ENETUNREACH - # In the case all network interfaces down. - # raise_error cannot deal with multiple expected exceptions - end - end - - ruby_version_is "3.2" do - it 'raises IO::TimeoutError with :connect_timeout when no server is listening on the given address' do - -> { - TCPSocket.send(@method, "192.0.2.1", 80, connect_timeout: 0) - }.should raise_error(IO::TimeoutError) - rescue Errno::ENETUNREACH - # In the case all network interfaces down. - # raise_error cannot deal with multiple expected exceptions end end @@ -98,9 +84,11 @@ describe :tcpsocket_new, shared: true do @socket.addr[2].should =~ /^#{@hostname}/ end - it "connects to a server when passed connect_timeout argument" do - @socket = TCPSocket.send(@method, @hostname, @server.port, connect_timeout: 1) - @socket.should be_an_instance_of(TCPSocket) + ruby_version_is "3.0" do + it "connects to a server when passed connect_timeout argument" do + @socket = TCPSocket.send(@method, @hostname, @server.port, connect_timeout: 1) + @socket.should be_an_instance_of(TCPSocket) + end end end end diff --git a/spec/ruby/library/socket/udpsocket/new_spec.rb b/spec/ruby/library/socket/udpsocket/new_spec.rb index 79bfcb624d..6cc0cadbcb 100644 --- a/spec/ruby/library/socket/udpsocket/new_spec.rb +++ b/spec/ruby/library/socket/udpsocket/new_spec.rb @@ -26,12 +26,6 @@ describe 'UDPSocket.new' do @socket.should be_an_instance_of(UDPSocket) end - it "does not use the given block and warns to use UDPSocket::open" do - -> { - @socket = UDPSocket.new { raise } - }.should complain(/warning: UDPSocket::new\(\) does not take block; use UDPSocket::open\(\) instead/) - end - it 'raises Errno::EAFNOSUPPORT or Errno::EPROTONOSUPPORT if unsupported family passed' do -> { UDPSocket.new(-1) }.should raise_error(SystemCallError) { |e| [Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT].should include(e.class) diff --git a/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb b/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb index dba3de7359..30688b46b6 100644 --- a/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb +++ b/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb @@ -1,8 +1,9 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXServer#accept_nonblock" do +describe "UNIXServer#accept_nonblock" do + + platform_is_not :windows do before :each do @path = SocketSpecs.socket_path @server = UNIXServer.open(@path) @@ -32,7 +33,9 @@ with_feature :unix_socket do @server.accept_nonblock(exception: false).should == :wait_readable end end +end +with_feature :unix_socket do describe 'UNIXServer#accept_nonblock' do before do @path = SocketSpecs.socket_path diff --git a/spec/ruby/library/socket/unixserver/accept_spec.rb b/spec/ruby/library/socket/unixserver/accept_spec.rb index 624782d6b9..c05fbe7f22 100644 --- a/spec/ruby/library/socket/unixserver/accept_spec.rb +++ b/spec/ruby/library/socket/unixserver/accept_spec.rb @@ -1,7 +1,7 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do +platform_is_not :windows do describe "UNIXServer#accept" do before :each do @path = SocketSpecs.socket_path diff --git a/spec/ruby/library/socket/unixserver/for_fd_spec.rb b/spec/ruby/library/socket/unixserver/for_fd_spec.rb index e00c4d9526..4f3816ad37 100644 --- a/spec/ruby/library/socket/unixserver/for_fd_spec.rb +++ b/spec/ruby/library/socket/unixserver/for_fd_spec.rb @@ -1,7 +1,7 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do +platform_is_not :windows do describe "UNIXServer#for_fd" do before :each do @unix_path = SocketSpecs.socket_path diff --git a/spec/ruby/library/socket/unixserver/new_spec.rb b/spec/ruby/library/socket/unixserver/new_spec.rb index a160e3ce5c..f831f40bc6 100644 --- a/spec/ruby/library/socket/unixserver/new_spec.rb +++ b/spec/ruby/library/socket/unixserver/new_spec.rb @@ -1,14 +1,6 @@ require_relative '../spec_helper' require_relative 'shared/new' -with_feature :unix_socket do - describe "UNIXServer.new" do - it_behaves_like :unixserver_new, :new - - it "does not use the given block and warns to use UNIXServer::open" do - -> { - @server = UNIXServer.new(@path) { raise } - }.should complain(/warning: UNIXServer::new\(\) does not take block; use UNIXServer::open\(\) instead/) - end - end +describe "UNIXServer.new" do + it_behaves_like :unixserver_new, :new end diff --git a/spec/ruby/library/socket/unixserver/open_spec.rb b/spec/ruby/library/socket/unixserver/open_spec.rb index 16453dd3bd..f2506d9f6f 100644 --- a/spec/ruby/library/socket/unixserver/open_spec.rb +++ b/spec/ruby/library/socket/unixserver/open_spec.rb @@ -2,10 +2,10 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' require_relative 'shared/new' -with_feature :unix_socket do - describe "UNIXServer.open" do - it_behaves_like :unixserver_new, :open +describe "UNIXServer.open" do + it_behaves_like :unixserver_new, :open + platform_is_not :windows do before :each do @path = SocketSpecs.socket_path end diff --git a/spec/ruby/library/socket/unixserver/shared/new.rb b/spec/ruby/library/socket/unixserver/shared/new.rb index b537f2a871..35395826c9 100644 --- a/spec/ruby/library/socket/unixserver/shared/new.rb +++ b/spec/ruby/library/socket/unixserver/shared/new.rb @@ -2,19 +2,21 @@ require_relative '../../spec_helper' require_relative '../../fixtures/classes' describe :unixserver_new, shared: true do - before :each do - @path = SocketSpecs.socket_path - end + platform_is_not :windows do + before :each do + @path = SocketSpecs.socket_path + end - after :each do - @server.close if @server - @server = nil - SocketSpecs.rm_socket @path - end + after :each do + @server.close if @server + @server = nil + SocketSpecs.rm_socket @path + end - it "creates a new UNIXServer" do - @server = UNIXServer.send(@method, @path) - @server.path.should == @path - @server.addr.should == ["AF_UNIX", @path] + it "creates a new UNIXServer" do + @server = UNIXServer.send(@method, @path) + @server.path.should == @path + @server.addr.should == ["AF_UNIX", @path] + end end end diff --git a/spec/ruby/library/socket/unixsocket/addr_spec.rb b/spec/ruby/library/socket/unixsocket/addr_spec.rb index d93e061312..e8431bea16 100644 --- a/spec/ruby/library/socket/unixsocket/addr_spec.rb +++ b/spec/ruby/library/socket/unixsocket/addr_spec.rb @@ -1,8 +1,9 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXSocket#addr" do +describe "UNIXSocket#addr" do + + platform_is_not :windows do before :each do @path = SocketSpecs.socket_path @server = UNIXServer.open(@path) diff --git a/spec/ruby/library/socket/unixsocket/inspect_spec.rb b/spec/ruby/library/socket/unixsocket/inspect_spec.rb index a542ba6db5..d2e3cabbd3 100644 --- a/spec/ruby/library/socket/unixsocket/inspect_spec.rb +++ b/spec/ruby/library/socket/unixsocket/inspect_spec.rb @@ -1,8 +1,8 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXSocket#inspect" do +describe "UNIXSocket#inspect" do + platform_is_not :windows do it "returns sockets fd for unnamed sockets" do begin s1, s2 = UNIXSocket.socketpair diff --git a/spec/ruby/library/socket/unixsocket/local_address_spec.rb b/spec/ruby/library/socket/unixsocket/local_address_spec.rb index 734253e7f5..cbf315f9f4 100644 --- a/spec/ruby/library/socket/unixsocket/local_address_spec.rb +++ b/spec/ruby/library/socket/unixsocket/local_address_spec.rb @@ -46,7 +46,9 @@ with_feature :unix_socket do end end end +end +with_feature :unix_socket do describe 'UNIXSocket#local_address with a UNIX socket pair' do before :each do @sock, @sock2 = Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM) diff --git a/spec/ruby/library/socket/unixsocket/new_spec.rb b/spec/ruby/library/socket/unixsocket/new_spec.rb index 6d8ea6dcfe..05a6b3eda2 100644 --- a/spec/ruby/library/socket/unixsocket/new_spec.rb +++ b/spec/ruby/library/socket/unixsocket/new_spec.rb @@ -1,14 +1,6 @@ require_relative '../spec_helper' require_relative 'shared/new' -with_feature :unix_socket do - describe "UNIXSocket.new" do - it_behaves_like :unixsocket_new, :new - - it "does not use the given block and warns to use UNIXSocket::open" do - -> { - @client = UNIXSocket.new(@path) { raise } - }.should complain(/warning: UNIXSocket::new\(\) does not take block; use UNIXSocket::open\(\) instead/) - end - end +describe "UNIXSocket.new" do + it_behaves_like :unixsocket_new, :new end diff --git a/spec/ruby/library/socket/unixsocket/open_spec.rb b/spec/ruby/library/socket/unixsocket/open_spec.rb index 61def30abb..99ad151bb8 100644 --- a/spec/ruby/library/socket/unixsocket/open_spec.rb +++ b/spec/ruby/library/socket/unixsocket/open_spec.rb @@ -2,12 +2,12 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' require_relative 'shared/new' -with_feature :unix_socket do - describe "UNIXSocket.open" do - it_behaves_like :unixsocket_new, :open - end +describe "UNIXSocket.open" do + it_behaves_like :unixsocket_new, :open +end - describe "UNIXSocket.open" do +describe "UNIXSocket.open" do + platform_is_not :windows do before :each do @path = SocketSpecs.socket_path @server = UNIXServer.open(@path) diff --git a/spec/ruby/library/socket/unixsocket/pair_spec.rb b/spec/ruby/library/socket/unixsocket/pair_spec.rb index 9a66c56c10..845ff76ecc 100644 --- a/spec/ruby/library/socket/unixsocket/pair_spec.rb +++ b/spec/ruby/library/socket/unixsocket/pair_spec.rb @@ -2,9 +2,10 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' require_relative '../shared/partially_closable_sockets' -with_feature :unix_socket do - describe "UNIXSocket#pair" do - it_should_behave_like :partially_closable_sockets +describe "UNIXSocket#pair" do + platform_is_not :windows do + + it_should_behave_like "partially closable sockets" before :each do @s1, @s2 = UNIXSocket.pair diff --git a/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb b/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb index ef7d0f0b2a..78a64fe6be 100644 --- a/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb +++ b/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb @@ -2,8 +2,9 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' require_relative '../shared/partially_closable_sockets' -with_feature :unix_socket do +platform_is_not :windows do describe "UNIXSocket partial closability" do + before :each do @path = SocketSpecs.socket_path @server = UNIXServer.open(@path) @@ -18,6 +19,7 @@ with_feature :unix_socket do SocketSpecs.rm_socket @path end - it_should_behave_like :partially_closable_sockets + it_should_behave_like "partially closable sockets" + end end diff --git a/spec/ruby/library/socket/unixsocket/path_spec.rb b/spec/ruby/library/socket/unixsocket/path_spec.rb index a608378e4f..317ffc0975 100644 --- a/spec/ruby/library/socket/unixsocket/path_spec.rb +++ b/spec/ruby/library/socket/unixsocket/path_spec.rb @@ -1,8 +1,9 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXSocket#path" do +describe "UNIXSocket#path" do + + platform_is_not :windows do before :each do @path = SocketSpecs.socket_path @server = UNIXServer.open(@path) @@ -23,4 +24,5 @@ with_feature :unix_socket do @client.path.should == "" end end + end diff --git a/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb b/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb index 72bc96b1fe..0b6b1ccf04 100644 --- a/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb +++ b/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb @@ -1,8 +1,9 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXSocket#peeraddr" do +describe "UNIXSocket#peeraddr" do + + platform_is_not :windows do before :each do @path = SocketSpecs.socket_path @server = UNIXServer.open(@path) @@ -25,4 +26,5 @@ with_feature :unix_socket do }.should raise_error(Errno::ENOTCONN) end end + end diff --git a/spec/ruby/library/socket/unixsocket/recv_io_spec.rb b/spec/ruby/library/socket/unixsocket/recv_io_spec.rb index 1dbc4538e3..533f02a0fa 100644 --- a/spec/ruby/library/socket/unixsocket/recv_io_spec.rb +++ b/spec/ruby/library/socket/unixsocket/recv_io_spec.rb @@ -1,8 +1,9 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXSocket#recv_io" do +describe "UNIXSocket#recv_io" do + + platform_is_not :windows do before :each do @path = SocketSpecs.socket_path @server = UNIXServer.open(@path) @@ -40,7 +41,9 @@ with_feature :unix_socket do @io.should be_an_instance_of(File) end end +end +with_feature :unix_socket do describe 'UNIXSocket#recv_io' do before do @file = File.open('/dev/null', 'w') diff --git a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb index fedf74bb2f..c0e1cf670b 100644 --- a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb +++ b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb @@ -1,8 +1,8 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXSocket#recvfrom" do +describe "UNIXSocket#recvfrom" do + platform_is_not :windows do before :each do @path = SocketSpecs.socket_path @server = UNIXServer.open(@path) @@ -42,7 +42,10 @@ with_feature :unix_socket do sock.close end end +end + +with_feature :unix_socket do describe 'UNIXSocket#recvfrom' do describe 'using a socket pair' do before do diff --git a/spec/ruby/library/socket/unixsocket/send_io_spec.rb b/spec/ruby/library/socket/unixsocket/send_io_spec.rb index 80f3550c6d..a2a7d26539 100644 --- a/spec/ruby/library/socket/unixsocket/send_io_spec.rb +++ b/spec/ruby/library/socket/unixsocket/send_io_spec.rb @@ -1,8 +1,9 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXSocket#send_io" do +describe "UNIXSocket#send_io" do + + platform_is_not :windows do before :each do @path = SocketSpecs.socket_path @server = UNIXServer.open(@path) @@ -31,7 +32,9 @@ with_feature :unix_socket do @io.read.should == File.read(@send_io_path) end end +end +with_feature :unix_socket do describe 'UNIXSocket#send_io' do before do @file = File.open('/dev/null', 'w') diff --git a/spec/ruby/library/socket/unixsocket/shared/new.rb b/spec/ruby/library/socket/unixsocket/shared/new.rb index f075b03c5e..bfb7ed3886 100644 --- a/spec/ruby/library/socket/unixsocket/shared/new.rb +++ b/spec/ruby/library/socket/unixsocket/shared/new.rb @@ -2,21 +2,23 @@ require_relative '../../spec_helper' require_relative '../../fixtures/classes' describe :unixsocket_new, shared: true do - before :each do - @path = SocketSpecs.socket_path - @server = UNIXServer.open(@path) - end + platform_is_not :windows do + before :each do + @path = SocketSpecs.socket_path + @server = UNIXServer.open(@path) + end - after :each do - @client.close if @client - @server.close - SocketSpecs.rm_socket @path - end + after :each do + @client.close if @client + @server.close + SocketSpecs.rm_socket @path + end - it "opens a unix socket on the specified file" do - @client = UNIXSocket.send(@method, @path) + it "opens a unix socket on the specified file" do + @client = UNIXSocket.send(@method, @path) - @client.addr[0].should == "AF_UNIX" - @client.should_not.closed? + @client.addr[0].should == "AF_UNIX" + @client.should_not.closed? + end end end diff --git a/spec/ruby/library/stringio/append_spec.rb b/spec/ruby/library/stringio/append_spec.rb index 5383e3e795..d0cf5550cd 100644 --- a/spec/ruby/library/stringio/append_spec.rb +++ b/spec/ruby/library/stringio/append_spec.rb @@ -29,6 +29,20 @@ describe "StringIO#<< when passed [Object]" do @io.string.should == "example\000\000\000\000\000\000\000\000just testing" end + ruby_version_is ""..."2.7" do + it "taints self's String when the passed argument is tainted" do + (@io << "test".taint) + @io.string.tainted?.should be_true + end + end + + ruby_version_is ""..."3.0" do + it "does not taint self when the passed argument is tainted" do + (@io << "test".taint) + @io.tainted?.should be_false + end + end + it "updates self's position" do @io << "test" @io.pos.should eql(4) diff --git a/spec/ruby/library/stringio/bytes_spec.rb b/spec/ruby/library/stringio/bytes_spec.rb new file mode 100644 index 0000000000..4ef7a490a5 --- /dev/null +++ b/spec/ruby/library/stringio/bytes_spec.rb @@ -0,0 +1,29 @@ +require_relative '../../spec_helper' +require 'stringio' +require_relative 'shared/each_byte' + +ruby_version_is ''...'3.0' do + describe "StringIO#bytes" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :stringio_each_byte, :bytes + end + + describe "StringIO#bytes when self is not readable" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :stringio_each_byte_not_readable, :bytes + end +end diff --git a/spec/ruby/library/stringio/chars_spec.rb b/spec/ruby/library/stringio/chars_spec.rb new file mode 100644 index 0000000000..58cba77634 --- /dev/null +++ b/spec/ruby/library/stringio/chars_spec.rb @@ -0,0 +1,29 @@ +require_relative '../../spec_helper' +require 'stringio' +require_relative 'shared/each_char' + +ruby_version_is ''...'3.0' do + describe "StringIO#chars" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :stringio_each_char, :chars + end + + describe "StringIO#chars when self is not readable" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :stringio_each_char_not_readable, :chars + end +end diff --git a/spec/ruby/library/stringio/codepoints_spec.rb b/spec/ruby/library/stringio/codepoints_spec.rb new file mode 100644 index 0000000000..ceaadefc32 --- /dev/null +++ b/spec/ruby/library/stringio/codepoints_spec.rb @@ -0,0 +1,19 @@ +# -*- encoding: utf-8 -*- +require_relative '../../spec_helper' +require_relative 'fixtures/classes' +require_relative 'shared/codepoints' + +ruby_version_is ''...'3.0' do + # See redmine #1667 + describe "StringIO#codepoints" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :stringio_codepoints, :codepoints + end +end diff --git a/spec/ruby/library/stringio/each_line_spec.rb b/spec/ruby/library/stringio/each_line_spec.rb index c68f7dae82..1389408399 100644 --- a/spec/ruby/library/stringio/each_line_spec.rb +++ b/spec/ruby/library/stringio/each_line_spec.rb @@ -17,7 +17,3 @@ end describe "StringIO#each_line when passed chomp" do it_behaves_like :stringio_each_chomp, :each_line end - -describe "StringIO#each_line when passed limit" do - it_behaves_like :stringio_each_limit, :each_line -end diff --git a/spec/ruby/library/stringio/each_spec.rb b/spec/ruby/library/stringio/each_spec.rb index 2c30ed5cda..a76460049b 100644 --- a/spec/ruby/library/stringio/each_spec.rb +++ b/spec/ruby/library/stringio/each_spec.rb @@ -17,11 +17,3 @@ end describe "StringIO#each when passed chomp" do it_behaves_like :stringio_each_chomp, :each end - -describe "StringIO#each when passed chomp" do - it_behaves_like :stringio_each_separator_and_chomp, :each -end - -describe "StringIO#each when passed limit" do - it_behaves_like :stringio_each_limit, :each -end diff --git a/spec/ruby/library/stringio/gets_spec.rb b/spec/ruby/library/stringio/gets_spec.rb index d597ec0e45..97429e6a29 100644 --- a/spec/ruby/library/stringio/gets_spec.rb +++ b/spec/ruby/library/stringio/gets_spec.rb @@ -171,10 +171,6 @@ describe "StringIO#gets when passed [limit]" do it "returns a blank string when passed a limit of 0" do @io.gets(0).should == "" end - - it "ignores it when passed a negative limit" do - @io.gets(-4).should == "this>is>an>example" - end end describe "StringIO#gets when passed [separator] and [limit]" do diff --git a/spec/ruby/library/stringio/initialize_spec.rb b/spec/ruby/library/stringio/initialize_spec.rb index 158c08488b..1e8096e3bb 100644 --- a/spec/ruby/library/stringio/initialize_spec.rb +++ b/spec/ruby/library/stringio/initialize_spec.rb @@ -163,91 +163,6 @@ describe "StringIO#initialize when passed [Object]" do end end -# NOTE: Synchronise with core/io/new_spec.rb (core/io/shared/new.rb) -describe "StringIO#initialize when passed keyword arguments" do - it "sets the mode based on the passed :mode option" do - io = StringIO.new("example", "r") - io.closed_read?.should be_false - io.closed_write?.should be_true - end - - it "accepts a mode argument set to nil with a valid :mode option" do - @io = StringIO.new('', nil, mode: "w") - @io.write("foo").should == 3 - end - - it "accepts a mode argument with a :mode option set to nil" do - @io = StringIO.new('', "w", mode: nil) - @io.write("foo").should == 3 - end - - it "sets binmode from :binmode option" do - @io = StringIO.new('', 'w', binmode: true) - @io.external_encoding.to_s.should == "ASCII-8BIT" # #binmode? isn't implemented in StringIO - end - - it "does not set binmode from false :binmode" do - @io = StringIO.new('', 'w', binmode: false) - @io.external_encoding.to_s.should == "UTF-8" # #binmode? isn't implemented in StringIO - end -end - -# NOTE: Synchronise with core/io/new_spec.rb (core/io/shared/new.rb) -describe "StringIO#initialize when passed keyword arguments and error happens" do - it "raises an error if passed encodings two ways" do - -> { - @io = StringIO.new('', 'w:ISO-8859-1', encoding: 'ISO-8859-1') - }.should raise_error(ArgumentError) - -> { - @io = StringIO.new('', 'w:ISO-8859-1', external_encoding: 'ISO-8859-1') - }.should raise_error(ArgumentError) - -> { - @io = StringIO.new('', 'w:ISO-8859-1:UTF-8', internal_encoding: 'ISO-8859-1') - }.should raise_error(ArgumentError) - end - - it "raises an error if passed matching binary/text mode two ways" do - -> { - @io = StringIO.new('', "wb", binmode: true) - }.should raise_error(ArgumentError) - -> { - @io = StringIO.new('', "wt", textmode: true) - }.should raise_error(ArgumentError) - - -> { - @io = StringIO.new('', "wb", textmode: false) - }.should raise_error(ArgumentError) - -> { - @io = StringIO.new('', "wt", binmode: false) - }.should raise_error(ArgumentError) - end - - it "raises an error if passed conflicting binary/text mode two ways" do - -> { - @io = StringIO.new('', "wb", binmode: false) - }.should raise_error(ArgumentError) - -> { - @io = StringIO.new('', "wt", textmode: false) - }.should raise_error(ArgumentError) - - -> { - @io = StringIO.new('', "wb", textmode: true) - }.should raise_error(ArgumentError) - -> { - @io = StringIO.new('', "wt", binmode: true) - }.should raise_error(ArgumentError) - end - - it "raises an error when trying to set both binmode and textmode" do - -> { - @io = StringIO.new('', "w", textmode: true, binmode: true) - }.should raise_error(ArgumentError) - -> { - @io = StringIO.new('', File::Constants::WRONLY, textmode: true, binmode: true) - }.should raise_error(ArgumentError) - end -end - describe "StringIO#initialize when passed no arguments" do before :each do @io = StringIO.allocate @@ -294,9 +209,14 @@ describe "StringIO#initialize sets" do io.string.encoding.should == Encoding::EUC_JP end - it "the #external_encoding to the encoding of the String when passed a String" do - s = ''.force_encoding(Encoding::EUC_JP) - io = StringIO.new(s) - io.external_encoding.should == Encoding::EUC_JP + guard_not -> { # [Bug #16497] + stringio_version = StringIO.const_defined?(:VERSION) ? StringIO::VERSION : "0.0.2" + version_is(stringio_version, "0.0.3"..."0.1.1") + } do + it "the #external_encoding to the encoding of the String when passed a String" do + s = ''.force_encoding(Encoding::EUC_JP) + io = StringIO.new(s) + io.external_encoding.should == Encoding::EUC_JP + end end end diff --git a/spec/ruby/library/stringio/lines_spec.rb b/spec/ruby/library/stringio/lines_spec.rb new file mode 100644 index 0000000000..42d11772ae --- /dev/null +++ b/spec/ruby/library/stringio/lines_spec.rb @@ -0,0 +1,53 @@ +require_relative '../../spec_helper' +require 'stringio' +require_relative 'shared/each' + +ruby_version_is ''...'3.0' do + describe "StringIO#lines when passed a separator" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :stringio_each_separator, :lines + end + + describe "StringIO#lines when passed no arguments" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :stringio_each_no_arguments, :lines + end + + describe "StringIO#lines when self is not readable" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :stringio_each_not_readable, :lines + end + + describe "StringIO#lines when passed chomp" do + before :each do + @verbose, $VERBOSE = $VERBOSE, nil + end + + after :each do + $VERBOSE = @verbose + end + + it_behaves_like :stringio_each_chomp, :lines + end +end diff --git a/spec/ruby/library/stringio/new_spec.rb b/spec/ruby/library/stringio/new_spec.rb deleted file mode 100644 index ec4b32aa11..0000000000 --- a/spec/ruby/library/stringio/new_spec.rb +++ /dev/null @@ -1,10 +0,0 @@ -require_relative '../../spec_helper' -require 'stringio' - -describe "StringIO.new" do - it "does not use the given block and warns to use StringIO::open" do - -> { - StringIO.new { raise } - }.should complain(/warning: StringIO::new\(\) does not take block; use StringIO::open\(\) instead/) - end -end diff --git a/spec/ruby/library/stringio/open_spec.rb b/spec/ruby/library/stringio/open_spec.rb index 3068e19435..acab6e9056 100644 --- a/spec/ruby/library/stringio/open_spec.rb +++ b/spec/ruby/library/stringio/open_spec.rb @@ -167,14 +167,10 @@ describe "StringIO.open when passed [Object]" do io.should equal(ret) end - it "sets the mode to read-write (r+)" do + it "sets the mode to read-write" do io = StringIO.open("example") io.closed_read?.should be_false io.closed_write?.should be_false - - io = StringIO.new("example") - io.printf("%d", 123) - io.string.should == "123mple" end it "tries to convert the passed Object to a String using #to_str" do @@ -199,14 +195,10 @@ describe "StringIO.open when passed no arguments" do io.should equal(ret) end - it "sets the mode to read-write (r+)" do + it "sets the mode to read-write" do io = StringIO.open io.closed_read?.should be_false io.closed_write?.should be_false - - io = StringIO.new("example") - io.printf("%d", 123) - io.string.should == "123mple" end it "uses an empty String as the StringIO backend" do diff --git a/spec/ruby/library/stringio/printf_spec.rb b/spec/ruby/library/stringio/printf_spec.rb index f3f669a185..9dd1a3b410 100644 --- a/spec/ruby/library/stringio/printf_spec.rb +++ b/spec/ruby/library/stringio/printf_spec.rb @@ -4,7 +4,7 @@ require_relative '../../core/kernel/shared/sprintf' describe "StringIO#printf" do before :each do - @io = StringIO.new() + @io = StringIO.new('example') end it "returns nil" do @@ -12,9 +12,9 @@ describe "StringIO#printf" do end it "pads self with \\000 when the current position is after the end" do - @io.pos = 3 + @io.pos = 10 @io.printf("%d", 123) - @io.string.should == "\000\000\000123" + @io.string.should == "example\000\000\000123" end it "performs format conversion" do @@ -39,27 +39,6 @@ describe "StringIO#printf" do end end -describe "StringIO#printf when in read-write mode" do - before :each do - @io = StringIO.new("example", "r+") - end - - it "starts from the beginning" do - @io.printf("%s", "abcdefghijk") - @io.string.should == "abcdefghijk" - end - - it "does not truncate existing string" do - @io.printf("%s", "abc") - @io.string.should == "abcmple" - end - - it "correctly updates self's position" do - @io.printf("%s", "abc") - @io.pos.should eql(3) - end -end - describe "StringIO#printf when in append mode" do before :each do @io = StringIO.new("example", "a") diff --git a/spec/ruby/library/stringio/putc_spec.rb b/spec/ruby/library/stringio/putc_spec.rb index 1ce53b7ef2..223b3523e5 100644 --- a/spec/ruby/library/stringio/putc_spec.rb +++ b/spec/ruby/library/stringio/putc_spec.rb @@ -35,21 +35,6 @@ describe "StringIO#putc when passed [String]" do @io.putc("t") @io.pos.should == 3 end - - it "handles concurrent writes correctly" do - @io = StringIO.new - n = 8 - go = false - threads = n.times.map { |i| - Thread.new { - Thread.pass until go - @io.putc i.to_s - } - } - go = true - threads.each(&:join) - @io.string.size.should == n - end end describe "StringIO#putc when passed [Object]" do diff --git a/spec/ruby/library/stringio/puts_spec.rb b/spec/ruby/library/stringio/puts_spec.rb index 9c890262dd..a9f289a5a5 100644 --- a/spec/ruby/library/stringio/puts_spec.rb +++ b/spec/ruby/library/stringio/puts_spec.rb @@ -101,20 +101,6 @@ describe "StringIO#puts when passed 1 or more objects" do @io.puts '' @io.string.should == "\n" end - - it "handles concurrent writes correctly" do - n = 8 - go = false - threads = n.times.map { |i| - Thread.new { - Thread.pass until go - @io.puts i - } - } - go = true - threads.each(&:join) - @io.string.size.should == n.times.map { |i| "#{i}\n" }.join.size - end end describe "StringIO#puts when passed no arguments" do diff --git a/spec/ruby/library/stringio/read_nonblock_spec.rb b/spec/ruby/library/stringio/read_nonblock_spec.rb index d4ec56d9aa..2a8f926bd0 100644 --- a/spec/ruby/library/stringio/read_nonblock_spec.rb +++ b/spec/ruby/library/stringio/read_nonblock_spec.rb @@ -5,21 +5,10 @@ require_relative 'shared/sysread' describe "StringIO#read_nonblock when passed length, buffer" do it_behaves_like :stringio_read, :read_nonblock - - it "accepts :exception option" do - io = StringIO.new("example") - io.read_nonblock(3, buffer = "", exception: true) - buffer.should == "exa" - end end describe "StringIO#read_nonblock when passed length" do it_behaves_like :stringio_read_length, :read_nonblock - - it "accepts :exception option" do - io = StringIO.new("example") - io.read_nonblock(3, exception: true).should == "exa" - end end describe "StringIO#read_nonblock when passed nil" do diff --git a/spec/ruby/library/stringio/readline_spec.rb b/spec/ruby/library/stringio/readline_spec.rb index b794e5fade..94b67bc92d 100644 --- a/spec/ruby/library/stringio/readline_spec.rb +++ b/spec/ruby/library/stringio/readline_spec.rb @@ -128,23 +128,3 @@ describe "StringIO#readline when passed [chomp]" do io.readline(chomp: true).should == "this>is>an>example" end end - -describe "StringIO#readline when passed [limit]" do - before :each do - @io = StringIO.new("this>is>an>example") - end - - it "returns the data read until the limit is met" do - io = StringIO.new("this>is>an>example\n") - io.readline(3).should == "thi" - end - - it "returns a blank string when passed a limit of 0" do - @io.readline(0).should == "" - end - - it "ignores it when the limit is negative" do - seen = [] - @io.readline(-4).should == "this>is>an>example" - end -end diff --git a/spec/ruby/library/stringio/readlines_spec.rb b/spec/ruby/library/stringio/readlines_spec.rb index c471d0fd73..4b007787e2 100644 --- a/spec/ruby/library/stringio/readlines_spec.rb +++ b/spec/ruby/library/stringio/readlines_spec.rb @@ -98,21 +98,3 @@ describe "StringIO#readlines when passed [chomp]" do io.readlines(chomp: true).should == ["this>is", "an>example"] end end - -describe "StringIO#readlines when passed [limit]" do - before :each do - @io = StringIO.new("a b c d e\n1 2 3 4 5") - end - - it "returns the data read until the limit is met" do - @io.readlines(4).should == ["a b ", "c d ", "e\n", "1 2 ", "3 4 ", "5"] - end - - it "raises ArgumentError when limit is 0" do - -> { @io.readlines(0) }.should raise_error(ArgumentError) - end - - it "ignores it when the limit is negative" do - @io.readlines(-4).should == ["a b c d e\n", "1 2 3 4 5"] - end -end diff --git a/spec/ruby/library/stringio/reopen_spec.rb b/spec/ruby/library/stringio/reopen_spec.rb index 9851c5b706..6752cf9970 100644 --- a/spec/ruby/library/stringio/reopen_spec.rb +++ b/spec/ruby/library/stringio/reopen_spec.rb @@ -23,6 +23,17 @@ describe "StringIO#reopen when passed [Object, Integer]" do @io.string.should == "reopened, another time" end + ruby_version_is ""..."3.0" do + # NOTE: WEIRD! + it "does not taint self when the passed Object was tainted" do + @io.reopen("reopened".taint, IO::RDONLY) + @io.tainted?.should be_false + + @io.reopen("reopened".taint, IO::WRONLY) + @io.tainted?.should be_false + end + end + it "tries to convert the passed Object to a String using #to_str" do obj = mock("to_str") obj.should_receive(:to_str).and_return("to_str") @@ -81,6 +92,17 @@ describe "StringIO#reopen when passed [Object, Object]" do str.should == "" end + ruby_version_is ""..."3.0" do + # NOTE: WEIRD! + it "does not taint self when the passed Object was tainted" do + @io.reopen("reopened".taint, "r") + @io.tainted?.should be_false + + @io.reopen("reopened".taint, "w") + @io.tainted?.should be_false + end + end + it "tries to convert the passed Object to a String using #to_str" do obj = mock("to_str") obj.should_receive(:to_str).and_return("to_str") @@ -142,6 +164,14 @@ describe "StringIO#reopen when passed [String]" do @io.string.should == "reopened" end + ruby_version_is ""..."3.0" do + # NOTE: WEIRD! + it "does not taint self when the passed Object was tainted" do + @io.reopen("reopened".taint) + @io.tainted?.should be_false + end + end + it "resets self's position to 0" do @io.read(5) @io.reopen("reopened") @@ -176,6 +206,14 @@ describe "StringIO#reopen when passed [Object]" do @io.reopen(obj) @io.string.should == "to_strio" end + + # NOTE: WEIRD! + ruby_version_is ""..."2.7" do + it "taints self when the passed Object was tainted" do + @io.reopen(StringIO.new("reopened").taint) + @io.tainted?.should be_true + end + end end describe "StringIO#reopen when passed no arguments" do @@ -240,6 +278,15 @@ describe "StringIO#reopen" do str.should == '' end + ruby_version_is ""..."2.7" do + it "taints self if the provided StringIO argument is tainted" do + new_io = StringIO.new("tainted") + new_io.taint + @io.reopen(new_io) + @io.should.tainted? + end + end + it "does not truncate the content even when the StringIO argument is in the truncate mode" do orig_io = StringIO.new("Original StringIO", IO::RDWR|IO::TRUNC) orig_io.write("BLAH") # make sure the content is not empty diff --git a/spec/ruby/library/stringio/set_encoding_spec.rb b/spec/ruby/library/stringio/set_encoding_spec.rb index 19ca0875bf..21d45750f3 100644 --- a/spec/ruby/library/stringio/set_encoding_spec.rb +++ b/spec/ruby/library/stringio/set_encoding_spec.rb @@ -17,12 +17,4 @@ describe "StringIO#set_encoding" do io.set_encoding Encoding::UTF_8 io.string.encoding.should == Encoding::US_ASCII end - - it "accepts a String" do - str = "".encode(Encoding::US_ASCII) - io = StringIO.new(str) - io.set_encoding("ASCII-8BIT") - io.external_encoding.should == Encoding::BINARY - str.encoding.should == Encoding::BINARY - end end diff --git a/spec/ruby/library/stringio/shared/each.rb b/spec/ruby/library/stringio/shared/each.rb index acd8d22c14..14b0a013b3 100644 --- a/spec/ruby/library/stringio/shared/each.rb +++ b/spec/ruby/library/stringio/shared/each.rb @@ -36,22 +36,11 @@ describe :stringio_each_separator, shared: true do seen.should == ["2 1 2 1 2"] end - version_is StringIO::VERSION, ""..."3.0.4" do #ruby_version_is ""..."3.2" do - it "yields each paragraph with two separation characters when passed an empty String as separator" do - seen = [] - io = StringIO.new("para1\n\npara2\n\n\npara3") - io.send(@method, "") {|s| seen << s} - seen.should == ["para1\n\n", "para2\n\n", "para3"] - end - end - - version_is StringIO::VERSION, "3.0.4" do #ruby_version_is "3.2" do - it "yields each paragraph with all separation characters when passed an empty String as separator" do - seen = [] - io = StringIO.new("para1\n\npara2\n\n\npara3") - io.send(@method, "") {|s| seen << s} - seen.should == ["para1\n\n", "para2\n\n\n", "para3"] - end + it "yields each paragraph when passed an empty String as separator" do + seen = [] + io = StringIO.new("para1\n\npara2\n\n\npara3") + io.send(@method, "") {|s| seen << s} + seen.should == ["para1\n\n", "para2\n\n", "para3"] end end @@ -123,41 +112,4 @@ describe :stringio_each_chomp, shared: true do io.send(@method, chomp: true) {|s| seen << s } seen.should == ["a b \rc d e", "1 2 3 4 5", "the end"] end - - it "returns each line with removed newline characters when called without block" do - seen = [] - io = StringIO.new("a b \rc d e\n1 2 3 4 5\r\nthe end") - enum = io.send(@method, chomp: true) - enum.each {|s| seen << s } - seen.should == ["a b \rc d e", "1 2 3 4 5", "the end"] - end -end - -describe :stringio_each_separator_and_chomp, shared: true do - it "yields each line with removed separator to the passed block" do - seen = [] - io = StringIO.new("a b \nc d e|1 2 3 4 5\n|the end") - io.send(@method, "|", chomp: true) {|s| seen << s } - seen.should == ["a b \nc d e", "1 2 3 4 5\n", "the end"] - end - - it "returns each line with removed separator when called without block" do - seen = [] - io = StringIO.new("a b \nc d e|1 2 3 4 5\n|the end") - enum = io.send(@method, "|", chomp: true) - enum.each {|s| seen << s } - seen.should == ["a b \nc d e", "1 2 3 4 5\n", "the end"] - end -end - -describe :stringio_each_limit, shared: true do - before :each do - @io = StringIO.new("a b c d e\n1 2 3 4 5") - end - - it "returns the data read until the limit is met" do - seen = [] - @io.send(@method, 4) { |s| seen << s } - seen.should == ["a b ", "c d ", "e\n", "1 2 ", "3 4 ", "5"] - end end diff --git a/spec/ruby/library/stringio/shared/read.rb b/spec/ruby/library/stringio/shared/read.rb index 252a85d89d..c60677bba7 100644 --- a/spec/ruby/library/stringio/shared/read.rb +++ b/spec/ruby/library/stringio/shared/read.rb @@ -89,12 +89,6 @@ describe :stringio_read_no_arguments, shared: true do @io.send(@method) @io.pos.should eql(7) end - - it "correctly update the current position in bytes when multi-byte characters are used" do - @io.print("example\u03A3") # Overwrite the original string with 8 characters containing 9 bytes. - @io.send(@method) - @io.pos.should eql(9) - end end describe :stringio_read_nil, shared: true do diff --git a/spec/ruby/library/stringio/shared/sysread.rb b/spec/ruby/library/stringio/shared/sysread.rb index 937bac705c..3376bd9907 100644 --- a/spec/ruby/library/stringio/shared/sysread.rb +++ b/spec/ruby/library/stringio/shared/sysread.rb @@ -1,4 +1,4 @@ -describe :stringio_sysread_length, shared: true do +describe :stringio_sysread_length, :shared => true do before :each do @io = StringIO.new("example") end diff --git a/spec/ruby/library/stringio/shared/write.rb b/spec/ruby/library/stringio/shared/write.rb index aa67bb73c7..080729217b 100644 --- a/spec/ruby/library/stringio/shared/write.rb +++ b/spec/ruby/library/stringio/shared/write.rb @@ -45,62 +45,18 @@ describe :stringio_write_string, shared: true do @io.pos.should eql(4) end - it "handles concurrent writes correctly" do - @io = StringIO.new - n = 8 - go = false - threads = n.times.map { |i| - Thread.new { - Thread.pass until go - @io.write i.to_s - } - } - go = true - threads.each(&:join) - @io.string.size.should == n.times.map(&:to_s).join.size - end - - it "handles writing non-ASCII UTF-8 after seek" do - @io.binmode - @io << "\x80" - @io.pos = 0 - @io << "\x81" - @io.string.should == "\x812345".b - end - - it "handles writing with position < buffer size" do - @io.pos = 2 - @io.write "abc" - @io.string.should == "12abc" - - @io.pos = 2 - @io.write "de" - @io.string.should == "12dec" - - @io.pos = 2 - @io.write "fghi" - @io.string.should == "12fghi" - end - - it "transcodes the given string when the external encoding is set and neither is BINARY" do - utf8_str = "hello" - io = StringIO.new.set_encoding(Encoding::UTF_16BE) - io.external_encoding.should == Encoding::UTF_16BE - - io.send(@method, utf8_str) - - expected = [0, 104, 0, 101, 0, 108, 0, 108, 0, 111] # UTF-16BE bytes for "hello" - io.string.bytes.should == expected - end - - it "does not transcode the given string when the external encoding is set and the string encoding is BINARY" do - str = "été".b - io = StringIO.new.set_encoding(Encoding::UTF_16BE) - io.external_encoding.should == Encoding::UTF_16BE - - io.send(@method, str) - - io.string.bytes.should == str.bytes + ruby_version_is ""..."2.7" do + it "taints self's String when the passed argument is tainted" do + @io.send(@method, "test".taint) + @io.string.tainted?.should be_true + end + end + + ruby_version_is ""..."3.0" do + it "does not taint self when the passed argument is tainted" do + @io.send(@method, "test".taint) + @io.tainted?.should be_false + end end end diff --git a/spec/ruby/library/stringio/truncate_spec.rb b/spec/ruby/library/stringio/truncate_spec.rb index e8d7f1a15d..ba910ee98c 100644 --- a/spec/ruby/library/stringio/truncate_spec.rb +++ b/spec/ruby/library/stringio/truncate_spec.rb @@ -6,8 +6,10 @@ describe "StringIO#truncate when passed [length]" do @io = StringIO.new('123456789') end - it "returns an Integer" do - @io.truncate(4).should be_kind_of(Integer) + # TODO: Report to Ruby-Core: The RDoc says it always returns 0 + it "returns the passed length" do + @io.truncate(4).should eql(4) + @io.truncate(10).should eql(10) end it "truncated the underlying string down to the passed length" do @@ -45,6 +47,12 @@ describe "StringIO#truncate when passed [length]" do @io.string.should == "1234" end + it "returns the passed length Object, NOT the result of #to_int" do + obj = mock("to_int") + obj.should_receive(:to_int).and_return(4) + @io.truncate(obj).should equal(obj) + end + it "raises a TypeError when the passed length can't be converted to an Integer" do -> { @io.truncate(Object.new) }.should raise_error(TypeError) end diff --git a/spec/ruby/library/stringio/write_nonblock_spec.rb b/spec/ruby/library/stringio/write_nonblock_spec.rb index a457b97667..4f4c5039fe 100644 --- a/spec/ruby/library/stringio/write_nonblock_spec.rb +++ b/spec/ruby/library/stringio/write_nonblock_spec.rb @@ -8,12 +8,6 @@ end describe "StringIO#write_nonblock when passed [String]" do it_behaves_like :stringio_write_string, :write_nonblock - - it "accepts :exception option" do - io = StringIO.new("12345", "a") - io.write_nonblock("67890", exception: true) - io.string.should == "1234567890" - end end describe "StringIO#write_nonblock when self is not writable" do diff --git a/spec/ruby/library/stringscanner/check_spec.rb b/spec/ruby/library/stringscanner/check_spec.rb index a97c26af83..21da785515 100644 --- a/spec/ruby/library/stringscanner/check_spec.rb +++ b/spec/ruby/library/stringscanner/check_spec.rb @@ -14,12 +14,14 @@ describe "StringScanner#check" do @s.matched.should == nil end - it "treats String as the pattern itself" do - @s.check("This").should == "This" - @s.matched.should == "This" - @s.pos.should == 0 - @s.check(/is/).should == nil - @s.matched.should == nil + ruby_version_is "2.7" do + it "treats String as the pattern itself" do + @s.check("This").should == "This" + @s.matched.should == "This" + @s.pos.should == 0 + @s.check(/is/).should == nil + @s.matched.should == nil + end end end diff --git a/spec/ruby/library/stringscanner/scan_spec.rb b/spec/ruby/library/stringscanner/scan_spec.rb index ea711767b9..2269abd6b3 100644 --- a/spec/ruby/library/stringscanner/scan_spec.rb +++ b/spec/ruby/library/stringscanner/scan_spec.rb @@ -50,9 +50,17 @@ describe "StringScanner#scan" do @s.scan(/./).should be_nil end - it "treats String as the pattern itself" do - @s.scan("this").should be_nil - @s.scan("This").should == "This" + ruby_version_is ""..."2.7" do + it "raises a TypeError if pattern is a String" do + -> { @s.scan("aoeu") }.should raise_error(TypeError) + end + end + + ruby_version_is "2.7" do + it "treats String as the pattern itself" do + @s.scan("this").should be_nil + @s.scan("This").should == "This" + end end it "raises a TypeError if pattern isn't a Regexp nor String" do @@ -67,21 +75,23 @@ describe "StringScanner#scan with fixed_anchor: true" do @s = StringScanner.new("This\nis\na\ntest", fixed_anchor: true) end - it "returns the matched string" do - @s.scan(/\w+/).should == "This" - @s.scan(/.../m).should == "\nis" - @s.scan(//).should == "" - @s.scan(/\s+/).should == "\n" - end + ruby_version_is "2.7" do + it "returns the matched string" do + @s.scan(/\w+/).should == "This" + @s.scan(/.../m).should == "\nis" + @s.scan(//).should == "" + @s.scan(/\s+/).should == "\n" + end - it "treats ^ as matching from the beginning of line" do - @s.scan(/\w+\n/).should == "This\n" - @s.scan(/^\w/).should == "i" - @s.scan(/^\w/).should be_nil - end + it "treats ^ as matching from the beginning of line" do + @s.scan(/\w+\n/).should == "This\n" + @s.scan(/^\w/).should == "i" + @s.scan(/^\w/).should be_nil + end - it "treats \\A as matching from the beginning of string" do - @s.scan(/\A\w/).should == "T" - @s.scan(/\A\w/).should be_nil + it "treats \\A as matching from the beginning of string" do + @s.scan(/\A\w/).should == "T" + @s.scan(/\A\w/).should be_nil + end end end diff --git a/spec/ruby/library/stringscanner/shared/extract_range.rb b/spec/ruby/library/stringscanner/shared/extract_range.rb index e7404fd0cb..1c14f716c9 100644 --- a/spec/ruby/library/stringscanner/shared/extract_range.rb +++ b/spec/ruby/library/stringscanner/shared/extract_range.rb @@ -8,4 +8,17 @@ describe :extract_range, shared: true do ch.should_not be_kind_of(cls) ch.should be_an_instance_of(String) end + + ruby_version_is ''...'2.7' do + it "taints the returned String if the input was tainted" do + str = 'abc' + str.taint + + s = StringScanner.new(str) + + s.send(@method).tainted?.should be_true + s.send(@method).tainted?.should be_true + s.send(@method).tainted?.should be_true + end + end end diff --git a/spec/ruby/library/stringscanner/shared/extract_range_matched.rb b/spec/ruby/library/stringscanner/shared/extract_range_matched.rb index 070a132812..5c536f5c01 100644 --- a/spec/ruby/library/stringscanner/shared/extract_range_matched.rb +++ b/spec/ruby/library/stringscanner/shared/extract_range_matched.rb @@ -10,4 +10,15 @@ describe :extract_range_matched, shared: true do ch.should_not be_kind_of(cls) ch.should be_an_instance_of(String) end + + ruby_version_is ''...'2.7' do + it "taints the returned String if the input was tainted" do + str = 'abc' + str.taint + + s = StringScanner.new(str) + s.scan(/\w{1}/) + s.send(@method).tainted?.should be_true + end + end end diff --git a/spec/ruby/library/stringscanner/shared/peek.rb b/spec/ruby/library/stringscanner/shared/peek.rb index 4c757866c1..4e2e643353 100644 --- a/spec/ruby/library/stringscanner/shared/peek.rb +++ b/spec/ruby/library/stringscanner/shared/peek.rb @@ -36,4 +36,14 @@ describe :strscan_peek, shared: true do ch.should_not be_kind_of(cls) ch.should be_an_instance_of(String) end + + ruby_version_is ''...'2.7' do + it "taints the returned String if the input was tainted" do + str = 'abc' + str.taint + + s = StringScanner.new(str) + s.send(@method, 1).tainted?.should be_true + end + end end diff --git a/spec/ruby/library/time/to_datetime_spec.rb b/spec/ruby/library/time/to_datetime_spec.rb index 9c44f38e5c..0e37a61108 100644 --- a/spec/ruby/library/time/to_datetime_spec.rb +++ b/spec/ruby/library/time/to_datetime_spec.rb @@ -1,13 +1,11 @@ require_relative '../../spec_helper' require 'time' -require 'date' -date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0' describe "Time#to_datetime" do it "returns a DateTime representing the same instant" do - time = Time.utc(2012, 12, 31, 23, 58, 59) + time = Time.utc(3, 12, 31, 23, 58, 59) datetime = time.to_datetime - datetime.year.should == 2012 + datetime.year.should == 3 datetime.month.should == 12 datetime.day.should == 31 datetime.hour.should == 23 @@ -15,19 +13,6 @@ describe "Time#to_datetime" do datetime.sec.should == 59 end - version_is date_version, '3.2.3' do #ruby_version_is '3.2' do - it "returns a DateTime representing the same instant before Gregorian" do - time = Time.utc(1582, 10, 14, 23, 58, 59) - datetime = time.to_datetime - datetime.year.should == 1582 - datetime.month.should == 10 - datetime.day.should == 4 - datetime.hour.should == 23 - datetime.min.should == 58 - datetime.sec.should == 59 - end - end - it "roundtrips" do time = Time.utc(3, 12, 31, 23, 58, 59) datetime = time.to_datetime diff --git a/spec/ruby/library/uri/generic/host_spec.rb b/spec/ruby/library/uri/generic/host_spec.rb index 210124ef66..f2076d2bc1 100644 --- a/spec/ruby/library/uri/generic/host_spec.rb +++ b/spec/ruby/library/uri/generic/host_spec.rb @@ -2,12 +2,7 @@ require_relative '../../../spec_helper' require 'uri' describe "URI::Generic#host" do - version_is URI::VERSION, "0.12" do #ruby_version_is "3.2" do - # https://hackerone.com/reports/156615 - it "returns empty string when host is empty" do - URI.parse('http:////foo.com').host.should == '' - end - end + it "needs to be reviewed for spec completeness" end describe "URI::Generic#host=" do diff --git a/spec/ruby/library/uri/generic/to_s_spec.rb b/spec/ruby/library/uri/generic/to_s_spec.rb index 8cebd374a1..8c90d7645b 100644 --- a/spec/ruby/library/uri/generic/to_s_spec.rb +++ b/spec/ruby/library/uri/generic/to_s_spec.rb @@ -2,10 +2,5 @@ require_relative '../../../spec_helper' require 'uri' describe "URI::Generic#to_s" do - version_is URI::VERSION, "0.12" do #ruby_version_is "3.2" do - # https://hackerone.com/reports/156615 - it "preserves / characters when host is empty" do - URI('http:///foo.com').to_s.should == 'http:///foo.com' - end - end + it "needs to be reviewed for spec completeness" end diff --git a/spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb b/spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb index 52cb978bea..940eebfb91 100644 --- a/spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb b/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb index 994c2e6d36..91f5091d24 100644 --- a/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/codepage_spec.rb b/spec/ruby/library/win32ole/win32ole/codepage_spec.rb index 07e93646ac..4e0cf5ca55 100644 --- a/spec/ruby/library/win32ole/win32ole/codepage_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/codepage_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/connect_spec.rb b/spec/ruby/library/win32ole/win32ole/connect_spec.rb index ac0976ddc1..72dceb1572 100644 --- a/spec/ruby/library/win32ole/win32ole/connect_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/connect_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/const_load_spec.rb b/spec/ruby/library/win32ole/win32ole/const_load_spec.rb index 2099c4aa66..cacc7a2b22 100644 --- a/spec/ruby/library/win32ole/win32ole/const_load_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/const_load_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/constants_spec.rb b/spec/ruby/library/win32ole/win32ole/constants_spec.rb index 8533741440..978b7ade92 100644 --- a/spec/ruby/library/win32ole/win32ole/constants_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/constants_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/create_guid_spec.rb b/spec/ruby/library/win32ole/win32ole/create_guid_spec.rb index 8aa853df9e..2e18b6ab11 100644 --- a/spec/ruby/library/win32ole/win32ole/create_guid_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/create_guid_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/invoke_spec.rb b/spec/ruby/library/win32ole/win32ole/invoke_spec.rb index d6ff7fade3..08a5156e05 100644 --- a/spec/ruby/library/win32ole/win32ole/invoke_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/invoke_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/locale_spec.rb b/spec/ruby/library/win32ole/win32ole/locale_spec.rb index 78ede4375a..75a82ddd7f 100644 --- a/spec/ruby/library/win32ole/win32ole/locale_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/locale_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/new_spec.rb b/spec/ruby/library/win32ole/win32ole/new_spec.rb index 7e91c2d3ea..6b717195f1 100644 --- a/spec/ruby/library/win32ole/win32ole/new_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/new_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb index 2bbe8c27d4..75748182fe 100644 --- a/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb index c1d1970214..a991624a23 100644 --- a/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb index 9cb3f9e6cf..8a26d79a20 100644 --- a/spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' require_relative 'shared/ole_method' diff --git a/spec/ruby/library/win32ole/win32ole/ole_method_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_method_spec.rb index e48ff8d905..f82a212f5d 100644 --- a/spec/ruby/library/win32ole/win32ole/ole_method_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/ole_method_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' require_relative 'shared/ole_method' diff --git a/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb index fe161ce9f0..5ac9ae9cfa 100644 --- a/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb index afcf16a051..ef8944ee39 100644 --- a/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb index c091c83c95..727291e9f0 100644 --- a/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole/setproperty_spec.rb b/spec/ruby/library/win32ole/win32ole/setproperty_spec.rb index bacdee63da..7409823f20 100644 --- a/spec/ruby/library/win32ole/win32ole/setproperty_spec.rb +++ b/spec/ruby/library/win32ole/win32ole/setproperty_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' require_relative 'shared/setproperty' diff --git a/spec/ruby/library/win32ole/win32ole_event/new_spec.rb b/spec/ruby/library/win32ole/win32ole_event/new_spec.rb index 94fabb1e3b..a1a1612393 100644 --- a/spec/ruby/library/win32ole/win32ole_event/new_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_event/new_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' diff --git a/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb b/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb index 0957bdd2d4..feb26b0637 100644 --- a/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' guard -> { WIN32OLESpecs::MSXML_AVAILABLE } do diff --git a/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb b/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb index ece71df0d4..69068683b7 100644 --- a/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb b/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb index 78634d2fde..70c8b30cca 100644 --- a/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' guard -> { WIN32OLESpecs::SYSTEM_MONITOR_CONTROL_AVAILABLE } do diff --git a/spec/ruby/library/win32ole/win32ole_method/event_spec.rb b/spec/ruby/library/win32ole/win32ole_method/event_spec.rb index 9b642a010c..c41f8fe99d 100644 --- a/spec/ruby/library/win32ole/win32ole_method/event_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/event_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require_relative '../fixtures/classes' guard -> { WIN32OLESpecs::SYSTEM_MONITOR_CONTROL_AVAILABLE } do diff --git a/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb b/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb index d1c5ee3be2..21b3ae8bde 100644 --- a/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb b/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb index 59dad9244c..b6d0a19a37 100644 --- a/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb b/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb index b2f24ba151..9f940fd4a0 100644 --- a/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb b/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb index d7fedf0d36..7fff479daf 100644 --- a/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb b/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb index d5536fd17b..e8638abd91 100644 --- a/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_method/name_spec.rb b/spec/ruby/library/win32ole/win32ole_method/name_spec.rb index 477b820f4d..cd5404fc54 100644 --- a/spec/ruby/library/win32ole/win32ole_method/name_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/name_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative 'shared/name' platform_is :windows do diff --git a/spec/ruby/library/win32ole/win32ole_method/new_spec.rb b/spec/ruby/library/win32ole/win32ole_method/new_spec.rb index 4e427421b9..8ebf93b992 100644 --- a/spec/ruby/library/win32ole/win32ole_method/new_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/new_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb b/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb index b3da9a8303..8e50c39787 100644 --- a/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_method/params_spec.rb b/spec/ruby/library/win32ole/win32ole_method/params_spec.rb index 09fb0eb5ac..2f8da3d45b 100644 --- a/spec/ruby/library/win32ole/win32ole_method/params_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/params_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb b/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb index 582a5951d5..f8ce3e1b3a 100644 --- a/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb b/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb index dd8add402d..58e26df77b 100644 --- a/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb b/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb index 3fca3d54ed..dc159dd09e 100644 --- a/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb b/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb index fe9facb53a..a38fe5c681 100644 --- a/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb b/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb index 8ea6e61e7d..0c5a94c338 100644 --- a/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb index 11107a77fc..ecb3c08038 100644 --- a/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative 'shared/name' platform_is :windows do diff --git a/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb b/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb index d1a50523fc..918b6ef782 100644 --- a/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_param/default_spec.rb b/spec/ruby/library/win32ole/win32ole_param/default_spec.rb index 44bd3d7fd3..af08c84782 100644 --- a/spec/ruby/library/win32ole/win32ole_param/default_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_param/default_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_param/input_spec.rb b/spec/ruby/library/win32ole/win32ole_param/input_spec.rb index e9134b1df8..e2a90daa56 100644 --- a/spec/ruby/library/win32ole/win32ole_param/input_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_param/input_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_param/name_spec.rb b/spec/ruby/library/win32ole/win32ole_param/name_spec.rb index 67a8955ba4..0c20c24720 100644 --- a/spec/ruby/library/win32ole/win32ole_param/name_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_param/name_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative 'shared/name' platform_is :windows do diff --git a/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb b/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb index f05455e3f1..e683d1c16e 100644 --- a/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb b/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb index 1467130e03..b9a3639c3e 100644 --- a/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb b/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb index b39ee41179..3fb9dc1867 100644 --- a/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb b/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb index dd613dd29a..f5546e79e5 100644 --- a/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb index e9153a2eb2..5b4b4c1c80 100644 --- a/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative 'shared/name' platform_is :windows do diff --git a/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb b/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb index abdf8d34b9..25907c8e32 100644 --- a/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb b/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb index eee23abc56..d436835188 100644 --- a/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb b/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb index 3a0a9ead94..01e6945138 100644 --- a/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb b/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb index 9ab0004668..3bd2cbe5dd 100644 --- a/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb b/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb index 7d2731f778..7dae16617d 100644 --- a/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb b/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb index 3904e78d42..ff412dd100 100644 --- a/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/name_spec.rb b/spec/ruby/library/win32ole/win32ole_type/name_spec.rb index d76998d7dc..b7a28c553a 100644 --- a/spec/ruby/library/win32ole/win32ole_type/name_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/name_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative 'shared/name' platform_is :windows do diff --git a/spec/ruby/library/win32ole/win32ole_type/new_spec.rb b/spec/ruby/library/win32ole/win32ole_type/new_spec.rb index cc691ffa67..3c3aa1c390 100644 --- a/spec/ruby/library/win32ole/win32ole_type/new_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/new_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb b/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb index a3a1d4ac58..0ce0fc98a4 100644 --- a/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb b/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb index 3b99b97a61..9265549d20 100644 --- a/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb b/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb index 24292b1c4f..2bc19aa85e 100644 --- a/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb b/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb index 340fdb34e8..f0d80ba39e 100644 --- a/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb b/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb index 793535b48d..19d8bf56e0 100644 --- a/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb b/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb index 3f89fe702a..71e304d80a 100644 --- a/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb index 9f086a5a35..b713990ed2 100644 --- a/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative 'shared/name' platform_is :windows do diff --git a/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb b/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb index 391d505e01..35f3562721 100644 --- a/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb b/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb index a487208caa..369e0274f3 100644 --- a/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb b/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb index 7f61b8af95..fbf3dd0341 100644 --- a/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb b/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb index 99e34edcdd..403b2b843b 100644 --- a/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_variable/name_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/name_spec.rb index dd9bfa594f..8bac1a9891 100644 --- a/spec/ruby/library/win32ole/win32ole_variable/name_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_variable/name_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative 'shared/name' platform_is :windows do diff --git a/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb index 7a9c791494..dab4edabaa 100644 --- a/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb index 03a9aa4c74..d08acc9bde 100644 --- a/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb index d4cab8e924..000ac14d7e 100644 --- a/spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative 'shared/name' platform_is :windows do diff --git a/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb index b7849793c5..4f240b561c 100644 --- a/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb index 7a79d32ddc..4cca7f8874 100644 --- a/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb index 9d7b8238c8..56cd1c337a 100644 --- a/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb index 60252e8139..7f7a557b57 100644 --- a/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb +++ b/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" platform_is :windows do require 'win32ole' diff --git a/spec/ruby/library/yaml/dump_spec.rb b/spec/ruby/library/yaml/dump_spec.rb index ea94b2f856..3107a8f51d 100644 --- a/spec/ruby/library/yaml/dump_spec.rb +++ b/spec/ruby/library/yaml/dump_spec.rb @@ -1,21 +1,17 @@ require_relative '../../spec_helper' +require_relative 'fixtures/common' -require 'yaml' - +# TODO: WTF is this using a global? describe "YAML.dump" do - before :each do - @test_file = tmp("yaml_test_file") - end - after :each do - rm_r @test_file + rm_r $test_file end it "converts an object to YAML and write result to io when io provided" do - File.open(@test_file, 'w' ) do |io| + File.open($test_file, 'w' ) do |io| YAML.dump( ['badger', 'elephant', 'tiger'], io ) end - YAML.load_file(@test_file).should == ['badger', 'elephant', 'tiger'] + YAML.load_file($test_file).should == ['badger', 'elephant', 'tiger'] end it "returns a string containing dumped YAML when no io provided" do diff --git a/spec/ruby/library/yaml/dump_stream_spec.rb b/spec/ruby/library/yaml/dump_stream_spec.rb index f0578fa800..9d30fef819 100644 --- a/spec/ruby/library/yaml/dump_stream_spec.rb +++ b/spec/ruby/library/yaml/dump_stream_spec.rb @@ -1,6 +1,5 @@ require_relative '../../spec_helper' - -require 'yaml' +require_relative 'fixtures/common' describe "YAML.dump_stream" do it "returns a YAML stream containing the objects passed" do diff --git a/spec/ruby/library/yaml/fixtures/common.rb b/spec/ruby/library/yaml/fixtures/common.rb new file mode 100644 index 0000000000..f7fb4037e7 --- /dev/null +++ b/spec/ruby/library/yaml/fixtures/common.rb @@ -0,0 +1,4 @@ +require 'yaml' + +$test_file = tmp("yaml_test_file") +$test_parse_file = File.dirname(__FILE__) + "/test_yaml.yml" diff --git a/spec/ruby/library/yaml/load_file_spec.rb b/spec/ruby/library/yaml/load_file_spec.rb index 4941d0485b..2363c08120 100644 --- a/spec/ruby/library/yaml/load_file_spec.rb +++ b/spec/ruby/library/yaml/load_file_spec.rb @@ -1,18 +1,13 @@ require_relative '../../spec_helper' - -require 'yaml' +require_relative 'fixtures/common' describe "YAML.load_file" do - before :each do - @test_file = tmp("yaml_test_file") - end - after :each do - rm_r @test_file + rm_r $test_file end it "returns a hash" do - File.open(@test_file,'w' ){|io| YAML.dump( {"bar"=>2, "car"=>1}, io ) } - YAML.load_file(@test_file).should == {"bar"=>2, "car"=>1} + File.open($test_file,'w' ){|io| YAML.dump( {"bar"=>2, "car"=>1}, io ) } + YAML.load_file($test_file).should == {"bar"=>2, "car"=>1} end end diff --git a/spec/ruby/library/yaml/load_stream_spec.rb b/spec/ruby/library/yaml/load_stream_spec.rb index 31bc862f5e..689653c8cd 100644 --- a/spec/ruby/library/yaml/load_stream_spec.rb +++ b/spec/ruby/library/yaml/load_stream_spec.rb @@ -1,9 +1,8 @@ require_relative '../../spec_helper' +require_relative 'fixtures/common' require_relative 'fixtures/strings' require_relative 'shared/each_document' -require 'yaml' - describe "YAML.load_stream" do it_behaves_like :yaml_each_document, :load_stream end diff --git a/spec/ruby/library/yaml/parse_file_spec.rb b/spec/ruby/library/yaml/parse_file_spec.rb index 7bffcdc62f..8c59a2d7ef 100644 --- a/spec/ruby/library/yaml/parse_file_spec.rb +++ b/spec/ruby/library/yaml/parse_file_spec.rb @@ -1,10 +1,8 @@ require_relative '../../spec_helper' +require_relative 'fixtures/common' -require 'yaml' - -describe "YAML.parse_file" do +describe "YAML#parse_file" do it "returns a YAML::Syck::Map object after parsing a YAML file" do - test_parse_file = fixture __FILE__, "test_yaml.yml" - YAML.parse_file(test_parse_file).should be_kind_of(Psych::Nodes::Document) + YAML.parse_file($test_parse_file).should be_kind_of(Psych::Nodes::Document) end end diff --git a/spec/ruby/library/yaml/parse_spec.rb b/spec/ruby/library/yaml/parse_spec.rb index 37e2b7fa0a..d5dbfdcee2 100644 --- a/spec/ruby/library/yaml/parse_spec.rb +++ b/spec/ruby/library/yaml/parse_spec.rb @@ -1,14 +1,13 @@ require_relative '../../spec_helper' +require_relative 'fixtures/common' -require 'yaml' - -describe "YAML.parse with an empty string" do +describe "YAML#parse with an empty string" do it "returns false" do YAML.parse('').should be_false end end -describe "YAML.parse" do +describe "YAML#parse" do before :each do @string_yaml = "foo".to_yaml end diff --git a/spec/ruby/library/yaml/shared/each_document.rb b/spec/ruby/library/yaml/shared/each_document.rb index 7d32c6001f..999123dc2a 100644 --- a/spec/ruby/library/yaml/shared/each_document.rb +++ b/spec/ruby/library/yaml/shared/each_document.rb @@ -9,8 +9,7 @@ describe :yaml_each_document, shared: true do end it "works on files" do - test_parse_file = fixture __FILE__, "test_yaml.yml" - File.open(test_parse_file, "r") do |file| + File.open($test_parse_file, "r") do |file| YAML.send(@method, file) do |doc| doc.should == {"project"=>{"name"=>"RubySpec"}} end diff --git a/spec/ruby/library/yaml/shared/load.rb b/spec/ruby/library/yaml/shared/load.rb index 1ebe08be2c..185a5a60cd 100644 --- a/spec/ruby/library/yaml/shared/load.rb +++ b/spec/ruby/library/yaml/shared/load.rb @@ -1,16 +1,14 @@ +require_relative '../fixtures/common' require_relative '../fixtures/strings' -require 'yaml' - describe :yaml_load_safe, shared: true do it "returns a document from current io stream when io provided" do - @test_file = tmp("yaml_test_file") - File.open(@test_file, 'w') do |io| + File.open($test_file, 'w') do |io| YAML.dump( ['badger', 'elephant', 'tiger'], io ) end - File.open(@test_file) { |yf| YAML.send(@method, yf ) }.should == ['badger', 'elephant', 'tiger'] + File.open($test_file) { |yf| YAML.send(@method, yf ) }.should == ['badger', 'elephant', 'tiger'] ensure - rm_r @test_file + rm_r $test_file end it "loads strings" do diff --git a/spec/ruby/library/yaml/to_yaml_spec.rb b/spec/ruby/library/yaml/to_yaml_spec.rb index 547009c942..03ec4f6916 100644 --- a/spec/ruby/library/yaml/to_yaml_spec.rb +++ b/spec/ruby/library/yaml/to_yaml_spec.rb @@ -1,8 +1,7 @@ require_relative '../../spec_helper' +require_relative 'fixtures/common' require_relative 'fixtures/example_class' -require 'yaml' - describe "Object#to_yaml" do it "returns the YAML representation of an Array object" do @@ -13,21 +12,13 @@ describe "Object#to_yaml" do { "a" => "b"}.to_yaml.should match_yaml("--- \na: b\n") end - it "returns the YAML representation of an object" do - YAMLSpecs::Example.new("baz").to_yaml.should match_yaml("--- !ruby/object:YAMLSpecs::Example\nname: baz\n") - end - it "returns the YAML representation of a Class object" do - YAMLSpecs::Example.to_yaml.should match_yaml("--- !ruby/class 'YAMLSpecs::Example'\n") - end - - it "returns the YAML representation of a Module object" do - Enumerable.to_yaml.should match_yaml("--- !ruby/module 'Enumerable'\n") + YAMLSpecs::Example.new("baz").to_yaml.should match_yaml("--- !ruby/object:YAMLSpecs::Example\nname: baz\n") end it "returns the YAML representation of a Date object" do require 'date' - Date.new(1997, 12, 30).to_yaml.should match_yaml("--- 1997-12-30\n") + Date.parse('1997/12/30').to_yaml.should match_yaml("--- 1997-12-30\n") end it "returns the YAML representation of a FalseClass" do @@ -67,11 +58,6 @@ describe "Object#to_yaml" do Person.new("Jane", "female").to_yaml.should match_yaml("--- !ruby/struct:Person\nname: Jane\ngender: female\n") end - it "returns the YAML representation of an unnamed Struct object" do - person = Struct.new(:name, :gender) - person.new("Jane", "female").to_yaml.should match_yaml("--- !ruby/struct\nname: Jane\ngender: female\n") - end - it "returns the YAML representation of a Symbol object" do :symbol.to_yaml.should match_yaml("--- :symbol\n") end @@ -86,8 +72,16 @@ describe "Object#to_yaml" do true_klass.to_yaml.should match_yaml("--- true\n") end - it "returns the YAML representation of a Error object" do - StandardError.new("foobar").to_yaml.should match_yaml("--- !ruby/exception:StandardError\nmessage: foobar\nbacktrace: \n") + ruby_version_is ""..."2.7" do + it "returns the YAML representation of a Error object" do + StandardError.new("foobar").to_yaml.should match_yaml("--- !ruby/exception:StandardError\nmessage: foobar\n") + end + end + + ruby_version_is "2.7" do + it "returns the YAML representation of a Error object" do + StandardError.new("foobar").to_yaml.should match_yaml("--- !ruby/exception:StandardError\nmessage: foobar\nbacktrace: \n") + end end it "returns the YAML representation for Range objects" do diff --git a/spec/ruby/library/zlib/crc_table_spec.rb b/spec/ruby/library/zlib/crc_table_spec.rb index de8876086b..f7fc2749fa 100644 --- a/spec/ruby/library/zlib/crc_table_spec.rb +++ b/spec/ruby/library/zlib/crc_table_spec.rb @@ -2,79 +2,74 @@ require_relative '../../spec_helper' require "zlib" describe "Zlib.crc_table" do - # This spec fails when zlib.h and libz.so are not from the same version. - # In older zlib (< 1.2.7 it seems), get_crc_table() is stored as u64[], - # but in newer zlib, get_crc_table() is stored as u32[]. - # Technically, there is ABI breakage between those zlib versions, - # but get_crc_table() is an "undocumented function" according to zlib.h. - guard -> { ENV["RUBY_SPEC_TEST_ZLIB_CRC_TABLE"] != "false" } do - it "returns the same value as zlib's get_crc_table()" do - Zlib.crc_table.should == [ - 0, 1996959894, 3993919788, 2567524794, - 124634137, 1886057615, 3915621685, 2657392035, - 249268274, 2044508324, 3772115230, 2547177864, - 162941995, 2125561021, 3887607047, 2428444049, - 498536548, 1789927666, 4089016648, 2227061214, - 450548861, 1843258603, 4107580753, 2211677639, - 325883990, 1684777152, 4251122042, 2321926636, - 335633487, 1661365465, 4195302755, 2366115317, - 997073096, 1281953886, 3579855332, 2724688242, - 1006888145, 1258607687, 3524101629, 2768942443, - 901097722, 1119000684, 3686517206, 2898065728, - 853044451, 1172266101, 3705015759, 2882616665, - 651767980, 1373503546, 3369554304, 3218104598, - 565507253, 1454621731, 3485111705, 3099436303, - 671266974, 1594198024, 3322730930, 2970347812, - 795835527, 1483230225, 3244367275, 3060149565, - 1994146192, 31158534, 2563907772, 4023717930, - 1907459465, 112637215, 2680153253, 3904427059, - 2013776290, 251722036, 2517215374, 3775830040, - 2137656763, 141376813, 2439277719, 3865271297, - 1802195444, 476864866, 2238001368, 4066508878, - 1812370925, 453092731, 2181625025, 4111451223, - 1706088902, 314042704, 2344532202, 4240017532, - 1658658271, 366619977, 2362670323, 4224994405, - 1303535960, 984961486, 2747007092, 3569037538, - 1256170817, 1037604311, 2765210733, 3554079995, - 1131014506, 879679996, 2909243462, 3663771856, - 1141124467, 855842277, 2852801631, 3708648649, - 1342533948, 654459306, 3188396048, 3373015174, - 1466479909, 544179635, 3110523913, 3462522015, - 1591671054, 702138776, 2966460450, 3352799412, - 1504918807, 783551873, 3082640443, 3233442989, - 3988292384, 2596254646, 62317068, 1957810842, - 3939845945, 2647816111, 81470997, 1943803523, - 3814918930, 2489596804, 225274430, 2053790376, - 3826175755, 2466906013, 167816743, 2097651377, - 4027552580, 2265490386, 503444072, 1762050814, - 4150417245, 2154129355, 426522225, 1852507879, - 4275313526, 2312317920, 282753626, 1742555852, - 4189708143, 2394877945, 397917763, 1622183637, - 3604390888, 2714866558, 953729732, 1340076626, - 3518719985, 2797360999, 1068828381, 1219638859, - 3624741850, 2936675148, 906185462, 1090812512, - 3747672003, 2825379669, 829329135, 1181335161, - 3412177804, 3160834842, 628085408, 1382605366, - 3423369109, 3138078467, 570562233, 1426400815, - 3317316542, 2998733608, 733239954, 1555261956, - 3268935591, 3050360625, 752459403, 1541320221, - 2607071920, 3965973030, 1969922972, 40735498, - 2617837225, 3943577151, 1913087877, 83908371, - 2512341634, 3803740692, 2075208622, 213261112, - 2463272603, 3855990285, 2094854071, 198958881, - 2262029012, 4057260610, 1759359992, 534414190, - 2176718541, 4139329115, 1873836001, 414664567, - 2282248934, 4279200368, 1711684554, 285281116, - 2405801727, 4167216745, 1634467795, 376229701, - 2685067896, 3608007406, 1308918612, 956543938, - 2808555105, 3495958263, 1231636301, 1047427035, - 2932959818, 3654703836, 1088359270, 936918000, - 2847714899, 3736837829, 1202900863, 817233897, - 3183342108, 3401237130, 1404277552, 615818150, - 3134207493, 3453421203, 1423857449, 601450431, - 3009837614, 3294710456, 1567103746, 711928724, - 3020668471, 3272380065, 1510334235, 755167117, - ] - end + + it "returns the same value as zlib's get_crc_table()" do + Zlib.crc_table.should == [ + 0, 1996959894, 3993919788, 2567524794, + 124634137, 1886057615, 3915621685, 2657392035, + 249268274, 2044508324, 3772115230, 2547177864, + 162941995, 2125561021, 3887607047, 2428444049, + 498536548, 1789927666, 4089016648, 2227061214, + 450548861, 1843258603, 4107580753, 2211677639, + 325883990, 1684777152, 4251122042, 2321926636, + 335633487, 1661365465, 4195302755, 2366115317, + 997073096, 1281953886, 3579855332, 2724688242, + 1006888145, 1258607687, 3524101629, 2768942443, + 901097722, 1119000684, 3686517206, 2898065728, + 853044451, 1172266101, 3705015759, 2882616665, + 651767980, 1373503546, 3369554304, 3218104598, + 565507253, 1454621731, 3485111705, 3099436303, + 671266974, 1594198024, 3322730930, 2970347812, + 795835527, 1483230225, 3244367275, 3060149565, + 1994146192, 31158534, 2563907772, 4023717930, + 1907459465, 112637215, 2680153253, 3904427059, + 2013776290, 251722036, 2517215374, 3775830040, + 2137656763, 141376813, 2439277719, 3865271297, + 1802195444, 476864866, 2238001368, 4066508878, + 1812370925, 453092731, 2181625025, 4111451223, + 1706088902, 314042704, 2344532202, 4240017532, + 1658658271, 366619977, 2362670323, 4224994405, + 1303535960, 984961486, 2747007092, 3569037538, + 1256170817, 1037604311, 2765210733, 3554079995, + 1131014506, 879679996, 2909243462, 3663771856, + 1141124467, 855842277, 2852801631, 3708648649, + 1342533948, 654459306, 3188396048, 3373015174, + 1466479909, 544179635, 3110523913, 3462522015, + 1591671054, 702138776, 2966460450, 3352799412, + 1504918807, 783551873, 3082640443, 3233442989, + 3988292384, 2596254646, 62317068, 1957810842, + 3939845945, 2647816111, 81470997, 1943803523, + 3814918930, 2489596804, 225274430, 2053790376, + 3826175755, 2466906013, 167816743, 2097651377, + 4027552580, 2265490386, 503444072, 1762050814, + 4150417245, 2154129355, 426522225, 1852507879, + 4275313526, 2312317920, 282753626, 1742555852, + 4189708143, 2394877945, 397917763, 1622183637, + 3604390888, 2714866558, 953729732, 1340076626, + 3518719985, 2797360999, 1068828381, 1219638859, + 3624741850, 2936675148, 906185462, 1090812512, + 3747672003, 2825379669, 829329135, 1181335161, + 3412177804, 3160834842, 628085408, 1382605366, + 3423369109, 3138078467, 570562233, 1426400815, + 3317316542, 2998733608, 733239954, 1555261956, + 3268935591, 3050360625, 752459403, 1541320221, + 2607071920, 3965973030, 1969922972, 40735498, + 2617837225, 3943577151, 1913087877, 83908371, + 2512341634, 3803740692, 2075208622, 213261112, + 2463272603, 3855990285, 2094854071, 198958881, + 2262029012, 4057260610, 1759359992, 534414190, + 2176718541, 4139329115, 1873836001, 414664567, + 2282248934, 4279200368, 1711684554, 285281116, + 2405801727, 4167216745, 1634467795, 376229701, + 2685067896, 3608007406, 1308918612, 956543938, + 2808555105, 3495958263, 1231636301, 1047427035, + 2932959818, 3654703836, 1088359270, 936918000, + 2847714899, 3736837829, 1202900863, 817233897, + 3183342108, 3401237130, 1404277552, 615818150, + 3134207493, 3453421203, 1423857449, 601450431, + 3009837614, 3294710456, 1567103746, 711928724, + 3020668471, 3272380065, 1510334235, 755167117, + ] end + end diff --git a/spec/ruby/library/zlib/deflate/deflate_spec.rb b/spec/ruby/library/zlib/deflate/deflate_spec.rb index 50a563ef6f..828880f8d8 100644 --- a/spec/ruby/library/zlib/deflate/deflate_spec.rb +++ b/spec/ruby/library/zlib/deflate/deflate_spec.rb @@ -58,11 +58,6 @@ describe "Zlib::Deflate#deflate" do Array.new(31, 0) + [24, 128, 0, 0, 1]).pack('C*') end - - it "has a binary encoding" do - @deflator.deflate("").encoding.should == Encoding::BINARY - @deflator.finish.encoding.should == Encoding::BINARY - end end describe "Zlib::Deflate#deflate" do diff --git a/spec/ruby/library/zlib/deflate/new_spec.rb b/spec/ruby/library/zlib/deflate/new_spec.rb new file mode 100644 index 0000000000..e15f14f95f --- /dev/null +++ b/spec/ruby/library/zlib/deflate/new_spec.rb @@ -0,0 +1 @@ +require_relative '../../../spec_helper' diff --git a/spec/ruby/library/zlib/gzipreader/each_line_spec.rb b/spec/ruby/library/zlib/gzipreader/each_line_spec.rb index 6f17365879..efaf27d6bb 100644 --- a/spec/ruby/library/zlib/gzipreader/each_line_spec.rb +++ b/spec/ruby/library/zlib/gzipreader/each_line_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative 'shared/each' describe "Zlib::GzipReader#each_line" do diff --git a/spec/ruby/library/zlib/gzipreader/each_spec.rb b/spec/ruby/library/zlib/gzipreader/each_spec.rb index 3b98391a87..59aa63e52c 100644 --- a/spec/ruby/library/zlib/gzipreader/each_spec.rb +++ b/spec/ruby/library/zlib/gzipreader/each_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require_relative 'shared/each' describe "Zlib::GzipReader#each" do diff --git a/spec/ruby/library/zlib/gzipreader/mtime_spec.rb b/spec/ruby/library/zlib/gzipreader/mtime_spec.rb deleted file mode 100644 index e8e71fa72e..0000000000 --- a/spec/ruby/library/zlib/gzipreader/mtime_spec.rb +++ /dev/null @@ -1,11 +0,0 @@ -require_relative '../../../spec_helper' -require 'zlib' -require 'stringio' - -describe "Zlib::GzipReader#mtime" do - it "returns the timestamp from the Gzip header" do - io = StringIO.new "\x1f\x8b\x08\x00\x44\x33\x22\x11\x00\xff\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00" - gz = Zlib::GzipReader.new(io) - gz.mtime.to_i.should == 0x11223344 - end -end diff --git a/spec/ruby/library/zlib/gzipreader/new_spec.rb b/spec/ruby/library/zlib/gzipreader/new_spec.rb new file mode 100644 index 0000000000..e15f14f95f --- /dev/null +++ b/spec/ruby/library/zlib/gzipreader/new_spec.rb @@ -0,0 +1 @@ +require_relative '../../../spec_helper' diff --git a/spec/ruby/library/zlib/inflate/finish_spec.rb b/spec/ruby/library/zlib/inflate/finish_spec.rb index 3e0663e265..f6e592fb6b 100644 --- a/spec/ruby/library/zlib/inflate/finish_spec.rb +++ b/spec/ruby/library/zlib/inflate/finish_spec.rb @@ -1,4 +1,3 @@ -require_relative "../../../spec_helper" require 'zlib' describe "Zlib::Inflate#finish" do diff --git a/spec/ruby/library/zlib/inflate/inflate_spec.rb b/spec/ruby/library/zlib/inflate/inflate_spec.rb index 79b72bf91c..cc33bd4c32 100644 --- a/spec/ruby/library/zlib/inflate/inflate_spec.rb +++ b/spec/ruby/library/zlib/inflate/inflate_spec.rb @@ -39,13 +39,6 @@ describe "Zlib::Inflate#inflate" do @inflator.finish.should == 'uncompressed_data' end - it "has a binary encoding" do - data = [120, 156, 99, 96, 128, 1, 0, 0, 10, 0, 1].pack('C*') - unzipped = @inflator.inflate data - @inflator.finish.encoding.should == Encoding::BINARY - unzipped.encoding.should == Encoding::BINARY - end - end describe "Zlib::Inflate.inflate" do diff --git a/spec/ruby/library/zlib/inflate/new_spec.rb b/spec/ruby/library/zlib/inflate/new_spec.rb new file mode 100644 index 0000000000..e15f14f95f --- /dev/null +++ b/spec/ruby/library/zlib/inflate/new_spec.rb @@ -0,0 +1 @@ +require_relative '../../../spec_helper' diff --git a/spec/ruby/optional/capi/array_spec.rb b/spec/ruby/optional/capi/array_spec.rb index 9c35017e21..8e90980c6a 100644 --- a/spec/ruby/optional/capi/array_spec.rb +++ b/spec/ruby/optional/capi/array_spec.rb @@ -343,40 +343,6 @@ describe "C-API Array function" do end end - describe "rb_iterate" do - it "calls an callback function as a block passed to an method" do - s = [1,2,3,4] - s2 = @s.rb_iterate(s) - - s2.should == s - - # Make sure they're different objects - s2.equal?(s).should be_false - end - - it "calls a function with the other function available as a block" do - h = {a: 1, b: 2} - - @s.rb_iterate_each_pair(h).sort.should == [1,2] - end - - it "calls a function which can yield into the original block" do - s2 = [] - - o = Object.new - def o.each - yield 1 - yield 2 - yield 3 - yield 4 - end - - @s.rb_iterate_then_yield(o) { |x| s2 << x } - - s2.should == [1,2,3,4] - end - end - describe "rb_block_call" do it "calls an callback function as a block passed to an method" do s = [1,2,3,4] diff --git a/spec/ruby/optional/capi/binding_spec.rb b/spec/ruby/optional/capi/binding_spec.rb index 2165705457..966d650c46 100644 --- a/spec/ruby/optional/capi/binding_spec.rb +++ b/spec/ruby/optional/capi/binding_spec.rb @@ -8,21 +8,12 @@ describe "CApiBindingSpecs" do end describe "Kernel#binding" do - ruby_version_is '3.2' do - it "raises when called from C" do - foo = 14 - -> { @b.get_binding }.should raise_error(RuntimeError) - end - end - - ruby_version_is ''...'3.2' do - it "gives the top-most Ruby binding when called from C" do - foo = 14 - b = @b.get_binding - b.local_variable_get(:foo).should == 14 - b.local_variable_set :foo, 12 - foo.should == 12 - end + it "gives the top-most Ruby binding when called from C" do + foo = 14 + b = @b.get_binding + b.local_variable_get(:foo).should == 14 + b.local_variable_set :foo, 12 + foo.should == 12 end end end diff --git a/spec/ruby/optional/capi/class_spec.rb b/spec/ruby/optional/capi/class_spec.rb index d0a9913570..a2d8b3e38a 100644 --- a/spec/ruby/optional/capi/class_spec.rb +++ b/spec/ruby/optional/capi/class_spec.rb @@ -108,35 +108,17 @@ describe "C-API Class function" do describe "rb_class_new_instance" do it "allocates and initializes a new object" do - o = @s.rb_class_new_instance([], CApiClassSpecs::Alloc) + o = @s.rb_class_new_instance(0, nil, CApiClassSpecs::Alloc) o.class.should == CApiClassSpecs::Alloc o.initialized.should be_true end it "passes arguments to the #initialize method" do - o = @s.rb_class_new_instance([:one, :two], CApiClassSpecs::Alloc) + o = @s.rb_class_new_instance(2, [:one, :two], CApiClassSpecs::Alloc) o.arguments.should == [:one, :two] end end - describe "rb_class_new_instance_kw" do - it "passes arguments and keywords to the #initialize method" do - obj = @s.rb_class_new_instance_kw([{pos: 1}, {kw: 2}], CApiClassSpecs::KeywordAlloc) - obj.args.should == [{pos: 1}] - obj.kwargs.should == {kw: 2} - - obj = @s.rb_class_new_instance_kw([{}], CApiClassSpecs::KeywordAlloc) - obj.args.should == [] - obj.kwargs.should == {} - end - - it "raises TypeError if the last argument is not a Hash" do - -> { - @s.rb_class_new_instance_kw([42], CApiClassSpecs::KeywordAlloc) - }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash') - end - end - describe "rb_include_module" do it "includes a module into a class" do c = Class.new @@ -194,6 +176,16 @@ describe "C-API Class function" do end end + describe "rb_define_method" do + it "defines a method taking variable arguments as a C array if the argument count is -1" do + @s.rb_method_varargs_1(1, 3, 7, 4).should == [1, 3, 7, 4] + end + + it "defines a method taking variable arguments as a Ruby array if the argument count is -2" do + @s.rb_method_varargs_2(1, 3, 7, 4).should == [1, 3, 7, 4] + end + end + describe "rb_class2name" do it "returns the class name" do @s.rb_class2name(CApiClassSpecs).should == "CApiClassSpecs" @@ -202,10 +194,6 @@ describe "C-API Class function" do it "returns a string for an anonymous class" do @s.rb_class2name(Class.new).should be_kind_of(String) end - - it "returns a string beginning with # for an anonymous class" do - @s.rb_class2name(Struct.new(:x, :y).new(1, 2).class).should.start_with?('#') - end end describe "rb_class_path" do @@ -321,15 +309,6 @@ describe "C-API Class function" do @s.rb_define_class("ClassSpecDefineClass4", nil) }.should raise_error(ArgumentError) end - - it "allows arbitrary names, including constant names not valid in Ruby" do - cls = @s.rb_define_class("_INVALID_CLASS", CApiClassSpecs::Super) - cls.name.should == "_INVALID_CLASS" - - -> { - Object.const_get(cls.name) - }.should raise_error(NameError, /wrong constant name/) - end end describe "rb_define_class_under" do @@ -374,15 +353,6 @@ describe "C-API Class function" do it "raises a TypeError if class is defined and its superclass mismatches the given one" do -> { @s.rb_define_class_under(CApiClassSpecs, "Sub", Object) }.should raise_error(TypeError) end - - it "allows arbitrary names, including constant names not valid in Ruby" do - cls = @s.rb_define_class_under(CApiClassSpecs, "_INVALID_CLASS", CApiClassSpecs::Super) - cls.name.should == "CApiClassSpecs::_INVALID_CLASS" - - -> { - CApiClassSpecs.const_get(cls.name) - }.should raise_error(NameError, /wrong constant name/) - end end describe "rb_define_class_id_under" do @@ -410,15 +380,6 @@ describe "C-API Class function" do it "raises a TypeError if class is defined and its superclass mismatches the given one" do -> { @s.rb_define_class_id_under(CApiClassSpecs, :Sub, Object) }.should raise_error(TypeError) end - - it "allows arbitrary names, including constant names not valid in Ruby" do - cls = @s.rb_define_class_id_under(CApiClassSpecs, :_INVALID_CLASS2, CApiClassSpecs::Super) - cls.name.should == "CApiClassSpecs::_INVALID_CLASS2" - - -> { - CApiClassSpecs.const_get(cls.name) - }.should raise_error(NameError, /wrong constant name/) - end end describe "rb_define_class_variable" do diff --git a/spec/ruby/optional/capi/encoding_spec.rb b/spec/ruby/optional/capi/encoding_spec.rb index 36437cc7b6..66c2dd40de 100644 --- a/spec/ruby/optional/capi/encoding_spec.rb +++ b/spec/ruby/optional/capi/encoding_spec.rb @@ -63,48 +63,6 @@ describe "C-API Encoding function" do end end - describe "rb_enc_strlen" do - before :each do - @str = 'こにちわ' # Each codepoint in this string is 3 bytes in UTF-8 - end - - it "returns the correct string length for the encoding" do - @s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_8).should == 4 - @s.rb_enc_strlen(@str, @str.bytesize, Encoding::BINARY).should == 12 - end - - it "returns the string length based on a fixed-width encoding's character length, even if the encoding is incompatible" do - @s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_16BE).should == 6 - @s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_16LE).should == 6 - @s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_32BE).should == 3 - @s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_32LE).should == 3 - end - - it "does not consider strings to be NUL-terminated" do - s = "abc\0def" - @s.rb_enc_strlen(s, s.bytesize, Encoding::US_ASCII).should == 7 - @s.rb_enc_strlen(s, s.bytesize, Encoding::UTF_8).should == 7 - end - - describe "handles broken strings" do - it "combines valid character and invalid character counts in UTF-8" do - # The result is 3 because `rb_enc_strlen` counts the first valid character and then adds - # the byte count for the invalid character that follows for 1 + 2. - @s.rb_enc_strlen(@str, 5, Encoding::UTF_8).should == 3 - end - - it "combines valid character and invalid character counts in UTF-16" do - @s.rb_enc_strlen(@str, 5, Encoding::UTF_16BE).should == 3 - end - - it "rounds up for fixed-width encodings" do - @s.rb_enc_strlen(@str, 7, Encoding::UTF_32BE).should == 2 - @s.rb_enc_strlen(@str, 7, Encoding::UTF_32LE).should == 2 - @s.rb_enc_strlen(@str, 5, Encoding::BINARY).should == 5 - end - end - end - describe "rb_enc_find" do it "returns the encoding of an Encoding" do @s.rb_enc_find("UTF-8").should == "UTF-8" @@ -170,16 +128,10 @@ describe "C-API Encoding function" do describe "rb_enc_mbc_to_codepoint" do it "returns the correct codepoint for the given character and size" do - @s.rb_enc_mbc_to_codepoint("é").should == 0xE9 - end - - it "returns 0 if p == e" do - @s.rb_enc_mbc_to_codepoint("").should == 0 - end - - it "returns the raw byte if incomplete character in UTF-8" do - @s.rb_enc_mbc_to_codepoint("\xC3").should == 0xC3 - @s.rb_enc_mbc_to_codepoint("\x80").should == 0x80 + @s.rb_enc_mbc_to_codepoint("é", 2).should == 0x00E9 + @s.rb_enc_mbc_to_codepoint("éa", 2).should == 0x00E9 + @s.rb_enc_mbc_to_codepoint("éa", 1).should == 0xC3 + @s.rb_enc_mbc_to_codepoint("éa", 3).should == 0x00E9 end end @@ -657,58 +609,27 @@ describe "C-API Encoding function" do end end - describe "rb_enc_raise" do - it "forces exception message encoding to the specified one" do - utf_8_incompatible_string = "\x81".b - - -> { - @s.rb_enc_raise(Encoding::UTF_8, RuntimeError, utf_8_incompatible_string) - }.should raise_error { |e| - e.message.encoding.should == Encoding::UTF_8 - e.message.valid_encoding?.should == false - e.message.bytes.should == utf_8_incompatible_string.bytes - } - end - end - describe "rb_uv_to_utf8" do it 'converts a Unicode codepoint to a UTF-8 C string' do str = ' ' * 6 { - 1 => "\x01", - 0x80 => "\xC2\x80", - 0x800 => "\xE0\xA0\x80", - 0x10000 => "\xF0\x90\x80\x80", - 0x200000 => "\xF8\x88\x80\x80\x80", - 0x4000000 => "\xFC\x84\x80\x80\x80\x80", + 0 => "\x01", + 0x7f => "\xC2\x80", + 0x7ff => "\xE0\xA0\x80", + 0xffff => "\xF0\x90\x80\x80", + 0x1fffff => "\xF8\x88\x80\x80\x80", + 0x3ffffff => "\xFC\x84\x80\x80\x80\x80", }.each do |num, result| - len = @s.rb_uv_to_utf8(str, num) - str.byteslice(0, len).should == result + len = @s.rb_uv_to_utf8(str, num + 1) + str[0..len-1].should == result end end end - describe "rb_enc_left_char_head" do - it 'returns the head position of a character' do - @s.rb_enc_left_char_head("é", 1).should == 0 - @s.rb_enc_left_char_head("éééé", 7).should == 6 - - @s.rb_enc_left_char_head("a", 0).should == 0 - - # unclear if this is intended to work - @s.rb_enc_left_char_head("a", 1).should == 1 - - # Works because for single-byte encodings rb_enc_left_char_head() just returns the pointer - @s.rb_enc_left_char_head("a".force_encoding(Encoding::US_ASCII), 88).should == 88 - @s.rb_enc_left_char_head("a".b, 88).should == 88 - end - end - describe "ONIGENC_MBC_CASE_FOLD" do it "returns the correct case fold for the given string" do @s.ONIGENC_MBC_CASE_FOLD("lower").should == ["l", 1] @s.ONIGENC_MBC_CASE_FOLD("Upper").should == ["u", 1] - @s.ONIGENC_MBC_CASE_FOLD("ABC"[1..-1]).should == ["b", 1] end it "works with other encodings" do diff --git a/spec/ruby/optional/capi/exception_spec.rb b/spec/ruby/optional/capi/exception_spec.rb index 5bb60608b2..b0a8a2860e 100644 --- a/spec/ruby/optional/capi/exception_spec.rb +++ b/spec/ruby/optional/capi/exception_spec.rb @@ -100,40 +100,6 @@ describe "C-API Exception function" do end end - describe "rb_syserr_new" do - it "returns system error with default message when passed message is NULL" do - exception = @s.rb_syserr_new(Errno::ENOENT::Errno, nil) - exception.class.should == Errno::ENOENT - exception.message.should include("No such file or directory") - exception.should.is_a?(SystemCallError) - end - - it "returns system error with custom message" do - exception = @s.rb_syserr_new(Errno::ENOENT::Errno, "custom message") - - exception.message.should include("custom message") - exception.class.should == Errno::ENOENT - exception.should.is_a?(SystemCallError) - end - end - - describe "rb_syserr_new_str" do - it "returns system error with default message when passed message is nil" do - exception = @s.rb_syserr_new_str(Errno::ENOENT::Errno, nil) - - exception.message.should include("No such file or directory") - exception.class.should == Errno::ENOENT - exception.should.is_a?(SystemCallError) - end - - it "returns system error with custom message" do - exception = @s.rb_syserr_new_str(Errno::ENOENT::Errno, "custom message") - exception.message.should include("custom message") - exception.class.should == Errno::ENOENT - exception.should.is_a?(SystemCallError) - end - end - describe "rb_make_exception" do it "returns a RuntimeError when given a String argument" do e = @s.rb_make_exception(["Message"]) diff --git a/spec/ruby/optional/capi/ext/array_spec.c b/spec/ruby/optional/capi/ext/array_spec.c index 2347798bb4..9386239813 100644 --- a/spec/ruby/optional/capi/ext/array_spec.c +++ b/spec/ruby/optional/capi/ext/array_spec.c @@ -196,14 +196,6 @@ static VALUE copy_ary(RB_BLOCK_CALL_FUNC_ARGLIST(el, new_ary)) { return rb_ary_push(new_ary, el); } -static VALUE array_spec_rb_iterate(VALUE self, VALUE ary) { - VALUE new_ary = rb_ary_new(); - - rb_iterate(rb_each, ary, copy_ary, new_ary); - - return new_ary; -} - static VALUE array_spec_rb_block_call(VALUE self, VALUE ary) { VALUE new_ary = rb_ary_new(); @@ -216,18 +208,6 @@ static VALUE sub_pair(RB_BLOCK_CALL_FUNC_ARGLIST(el, holder)) { return rb_ary_push(holder, rb_ary_entry(el, 1)); } -static VALUE each_pair(VALUE obj) { - return rb_funcall(obj, rb_intern("each_pair"), 0); -} - -static VALUE array_spec_rb_iterate_each_pair(VALUE self, VALUE obj) { - VALUE new_ary = rb_ary_new(); - - rb_iterate(each_pair, obj, sub_pair, new_ary); - - return new_ary; -} - static VALUE array_spec_rb_block_call_each_pair(VALUE self, VALUE obj) { VALUE new_ary = rb_ary_new(); @@ -241,11 +221,6 @@ static VALUE iter_yield(RB_BLOCK_CALL_FUNC_ARGLIST(el, ary)) { return Qnil; } -static VALUE array_spec_rb_iterate_then_yield(VALUE self, VALUE obj) { - rb_iterate(rb_each, obj, iter_yield, obj); - return Qnil; -} - static VALUE array_spec_rb_block_call_then_yield(VALUE self, VALUE obj) { rb_block_call(obj, rb_intern("each"), 0, 0, iter_yield, obj); return Qnil; @@ -308,9 +283,6 @@ void Init_array_spec(void) { rb_define_method(cls, "rb_ary_plus", array_spec_rb_ary_plus, 2); rb_define_method(cls, "rb_ary_unshift", array_spec_rb_ary_unshift, 2); rb_define_method(cls, "rb_assoc_new", array_spec_rb_assoc_new, 2); - rb_define_method(cls, "rb_iterate", array_spec_rb_iterate, 1); - rb_define_method(cls, "rb_iterate_each_pair", array_spec_rb_iterate_each_pair, 1); - rb_define_method(cls, "rb_iterate_then_yield", array_spec_rb_iterate_then_yield, 1); rb_define_method(cls, "rb_block_call", array_spec_rb_block_call, 1); rb_define_method(cls, "rb_block_call_each_pair", array_spec_rb_block_call_each_pair, 1); rb_define_method(cls, "rb_block_call_then_yield", array_spec_rb_block_call_then_yield, 1); diff --git a/spec/ruby/optional/capi/ext/class_spec.c b/spec/ruby/optional/capi/ext/class_spec.c index f376534924..36b8c8f2f3 100644 --- a/spec/ruby/optional/capi/ext/class_spec.c +++ b/spec/ruby/optional/capi/ext/class_spec.c @@ -61,18 +61,21 @@ static VALUE class_spec_rb_class_new(VALUE self, VALUE super) { return rb_class_new(super); } -static VALUE class_spec_rb_class_new_instance(VALUE self, VALUE args, VALUE klass) { - return rb_class_new_instance(RARRAY_LENINT(args), RARRAY_PTR(args), klass); -} +static VALUE class_spec_rb_class_new_instance(VALUE self, + VALUE nargs, VALUE args, + VALUE klass) { + int c_nargs = FIX2INT(nargs); + VALUE *c_args = (VALUE*)alloca(sizeof(VALUE) * c_nargs); + int i; + + for (i = 0; i < c_nargs; i++) + c_args[i] = rb_ary_entry(args, i); -#ifdef RUBY_VERSION_IS_3_0 -static VALUE class_spec_rb_class_new_instance_kw(VALUE self, VALUE args, VALUE klass) { - return rb_class_new_instance_kw(RARRAY_LENINT(args), RARRAY_PTR(args), klass, RB_PASS_KEYWORDS); + return rb_class_new_instance(c_nargs, c_args, klass); } -#endif static VALUE class_spec_rb_class_real(VALUE self, VALUE object) { - if (rb_type_p(object, T_FIXNUM)) { + if(rb_type_p(object, T_FIXNUM)) { return INT2FIX(rb_class_real(FIX2INT(object))); } else { return rb_class_real(CLASS_OF(object)); @@ -116,19 +119,19 @@ VALUE class_spec_define_attr(VALUE self, VALUE klass, VALUE sym, VALUE read, VAL } static VALUE class_spec_rb_define_class(VALUE self, VALUE name, VALUE super) { - if (NIL_P(super)) super = 0; + if(NIL_P(super)) super = 0; return rb_define_class(RSTRING_PTR(name), super); } static VALUE class_spec_rb_define_class_under(VALUE self, VALUE outer, VALUE name, VALUE super) { - if (NIL_P(super)) super = 0; + if(NIL_P(super)) super = 0; return rb_define_class_under(outer, RSTRING_PTR(name), super); } static VALUE class_spec_rb_define_class_id_under(VALUE self, VALUE outer, VALUE name, VALUE super) { - if (NIL_P(super)) super = 0; + if(NIL_P(super)) super = 0; return rb_define_class_id_under(outer, SYM2ID(name), super); } @@ -142,6 +145,19 @@ static VALUE class_spec_include_module(VALUE self, VALUE klass, VALUE module) { return klass; } +static VALUE class_spec_method_var_args_1(int argc, VALUE *argv, VALUE self) { + VALUE ary = rb_ary_new(); + int i; + for (i = 0; i < argc; i++) { + rb_ary_push(ary, argv[i]); + } + return ary; +} + +static VALUE class_spec_method_var_args_2(VALUE self, VALUE argv) { + return argv; +} + void Init_class_spec(void) { VALUE cls = rb_define_class("CApiClassSpecs", rb_cObject); rb_define_method(cls, "define_call_super_method", class_spec_define_call_super_method, 2); @@ -155,10 +171,7 @@ void Init_class_spec(void) { rb_define_method(cls, "rb_class_protected_instance_methods", class_spec_rb_class_protected_instance_methods, -1); rb_define_method(cls, "rb_class_private_instance_methods", class_spec_rb_class_private_instance_methods, -1); rb_define_method(cls, "rb_class_new", class_spec_rb_class_new, 1); - rb_define_method(cls, "rb_class_new_instance", class_spec_rb_class_new_instance, 2); -#ifdef RUBY_VERSION_IS_3_0 - rb_define_method(cls, "rb_class_new_instance_kw", class_spec_rb_class_new_instance_kw, 2); -#endif + rb_define_method(cls, "rb_class_new_instance", class_spec_rb_class_new_instance, 3); rb_define_method(cls, "rb_class_real", class_spec_rb_class_real, 1); rb_define_method(cls, "rb_class_superclass", class_spec_rb_class_superclass, 1); rb_define_method(cls, "rb_cvar_defined", class_spec_cvar_defined, 2); @@ -172,6 +185,8 @@ void Init_class_spec(void) { rb_define_method(cls, "rb_define_class_id_under", class_spec_rb_define_class_id_under, 3); rb_define_method(cls, "rb_define_class_variable", class_spec_define_class_variable, 3); rb_define_method(cls, "rb_include_module", class_spec_include_module, 2); + rb_define_method(cls, "rb_method_varargs_1", class_spec_method_var_args_1, -1); + rb_define_method(cls, "rb_method_varargs_2", class_spec_method_var_args_2, -2); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/ext/debug_spec.c b/spec/ruby/optional/capi/ext/debug_spec.c index 9131eda78b..344dfc33fa 100644 --- a/spec/ruby/optional/capi/ext/debug_spec.c +++ b/spec/ruby/optional/capi/ext/debug_spec.c @@ -45,7 +45,7 @@ static VALUE rb_debug_inspector_frame_iseq_get_callback(const rb_debug_inspector return rb_debug_inspector_frame_iseq_get(dc, NUM2LONG((VALUE) ptr)); } -static VALUE debug_spec_callback_data(VALUE self) { +static VALUE debug_spec_callback_data(VALUE self){ return callback_data; } diff --git a/spec/ruby/optional/capi/ext/encoding_spec.c b/spec/ruby/optional/capi/ext/encoding_spec.c index 3343848b54..cde4d0c351 100644 --- a/spec/ruby/optional/capi/ext/encoding_spec.c +++ b/spec/ruby/optional/capi/ext/encoding_spec.c @@ -12,7 +12,7 @@ static VALUE encoding_spec_MBCLEN_CHARFOUND_P(VALUE self, VALUE obj) { } static VALUE encoding_spec_ENC_CODERANGE_ASCIIONLY(VALUE self, VALUE obj) { - if (ENC_CODERANGE_ASCIIONLY(obj)) { + if(ENC_CODERANGE_ASCIIONLY(obj)) { return Qtrue; } else { return Qfalse; @@ -61,19 +61,21 @@ static VALUE encoding_spec_rb_filesystem_encindex(VALUE self) { static VALUE encoding_spec_rb_default_internal_encoding(VALUE self) { rb_encoding* enc = rb_default_internal_encoding(); - if (enc == 0) return Qnil; + if(enc == 0) return Qnil; return rb_str_new2(enc->name); } static VALUE encoding_spec_rb_default_external_encoding(VALUE self) { rb_encoding* enc = rb_default_external_encoding(); - if (enc == 0) return Qnil; + if(enc == 0) return Qnil; return rb_str_new2(enc->name); } +#ifdef RUBY_VERSION_IS_2_6 static VALUE encoding_spec_rb_enc_alias(VALUE self, VALUE alias, VALUE orig) { return INT2NUM(rb_enc_alias(RSTRING_PTR(alias), RSTRING_PTR(orig))); } +#endif static VALUE encoding_spec_rb_enc_associate(VALUE self, VALUE obj, VALUE enc) { return rb_enc_associate(obj, NIL_P(enc) ? NULL : rb_enc_find(RSTRING_PTR(enc))); @@ -86,7 +88,7 @@ static VALUE encoding_spec_rb_enc_associate_index(VALUE self, VALUE obj, VALUE i static VALUE encoding_spec_rb_enc_compatible(VALUE self, VALUE a, VALUE b) { rb_encoding* enc = rb_enc_compatible(a, b); - if (!enc) return INT2FIX(0); + if(!enc) return INT2FIX(0); return rb_enc_from_encoding(enc); } @@ -118,9 +120,10 @@ static VALUE encoding_spec_rb_enc_from_index(VALUE self, VALUE index) { return rb_str_new2(rb_enc_from_index(NUM2INT(index))->name); } -static VALUE encoding_spec_rb_enc_mbc_to_codepoint(VALUE self, VALUE str) { +static VALUE encoding_spec_rb_enc_mbc_to_codepoint(VALUE self, VALUE str, VALUE offset) { + int o = FIX2INT(offset); char *p = RSTRING_PTR(str); - char *e = RSTRING_END(str); + char *e = p + o; return INT2FIX(rb_enc_mbc_to_codepoint(p, e, rb_enc_get(str))); } @@ -271,17 +274,8 @@ static VALUE encoding_spec_rb_enc_str_asciionly_p(VALUE self, VALUE str) { } } -static VALUE encoding_spec_rb_enc_raise(VALUE self, VALUE encoding, VALUE exception_class, VALUE format) { - rb_encoding *e = rb_to_encoding(encoding); - const char *f = RSTRING_PTR(format); - - rb_enc_raise(e, exception_class, "%s", f); -} - static VALUE encoding_spec_rb_uv_to_utf8(VALUE self, VALUE buf, VALUE num) { - int len = rb_uv_to_utf8(RSTRING_PTR(buf), NUM2INT(num)); - RB_ENC_CODERANGE_CLEAR(buf); - return INT2NUM(len); + return INT2NUM(rb_uv_to_utf8(RSTRING_PTR(buf), NUM2INT(num))); } static VALUE encoding_spec_ONIGENC_MBC_CASE_FOLD(VALUE self, VALUE str) { @@ -306,20 +300,6 @@ static VALUE encoding_spec_rb_enc_codelen(VALUE self, VALUE code, VALUE encoding return INT2FIX(rb_enc_codelen(c, enc)); } -static VALUE encoding_spec_rb_enc_strlen(VALUE self, VALUE str, VALUE length, VALUE encoding) { - int l = FIX2INT(length); - char *p = RSTRING_PTR(str); - char *e = p + l; - - return LONG2FIX(rb_enc_strlen(p, e, rb_to_encoding(encoding))); -} - -static VALUE encoding_spec_rb_enc_left_char_head(VALUE self, VALUE str, VALUE offset) { - char *ptr = RSTRING_PTR(str); - char *result = rb_enc_left_char_head(ptr, ptr + NUM2INT(offset), RSTRING_END(str), rb_enc_get(str)); - return LONG2NUM(result - ptr); -} - void Init_encoding_spec(void) { VALUE cls; native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*)); @@ -338,22 +318,28 @@ void Init_encoding_spec(void) { rb_define_method(cls, "rb_locale_encindex", encoding_spec_rb_locale_encindex, 0); rb_define_method(cls, "rb_filesystem_encoding", encoding_spec_rb_filesystem_encoding, 0); rb_define_method(cls, "rb_filesystem_encindex", encoding_spec_rb_filesystem_encindex, 0); - rb_define_method(cls, "rb_default_internal_encoding", encoding_spec_rb_default_internal_encoding, 0); - rb_define_method(cls, "rb_default_external_encoding", encoding_spec_rb_default_external_encoding, 0); + rb_define_method(cls, "rb_default_internal_encoding", + encoding_spec_rb_default_internal_encoding, 0); + + rb_define_method(cls, "rb_default_external_encoding", + encoding_spec_rb_default_external_encoding, 0); + +#ifdef RUBY_VERSION_IS_2_6 rb_define_method(cls, "rb_enc_alias", encoding_spec_rb_enc_alias, 2); +#endif + rb_define_method(cls, "MBCLEN_CHARFOUND_P", encoding_spec_MBCLEN_CHARFOUND_P, 1); rb_define_method(cls, "rb_enc_associate", encoding_spec_rb_enc_associate, 2); rb_define_method(cls, "rb_enc_associate_index", encoding_spec_rb_enc_associate_index, 2); rb_define_method(cls, "rb_enc_compatible", encoding_spec_rb_enc_compatible, 2); rb_define_method(cls, "rb_enc_copy", encoding_spec_rb_enc_copy, 2); rb_define_method(cls, "rb_enc_codelen", encoding_spec_rb_enc_codelen, 2); - rb_define_method(cls, "rb_enc_strlen", encoding_spec_rb_enc_strlen, 3); rb_define_method(cls, "rb_enc_find", encoding_spec_rb_enc_find, 1); rb_define_method(cls, "rb_enc_find_index", encoding_spec_rb_enc_find_index, 1); rb_define_method(cls, "rb_enc_isalnum", encoding_spec_rb_enc_isalnum, 2); rb_define_method(cls, "rb_enc_isspace", encoding_spec_rb_enc_isspace, 2); rb_define_method(cls, "rb_enc_from_index", encoding_spec_rb_enc_from_index, 1); - rb_define_method(cls, "rb_enc_mbc_to_codepoint", encoding_spec_rb_enc_mbc_to_codepoint, 1); + rb_define_method(cls, "rb_enc_mbc_to_codepoint", encoding_spec_rb_enc_mbc_to_codepoint, 2); rb_define_method(cls, "rb_enc_mbcput", encoding_spec_rb_enc_mbcput, 2); rb_define_method(cls, "rb_enc_from_encoding", encoding_spec_rb_enc_from_encoding, 1); rb_define_method(cls, "rb_enc_get", encoding_spec_rb_enc_get, 1); @@ -375,10 +361,8 @@ void Init_encoding_spec(void) { rb_define_method(cls, "rb_enc_nth", encoding_spec_rb_enc_nth, 2); rb_define_method(cls, "rb_enc_codepoint_len", encoding_spec_rb_enc_codepoint_len, 1); rb_define_method(cls, "rb_enc_str_asciionly_p", encoding_spec_rb_enc_str_asciionly_p, 1); - rb_define_method(cls, "rb_enc_raise", encoding_spec_rb_enc_raise, 3); rb_define_method(cls, "rb_uv_to_utf8", encoding_spec_rb_uv_to_utf8, 2); rb_define_method(cls, "ONIGENC_MBC_CASE_FOLD", encoding_spec_ONIGENC_MBC_CASE_FOLD, 1); - rb_define_method(cls, "rb_enc_left_char_head", encoding_spec_rb_enc_left_char_head, 2); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/ext/exception_spec.c b/spec/ruby/optional/capi/ext/exception_spec.c index 0e8347ab0d..e1114aabb8 100644 --- a/spec/ruby/optional/capi/ext/exception_spec.c +++ b/spec/ruby/optional/capi/ext/exception_spec.c @@ -27,7 +27,7 @@ VALUE exception_spec_rb_exc_new3(VALUE self, VALUE str) { } VALUE exception_spec_rb_exc_raise(VALUE self, VALUE exc) { - if (self != Qundef) rb_exc_raise(exc); + if (self != Qundef) rb_exc_raise(exc); return Qnil; } @@ -36,21 +36,6 @@ VALUE exception_spec_rb_set_errinfo(VALUE self, VALUE exc) { return Qnil; } -VALUE exception_spec_rb_syserr_new(VALUE self, VALUE num, VALUE msg) { - int n = NUM2INT(num); - char *cstr = NULL; - - if (msg != Qnil) { - cstr = StringValuePtr(msg); - } - - return rb_syserr_new(n, cstr); -} - -VALUE exception_spec_rb_syserr_new_str(VALUE self, VALUE num, VALUE msg) { - int n = NUM2INT(num); - return rb_syserr_new_str(n, msg); -} VALUE exception_spec_rb_make_exception(VALUE self, VALUE ary) { int argc = RARRAY_LENINT(ary); @@ -66,8 +51,6 @@ void Init_exception_spec(void) { rb_define_method(cls, "rb_exc_new3", exception_spec_rb_exc_new3, 1); rb_define_method(cls, "rb_exc_raise", exception_spec_rb_exc_raise, 1); rb_define_method(cls, "rb_set_errinfo", exception_spec_rb_set_errinfo, 1); - rb_define_method(cls, "rb_syserr_new", exception_spec_rb_syserr_new, 2); - rb_define_method(cls, "rb_syserr_new_str", exception_spec_rb_syserr_new_str, 2); rb_define_method(cls, "rb_make_exception", exception_spec_rb_make_exception, 1); } diff --git a/spec/ruby/optional/capi/ext/gc_spec.c b/spec/ruby/optional/capi/ext/gc_spec.c index 7dd0b87655..7dc9c347c7 100644 --- a/spec/ruby/optional/capi/ext/gc_spec.c +++ b/spec/ruby/optional/capi/ext/gc_spec.c @@ -7,9 +7,6 @@ extern "C" { VALUE registered_tagged_value; VALUE registered_reference_value; -VALUE registered_before_rb_gc_register_address; -VALUE registered_before_rb_global_variable; -VALUE rb_gc_register_address_outside_init; static VALUE registered_tagged_address(VALUE self) { return registered_tagged_value; @@ -19,25 +16,6 @@ static VALUE registered_reference_address(VALUE self) { return registered_reference_value; } -static VALUE get_registered_before_rb_gc_register_address(VALUE self) { - return registered_before_rb_gc_register_address; -} - -static VALUE get_registered_before_rb_global_variable(VALUE self) { - return registered_before_rb_global_variable; -} - -static VALUE gc_spec_rb_gc_register_address(VALUE self) { - rb_gc_register_address(&rb_gc_register_address_outside_init); - rb_gc_register_address_outside_init = rb_str_new_cstr("rb_gc_register_address() outside Init_"); - return rb_gc_register_address_outside_init; -} - -static VALUE gc_spec_rb_gc_unregister_address(VALUE self) { - rb_gc_unregister_address(&rb_gc_register_address_outside_init); - return Qnil; -} - static VALUE gc_spec_rb_gc_enable(VALUE self) { return rb_gc_enable(); } @@ -51,7 +29,7 @@ static VALUE gc_spec_rb_gc(VALUE self) { return Qnil; } -static VALUE gc_spec_rb_gc_latest_gc_info(VALUE self, VALUE hash_or_key) { +static VALUE gc_spec_rb_gc_latest_gc_info(VALUE self, VALUE hash_or_key){ return rb_gc_latest_gc_info(hash_or_key); } @@ -67,23 +45,14 @@ static VALUE gc_spec_rb_gc_register_mark_object(VALUE self, VALUE obj) { void Init_gc_spec(void) { VALUE cls = rb_define_class("CApiGCSpecs", rb_cObject); + registered_tagged_value = INT2NUM(10); + registered_reference_value = rb_str_new2("Globally registered data"); rb_gc_register_address(®istered_tagged_value); rb_gc_register_address(®istered_reference_value); - rb_gc_register_address(®istered_before_rb_gc_register_address); - rb_global_variable(®istered_before_rb_global_variable); - - registered_tagged_value = INT2NUM(10); - registered_reference_value = rb_str_new2("Globally registered data"); - registered_before_rb_gc_register_address = rb_str_new_cstr("registered before rb_gc_register_address()"); - registered_before_rb_global_variable = rb_str_new_cstr("registered before rb_global_variable()"); rb_define_method(cls, "registered_tagged_address", registered_tagged_address, 0); rb_define_method(cls, "registered_reference_address", registered_reference_address, 0); - rb_define_method(cls, "registered_before_rb_gc_register_address", get_registered_before_rb_gc_register_address, 0); - rb_define_method(cls, "registered_before_rb_global_variable", get_registered_before_rb_global_variable, 0); - rb_define_method(cls, "rb_gc_register_address", gc_spec_rb_gc_register_address, 0); - rb_define_method(cls, "rb_gc_unregister_address", gc_spec_rb_gc_unregister_address, 0); rb_define_method(cls, "rb_gc_enable", gc_spec_rb_gc_enable, 0); rb_define_method(cls, "rb_gc_disable", gc_spec_rb_gc_disable, 0); rb_define_method(cls, "rb_gc", gc_spec_rb_gc, 0); diff --git a/spec/ruby/optional/capi/ext/globals_spec.c b/spec/ruby/optional/capi/ext/globals_spec.c index 20dea1a05a..28a9633f98 100644 --- a/spec/ruby/optional/capi/ext/globals_spec.c +++ b/spec/ruby/optional/capi/ext/globals_spec.c @@ -20,16 +20,6 @@ static VALUE sb_define_hooked_variable(VALUE self, VALUE var_name) { return Qnil; } -static VALUE sb_define_hooked_variable_default_accessors(VALUE self, VALUE var_name) { - rb_define_hooked_variable(StringValuePtr(var_name), &g_hooked_var, (rb_gvar_getter_t*) NULL, (rb_gvar_setter_t*) NULL); - return Qnil; -} - -static VALUE sb_define_hooked_variable_null_var(VALUE self, VALUE var_name) { - rb_define_hooked_variable(StringValuePtr(var_name), NULL, (rb_gvar_getter_t*) NULL, (rb_gvar_setter_t*) NULL); - return Qnil; -} - VALUE g_ro_var; static VALUE sb_define_readonly_variable(VALUE self, VALUE var_name, VALUE val) { @@ -50,26 +40,6 @@ static VALUE sb_define_variable(VALUE self, VALUE var_name, VALUE val) { return Qnil; } -long virtual_var_storage; - -VALUE incrementing_getter(ID id, VALUE *data) { - return LONG2FIX(virtual_var_storage++); -} - -void incrementing_setter(VALUE val, ID id, VALUE *data) { - virtual_var_storage = FIX2LONG(val); -} - -static VALUE sb_define_virtual_variable_default_accessors(VALUE self, VALUE name) { - rb_define_virtual_variable(StringValuePtr(name), (rb_gvar_getter_t*) NULL, (rb_gvar_setter_t*) NULL); - return Qnil; -} - -static VALUE sb_define_virtual_variable_incrementing_accessors(VALUE self, VALUE name) { - rb_define_virtual_variable(StringValuePtr(name), incrementing_getter, incrementing_setter); - return Qnil; -} - static VALUE sb_f_global_variables(VALUE self) { return rb_f_global_variables(); } @@ -131,14 +101,10 @@ void Init_globals_spec(void) { VALUE cls = rb_define_class("CApiGlobalSpecs", rb_cObject); g_hooked_var = Qnil; rb_define_method(cls, "rb_define_hooked_variable_2x", sb_define_hooked_variable, 1); - rb_define_method(cls, "rb_define_hooked_variable_default_accessors", sb_define_hooked_variable_default_accessors, 1); - rb_define_method(cls, "rb_define_hooked_variable_null_var", sb_define_hooked_variable_null_var, 1); g_ro_var = Qnil; rb_define_method(cls, "rb_define_readonly_variable", sb_define_readonly_variable, 2); g_var = Qnil; rb_define_method(cls, "rb_define_variable", sb_define_variable, 2); - rb_define_method(cls, "rb_define_virtual_variable_default_accessors", sb_define_virtual_variable_default_accessors, 1); - rb_define_method(cls, "rb_define_virtual_variable_incrementing_accessors", sb_define_virtual_variable_incrementing_accessors, 1); rb_define_method(cls, "sb_get_global_value", sb_get_global_value, 0); rb_define_method(cls, "rb_f_global_variables", sb_f_global_variables, 0); rb_define_method(cls, "sb_gv_get", sb_gv_get, 1); diff --git a/spec/ruby/optional/capi/ext/hash_spec.c b/spec/ruby/optional/capi/ext/hash_spec.c index 69ef02d5da..7f38708915 100644 --- a/spec/ruby/optional/capi/ext/hash_spec.c +++ b/spec/ruby/optional/capi/ext/hash_spec.c @@ -105,12 +105,6 @@ VALUE hash_spec_rb_hash_new(VALUE self) { return rb_hash_new(); } -#ifdef RUBY_VERSION_IS_3_2 -VALUE hash_spec_rb_hash_new_capa(VALUE self, VALUE capacity) { - return rb_hash_new_capa(NUM2LONG(capacity)); -} -#endif - VALUE rb_ident_hash_new(void); /* internal.h, used in ripper */ VALUE hash_spec_rb_ident_hash_new(VALUE self) { @@ -155,9 +149,6 @@ void Init_hash_spec(void) { rb_define_method(cls, "rb_hash_lookup2", hash_spec_rb_hash_lookup2, 3); rb_define_method(cls, "rb_hash_lookup2_default_undef", hash_spec_rb_hash_lookup2_default_undef, 2); rb_define_method(cls, "rb_hash_new", hash_spec_rb_hash_new, 0); -#ifdef RUBY_VERSION_IS_3_2 - rb_define_method(cls, "rb_hash_new_capa", hash_spec_rb_hash_new_capa, 1); -#endif rb_define_method(cls, "rb_ident_hash_new", hash_spec_rb_ident_hash_new, 0); rb_define_method(cls, "rb_hash_size", hash_spec_rb_hash_size, 1); rb_define_method(cls, "rb_hash_set_ifnone", hash_spec_rb_hash_set_ifnone, 2); diff --git a/spec/ruby/optional/capi/ext/integer_spec.c b/spec/ruby/optional/capi/ext/integer_spec.c index 792fc0652a..16cd95f111 100644 --- a/spec/ruby/optional/capi/ext/integer_spec.c +++ b/spec/ruby/optional/capi/ext/integer_spec.c @@ -6,7 +6,8 @@ extern "C" { #endif static VALUE integer_spec_rb_integer_pack(VALUE self, VALUE value, - VALUE words, VALUE numwords, VALUE wordsize, VALUE nails, VALUE flags) { + VALUE words, VALUE numwords, VALUE wordsize, VALUE nails, VALUE flags) +{ int result = rb_integer_pack(value, (void*)RSTRING_PTR(words), FIX2INT(numwords), FIX2INT(wordsize), FIX2INT(nails), FIX2INT(flags)); return INT2FIX(result); @@ -14,7 +15,7 @@ static VALUE integer_spec_rb_integer_pack(VALUE self, VALUE value, RUBY_EXTERN VALUE rb_int_positive_pow(long x, unsigned long y); /* internal.h, used in ripper */ -static VALUE integer_spec_rb_int_positive_pow(VALUE self, VALUE a, VALUE b) { +static VALUE integer_spec_rb_int_positive_pow(VALUE self, VALUE a, VALUE b){ return rb_int_positive_pow(FIX2INT(a), FIX2INT(b)); } diff --git a/spec/ruby/optional/capi/ext/io_spec.c b/spec/ruby/optional/capi/ext/io_spec.c index ab3aef4c92..b4ffe9207a 100644 --- a/spec/ruby/optional/capi/ext/io_spec.c +++ b/spec/ruby/optional/capi/ext/io_spec.c @@ -28,13 +28,9 @@ static int set_non_blocking(int fd) { } static int io_spec_get_fd(VALUE io) { -#ifdef RUBY_VERSION_IS_3_1 - return rb_io_descriptor(io); -#else rb_io_t* fp; GetOpenFile(io, fp); return fp->fd; -#endif } VALUE io_spec_GetOpenFile_fd(VALUE self, VALUE io) { @@ -134,7 +130,7 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) { rb_sys_fail("set_non_blocking failed"); #ifndef SET_NON_BLOCKING_FAILS_ALWAYS - if (RTEST(read_p)) { + if(RTEST(read_p)) { if (read(fd, buf, RB_IO_WAIT_READABLE_BUF) != -1) { return Qnil; } @@ -145,7 +141,7 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) { ret = rb_io_wait_readable(fd); - if (RTEST(read_p)) { + if(RTEST(read_p)) { ssize_t r = read(fd, buf, RB_IO_WAIT_READABLE_BUF); if (r != RB_IO_WAIT_READABLE_BUF) { perror("read"); @@ -166,60 +162,6 @@ VALUE io_spec_rb_io_wait_writable(VALUE self, VALUE io) { return ret ? Qtrue : Qfalse; } -#ifdef RUBY_VERSION_IS_3_1 -VALUE io_spec_rb_io_maybe_wait_writable(VALUE self, VALUE error, VALUE io, VALUE timeout) { - int ret = rb_io_maybe_wait_writable(NUM2INT(error), io, timeout); - return INT2NUM(ret); -} -#endif - -#ifdef RUBY_VERSION_IS_3_1 -VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE timeout, VALUE read_p) { - int fd = io_spec_get_fd(io); -#ifndef SET_NON_BLOCKING_FAILS_ALWAYS - char buf[RB_IO_WAIT_READABLE_BUF]; - int ret, saved_errno; -#endif - - if (set_non_blocking(fd) == -1) - rb_sys_fail("set_non_blocking failed"); - -#ifndef SET_NON_BLOCKING_FAILS_ALWAYS - if (RTEST(read_p)) { - if (read(fd, buf, RB_IO_WAIT_READABLE_BUF) != -1) { - return Qnil; - } - saved_errno = errno; - rb_ivar_set(self, rb_intern("@write_data"), Qtrue); - errno = saved_errno; - } - - // main part - ret = rb_io_maybe_wait_readable(NUM2INT(error), io, timeout); - - if (RTEST(read_p)) { - ssize_t r = read(fd, buf, RB_IO_WAIT_READABLE_BUF); - if (r != RB_IO_WAIT_READABLE_BUF) { - perror("read"); - return SSIZET2NUM(r); - } - rb_ivar_set(self, rb_intern("@read_data"), - rb_str_new(buf, RB_IO_WAIT_READABLE_BUF)); - } - - return INT2NUM(ret); -#else - UNREACHABLE; -#endif -} -#endif - -#ifdef RUBY_VERSION_IS_3_1 -VALUE io_spec_rb_io_maybe_wait(VALUE self, VALUE error, VALUE io, VALUE events, VALUE timeout) { - return rb_io_maybe_wait(NUM2INT(error), io, events, timeout); -} -#endif - VALUE io_spec_rb_thread_wait_fd(VALUE self, VALUE io) { rb_thread_wait_fd(io_spec_get_fd(io)); return Qnil; @@ -240,46 +182,6 @@ VALUE io_spec_rb_thread_fd_writable(VALUE self, VALUE io) { return Qnil; } -VALUE io_spec_rb_thread_fd_select_read(VALUE self, VALUE io) { - int fd = io_spec_get_fd(io); - - rb_fdset_t fds; - rb_fd_init(&fds); - rb_fd_set(fd, &fds); - - int r = rb_thread_fd_select(fd + 1, &fds, NULL, NULL, NULL); - rb_fd_term(&fds); - return INT2FIX(r); -} - -VALUE io_spec_rb_thread_fd_select_write(VALUE self, VALUE io) { - int fd = io_spec_get_fd(io); - - rb_fdset_t fds; - rb_fd_init(&fds); - rb_fd_set(fd, &fds); - - int r = rb_thread_fd_select(fd + 1, NULL, &fds, NULL, NULL); - rb_fd_term(&fds); - return INT2FIX(r); -} - -VALUE io_spec_rb_thread_fd_select_timeout(VALUE self, VALUE io) { - int fd = io_spec_get_fd(io); - - struct timeval timeout; - timeout.tv_sec = 10; - timeout.tv_usec = 20; - - rb_fdset_t fds; - rb_fd_init(&fds); - rb_fd_set(fd, &fds); - - int r = rb_thread_fd_select(fd + 1, NULL, &fds, NULL, &timeout); - rb_fd_term(&fds); - return INT2FIX(r); -} - VALUE io_spec_rb_io_binmode(VALUE self, VALUE io) { return rb_io_binmode(io); } @@ -307,7 +209,7 @@ VALUE io_spec_rb_io_set_nonblock(VALUE self, VALUE io) { GetOpenFile(io, fp); rb_io_set_nonblock(fp); #ifdef F_GETFL - flags = fcntl(io_spec_get_fd(io), F_GETFL, 0); + flags = fcntl(fp->fd, F_GETFL, 0); return flags & O_NONBLOCK ? Qtrue : Qfalse; #else return Qfalse; @@ -326,13 +228,9 @@ static VALUE io_spec_errno_set(VALUE self, VALUE val) { } VALUE io_spec_mode_sync_flag(VALUE self, VALUE io) { -#ifdef RUBY_VERSION_IS_3_3 - if (rb_io_mode(io) & FMODE_SYNC) { -#else rb_io_t *fp; GetOpenFile(io, fp); if (fp->mode & FMODE_SYNC) { -#endif return Qtrue; } else { return Qfalse; @@ -356,16 +254,8 @@ void Init_io_spec(void) { rb_define_method(cls, "rb_io_taint_check", io_spec_rb_io_taint_check, 1); rb_define_method(cls, "rb_io_wait_readable", io_spec_rb_io_wait_readable, 2); rb_define_method(cls, "rb_io_wait_writable", io_spec_rb_io_wait_writable, 1); -#ifdef RUBY_VERSION_IS_3_1 - rb_define_method(cls, "rb_io_maybe_wait_writable", io_spec_rb_io_maybe_wait_writable, 3); - rb_define_method(cls, "rb_io_maybe_wait_readable", io_spec_rb_io_maybe_wait_readable, 4); - rb_define_method(cls, "rb_io_maybe_wait", io_spec_rb_io_maybe_wait, 4); -#endif rb_define_method(cls, "rb_thread_wait_fd", io_spec_rb_thread_wait_fd, 1); rb_define_method(cls, "rb_thread_fd_writable", io_spec_rb_thread_fd_writable, 1); - rb_define_method(cls, "rb_thread_fd_select_read", io_spec_rb_thread_fd_select_read, 1); - rb_define_method(cls, "rb_thread_fd_select_write", io_spec_rb_thread_fd_select_write, 1); - rb_define_method(cls, "rb_thread_fd_select_timeout", io_spec_rb_thread_fd_select_timeout, 1); rb_define_method(cls, "rb_wait_for_single_fd", io_spec_rb_wait_for_single_fd, 4); rb_define_method(cls, "rb_io_binmode", io_spec_rb_io_binmode, 1); rb_define_method(cls, "rb_fd_fix_cloexec", io_spec_rb_fd_fix_cloexec, 1); diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c index a921eb13e0..bbfeb198b7 100644 --- a/spec/ruby/optional/capi/ext/kernel_spec.c +++ b/spec/ruby/optional/capi/ext/kernel_spec.c @@ -112,10 +112,6 @@ VALUE kernel_spec_rb_eval_string(VALUE self, VALUE str) { return rb_eval_string(RSTRING_PTR(str)); } -VALUE kernel_spec_rb_eval_cmd_kw(VALUE self, VALUE cmd, VALUE args, VALUE kw_splat) { - return rb_eval_cmd_kw(cmd, args, NUM2INT(kw_splat)); -} - VALUE kernel_spec_rb_raise(VALUE self, VALUE hash) { rb_hash_aset(hash, ID2SYM(rb_intern("stage")), ID2SYM(rb_intern("before"))); if (self != Qundef) @@ -146,7 +142,7 @@ VALUE kernel_spec_call_proc_with_raised_exc(VALUE arg_array, VALUE raised_exc) { argc = 2; - return rb_funcallv(proc, rb_intern("call"), argc, argv); + return rb_funcall2(proc, rb_intern("call"), argc, argv); } VALUE kernel_spec_rb_rescue(VALUE self, VALUE main_proc, VALUE arg, @@ -220,7 +216,7 @@ static VALUE kernel_spec_rb_eval_string_protect(VALUE self, VALUE str, VALUE ary VALUE kernel_spec_rb_sys_fail(VALUE self, VALUE msg) { errno = 1; - if (msg == Qnil) { + if(msg == Qnil) { rb_sys_fail(0); } else if (self != Qundef) { rb_sys_fail(StringValuePtr(msg)); @@ -229,7 +225,7 @@ VALUE kernel_spec_rb_sys_fail(VALUE self, VALUE msg) { } VALUE kernel_spec_rb_syserr_fail(VALUE self, VALUE err, VALUE msg) { - if (msg == Qnil) { + if(msg == Qnil) { rb_syserr_fail(NUM2INT(err), NULL); } else if (self != Qundef) { rb_syserr_fail(NUM2INT(err), StringValuePtr(msg)); @@ -292,9 +288,9 @@ static VALUE kernel_spec_rb_yield_values2(VALUE self, VALUE ary) { } static VALUE do_rec(VALUE obj, VALUE arg, int is_rec) { - if (is_rec) { + if(is_rec) { return obj; - } else if (arg == Qtrue) { + } else if(arg == Qtrue) { return rb_exec_recursive(do_rec, obj, Qnil); } else { return Qnil; @@ -322,30 +318,12 @@ static VALUE kernel_spec_rb_make_backtrace(VALUE self) { return rb_make_backtrace(); } -static VALUE kernel_spec_rb_funcallv(VALUE self, VALUE obj, VALUE method, VALUE args) { - return rb_funcallv(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args)); -} - -#ifdef RUBY_VERSION_IS_3_0 -static VALUE kernel_spec_rb_funcallv_kw(VALUE self, VALUE obj, VALUE method, VALUE args) { - return rb_funcallv_kw(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args), RB_PASS_KEYWORDS); -} - -static VALUE kernel_spec_rb_keyword_given_p(int argc, VALUE *args, VALUE self) { - return rb_keyword_given_p() ? Qtrue : Qfalse; -} -#endif - -static VALUE kernel_spec_rb_funcallv_public(VALUE self, VALUE obj, VALUE method) { - return rb_funcallv_public(obj, SYM2ID(method), 0, NULL); +static VALUE kernel_spec_rb_funcall3(VALUE self, VALUE obj, VALUE method) { + return rb_funcall3(obj, SYM2ID(method), 0, NULL); } -static VALUE kernel_spec_rb_funcall_with_block(VALUE self, VALUE obj, VALUE method, VALUE args, VALUE block) { - return rb_funcall_with_block(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args), block); -} - -static VALUE kernel_spec_rb_funcall_with_block_kw(VALUE self, VALUE obj, VALUE method, VALUE args, VALUE block) { - return rb_funcall_with_block_kw(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args), block, RB_PASS_KEYWORDS); +static VALUE kernel_spec_rb_funcall_with_block(VALUE self, VALUE obj, VALUE method, VALUE block) { + return rb_funcall_with_block(obj, SYM2ID(method), 0, NULL, block); } static VALUE kernel_spec_rb_funcall_many_args(VALUE self, VALUE obj, VALUE method) { @@ -369,7 +347,6 @@ void Init_kernel_spec(void) { rb_define_method(cls, "rb_frame_this_func_test_again", kernel_spec_rb_frame_this_func, 0); rb_define_method(cls, "rb_ensure", kernel_spec_rb_ensure, 4); rb_define_method(cls, "rb_eval_string", kernel_spec_rb_eval_string, 1); - rb_define_method(cls, "rb_eval_cmd_kw", kernel_spec_rb_eval_cmd_kw, 3); rb_define_method(cls, "rb_raise", kernel_spec_rb_raise, 1); rb_define_method(cls, "rb_throw", kernel_spec_rb_throw, 1); rb_define_method(cls, "rb_throw_obj", kernel_spec_rb_throw_obj, 2); @@ -394,15 +371,9 @@ void Init_kernel_spec(void) { rb_define_method(cls, "rb_set_end_proc", kernel_spec_rb_set_end_proc, 1); rb_define_method(cls, "rb_f_sprintf", kernel_spec_rb_f_sprintf, 1); rb_define_method(cls, "rb_make_backtrace", kernel_spec_rb_make_backtrace, 0); - rb_define_method(cls, "rb_funcallv", kernel_spec_rb_funcallv, 3); -#ifdef RUBY_VERSION_IS_3_0 - rb_define_method(cls, "rb_funcallv_kw", kernel_spec_rb_funcallv_kw, 3); - rb_define_method(cls, "rb_keyword_given_p", kernel_spec_rb_keyword_given_p, -1); -#endif - rb_define_method(cls, "rb_funcallv_public", kernel_spec_rb_funcallv_public, 2); + rb_define_method(cls, "rb_funcall3", kernel_spec_rb_funcall3, 2); rb_define_method(cls, "rb_funcall_many_args", kernel_spec_rb_funcall_many_args, 2); - rb_define_method(cls, "rb_funcall_with_block", kernel_spec_rb_funcall_with_block, 4); - rb_define_method(cls, "rb_funcall_with_block_kw", kernel_spec_rb_funcall_with_block_kw, 4); + rb_define_method(cls, "rb_funcall_with_block", kernel_spec_rb_funcall_with_block, 3); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/ext/module_spec.c b/spec/ruby/optional/capi/ext/module_spec.c index 12bcf99983..7475994fa1 100644 --- a/spec/ruby/optional/capi/ext/module_spec.c +++ b/spec/ruby/optional/capi/ext/module_spec.c @@ -9,6 +9,18 @@ static VALUE module_specs_test_method(VALUE self) { return ID2SYM(rb_intern("test_method")); } +static VALUE module_specs_test_method_2required(VALUE self, VALUE arg1, VALUE arg2) { + return ID2SYM(rb_intern("test_method_2required")); +} + +static VALUE module_specs_test_method_c_array(int argc, VALUE *argv, VALUE self) { + return ID2SYM(rb_intern("test_method_c_array")); +} + +static VALUE module_specs_test_method_ruby_array(VALUE self, VALUE args) { + return ID2SYM(rb_intern("test_method_ruby_array")); +} + static VALUE module_specs_const_defined(VALUE self, VALUE klass, VALUE id) { return rb_const_defined(klass, SYM2ID(id)) ? Qtrue : Qfalse; } @@ -76,25 +88,19 @@ static VALUE module_specs_rb_define_method(VALUE self, VALUE cls, VALUE str_name return Qnil; } -static VALUE module_specs_method_var_args_1(int argc, VALUE *argv, VALUE self) { - VALUE ary = rb_ary_new(); - int i; - for (i = 0; i < argc; i++) { - rb_ary_push(ary, argv[i]); - } - return ary; -} - -static VALUE module_specs_method_var_args_2(VALUE self, VALUE argv) { - return argv; +static VALUE module_specs_rb_define_method_2required(VALUE self, VALUE cls, VALUE str_name) { + rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_2required, 2); + return Qnil; } -static VALUE module_specs_rb_define_method_1required(VALUE self, VALUE arg1) { - return arg1; +static VALUE module_specs_rb_define_method_c_array(VALUE self, VALUE cls, VALUE str_name) { + rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_c_array, -1); + return Qnil; } -static VALUE module_specs_rb_define_method_2required(VALUE self, VALUE arg1, VALUE arg2) { - return arg2; +static VALUE module_specs_rb_define_method_ruby_array(VALUE self, VALUE cls, VALUE str_name) { + rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_ruby_array, -2); + return Qnil; } static VALUE module_specs_rb_define_module_function(VALUE self, VALUE cls, VALUE str_name) { @@ -149,21 +155,25 @@ void Init_module_spec(void) { rb_define_method(cls, "rb_define_module_under", module_specs_rb_define_module_under, 2); rb_define_method(cls, "rb_define_const", module_specs_define_const, 3); rb_define_method(cls, "rb_define_global_const", module_specs_define_global_const, 2); - rb_define_method(cls, "rb_define_global_function", module_specs_rb_define_global_function, 1); + rb_define_method(cls, "rb_define_global_function", + module_specs_rb_define_global_function, 1); rb_define_method(cls, "rb_define_method", module_specs_rb_define_method, 2); - rb_define_method(cls, "rb_define_method_varargs_1", module_specs_method_var_args_1, -1); - rb_define_method(cls, "rb_define_method_varargs_2", module_specs_method_var_args_2, -2); - rb_define_method(cls, "rb_define_method_1required", module_specs_rb_define_method_1required, 1); rb_define_method(cls, "rb_define_method_2required", module_specs_rb_define_method_2required, 2); + rb_define_method(cls, "rb_define_method_c_array", module_specs_rb_define_method_c_array, 2); + rb_define_method(cls, "rb_define_method_ruby_array", module_specs_rb_define_method_ruby_array, 2); - rb_define_method(cls, "rb_define_module_function", module_specs_rb_define_module_function, 2); + rb_define_method(cls, "rb_define_module_function", + module_specs_rb_define_module_function, 2); - rb_define_method(cls, "rb_define_private_method", module_specs_rb_define_private_method, 2); + rb_define_method(cls, "rb_define_private_method", + module_specs_rb_define_private_method, 2); - rb_define_method(cls, "rb_define_protected_method", module_specs_rb_define_protected_method, 2); + rb_define_method(cls, "rb_define_protected_method", + module_specs_rb_define_protected_method, 2); - rb_define_method(cls, "rb_define_singleton_method", module_specs_rb_define_singleton_method, 2); + rb_define_method(cls, "rb_define_singleton_method", + module_specs_rb_define_singleton_method, 2); rb_define_method(cls, "rb_undef_method", module_specs_rb_undef_method, 2); rb_define_method(cls, "rb_undef", module_specs_rb_undef, 2); diff --git a/spec/ruby/optional/capi/ext/object_spec.c b/spec/ruby/optional/capi/ext/object_spec.c index 7023c29bdb..c1f3b09ff8 100644 --- a/spec/ruby/optional/capi/ext/object_spec.c +++ b/spec/ruby/optional/capi/ext/object_spec.c @@ -118,14 +118,11 @@ static VALUE so_rb_obj_call_init(VALUE self, VALUE object, return Qnil; } -static VALUE so_rb_obj_class(VALUE self, VALUE obj) { - return rb_obj_class(obj); -} - static VALUE so_rbobjclassname(VALUE self, VALUE obj) { return rb_str_new2(rb_obj_classname(obj)); } + static VALUE object_spec_rb_obj_freeze(VALUE self, VALUE obj) { return rb_obj_freeze(obj); } @@ -154,10 +151,26 @@ static VALUE object_specs_rb_obj_method(VALUE self, VALUE obj, VALUE method) { return rb_obj_method(obj, method); } -#ifndef RUBY_VERSION_IS_3_2 +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#elif defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wdeprecated-declarations") +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +# endif +#endif + static VALUE object_spec_rb_obj_taint(VALUE self, VALUE obj) { return rb_obj_taint(obj); } + +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +# pragma GCC diagnostic pop +#elif defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wdeprecated-declarations") +# pragma clang diagnostic pop +# endif #endif static VALUE so_require(VALUE self) { @@ -200,126 +213,119 @@ static VALUE so_check_type(VALUE self, VALUE obj, VALUE other) { } static VALUE so_is_type_nil(VALUE self, VALUE obj) { - if (TYPE(obj) == T_NIL) { + if(TYPE(obj) == T_NIL) { return Qtrue; } return Qfalse; } static VALUE so_is_type_object(VALUE self, VALUE obj) { - if (TYPE(obj) == T_OBJECT) { + if(TYPE(obj) == T_OBJECT) { return Qtrue; } return Qfalse; } static VALUE so_is_type_array(VALUE self, VALUE obj) { - if (TYPE(obj) == T_ARRAY) { + if(TYPE(obj) == T_ARRAY) { return Qtrue; } return Qfalse; } static VALUE so_is_type_module(VALUE self, VALUE obj) { - if (TYPE(obj) == T_MODULE) { + if(TYPE(obj) == T_MODULE) { return Qtrue; } return Qfalse; } static VALUE so_is_type_class(VALUE self, VALUE obj) { - if (TYPE(obj) == T_CLASS) { + if(TYPE(obj) == T_CLASS) { return Qtrue; } return Qfalse; } static VALUE so_is_type_data(VALUE self, VALUE obj) { - if (TYPE(obj) == T_DATA) { + if(TYPE(obj) == T_DATA) { return Qtrue; } return Qfalse; } static VALUE so_is_rb_type_p_nil(VALUE self, VALUE obj) { - if (rb_type_p(obj, T_NIL)) { + if(rb_type_p(obj, T_NIL)) { return Qtrue; } return Qfalse; } static VALUE so_is_rb_type_p_object(VALUE self, VALUE obj) { - if (rb_type_p(obj, T_OBJECT)) { + if(rb_type_p(obj, T_OBJECT)) { return Qtrue; } return Qfalse; } static VALUE so_is_rb_type_p_array(VALUE self, VALUE obj) { - if (rb_type_p(obj, T_ARRAY)) { + if(rb_type_p(obj, T_ARRAY)) { return Qtrue; } return Qfalse; } static VALUE so_is_rb_type_p_module(VALUE self, VALUE obj) { - if (rb_type_p(obj, T_MODULE)) { + if(rb_type_p(obj, T_MODULE)) { return Qtrue; } return Qfalse; } static VALUE so_is_rb_type_p_class(VALUE self, VALUE obj) { - if (rb_type_p(obj, T_CLASS)) { + if(rb_type_p(obj, T_CLASS)) { return Qtrue; } return Qfalse; } static VALUE so_is_rb_type_p_data(VALUE self, VALUE obj) { - if (rb_type_p(obj, T_DATA)) { - return Qtrue; - } - return Qfalse; -} - -static VALUE so_is_rb_type_p_file(VALUE self, VALUE obj) { - if (rb_type_p(obj, T_FILE)) { + if(rb_type_p(obj, T_DATA)) { return Qtrue; } return Qfalse; } static VALUE so_is_builtin_type_object(VALUE self, VALUE obj) { - if (BUILTIN_TYPE(obj) == T_OBJECT) { + if(BUILTIN_TYPE(obj) == T_OBJECT) { return Qtrue; } return Qfalse; } static VALUE so_is_builtin_type_array(VALUE self, VALUE obj) { - if (BUILTIN_TYPE(obj) == T_ARRAY) { + if(BUILTIN_TYPE(obj) == T_ARRAY) { return Qtrue; } return Qfalse; } static VALUE so_is_builtin_type_module(VALUE self, VALUE obj) { - if (BUILTIN_TYPE(obj) == T_MODULE) { + if(BUILTIN_TYPE(obj) == T_MODULE) { return Qtrue; } return Qfalse; } static VALUE so_is_builtin_type_class(VALUE self, VALUE obj) { - if (BUILTIN_TYPE(obj) == T_CLASS) { + if(BUILTIN_TYPE(obj) == T_CLASS) { return Qtrue; } return Qfalse; } static VALUE so_is_builtin_type_data(VALUE self, VALUE obj) { - if (BUILTIN_TYPE(obj) == T_DATA) { + if(BUILTIN_TYPE(obj) == T_DATA) { return Qtrue; } return Qfalse; @@ -375,18 +381,6 @@ static VALUE object_spec_rb_class_inherited_p(VALUE self, VALUE mod, VALUE arg) return rb_class_inherited_p(mod, arg); } -static int foreach_f(ID key, VALUE val, VALUE ary) { - rb_ary_push(ary, ID2SYM(key)); - rb_ary_push(ary, val); - return ST_CONTINUE; -} - -static VALUE object_spec_rb_ivar_foreach(VALUE self, VALUE obj) { - VALUE ary = rb_ary_new(); - rb_ivar_foreach(obj, foreach_f, ary); - return ary; -} - static VALUE speced_allocator(VALUE klass) { VALUE flags = 0; VALUE instance; @@ -446,7 +440,6 @@ void Init_object_spec(void) { rb_define_method(cls, "rb_obj_alloc", so_rb_obj_alloc, 1); rb_define_method(cls, "rb_obj_dup", so_rb_obj_dup, 1); rb_define_method(cls, "rb_obj_call_init", so_rb_obj_call_init, 3); - rb_define_method(cls, "rb_obj_class", so_rb_obj_class, 1); rb_define_method(cls, "rb_obj_classname", so_rbobjclassname, 1); rb_define_method(cls, "rb_obj_freeze", object_spec_rb_obj_freeze, 1); rb_define_method(cls, "rb_obj_frozen_p", object_spec_rb_obj_frozen_p, 1); @@ -455,9 +448,7 @@ void Init_object_spec(void) { rb_define_method(cls, "rb_obj_is_kind_of", so_kind_of, 2); rb_define_method(cls, "rb_obj_method_arity", object_specs_rb_obj_method_arity, 2); rb_define_method(cls, "rb_obj_method", object_specs_rb_obj_method, 2); -#ifndef RUBY_VERSION_IS_3_2 rb_define_method(cls, "rb_obj_taint", object_spec_rb_obj_taint, 1); -#endif rb_define_method(cls, "rb_require", so_require, 0); rb_define_method(cls, "rb_respond_to", so_respond_to, 2); rb_define_method(cls, "rb_method_boundp", object_spec_rb_method_boundp, 3); @@ -479,7 +470,6 @@ void Init_object_spec(void) { rb_define_method(cls, "rb_is_rb_type_p_module", so_is_rb_type_p_module, 1); rb_define_method(cls, "rb_is_rb_type_p_class", so_is_rb_type_p_class, 1); rb_define_method(cls, "rb_is_rb_type_p_data", so_is_rb_type_p_data, 1); - rb_define_method(cls, "rb_is_rb_type_p_file", so_is_rb_type_p_file, 1); rb_define_method(cls, "rb_is_builtin_type_object", so_is_builtin_type_object, 1); rb_define_method(cls, "rb_is_builtin_type_array", so_is_builtin_type_array, 1); rb_define_method(cls, "rb_is_builtin_type_module", so_is_builtin_type_module, 1); @@ -502,7 +492,6 @@ void Init_object_spec(void) { rb_define_method(cls, "speced_allocator?", speced_allocator_p, 1); rb_define_method(cls, "custom_alloc_func?", custom_alloc_func_p, 1); rb_define_method(cls, "not_implemented_method", rb_f_notimplement, -1); - rb_define_method(cls, "rb_ivar_foreach", object_spec_rb_ivar_foreach, 1); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/ext/proc_spec.c b/spec/ruby/optional/capi/ext/proc_spec.c index b7cd5d6262..e0bd8b1bbc 100644 --- a/spec/ruby/optional/capi/ext/proc_spec.c +++ b/spec/ruby/optional/capi/ext/proc_spec.c @@ -11,63 +11,10 @@ VALUE proc_spec_rb_proc_new_function(RB_BLOCK_CALL_FUNC_ARGLIST(args, dummy)) { return rb_funcall(args, rb_intern("inspect"), 0); } -VALUE proc_spec_rb_proc_new_function_arg(VALUE arg, VALUE callback_arg, int argc, const VALUE *argv, VALUE blockarg) { - return arg; -} - -VALUE proc_spec_rb_proc_new_function_argc(VALUE arg, VALUE callback_arg, int argc, const VALUE *argv, VALUE blockarg) { - return INT2FIX(argc); -} - -VALUE proc_spec_rb_proc_new_function_argv_n(VALUE arg, VALUE callback_arg, int argc, const VALUE *argv, VALUE blockarg) { - int n = FIX2INT(arg); - if (n < argc) { - return argv[n]; - } else { - rb_exc_raise(rb_exc_new2(rb_eArgError, "Arg index out of bounds.")); - } -} - -VALUE proc_spec_rb_proc_new_function_callback_arg(VALUE arg, VALUE callback_arg, int argc, const VALUE *argv, VALUE blockarg) { - return callback_arg; -} - -VALUE proc_spec_rb_proc_new_function_blockarg(VALUE arg, VALUE callback_arg, int argc, const VALUE *argv, VALUE blockarg) { - return blockarg; -} - -VALUE proc_spec_rb_proc_new_function_block_given_p(VALUE arg, VALUE callback_arg, int argc, const VALUE *argv, VALUE blockarg) { - return rb_block_given_p() ? Qtrue : Qfalse; -} - VALUE proc_spec_rb_proc_new(VALUE self) { return rb_proc_new(proc_spec_rb_proc_new_function, Qnil); } -VALUE proc_spec_rb_proc_new_arg(VALUE self) { - return rb_proc_new(proc_spec_rb_proc_new_function_arg, Qnil); -} - -VALUE proc_spec_rb_proc_new_argc(VALUE self) { - return rb_proc_new(proc_spec_rb_proc_new_function_argc, Qnil); -} - -VALUE proc_spec_rb_proc_new_argv_n(VALUE self) { - return rb_proc_new(proc_spec_rb_proc_new_function_argv_n, Qnil); -} - -VALUE proc_spec_rb_proc_new_callback_arg(VALUE self, VALUE arg) { - return rb_proc_new(proc_spec_rb_proc_new_function_callback_arg, arg); -} - -VALUE proc_spec_rb_proc_new_blockarg(VALUE self) { - return rb_proc_new(proc_spec_rb_proc_new_function_blockarg, Qnil); -} - -VALUE proc_spec_rb_proc_new_block_given_p(VALUE self) { - return rb_proc_new(proc_spec_rb_proc_new_function_block_given_p, Qnil); -} - VALUE proc_spec_rb_proc_arity(VALUE self, VALUE prc) { return INT2FIX(rb_proc_arity(prc)); } @@ -76,18 +23,6 @@ VALUE proc_spec_rb_proc_call(VALUE self, VALUE prc, VALUE args) { return rb_proc_call(prc, args); } -VALUE proc_spec_rb_proc_call_kw(VALUE self, VALUE prc, VALUE args) { - return rb_proc_call_kw(prc, args, RB_PASS_KEYWORDS); -} - -VALUE proc_spec_rb_proc_call_with_block(VALUE self, VALUE prc, VALUE args, VALUE block) { - return rb_proc_call_with_block(prc, RARRAY_LENINT(args), RARRAY_PTR(args), block); -} - -static VALUE proc_spec_rb_proc_call_with_block_kw(VALUE self, VALUE prc, VALUE args, VALUE block) { - return rb_proc_call_with_block_kw(prc, RARRAY_LENINT(args), RARRAY_PTR(args), block, RB_PASS_KEYWORDS); -} - VALUE proc_spec_rb_obj_is_proc(VALUE self, VALUE prc) { return rb_obj_is_proc(prc); } @@ -127,17 +62,8 @@ VALUE proc_spec_rb_Proc_new(VALUE self, VALUE scenario) { void Init_proc_spec(void) { VALUE cls = rb_define_class("CApiProcSpecs", rb_cObject); rb_define_method(cls, "rb_proc_new", proc_spec_rb_proc_new, 0); - rb_define_method(cls, "rb_proc_new_arg", proc_spec_rb_proc_new_arg, 0); - rb_define_method(cls, "rb_proc_new_argc", proc_spec_rb_proc_new_argc, 0); - rb_define_method(cls, "rb_proc_new_argv_n", proc_spec_rb_proc_new_argv_n, 0); - rb_define_method(cls, "rb_proc_new_callback_arg", proc_spec_rb_proc_new_callback_arg, 1); - rb_define_method(cls, "rb_proc_new_blockarg", proc_spec_rb_proc_new_blockarg, 0); - rb_define_method(cls, "rb_proc_new_block_given_p", proc_spec_rb_proc_new_block_given_p, 0); rb_define_method(cls, "rb_proc_arity", proc_spec_rb_proc_arity, 1); rb_define_method(cls, "rb_proc_call", proc_spec_rb_proc_call, 2); - rb_define_method(cls, "rb_proc_call_kw", proc_spec_rb_proc_call_kw, 2); - rb_define_method(cls, "rb_proc_call_with_block", proc_spec_rb_proc_call_with_block, 3); - rb_define_method(cls, "rb_proc_call_with_block_kw", proc_spec_rb_proc_call_with_block_kw, 3); rb_define_method(cls, "rb_Proc_new", proc_spec_rb_Proc_new, 1); rb_define_method(cls, "rb_obj_is_proc", proc_spec_rb_obj_is_proc, 1); } diff --git a/spec/ruby/optional/capi/ext/range_spec.c b/spec/ruby/optional/capi/ext/range_spec.c index b0cf1a8662..7a475ec695 100644 --- a/spec/ruby/optional/capi/ext/range_spec.c +++ b/spec/ruby/optional/capi/ext/range_spec.c @@ -7,7 +7,7 @@ extern "C" { VALUE range_spec_rb_range_new(int argc, VALUE* argv, VALUE self) { int exclude_end = 0; - if (argc == 3) { + if(argc == 3) { exclude_end = RTEST(argv[2]); } return rb_range_new(argv[0], argv[1], exclude_end); diff --git a/spec/ruby/optional/capi/ext/rbasic_spec.c b/spec/ruby/optional/capi/ext/rbasic_spec.c index 26be2fed6d..9178e5f639 100644 --- a/spec/ruby/optional/capi/ext/rbasic_spec.c +++ b/spec/ruby/optional/capi/ext/rbasic_spec.c @@ -5,14 +5,6 @@ extern "C" { #endif -#ifndef RBASIC_FLAGS -#define RBASIC_FLAGS(obj) (RBASIC(obj)->flags) -#endif - -#ifndef RBASIC_SET_FLAGS -#define RBASIC_SET_FLAGS(obj, flags_to_set) (RBASIC(obj)->flags = flags_to_set) -#endif - #ifndef FL_SHAREABLE static const VALUE VISIBLE_BITS = FL_TAINT | FL_FREEZE; static const VALUE DATA_VISIBLE_BITS = FL_TAINT | FL_FREEZE | ~(FL_USER0 - 1); @@ -42,53 +34,47 @@ VALUE rbasic_spec_freeze_flag(VALUE self) { return VALUE2NUM(RUBY_FL_FREEZE); } -static VALUE spec_get_flags(VALUE obj, VALUE visible_bits) { - VALUE flags = RB_FL_TEST(obj, visible_bits); + static VALUE spec_get_flags(const struct RBasic *b, VALUE visible_bits) { + VALUE flags = b->flags & visible_bits; return VALUE2NUM(flags); } -static VALUE spec_set_flags(VALUE obj, VALUE flags, VALUE visible_bits) { +static VALUE spec_set_flags(struct RBasic *b, VALUE flags, VALUE visible_bits) { flags &= visible_bits; - - // Could also be done like: - // RB_FL_UNSET(obj, visible_bits); - // RB_FL_SET(obj, flags); - // But that seems rather indirect - RBASIC_SET_FLAGS(obj, (RBASIC_FLAGS(obj) & ~visible_bits) | flags); - + b->flags = (b->flags & ~visible_bits) | flags; return VALUE2NUM(flags); } -static VALUE rbasic_spec_get_flags(VALUE self, VALUE obj) { - return spec_get_flags(obj, VISIBLE_BITS); +VALUE rbasic_spec_get_flags(VALUE self, VALUE val) { + return spec_get_flags(RBASIC(val), VISIBLE_BITS); } -static VALUE rbasic_spec_set_flags(VALUE self, VALUE obj, VALUE flags) { - return spec_set_flags(obj, NUM2VALUE(flags), VISIBLE_BITS); +VALUE rbasic_spec_set_flags(VALUE self, VALUE val, VALUE flags) { + return spec_set_flags(RBASIC(val), NUM2VALUE(flags), VISIBLE_BITS); } -static VALUE rbasic_spec_copy_flags(VALUE self, VALUE to, VALUE from) { - return spec_set_flags(to, RBASIC_FLAGS(from), VISIBLE_BITS); +VALUE rbasic_spec_copy_flags(VALUE self, VALUE to, VALUE from) { + return spec_set_flags(RBASIC(to), RBASIC(from)->flags, VISIBLE_BITS); } -static VALUE rbasic_spec_get_klass(VALUE self, VALUE obj) { - return RBASIC_CLASS(obj); +VALUE rbasic_spec_get_klass(VALUE self, VALUE val) { + return RBASIC(val)->klass; } -static VALUE rbasic_rdata_spec_get_flags(VALUE self, VALUE structure) { - return spec_get_flags(structure, DATA_VISIBLE_BITS); +VALUE rbasic_rdata_spec_get_flags(VALUE self, VALUE structure) { + return spec_get_flags(&RDATA(structure)->basic, DATA_VISIBLE_BITS); } -static VALUE rbasic_rdata_spec_set_flags(VALUE self, VALUE structure, VALUE flags) { - return spec_set_flags(structure, NUM2VALUE(flags), DATA_VISIBLE_BITS); +VALUE rbasic_rdata_spec_set_flags(VALUE self, VALUE structure, VALUE flags) { + return spec_set_flags(&RDATA(structure)->basic, NUM2VALUE(flags), DATA_VISIBLE_BITS); } -static VALUE rbasic_rdata_spec_copy_flags(VALUE self, VALUE to, VALUE from) { - return spec_set_flags(to, RBASIC_FLAGS(from), DATA_VISIBLE_BITS); +VALUE rbasic_rdata_spec_copy_flags(VALUE self, VALUE to, VALUE from) { + return spec_set_flags(&RDATA(to)->basic, RDATA(from)->basic.flags, DATA_VISIBLE_BITS); } -static VALUE rbasic_rdata_spec_get_klass(VALUE self, VALUE structure) { - return RBASIC_CLASS(structure); +VALUE rbasic_rdata_spec_get_klass(VALUE self, VALUE structure) { + return RDATA(structure)->basic.klass; } void Init_rbasic_spec(void) { diff --git a/spec/ruby/optional/capi/ext/regexp_spec.c b/spec/ruby/optional/capi/ext/regexp_spec.c index 9de7982b50..0a62616f33 100644 --- a/spec/ruby/optional/capi/ext/regexp_spec.c +++ b/spec/ruby/optional/capi/ext/regexp_spec.c @@ -49,12 +49,6 @@ VALUE regexp_spec_match(VALUE self, VALUE regexp, VALUE str) { return rb_funcall(regexp, rb_intern("match"), 1, str); } -VALUE regexp_spec_memcicmp(VALUE self, VALUE str1, VALUE str2) { - long l1 = RSTRING_LEN(str1); - long l2 = RSTRING_LEN(str2); - return INT2FIX(rb_memcicmp(RSTRING_PTR(str1), RSTRING_PTR(str2), l1 < l2 ? l1 : l2)); -} - void Init_regexp_spec(void) { VALUE cls = rb_define_class("CApiRegexpSpecs", rb_cObject); rb_define_method(cls, "match", regexp_spec_match, 2); @@ -66,7 +60,6 @@ void Init_regexp_spec(void) { rb_define_method(cls, "rb_reg_match_backref_get", regexp_spec_reg_match_backref_get, 2); rb_define_method(cls, "rb_reg_options", regexp_spec_rb_reg_options, 1); rb_define_method(cls, "rb_reg_regcomp", regexp_spec_rb_reg_regcomp, 1); - rb_define_method(cls, "rb_memcicmp", regexp_spec_memcicmp, 2); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/ext/rubyspec.h b/spec/ruby/optional/capi/ext/rubyspec.h index 09135774af..7e4a252b38 100644 --- a/spec/ruby/optional/capi/ext/rubyspec.h +++ b/spec/ruby/optional/capi/ext/rubyspec.h @@ -11,29 +11,6 @@ # include <version.h> #endif -/* copied from ext/-test-/cxxanyargs/cxxanyargs.cpp */ -#if 0 /* Ignore deprecation warnings */ - -#elif defined(_MSC_VER) -#pragma warning(disable : 4996) - -#elif defined(__INTEL_COMPILER) -#pragma warning(disable : 1786) - -#elif defined(__clang__) -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - -#elif defined(__GNUC__) -#pragma GCC diagnostic ignored "-Wdeprecated-declarations" - -#elif defined(__SUNPRO_CC) -#pragma error_messages (off,symdeprecated) - -#else -// :FIXME: improve here for your compiler. - -#endif - #ifndef RUBY_VERSION_MAJOR #define RUBY_VERSION_MAJOR RUBY_API_VERSION_MAJOR #define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR @@ -44,22 +21,43 @@ ((RUBY_VERSION_MAJOR < (major)) || \ (RUBY_VERSION_MAJOR == (major) && RUBY_VERSION_MINOR < (minor)) || \ (RUBY_VERSION_MAJOR == (major) && RUBY_VERSION_MINOR == (minor) && RUBY_VERSION_TEENY < (teeny))) -#define RUBY_VERSION_SINCE(major,minor,teeny) (!RUBY_VERSION_BEFORE(major, minor, teeny)) - -#if RUBY_VERSION_SINCE(3, 3, 0) -#define RUBY_VERSION_IS_3_3 -#endif -#if RUBY_VERSION_SINCE(3, 2, 0) -#define RUBY_VERSION_IS_3_2 -#endif - -#if RUBY_VERSION_SINCE(3, 1, 0) +#if RUBY_VERSION_MAJOR > 3 || (RUBY_VERSION_MAJOR == 3 && RUBY_VERSION_MINOR >= 1) #define RUBY_VERSION_IS_3_1 #endif -#if RUBY_VERSION_SINCE(3, 0, 0) +#if RUBY_VERSION_MAJOR > 3 || (RUBY_VERSION_MAJOR == 3 && RUBY_VERSION_MINOR >= 0) #define RUBY_VERSION_IS_3_0 #endif +#if RUBY_VERSION_MAJOR > 2 || (RUBY_VERSION_MAJOR == 2 && RUBY_VERSION_MINOR >= 7) +#define RUBY_VERSION_IS_2_7 +#endif + +#if RUBY_VERSION_MAJOR > 2 || (RUBY_VERSION_MAJOR == 2 && RUBY_VERSION_MINOR >= 6) +#define RUBY_VERSION_IS_2_6 +#endif + +#if defined(__cplusplus) && !defined(RUBY_VERSION_IS_2_7) +/* Ruby < 2.7 needs this to let these function with callbacks and compile in C++ code */ +#define rb_define_method(mod, name, func, argc) rb_define_method(mod, name, RUBY_METHOD_FUNC(func), argc) +#define rb_define_protected_method(mod, name, func, argc) rb_define_protected_method(mod, name, RUBY_METHOD_FUNC(func), argc) +#define rb_define_private_method(mod, name, func, argc) rb_define_private_method(mod, name, RUBY_METHOD_FUNC(func), argc) +#define rb_define_singleton_method(mod, name, func, argc) rb_define_singleton_method(mod, name, RUBY_METHOD_FUNC(func), argc) +#define rb_define_module_function(mod, name, func, argc) rb_define_module_function(mod, name, RUBY_METHOD_FUNC(func), argc) +#define rb_define_global_function(name, func, argc) rb_define_global_function(name, RUBY_METHOD_FUNC(func), argc) +#define rb_hash_foreach(hash, func, farg) rb_hash_foreach(hash, (int (*)(...))func, farg) +#define st_foreach(tab, func, arg) st_foreach(tab, (int (*)(...))func, arg) +#define rb_block_call(object, name, args_count, args, block_call_func, data) rb_block_call(object, name, args_count, args, RUBY_METHOD_FUNC(block_call_func), data) +#define rb_ensure(b_proc, data1, e_proc, data2) rb_ensure(RUBY_METHOD_FUNC(b_proc), data1, RUBY_METHOD_FUNC(e_proc), data2) +#define rb_rescue(b_proc, data1, e_proc, data2) rb_rescue(RUBY_METHOD_FUNC(b_proc), data1, RUBY_METHOD_FUNC(e_proc), data2) +#define rb_rescue2(b_proc, data1, e_proc, data2, ...) rb_rescue2(RUBY_METHOD_FUNC(b_proc), data1, RUBY_METHOD_FUNC(e_proc), data2, __VA_ARGS__) +#define rb_catch(tag, func, data) rb_catch(tag, RUBY_METHOD_FUNC(func), data) +#define rb_catch_obj(tag, func, data) rb_catch_obj(tag, RUBY_METHOD_FUNC(func), data) +#define rb_proc_new(fn, arg) rb_proc_new(RUBY_METHOD_FUNC(fn), arg) +#define rb_fiber_new(fn, arg) rb_fiber_new(RUBY_METHOD_FUNC(fn), arg) +#define rb_thread_create(fn, arg) rb_thread_create(RUBY_METHOD_FUNC(fn), arg) +#define rb_define_hooked_variable(name, var, getter, setter) rb_define_hooked_variable(name, var, RUBY_METHOD_FUNC(getter), (void (*)(...))setter) +#endif + #endif diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c index 2bd789fb72..2a21304a10 100644 --- a/spec/ruby/optional/capi/ext/string_spec.c +++ b/spec/ruby/optional/capi/ext/string_spec.c @@ -62,7 +62,7 @@ VALUE string_spec_rb_str_buf_new(VALUE self, VALUE len, VALUE str) { buf = rb_str_buf_new(NUM2LONG(len)); - if (RTEST(str)) { + if(RTEST(str)) { snprintf(RSTRING_PTR(buf), NUM2LONG(len), "%s", RSTRING_PTR(str)); } @@ -87,10 +87,6 @@ VALUE string_spec_rb_str_tmp_new_klass(VALUE self, VALUE len) { return RBASIC_CLASS(rb_str_tmp_new(NUM2LONG(len))); } -VALUE string_spec_rb_str_buf_append(VALUE self, VALUE str, VALUE two) { - return rb_str_buf_append(str, two); -} - VALUE string_spec_rb_str_buf_cat(VALUE self, VALUE str) { const char *question_mark = "?"; rb_str_buf_cat(str, question_mark, strlen(question_mark)); @@ -129,7 +125,7 @@ VALUE string_spec_rb_str_conv_enc(VALUE self, VALUE str, VALUE from, VALUE to) { from_enc = rb_to_encoding(from); - if (NIL_P(to)) { + if(NIL_P(to)) { to_enc = 0; } else { to_enc = rb_to_encoding(to); @@ -139,13 +135,14 @@ VALUE string_spec_rb_str_conv_enc(VALUE self, VALUE str, VALUE from, VALUE to) { } VALUE string_spec_rb_str_conv_enc_opts(VALUE self, VALUE str, VALUE from, VALUE to, - VALUE ecflags, VALUE ecopts) { + VALUE ecflags, VALUE ecopts) +{ rb_encoding* from_enc; rb_encoding* to_enc; from_enc = rb_to_encoding(from); - if (NIL_P(to)) { + if(NIL_P(to)) { to_enc = 0; } else { to_enc = rb_to_encoding(to); @@ -199,7 +196,7 @@ VALUE string_spec_rb_str_new_offset(VALUE self, VALUE str, VALUE offset, VALUE l } VALUE string_spec_rb_str_new2(VALUE self, VALUE str) { - if (NIL_P(str)) { + if(NIL_P(str)) { return rb_str_new2(""); } else { return rb_str_new2(RSTRING_PTR(str)); @@ -215,7 +212,7 @@ VALUE string_spec_rb_str_export_to_enc(VALUE self, VALUE str, VALUE enc) { } VALUE string_spec_rb_str_new_cstr(VALUE self, VALUE str) { - if (NIL_P(str)) { + if(NIL_P(str)) { return rb_str_new_cstr(""); } else { return rb_str_new_cstr(RSTRING_PTR(str)); @@ -254,7 +251,16 @@ VALUE string_spec_rb_str_new5(VALUE self, VALUE str, VALUE ptr, VALUE len) { return rb_str_new5(str, RSTRING_PTR(ptr), FIX2INT(len)); } -#ifndef RUBY_VERSION_IS_3_2 +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#elif defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wdeprecated-declarations") +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wdeprecated-declarations" +# endif +#endif + VALUE string_spec_rb_tainted_str_new(VALUE self, VALUE str, VALUE len) { return rb_tainted_str_new(RSTRING_PTR(str), FIX2INT(len)); } @@ -262,6 +268,13 @@ VALUE string_spec_rb_tainted_str_new(VALUE self, VALUE str, VALUE len) { VALUE string_spec_rb_tainted_str_new2(VALUE self, VALUE str) { return rb_tainted_str_new2(RSTRING_PTR(str)); } + +#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) +# pragma GCC diagnostic pop +#elif defined(__clang__) && defined(__has_warning) +# if __has_warning("-Wdeprecated-declarations") +# pragma clang diagnostic pop +# endif #endif VALUE string_spec_rb_str_plus(VALUE self, VALUE str1, VALUE str2) { @@ -371,7 +384,7 @@ VALUE string_spec_RSTRING_PTR_set(VALUE self, VALUE str, VALUE i, VALUE chr) { VALUE string_spec_RSTRING_PTR_after_funcall(VALUE self, VALUE str, VALUE cb) { /* Silence gcc 4.3.2 warning about computed value not used */ - if (RSTRING_PTR(str)) { /* force it out */ + if(RSTRING_PTR(str)) { /* force it out */ rb_funcall(cb, rb_intern("call"), 1, str); } @@ -418,12 +431,6 @@ VALUE string_spec_RSTRING_PTR_read(VALUE self, VALUE str, VALUE path) { return capacities; } -VALUE string_spec_RSTRING_PTR_null_terminate(VALUE self, VALUE str, VALUE min_length) { - char* ptr = RSTRING_PTR(str); - char* end = ptr + RSTRING_LEN(str); - return rb_str_new(end, FIX2LONG(min_length)); -} - VALUE string_spec_StringValue(VALUE self, VALUE str) { return StringValue(str); } @@ -554,7 +561,7 @@ static VALUE string_spec_rb_utf8_str_new_cstr(VALUE self) { } PRINTF_ARGS(static VALUE call_rb_str_vcatf(VALUE mesg, const char *fmt, ...), 2, 3); -static VALUE call_rb_str_vcatf(VALUE mesg, const char *fmt, ...) { +static VALUE call_rb_str_vcatf(VALUE mesg, const char *fmt, ...){ va_list ap; va_start(ap, fmt); VALUE result = rb_str_vcatf(mesg, fmt, ap); @@ -590,7 +597,6 @@ void Init_string_spec(void) { rb_define_method(cls, "rb_str_buf_new2", string_spec_rb_str_buf_new2, 0); rb_define_method(cls, "rb_str_tmp_new", string_spec_rb_str_tmp_new, 1); rb_define_method(cls, "rb_str_tmp_new_klass", string_spec_rb_str_tmp_new_klass, 1); - rb_define_method(cls, "rb_str_buf_append", string_spec_rb_str_buf_append, 2); rb_define_method(cls, "rb_str_buf_cat", string_spec_rb_str_buf_cat, 1); rb_define_method(cls, "rb_enc_str_buf_cat", string_spec_rb_enc_str_buf_cat, 3); rb_define_method(cls, "rb_str_cat", string_spec_rb_str_cat, 1); @@ -623,10 +629,8 @@ void Init_string_spec(void) { rb_define_method(cls, "rb_str_new3", string_spec_rb_str_new3, 1); rb_define_method(cls, "rb_str_new4", string_spec_rb_str_new4, 1); rb_define_method(cls, "rb_str_new5", string_spec_rb_str_new5, 3); -#ifndef RUBY_VERSION_IS_3_2 rb_define_method(cls, "rb_tainted_str_new", string_spec_rb_tainted_str_new, 2); rb_define_method(cls, "rb_tainted_str_new2", string_spec_rb_tainted_str_new2, 1); -#endif rb_define_method(cls, "rb_str_plus", string_spec_rb_str_plus, 2); rb_define_method(cls, "rb_str_times", string_spec_rb_str_times, 2); rb_define_method(cls, "rb_str_modify_expand", string_spec_rb_str_modify_expand, 2); @@ -649,7 +653,6 @@ void Init_string_spec(void) { rb_define_method(cls, "RSTRING_PTR_after_funcall", string_spec_RSTRING_PTR_after_funcall, 2); rb_define_method(cls, "RSTRING_PTR_after_yield", string_spec_RSTRING_PTR_after_yield, 1); rb_define_method(cls, "RSTRING_PTR_read", string_spec_RSTRING_PTR_read, 2); - rb_define_method(cls, "RSTRING_PTR_null_terminate", string_spec_RSTRING_PTR_null_terminate, 2); rb_define_method(cls, "StringValue", string_spec_StringValue, 1); rb_define_method(cls, "SafeStringValue", string_spec_SafeStringValue, 1); rb_define_method(cls, "rb_str_hash", string_spec_rb_str_hash, 1); diff --git a/spec/ruby/optional/capi/ext/struct_spec.c b/spec/ruby/optional/capi/ext/struct_spec.c index 9c45bd5672..0393d6937d 100644 --- a/spec/ruby/optional/capi/ext/struct_spec.c +++ b/spec/ruby/optional/capi/ext/struct_spec.c @@ -15,11 +15,13 @@ static VALUE struct_spec_rb_struct_getmember(VALUE self, VALUE st, VALUE key) { return rb_struct_getmember(st, SYM2ID(key)); } -static VALUE struct_spec_rb_struct_s_members(VALUE self, VALUE klass) { +static VALUE struct_spec_rb_struct_s_members(VALUE self, VALUE klass) +{ return rb_ary_dup(rb_struct_s_members(klass)); } -static VALUE struct_spec_rb_struct_members(VALUE self, VALUE st) { +static VALUE struct_spec_rb_struct_members(VALUE self, VALUE st) +{ return rb_ary_dup(rb_struct_members(st)); } @@ -54,11 +56,14 @@ static VALUE struct_spec_struct_define_under(VALUE self, VALUE outer, } static VALUE struct_spec_rb_struct_new(VALUE self, VALUE klass, - VALUE a, VALUE b, VALUE c) { + VALUE a, VALUE b, VALUE c) +{ + return rb_struct_new(klass, a, b, c); } -static VALUE struct_spec_rb_struct_size(VALUE self, VALUE st) { +static VALUE struct_spec_rb_struct_size(VALUE self, VALUE st) +{ return rb_struct_size(st); } diff --git a/spec/ruby/optional/capi/ext/symbol_spec.c b/spec/ruby/optional/capi/ext/symbol_spec.c index ba88635faa..7d9a7b4379 100644 --- a/spec/ruby/optional/capi/ext/symbol_spec.c +++ b/spec/ruby/optional/capi/ext/symbol_spec.c @@ -47,19 +47,10 @@ VALUE symbol_spec_rb_id2name(VALUE self, VALUE symbol) { return rb_str_new(c_str, strlen(c_str)); } -VALUE symbol_spec_rb_id2name_id_zero(VALUE self) { - const char* c_str = rb_id2name((ID) 0); - return c_str ? rb_str_new(c_str, strlen(c_str)) : Qnil; -} - VALUE symbol_spec_rb_id2str(VALUE self, VALUE symbol) { return rb_id2str(SYM2ID(symbol)); } -VALUE symbol_spec_rb_id2str_id_zero(VALUE self) { - return rb_id2str((ID) 0); -} - VALUE symbol_spec_rb_intern_str(VALUE self, VALUE str) { return ID2SYM(rb_intern_str(str)); } @@ -99,9 +90,7 @@ void Init_symbol_spec(void) { rb_define_method(cls, "rb_intern3", symbol_spec_rb_intern3, 3); rb_define_method(cls, "rb_intern3_c_compare", symbol_spec_rb_intern3_c_compare, 4); rb_define_method(cls, "rb_id2name", symbol_spec_rb_id2name, 1); - rb_define_method(cls, "rb_id2name_id_zero", symbol_spec_rb_id2name_id_zero, 0); rb_define_method(cls, "rb_id2str", symbol_spec_rb_id2str, 1); - rb_define_method(cls, "rb_id2str_id_zero", symbol_spec_rb_id2str_id_zero, 0); rb_define_method(cls, "rb_intern_str", symbol_spec_rb_intern_str, 1); rb_define_method(cls, "rb_check_symbol_cstr", symbol_spec_rb_check_symbol_cstr, 1); rb_define_method(cls, "rb_is_class_id", symbol_spec_rb_is_class_id, 1); diff --git a/spec/ruby/optional/capi/ext/thread_spec.c b/spec/ruby/optional/capi/ext/thread_spec.c index 7d08d45098..21f98dec52 100644 --- a/spec/ruby/optional/capi/ext/thread_spec.c +++ b/spec/ruby/optional/capi/ext/thread_spec.c @@ -8,14 +8,7 @@ #include <unistd.h> #endif #if defined(_WIN32) -#include "ruby/win32.h" -#define read rb_w32_read -#define write rb_w32_write -#define pipe rb_w32_pipe -#endif - -#ifndef _WIN32 -#include <pthread.h> +#define pipe(p) rb_w32_pipe(p) #endif #ifdef __cplusplus @@ -26,6 +19,10 @@ static VALUE thread_spec_rb_thread_alone(VALUE self) { return rb_thread_alone() ? Qtrue : Qfalse; } +#if defined(__GNUC__) +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +#endif + /* This is unblocked by unblock_func(). */ static void* blocking_gvl_func(void* data) { int rfd = *(int *)data; @@ -134,38 +131,6 @@ static VALUE thread_spec_rb_thread_create(VALUE self, VALUE proc, VALUE arg) { return rb_thread_create(thread_spec_call_proc, (void*)args); } -static VALUE thread_spec_ruby_native_thread_p(VALUE self) { - if (ruby_native_thread_p()) { - return Qtrue; - } else { - return Qfalse; - } -} - -#ifndef _WIN32 -static VALUE false_result = Qfalse; -static VALUE true_result = Qtrue; - -static void *new_thread_check(void *args) { - if (ruby_native_thread_p()) { - return &true_result; - } else { - return &false_result; - } -} -#endif - -static VALUE thread_spec_ruby_native_thread_p_new_thread(VALUE self) { -#ifndef _WIN32 - pthread_t t; - void *result = &true_result; - pthread_create(&t, NULL, new_thread_check, NULL); - pthread_join(t, &result); - return *(VALUE *)result; -#else - return Qfalse; -#endif -} void Init_thread_spec(void) { VALUE cls = rb_define_class("CApiThreadSpecs", rb_cObject); @@ -178,8 +143,6 @@ void Init_thread_spec(void) { rb_define_method(cls, "rb_thread_wakeup", thread_spec_rb_thread_wakeup, 1); rb_define_method(cls, "rb_thread_wait_for", thread_spec_rb_thread_wait_for, 2); rb_define_method(cls, "rb_thread_create", thread_spec_rb_thread_create, 2); - rb_define_method(cls, "ruby_native_thread_p", thread_spec_ruby_native_thread_p, 0); - rb_define_method(cls, "ruby_native_thread_p_new_thread", thread_spec_ruby_native_thread_p_new_thread, 0); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/ext/tracepoint_spec.c b/spec/ruby/optional/capi/ext/tracepoint_spec.c index 6666c8f85c..78c459d6cb 100644 --- a/spec/ruby/optional/capi/ext/tracepoint_spec.c +++ b/spec/ruby/optional/capi/ext/tracepoint_spec.c @@ -17,7 +17,7 @@ static VALUE tracepoint_spec_rb_tracepoint_new(VALUE self, VALUE data) { return rb_tracepoint_new(Qnil, RUBY_EVENT_LINE, callback, (void*) data); } -static VALUE tracepoint_spec_callback_called(VALUE self) { +static VALUE tracepoint_spec_callback_called(VALUE self){ return callback_called; } diff --git a/spec/ruby/optional/capi/ext/typed_data_spec.c b/spec/ruby/optional/capi/ext/typed_data_spec.c index 38889ecf5c..eca2b667cc 100644 --- a/spec/ruby/optional/capi/ext/typed_data_spec.c +++ b/spec/ruby/optional/capi/ext/typed_data_spec.c @@ -106,12 +106,6 @@ VALUE sws_typed_wrap_struct(VALUE self, VALUE val) { return TypedData_Wrap_Struct(rb_cObject, &sample_typed_wrapped_struct_data_type, bar); } -VALUE sws_untyped_wrap_struct(VALUE self, VALUE val) { - int* data = (int*) malloc(sizeof(int)); - *data = FIX2INT(val); - return Data_Wrap_Struct(rb_cObject, NULL, free, data); -} - VALUE sws_typed_get_struct(VALUE self, VALUE obj) { struct sample_typed_wrapped_struct* bar; TypedData_Get_Struct(obj, struct sample_typed_wrapped_struct, &sample_typed_wrapped_struct_data_type, bar); @@ -171,17 +165,12 @@ VALUE sws_typed_rb_check_typeddata_different_type(VALUE self, VALUE obj) { return rb_check_typeddata(obj, &sample_typed_wrapped_struct_other_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse; } -VALUE sws_typed_RTYPEDDATA_P(VALUE self, VALUE obj) { - return RTYPEDDATA_P(obj) ? Qtrue : Qfalse; -} - void Init_typed_data_spec(void) { VALUE cls = rb_define_class("CApiAllocTypedSpecs", rb_cObject); rb_define_alloc_func(cls, sdaf_alloc_typed_func); rb_define_method(cls, "typed_wrapped_data", sdaf_typed_get_struct, 0); cls = rb_define_class("CApiWrappedTypedStructSpecs", rb_cObject); rb_define_method(cls, "typed_wrap_struct", sws_typed_wrap_struct, 1); - rb_define_method(cls, "untyped_wrap_struct", sws_untyped_wrap_struct, 1); rb_define_method(cls, "typed_get_struct", sws_typed_get_struct, 1); rb_define_method(cls, "typed_get_struct_other", sws_typed_get_struct_different_type, 1); rb_define_method(cls, "typed_get_struct_parent", sws_typed_get_struct_parent_type, 1); @@ -192,7 +181,6 @@ void Init_typed_data_spec(void) { rb_define_method(cls, "rb_check_typeddata_same_type", sws_typed_rb_check_typeddata_same_type, 1); rb_define_method(cls, "rb_check_typeddata_same_type_parent", sws_typed_rb_check_typeddata_same_type_parent, 1); rb_define_method(cls, "rb_check_typeddata_different_type", sws_typed_rb_check_typeddata_different_type, 1); - rb_define_method(cls, "RTYPEDDATA_P", sws_typed_RTYPEDDATA_P, 1); } #ifdef __cplusplus diff --git a/spec/ruby/optional/capi/ext/util_spec.c b/spec/ruby/optional/capi/ext/util_spec.c index 95ba71ea9d..a7269353c2 100644 --- a/spec/ruby/optional/capi/ext/util_spec.c +++ b/spec/ruby/optional/capi/ext/util_spec.c @@ -7,18 +7,15 @@ extern "C" { #endif VALUE util_spec_rb_scan_args(VALUE self, VALUE argv, VALUE fmt, VALUE expected, VALUE acc) { - int result, argc; - VALUE a1, a2, a3, a4, a5, a6; - - argc = (int) RARRAY_LEN(argv); - VALUE* args = RARRAY_PTR(argv); - /* the line above can be replaced with this for Ruby implementations which do not support RARRAY_PTR() yet - VALUE args[6]; - for(int i = 0; i < argc; i++) { - args[i] = rb_ary_entry(argv, i); - } */ - - a1 = a2 = a3 = a4 = a5 = a6 = INT2FIX(-1); + int i, result, argc = (int)RARRAY_LEN(argv); + VALUE args[6], failed, a1, a2, a3, a4, a5, a6; + + failed = rb_intern("failed"); + a1 = a2 = a3 = a4 = a5 = a6 = failed; + + for(i = 0; i < argc; i++) { + args[i] = rb_ary_entry(argv, i); + } #ifdef RB_SCAN_ARGS_KEYWORDS if (*RSTRING_PTR(fmt) == 'k') { diff --git a/spec/ruby/optional/capi/fixtures/class.rb b/spec/ruby/optional/capi/fixtures/class.rb index b463e3b4c3..193c7174e0 100644 --- a/spec/ruby/optional/capi/fixtures/class.rb +++ b/spec/ruby/optional/capi/fixtures/class.rb @@ -15,16 +15,6 @@ class CApiClassSpecs end end - class KeywordAlloc - attr_reader :initialized, :args, :kwargs - - def initialize(*args, **kwargs) - @initialized = true - @args = args - @kwargs = kwargs - end - end - class Attr def initialize @foo, @bar, @baz = 1, 2, 3 diff --git a/spec/ruby/optional/capi/fixtures/kernel.rb b/spec/ruby/optional/capi/fixtures/kernel.rb deleted file mode 100644 index f5b95e0fea..0000000000 --- a/spec/ruby/optional/capi/fixtures/kernel.rb +++ /dev/null @@ -1,19 +0,0 @@ -class CApiKernelSpecs - class ClassWithPublicMethod - def public_method(*, **) - 0 - end - end - - class ClassWithPrivateMethod - private def private_method(*, **) - 0 - end - end - - class ClassWithProtectedMethod - protected def protected_method(*, **) - 0 - end - end -end diff --git a/spec/ruby/optional/capi/fixtures/object.rb b/spec/ruby/optional/capi/fixtures/object.rb deleted file mode 100644 index a59f2309d8..0000000000 --- a/spec/ruby/optional/capi/fixtures/object.rb +++ /dev/null @@ -1,29 +0,0 @@ -class CApiObjectSpecs - class IVars - def initialize - @a = 3 - @b = 7 - @c = 4 - end - - def self.set_class_variables - @@foo = :a - @@bar = :b - @@baz = :c - end - end - - module MVars - @@mvar = :foo - @@mvar2 = :bar - - @ivar = :baz - end - - module CVars - @@cvar = :foo - @@cvar2 = :bar - - @ivar = :baz - end -end diff --git a/spec/ruby/optional/capi/gc_spec.rb b/spec/ruby/optional/capi/gc_spec.rb index d76ea7394f..23e2b7c9ab 100644 --- a/spec/ruby/optional/capi/gc_spec.rb +++ b/spec/ruby/optional/capi/gc_spec.rb @@ -7,33 +7,15 @@ describe "CApiGCSpecs" do @f = CApiGCSpecs.new end - describe "rb_gc_register_address" do - it "correctly gets the value from a registered address" do - @f.registered_tagged_address.should == 10 - @f.registered_tagged_address.should equal(@f.registered_tagged_address) - @f.registered_reference_address.should == "Globally registered data" - @f.registered_reference_address.should equal(@f.registered_reference_address) - end - - it "keeps the value alive even if the value is assigned after rb_gc_register_address() is called" do - GC.start - @f.registered_before_rb_gc_register_address.should == "registered before rb_gc_register_address()" - end - - it "can be called outside Init_" do - @f.rb_gc_register_address.should == "rb_gc_register_address() outside Init_" - @f.rb_gc_unregister_address - end - end - - describe "rb_global_variable" do - it "keeps the value alive even if the value is assigned after rb_global_variable() is called" do - GC.start - @f.registered_before_rb_global_variable.should == "registered before rb_global_variable()" - end + it "correctly gets the value from a registered address" do + @f.registered_tagged_address.should == 10 + @f.registered_tagged_address.should equal(@f.registered_tagged_address) + @f.registered_reference_address.should == "Globally registered data" + @f.registered_reference_address.should equal(@f.registered_reference_address) end describe "rb_gc_enable" do + after do GC.enable end diff --git a/spec/ruby/optional/capi/globals_spec.rb b/spec/ruby/optional/capi/globals_spec.rb index 48677620bc..cc6f6ef3a8 100644 --- a/spec/ruby/optional/capi/globals_spec.rb +++ b/spec/ruby/optional/capi/globals_spec.rb @@ -9,7 +9,7 @@ describe "CApiGlobalSpecs" do end it "correctly gets global values" do - suppress_warning { @f.sb_gv_get("$BLAH") }.should == nil + @f.sb_gv_get("$BLAH").should == nil @f.sb_gv_get("$\\").should == nil @f.sb_gv_get("\\").should == nil # rb_gv_get should change \ to $\ end @@ -21,7 +21,7 @@ describe "CApiGlobalSpecs" do end it "correctly sets global values" do - suppress_warning { @f.sb_gv_get("$BLAH") }.should == nil + @f.sb_gv_get("$BLAH").should == nil @f.sb_gv_set("$BLAH", 10) begin @f.sb_gv_get("$BLAH").should == 10 @@ -42,10 +42,6 @@ describe "CApiGlobalSpecs" do end it "rb_define_readonly_variable should define a new readonly global variable" do - # Check the gvar doesn't exist and ensure rb_gv_get doesn't implicitly declare the gvar, - # otherwise the rb_define_readonly_variable call will conflict. - suppress_warning { @f.sb_gv_get("ro_gvar") } .should == nil - @f.rb_define_readonly_variable("ro_gvar", 15) $ro_gvar.should == 15 -> { $ro_gvar = 10 }.should raise_error(NameError) @@ -57,52 +53,6 @@ describe "CApiGlobalSpecs" do $hooked_gvar.should == 4 end - it "rb_define_hooked_variable should use default accessors if NULL ones are supplied" do - @f.rb_define_hooked_variable_default_accessors("$hooked_gvar_default_accessors") - $hooked_gvar_default_accessors = 10 - $hooked_gvar_default_accessors.should == 10 - end - - it "rb_define_hooked_variable with default accessors should return nil for NULL variables" do - @f.rb_define_hooked_variable_null_var("$hooked_gvar_null_value") - $hooked_gvar_null_value.should == nil - end - - describe "rb_define_virtual_variable" do - describe "with default accessors" do - before :all do - @f.rb_define_virtual_variable_default_accessors("$virtual_variable_default_accessors") - end - - it "is read-only" do - -> { $virtual_variable_default_accessors = 10 }.should raise_error(NameError, /read-only/) - end - - it "returns false with the default getter" do - $virtual_variable_default_accessors.should == false - $virtual_variable_default_accessors.should == false - end - end - - describe "with supplied accessors" do - before :all do - @f.rb_define_virtual_variable_incrementing_accessors("$virtual_variable_incrementing_accessors") - end - - it "returns a dynamically changing value" do - $virtual_variable_incrementing_accessors = 20 - $virtual_variable_incrementing_accessors.should == 20 - $virtual_variable_incrementing_accessors.should == 21 - $virtual_variable_incrementing_accessors.should == 22 - - $virtual_variable_incrementing_accessors = 100 - $virtual_variable_incrementing_accessors.should == 100 - $virtual_variable_incrementing_accessors.should == 101 - $virtual_variable_incrementing_accessors.should == 102 - end - end - end - describe "rb_fs" do before :each do @field_separator = $; diff --git a/spec/ruby/optional/capi/hash_spec.rb b/spec/ruby/optional/capi/hash_spec.rb index a0e49ffc4c..a60467a66b 100644 --- a/spec/ruby/optional/capi/hash_spec.rb +++ b/spec/ruby/optional/capi/hash_spec.rb @@ -50,22 +50,6 @@ describe "C-API Hash function" do end end - ruby_version_is '3.2' do - describe "rb_hash_new_capa" do - it "returns a new hash" do - @s.rb_hash_new_capa(3).should == {} - end - - it "creates a hash with no default proc" do - @s.rb_hash_new_capa(3) {}.default_proc.should be_nil - end - - it "raises RuntimeError when negative index is provided" do - -> { @s.rb_hash_new_capa(-1) }.should raise_error(RuntimeError, "st_table too big") - end - end - end - describe "rb_ident_hash_new" do it "returns a new compare by identity hash" do result = @s.rb_ident_hash_new diff --git a/spec/ruby/optional/capi/io_spec.rb b/spec/ruby/optional/capi/io_spec.rb index e5fb86a837..489a01c515 100644 --- a/spec/ruby/optional/capi/io_spec.rb +++ b/spec/ruby/optional/capi/io_spec.rb @@ -175,18 +175,13 @@ describe "C-API IO function" do end end - describe "rb_io_descriptor or GetOpenFile" do + describe "GetOpenFile" do it "allows access to the system fileno" do @o.GetOpenFile_fd($stdin).should == 0 @o.GetOpenFile_fd($stdout).should == 1 @o.GetOpenFile_fd($stderr).should == 2 @o.GetOpenFile_fd(@io).should == @io.fileno end - - it "raises IOError if the IO is closed" do - @io.close - -> { @o.GetOpenFile_fd(@io) }.should raise_error(IOError, "closed stream") - end end describe "rb_io_binmode" do @@ -261,48 +256,12 @@ describe "C-API IO function" do end end - ruby_version_is "3.1" do - describe "rb_io_maybe_wait_writable" do - it "returns mask for events if operation was interrupted" do - @o.rb_io_maybe_wait_writable(Errno::EINTR::Errno, @w_io, nil).should == IO::WRITABLE - end - - it "returns 0 if there is no error condition" do - @o.rb_io_maybe_wait_writable(0, @w_io, nil).should == 0 - end - - it "raises an IOError if the IO is closed" do - @w_io.close - -> { @o.rb_io_maybe_wait_writable(0, @w_io, nil) }.should raise_error(IOError, "closed stream") - end - - it "raises an IOError if the IO is not initialized" do - -> { @o.rb_io_maybe_wait_writable(0, IO.allocate, nil) }.should raise_error(IOError, "uninitialized stream") - end - end - end - describe "rb_thread_fd_writable" do it "waits til an fd is ready for writing" do @o.rb_thread_fd_writable(@w_io).should be_nil end end - describe "rb_thread_fd_select" do - it "waits until an fd is ready for reading" do - @w_io.write "rb_thread_fd_select" - @o.rb_thread_fd_select_read(@r_io).should == 1 - end - - it "waits until an fd is ready for writing" do - @o.rb_thread_fd_select_write(@w_io).should == 1 - end - - it "waits until an fd is ready for writing with timeout" do - @o.rb_thread_fd_select_timeout(@w_io).should == 1 - end - end - platform_is_not :windows do describe "rb_io_wait_readable" do it "returns false if there is no error condition" do @@ -331,40 +290,6 @@ describe "C-API IO function" do thr.join end end - - ruby_version_is "3.1" do - describe "rb_io_maybe_wait_readable" do - it "returns mask for events if operation was interrupted" do - @o.rb_io_maybe_wait_readable(Errno::EINTR::Errno, @r_io, nil, false).should == IO::READABLE - end - - it "returns 0 if there is no error condition" do - @o.rb_io_maybe_wait_readable(0, @r_io, nil, false).should == 0 - end - - it "blocks until the io is readable and returns events that actually occurred" do - @o.instance_variable_set :@write_data, false - thr = Thread.new do - Thread.pass until @o.instance_variable_get(:@write_data) - @w_io.write "rb_io_wait_readable" - end - - @o.rb_io_maybe_wait_readable(Errno::EAGAIN::Errno, @r_io, IO::READABLE, true).should == IO::READABLE - @o.instance_variable_get(:@read_data).should == "rb_io_wait_re" - - thr.join - end - - it "raises an IOError if the IO is closed" do - @r_io.close - -> { @o.rb_io_maybe_wait_readable(0, @r_io, nil, false) }.should raise_error(IOError, "closed stream") - end - - it "raises an IOError if the IO is not initialized" do - -> { @o.rb_io_maybe_wait_readable(0, IO.allocate, nil, false) }.should raise_error(IOError, "uninitialized stream") - end - end - end end describe "rb_thread_wait_fd" do @@ -404,42 +329,6 @@ describe "C-API IO function" do @o.rb_wait_for_single_fd(@r_io, 1, 0, 0).should == 0 end end - - ruby_version_is "3.1" do - describe "rb_io_maybe_wait" do - it "waits til an fd is ready for reading" do - start = false - thr = Thread.new do - start = true - sleep 0.05 - @w_io.write "rb_io_maybe_wait" - end - - Thread.pass until start - - @o.rb_io_maybe_wait(Errno::EAGAIN::Errno, @r_io, IO::READABLE, nil).should == IO::READABLE - - thr.join - end - - it "returns mask for events if operation was interrupted" do - @o.rb_io_maybe_wait(Errno::EINTR::Errno, @w_io, IO::WRITABLE, nil).should == IO::WRITABLE - end - - it "returns false if there is no error condition" do - @o.rb_io_maybe_wait(0, @w_io, IO::WRITABLE, nil).should == false - end - - it "raises an IOError if the IO is closed" do - @w_io.close - -> { @o.rb_io_maybe_wait(0, @w_io, IO::WRITABLE, nil) }.should raise_error(IOError, "closed stream") - end - - it "raises an IOError if the IO is not initialized" do - -> { @o.rb_io_maybe_wait(0, IO.allocate, IO::WRITABLE, nil) }.should raise_error(IOError, "uninitialized stream") - end - end - end end describe "rb_fd_fix_cloexec" do diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb index 17c49b2155..758d944da9 100644 --- a/spec/ruby/optional/capi/kernel_spec.rb +++ b/spec/ruby/optional/capi/kernel_spec.rb @@ -1,5 +1,4 @@ require_relative 'spec_helper' -require_relative 'fixtures/kernel' kernel_path = load_extension("kernel") @@ -413,10 +412,12 @@ describe "C-API Kernel function" do }.should raise_error(Exception, 'custom error') end - it "raises TypeError if one of the passed exceptions is not a Module" do - -> { - @s.rb_rescue2(-> *_ { raise RuntimeError, "foo" }, :no_exc, -> x { x }, :exc, Object.new, 42) - }.should raise_error(TypeError, /class or module required/) + ruby_bug "#17305", ""..."2.7" do + it "raises TypeError if one of the passed exceptions is not a Module" do + -> { + @s.rb_rescue2(-> *_ { raise RuntimeError, "foo" }, :no_exc, -> x { x }, :exc, Object.new, 42) + }.should raise_error(TypeError, /class or module required/) + end end end @@ -503,30 +504,6 @@ describe "C-API Kernel function" do it "evaluates a string of ruby code" do @s.rb_eval_string("1+1").should == 2 end - - it "captures local variables when called within a method" do - a = 2 - @s.rb_eval_string("a+1").should == 3 - end - end - - describe "rb_eval_cmd_kw" do - it "evaluates a string of ruby code" do - @s.rb_eval_cmd_kw("1+1", [], 0).should == 2 - end - - it "calls a proc with the supplied arguments" do - @s.rb_eval_cmd_kw(-> *x { x.map { |i| i + 1 } }, [1, 3, 7], 0).should == [2, 4, 8] - end - - it "calls a proc with keyword arguments if kw_splat is non zero" do - a_proc = -> *x, **y { - res = x.map { |i| i + 1 } - y.each { |k, v| res << k; res << v } - res - } - @s.rb_eval_cmd_kw(a_proc, [1, 3, 7, {a: 1, b: 2, c: 3}], 1).should == [2, 4, 8, :a, 1, :b, 2, :c, 3] - end end describe "rb_block_proc" do @@ -590,82 +567,7 @@ describe "C-API Kernel function" do end end - describe "rb_funcallv" do - def empty - 42 - end - - def sum(a, b) - a + b - end - - it "calls a method" do - @s.rb_funcallv(self, :empty, []).should == 42 - @s.rb_funcallv(self, :sum, [1, 2]).should == 3 - end - - it "calls a private method" do - object = CApiKernelSpecs::ClassWithPrivateMethod.new - @s.rb_funcallv(object, :private_method, []).should == 0 - end - - it "calls a protected method" do - object = CApiKernelSpecs::ClassWithProtectedMethod.new - @s.rb_funcallv(object, :protected_method, []).should == 0 - end - end - - describe "rb_funcallv_kw" do - it "passes keyword arguments to the callee" do - def m(*args, **kwargs) - [args, kwargs] - end - - @s.rb_funcallv_kw(self, :m, [{}]).should == [[], {}] - @s.rb_funcallv_kw(self, :m, [{a: 1}]).should == [[], {a: 1}] - @s.rb_funcallv_kw(self, :m, [{b: 2}, {a: 1}]).should == [[{b: 2}], {a: 1}] - @s.rb_funcallv_kw(self, :m, [{b: 2}, {}]).should == [[{b: 2}], {}] - end - - it "calls a private method" do - object = CApiKernelSpecs::ClassWithPrivateMethod.new - @s.rb_funcallv_kw(object, :private_method, [{}]).should == 0 - end - - it "calls a protected method" do - object = CApiKernelSpecs::ClassWithProtectedMethod.new - @s.rb_funcallv_kw(object, :protected_method, [{}]).should == 0 - end - - it "raises TypeError if the last argument is not a Hash" do - def m(*args, **kwargs) - [args, kwargs] - end - - -> { - @s.rb_funcallv_kw(self, :m, [42]) - }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash') - end - end - - describe "rb_keyword_given_p" do - it "returns whether keywords were given to the C extension method" do - h = {a: 1} - empty = {} - @s.rb_keyword_given_p(a: 1).should == true - @s.rb_keyword_given_p("foo" => "bar").should == true - @s.rb_keyword_given_p(**h).should == true - - @s.rb_keyword_given_p(h).should == false - @s.rb_keyword_given_p().should == false - @s.rb_keyword_given_p(**empty).should == false - - @s.rb_funcallv_kw(@s, :rb_keyword_given_p, [{a: 1}]).should == true - @s.rb_funcallv_kw(@s, :rb_keyword_given_p, [{}]).should == false - end - end - - describe "rb_funcallv_public" do + describe "rb_funcall3" do before :each do @obj = Object.new class << @obj @@ -676,11 +578,10 @@ describe "C-API Kernel function" do end it "calls a public method" do - @s.rb_funcallv_public(@obj, :method_public).should == :method_public + @s.rb_funcall3(@obj, :method_public).should == :method_public end - it "does not call a private method" do - -> { @s.rb_funcallv_public(@obj, :method_private) }.should raise_error(NoMethodError, /private/) + -> { @s.rb_funcall3(@obj, :method_private) }.should raise_error(NoMethodError, /private/) end end @@ -698,58 +599,22 @@ describe "C-API Kernel function" do @s.rb_funcall_many_args(@obj, :many_args).should == 15.downto(1).to_a end end - describe 'rb_funcall_with_block' do - it "calls a method with block" do + before :each do @obj = Object.new class << @obj - def method_public(*args); [args, yield] end + def method_public; yield end + def method_private; yield end + private :method_private end - - @s.rb_funcall_with_block(@obj, :method_public, [1, 2], proc { :result }).should == [[1, 2], :result] - end - - it "does not call a private method" do - object = CApiKernelSpecs::ClassWithPrivateMethod.new - - -> { - @s.rb_funcall_with_block(object, :private_method, [], proc { }) - }.should raise_error(NoMethodError, /private/) end - it "does not call a protected method" do - object = CApiKernelSpecs::ClassWithProtectedMethod.new - - -> { - @s.rb_funcall_with_block(object, :protected_method, [], proc { }) - }.should raise_error(NoMethodError, /protected/) - end - end - - describe 'rb_funcall_with_block_kw' do - it "calls a method with keyword arguments and a block" do - @obj = Object.new - class << @obj - def method_public(*args, **kw, &block); [args, kw, block.call] end - end - - @s.rb_funcall_with_block_kw(@obj, :method_public, [1, 2, {a: 2}], proc { :result }).should == [[1, 2], {a: 2}, :result] + it "calls a method with block" do + @s.rb_funcall_with_block(@obj, :method_public, proc { :result }).should == :result end it "does not call a private method" do - object = CApiKernelSpecs::ClassWithPrivateMethod.new - - -> { - @s.rb_funcall_with_block_kw(object, :private_method, [{}], proc { }) - }.should raise_error(NoMethodError, /private/) - end - - it "does not call a protected method" do - object = CApiKernelSpecs::ClassWithProtectedMethod.new - - -> { - @s.rb_funcall_with_block_kw(object, :protected_method, [{}], proc { }) - }.should raise_error(NoMethodError, /protected/) + -> { @s.rb_funcall_with_block(@obj, :method_private, proc { :result }) }.should raise_error(NoMethodError, /private/) end end end diff --git a/spec/ruby/optional/capi/module_spec.rb b/spec/ruby/optional/capi/module_spec.rb index d7c0ab9c52..acf4d1fe48 100644 --- a/spec/ruby/optional/capi/module_spec.rb +++ b/spec/ruby/optional/capi/module_spec.rb @@ -252,30 +252,22 @@ describe "CApiModule" do cls.new.method(:test_method).arity.should == 0 end - it "returns the correct arity when argc of the method in class is 1" do - @m.rb_define_method_1required(42).should == 42 - @m.method(:rb_define_method_1required).arity.should == 1 - end - - it "returns the correct arity when argc of the method in class is 2" do - @m.rb_define_method_2required(1, 2).should == 2 - @m.method(:rb_define_method_2required).arity.should == 2 - end - - it "defines a method taking variable arguments as a C array if the argument count is -1" do - @m.rb_define_method_varargs_1(1, 3, 7, 4).should == [1, 3, 7, 4] - end - it "returns the correct arity when argc of the method in class is -1" do - @m.method(:rb_define_method_varargs_1).arity.should == -1 + cls = Class.new + @m.rb_define_method_c_array(cls, "test_method_c_array") + cls.new.method(:test_method_c_array).arity.should == -1 end - it "defines a method taking variable arguments as a Ruby array if the argument count is -2" do - @m.rb_define_method_varargs_2(1, 3, 7, 4).should == [1, 3, 7, 4] + it "returns the correct arity when argc of the method in class is -2" do + cls = Class.new + @m.rb_define_method_ruby_array(cls, "test_method_ruby_array") + cls.new.method(:test_method_ruby_array).arity.should == -1 end - it "returns the correct arity when argc of the method in class is -2" do - @m.method(:rb_define_method_varargs_2).arity.should == -1 + it "returns the correct arity when argc of the method in class is 2" do + cls = Class.new + @m.rb_define_method_2required(cls, "test_method_2required") + cls.new.method(:test_method_2required).arity.should == 2 end it "defines a method on a module" do diff --git a/spec/ruby/optional/capi/object_spec.rb b/spec/ruby/optional/capi/object_spec.rb index 6ee6d65680..ab11367060 100644 --- a/spec/ruby/optional/capi/object_spec.rb +++ b/spec/ruby/optional/capi/object_spec.rb @@ -1,5 +1,4 @@ require_relative 'spec_helper' -require_relative 'fixtures/object' load_extension("object") @@ -31,7 +30,6 @@ describe "CApiObject" do class ObjectTest def initialize @foo = 7 - yield if block_given? end def foo @@ -90,15 +88,6 @@ describe "CApiObject" do o.initialized.should be_true o.arguments.should == [:one, :two] end - - it "passes the block to #initialize" do - v = nil - o = @o.rb_obj_alloc(ObjectTest) - @o.rb_obj_call_init(o, 0, []) do - v = :foo - end - v.should == :foo - end end describe "rb_is_instance_of" do @@ -219,7 +208,7 @@ describe "CApiObject" do end it "requires a ruby file" do - $:.unshift __dir__ + $:.unshift File.dirname(__FILE__) @o.rb_require() $foo.should == 7 end @@ -449,6 +438,15 @@ describe "CApiObject" do end describe "FL_TEST" do + ruby_version_is ''...'2.7' do + it "returns correct status for FL_TAINT" do + obj = Object.new + @o.FL_TEST(obj, "FL_TAINT").should == 0 + obj.taint + @o.FL_TEST(obj, "FL_TAINT").should_not == 0 + end + end + it "returns correct status for FL_FREEZE" do obj = Object.new @o.FL_TEST(obj, "FL_FREEZE").should == 0 @@ -482,31 +480,12 @@ describe "CApiObject" do end end - describe "rb_obj_class" do - it "returns the class of an object" do - @o.rb_obj_class(nil).should == NilClass - @o.rb_obj_class(0).should == Integer - @o.rb_obj_class(0.1).should == Float - @o.rb_obj_class(ObjectTest.new).should == ObjectTest - end - - it "does not return the singleton class if it exists" do - o = ObjectTest.new - o.singleton_class - @o.rb_obj_class(o).should equal ObjectTest - end - end - describe "rb_obj_classname" do it "returns the class name of an object" do @o.rb_obj_classname(nil).should == 'NilClass' @o.rb_obj_classname(0).should == 'Integer' @o.rb_obj_classname(0.1).should == 'Float' @o.rb_obj_classname(ObjectTest.new).should == 'ObjectTest' - - o = ObjectTest.new - o.singleton_class - @o.rb_obj_classname(o).should == 'ObjectTest' end end @@ -524,21 +503,6 @@ describe "CApiObject" do @o.rb_is_type_class(ObjectTest).should == true @o.rb_is_type_data(Time.now).should == true end - - it "returns T_FILE for instances of IO and subclasses" do - STDERR.class.should == IO - @o.rb_is_rb_type_p_file(STDERR).should == true - - File.open(__FILE__) do |f| - f.class.should == File - @o.rb_is_rb_type_p_file(f).should == true - end - - require 'socket' - TCPServer.open(0) do |s| - @o.rb_is_rb_type_p_file(s).should == true - end - end end describe "rb_check_type" do @@ -653,12 +617,68 @@ describe "CApiObject" do end describe "OBJ_TAINT" do + ruby_version_is ''...'2.7' do + it "taints the object" do + obj = mock("tainted") + @o.OBJ_TAINT(obj) + obj.tainted?.should be_true + end + end end describe "OBJ_TAINTED" do + ruby_version_is ''...'2.7' do + it "returns C true if the object is tainted" do + obj = mock("tainted") + obj.taint + @o.OBJ_TAINTED(obj).should be_true + end + + it "returns C false if the object is not tainted" do + obj = mock("untainted") + @o.OBJ_TAINTED(obj).should be_false + end + end end describe "OBJ_INFECT" do + ruby_version_is ''...'2.7' do + it "does not taint the first argument if the second argument is not tainted" do + host = mock("host") + source = mock("source") + @o.OBJ_INFECT(host, source) + host.tainted?.should be_false + end + + it "taints the first argument if the second argument is tainted" do + host = mock("host") + source = mock("source").taint + @o.OBJ_INFECT(host, source) + host.tainted?.should be_true + end + + it "does not untrust the first argument if the second argument is trusted" do + host = mock("host") + source = mock("source") + @o.OBJ_INFECT(host, source) + host.untrusted?.should be_false + end + + it "untrusts the first argument if the second argument is untrusted" do + host = mock("host") + source = mock("source").untrust + @o.OBJ_INFECT(host, source) + host.untrusted?.should be_true + end + + it "propagates both taint and distrust" do + host = mock("host") + source = mock("source").taint.untrust + @o.OBJ_INFECT(host, source) + host.tainted?.should be_true + host.untrusted?.should be_true + end + end end describe "rb_obj_freeze" do @@ -692,6 +712,18 @@ describe "CApiObject" do end describe "rb_obj_taint" do + ruby_version_is ''...'2.7' do + it "marks the object passed as tainted" do + obj = "" + obj.should_not.tainted? + @o.rb_obj_taint(obj) + obj.should.tainted? + end + + it "raises a FrozenError if the object passed is frozen" do + -> { @o.rb_obj_taint("".freeze) }.should raise_error(FrozenError) + end + end end describe "rb_check_frozen" do @@ -984,30 +1016,5 @@ describe "CApiObject" do @o.speced_allocator?(parent).should == true end end - - describe "rb_ivar_foreach" do - it "calls the callback function for each instance variable on an object" do - o = CApiObjectSpecs::IVars.new - ary = @o.rb_ivar_foreach(o) - ary.should == [:@a, 3, :@b, 7, :@c, 4] - end - - it "calls the callback function for each cvar and ivar on a class" do - exp = [:@@cvar, :foo, :@@cvar2, :bar, :@ivar, :baz] - exp.unshift(:__classpath__, 'CApiObjectSpecs::CVars') if RUBY_VERSION < "3.3" - - ary = @o.rb_ivar_foreach(CApiObjectSpecs::CVars) - ary.should == exp - end - - it "calls the callback function for each cvar and ivar on a module" do - exp = [:@@mvar, :foo, :@@mvar2, :bar, :@ivar, :baz] - exp.unshift(:__classpath__, 'CApiObjectSpecs::MVars') if RUBY_VERSION < "3.3" - - ary = @o.rb_ivar_foreach(CApiObjectSpecs::MVars) - ary.should == exp - end - - end end end diff --git a/spec/ruby/optional/capi/proc_spec.rb b/spec/ruby/optional/capi/proc_spec.rb index 8b94432f3e..6e797fdeb4 100644 --- a/spec/ruby/optional/capi/proc_spec.rb +++ b/spec/ruby/optional/capi/proc_spec.rb @@ -7,8 +7,6 @@ describe "C-API Proc function" do before :each do @p = CApiProcSpecs.new @prc = @p.rb_proc_new - @prc2 = @p.rb_proc_new_argv_n - @prc3 = @p.rb_proc_new_argc end describe "rb_proc_new" do @@ -17,7 +15,6 @@ describe "C-API Proc function" do end it "calls the C function wrapped by the Proc instance when sent #call" do - @p.rb_proc_new_arg.call().should == nil @prc.call(:foo_bar).should == ":foo_bar" @prc.call([:foo, :bar]).should == "[:foo, :bar]" end @@ -27,30 +24,6 @@ describe "C-API Proc function" do @prc[[:foo, :bar]].should == "[:foo, :bar]" end - it "calls the C function with the arg count in argc" do - @prc3.call().should == 0 - @prc3.call(:foo).should == 1 - @prc3.call(:foo, :bar).should == 2 - end - - it "calls the C function with arguments in argv" do - @prc2.call(1, :foo).should == :foo - @prc2.call(2, :foo, :bar).should == :bar - -> { @prc2.call(3, :foo, :bar) }.should raise_error(ArgumentError) - end - - it "calls the C function with the block passed in blockarg" do - a_block = :foo.to_proc - @p.rb_proc_new_blockarg.call(&a_block).should == a_block - @p.rb_proc_new_blockarg.call().should == nil - end - - it "calls the C function and yields to the block passed in blockarg" do - @p.rb_proc_new_block_given_p.call() do - end.should == false - @p.rb_proc_new_block_given_p.call().should == false - end - it "returns a Proc instance correctly described in #inspect without source location" do @prc.inspect.should =~ /^#<Proc:([^ :@]*?)>$/ end @@ -82,59 +55,6 @@ describe "C-API Proc function" do end end - describe "rb_proc_call_kw" do - it "passes keyword arguments to the proc" do - prc = proc { |*args, **kw| [args, kw] } - - @p.rb_proc_call_kw(prc, [{}]).should == [[], {}] - @p.rb_proc_call_kw(prc, [{a: 1}]).should == [[], {a: 1}] - @p.rb_proc_call_kw(prc, [{b: 2}, {a: 1}]).should == [[{b: 2}], {a: 1}] - @p.rb_proc_call_kw(prc, [{b: 2}, {}]).should == [[{b: 2}], {}] - end - - it "raises TypeError if the last argument is not a Hash" do - -> { - @p.rb_proc_call_kw(proc {}, [42]) - }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash') - end - end - - describe "rb_proc_call_with_block" do - it "calls the Proc and passes arguments and a block" do - prc = Proc.new { |a, b, &block| block.call(a * b) } - @p.rb_proc_call_with_block(prc, [6, 7], proc { |n| n * 2 }).should == 6 * 7 * 2 - end - - it "calls the Proc and passes arguments when a block is nil" do - prc = Proc.new { |a, b| a * b } - @p.rb_proc_call_with_block(prc, [6, 7], nil).should == 6 * 7 - end - end - - describe "rb_proc_call_with_block_kw" do - it "passes keyword arguments and a block to the proc" do - prc = proc { |*args, **kw, &block| [args, kw, block.call(42)] } - block = proc { |n| n } - - @p.rb_proc_call_with_block_kw(prc, [{}], block).should == [[], {}, 42] - @p.rb_proc_call_with_block_kw(prc, [{a: 1}], block).should == [[], {a: 1}, 42] - @p.rb_proc_call_with_block_kw(prc, [{b: 2}, {a: 1}], block).should == [[{b: 2}], {a: 1}, 42] - @p.rb_proc_call_with_block_kw(prc, [{b: 2}, {}], block).should == [[{b: 2}], {}, 42] - end - - it "raises TypeError if the last argument is not a Hash" do - -> { - @p.rb_proc_call_with_block_kw(proc {}, [42], proc {}) - }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash') - end - - it "passes keyword arguments to the proc when a block is nil" do - prc = proc { |*args, **kw| [args, kw] } - - @p.rb_proc_call_with_block_kw(prc, [{}], nil).should == [[], {}] - end - end - describe "rb_obj_is_proc" do it "returns true for Proc" do prc = Proc.new {|a,b| a * b } @@ -168,6 +88,20 @@ describe "C-API when calling Proc.new from a C function" do # For example: C -> Ruby <- C -> Ruby means a C function called into Ruby # code which returned to C, then C called into Ruby code again. + ruby_version_is ""..."2.7" do + # Ruby -> C -> rb_funcall(Proc.new) + it "returns the Proc passed by the Ruby code calling the C function" do + prc = @p.rb_Proc_new(0) { :called } + prc.call.should == :called + end + + # Ruby -> C -> Ruby <- C -> rb_funcall(Proc.new) + it "returns the Proc passed to the Ruby method when the C function calls other Ruby methods before calling Proc.new" do + prc = @p.rb_Proc_new(1) { :called } + prc.call.should == :called + end + end + # Ruby -> C -> Ruby -> Proc.new it "raises an ArgumentError when the C function calls a Ruby method that calls Proc.new" do -> { @@ -181,6 +115,20 @@ describe "C-API when calling Proc.new from a C function" do -> { @p.rb_Proc_new(3) { :called } }.should raise_error(ArgumentError) end + ruby_version_is ""..."2.7" do + # Ruby -> C -> Ruby -> C (with new block) -> rb_funcall(Proc.new) + it "returns the most recent Proc passed when the Ruby method called the C function" do + prc = @p.rb_Proc_new(4) { :called } + prc.call.should == :calling_with_block + end + + # Ruby -> C -> Ruby -> C (with new block) <- Ruby <- C -> # rb_funcall(Proc.new) + it "returns the Proc passed from the original Ruby call to the C function" do + prc = @p.rb_Proc_new(5) { :called } + prc.call.should == :called + end + end + # Ruby -> C -> Ruby -> block_given? it "returns false from block_given? in a Ruby method called by the C function" do @p.rb_Proc_new(6).should be_false diff --git a/spec/ruby/optional/capi/rbasic_spec.rb b/spec/ruby/optional/capi/rbasic_spec.rb index f3367e05ff..6300680d99 100644 --- a/spec/ruby/optional/capi/rbasic_spec.rb +++ b/spec/ruby/optional/capi/rbasic_spec.rb @@ -1,6 +1,7 @@ require_relative 'spec_helper' require_relative 'shared/rbasic' load_extension("rbasic") +return if /mswin/ =~ RUBY_PLATFORM && ENV.key?('GITHUB_ACTIONS') # not working from the beginning load_extension("data") load_extension("array") @@ -33,8 +34,6 @@ describe "RBasic support for RData" do initial = @specs.get_flags(obj1) @specs.get_flags(obj2).should == initial @specs.set_flags(obj1, 1 << 14 | 1 << 16 | initial) - @specs.get_flags(obj1).should == 1 << 14 | 1 << 16 | initial - @specs.copy_flags(obj2, obj1) @specs.get_flags(obj2).should == 1 << 14 | 1 << 16 | initial @specs.set_flags(obj1, initial) diff --git a/spec/ruby/optional/capi/regexp_spec.rb b/spec/ruby/optional/capi/regexp_spec.rb index af366e17a2..81844e2a6e 100644 --- a/spec/ruby/optional/capi/regexp_spec.rb +++ b/spec/ruby/optional/capi/regexp_spec.rb @@ -109,20 +109,4 @@ describe "C-API Regexp function" do thr.join end end - - describe "rb_memicmp" do - it "returns 0 for identical strings" do - @p.rb_memcicmp('Hello', 'Hello').should == 0 - end - - it "returns 0 for strings which only differ in case" do - @p.rb_memcicmp('Hello', 'HELLO').should == 0 - @p.rb_memcicmp('HELLO', 'Hello').should == 0 - end - - it "returns the difference between the first non matching characters" do - @p.rb_memcicmp('Hello', 'HELLP').should == -1 - @p.rb_memcicmp('HELLp', 'Hello').should == 1 - end - end end diff --git a/spec/ruby/optional/capi/shared/rbasic.rb b/spec/ruby/optional/capi/shared/rbasic.rb index 9d80a93e1d..5ef63e81e3 100644 --- a/spec/ruby/optional/capi/shared/rbasic.rb +++ b/spec/ruby/optional/capi/shared/rbasic.rb @@ -1,4 +1,5 @@ describe :rbasic, shared: true do + before :all do specs = CApiRBasicSpecs.new @taint = ruby_version_is(''...'3.1') ? specs.taint_flag : 0 @@ -9,7 +10,7 @@ describe :rbasic, shared: true do obj, _ = @data.call initial = @specs.get_flags(obj) obj.freeze - (@specs.get_flags(obj) & 0xFFFF).should == (@freeze | initial) & 0xFFFF + @specs.get_flags(obj).should == @freeze | initial end it "supports setting the FREEZE flag" do @@ -19,6 +20,40 @@ describe :rbasic, shared: true do obj.should.frozen? end + ruby_version_is ""..."2.7" do + it "reports the appropriate FREEZE and TAINT flags for the object when reading" do + obj, _ = @data.call + initial = @specs.get_flags(obj) + obj.taint + @specs.get_flags(obj).should == @taint | initial + obj.untaint + @specs.get_flags(obj).should == initial + obj.freeze + @specs.get_flags(obj).should == @freeze | initial + + obj, _ = @data.call + obj.taint + obj.freeze + @specs.get_flags(obj).should == @freeze | @taint | initial + end + + it "supports setting the FREEZE and TAINT flags" do + obj, _ = @data.call + initial = @specs.get_flags(obj) + @specs.set_flags(obj, @taint | initial).should == @taint | initial + obj.should.tainted? + @specs.set_flags(obj, initial).should == initial + obj.should_not.tainted? + @specs.set_flags(obj, @freeze | initial).should == @freeze | initial + obj.should.frozen? + + obj, _ = @data.call + @specs.set_flags(obj, @freeze | @taint | initial).should == @freeze | @taint | initial + obj.should.tainted? + obj.should.frozen? + end + end + it "supports retrieving the (meta)class" do obj, _ = @data.call @specs.get_klass(obj).should == obj.class diff --git a/spec/ruby/optional/capi/spec_helper.rb b/spec/ruby/optional/capi/spec_helper.rb index 2691aa1332..9bd2d9791c 100644 --- a/spec/ruby/optional/capi/spec_helper.rb +++ b/spec/ruby/optional/capi/spec_helper.rb @@ -29,13 +29,10 @@ def compile_extension(name) ext = "#{name}_spec" lib = "#{object_path}/#{ext}.#{RbConfig::CONFIG['DLEXT']}" - rubyhdrdir = RbConfig::CONFIG['rubyhdrdir'] - ruby_header = "#{rubyhdrdir}/ruby.h" - abi_header = "#{rubyhdrdir}/ruby/internal/abi.h" + ruby_header = "#{RbConfig::CONFIG['rubyhdrdir']}/ruby.h" if RbConfig::CONFIG["ENABLE_SHARED"] == "yes" - # below is defined since 2.1, except for mswin, and maybe other platforms - libdirname = RbConfig::CONFIG.fetch 'libdirname', 'libdir' + libdirname = RbConfig::CONFIG['libdirname'] # defined since 2.1 libruby = "#{RbConfig::CONFIG[libdirname]}/#{RbConfig::CONFIG['LIBRUBY']}" end @@ -48,7 +45,6 @@ def compile_extension(name) when mtime <= File.mtime("#{core_ext_dir}/rubyspec.h") when mtime <= File.mtime("#{spec_ext_dir}/#{ext}.c") when mtime <= File.mtime(ruby_header) - when (mtime <= File.mtime(abi_header) rescue nil) when libruby && mtime <= File.mtime(libruby) else return lib # up-to-date diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb index 3a47fa9762..ce387ffa49 100644 --- a/spec/ruby/optional/capi/string_spec.rb +++ b/spec/ruby/optional/capi/string_spec.rb @@ -97,32 +97,6 @@ describe "C-API String function" do end end - describe "rb_str_set_len on a UTF-16 String" do - before :each do - @str = "abcdefghij".force_encoding(Encoding::UTF_16BE) - # Make sure to unshare the string - @s.rb_str_modify(@str) - end - - it "inserts two NULL bytes at the length" do - @s.rb_str_set_len(@str, 4).b.should == "abcd".b - @s.rb_str_set_len(@str, 8).b.should == "abcd\x00\x00gh".b - end - end - - describe "rb_str_set_len on a UTF-32 String" do - before :each do - @str = "abcdefghijkl".force_encoding(Encoding::UTF_32BE) - # Make sure to unshare the string - @s.rb_str_modify(@str) - end - - it "inserts four NULL bytes at the length" do - @s.rb_str_set_len(@str, 4).b.should == "abcd".b - @s.rb_str_set_len(@str, 12).b.should == "abcd\x00\x00\x00\x00ijkl".b - end - end - describe "rb_str_buf_new" do it "returns the equivalent of an empty string" do buf = @s.rb_str_buf_new(10, nil) @@ -207,6 +181,12 @@ describe "C-API String function" do @s.rb_str_new("hello", 3).should == "hel" end + ruby_version_is ''...'2.7' do + it "returns a non-tainted string" do + @s.rb_str_new("hello", 5).should_not.tainted? + end + end + it "returns an empty string if len is 0" do @s.rb_str_new("hello", 0).should == "" end @@ -355,6 +335,24 @@ describe "C-API String function" do end end + ruby_version_is ''...'2.7' do + describe "rb_tainted_str_new" do + it "creates a new tainted String" do + newstring = @s.rb_tainted_str_new("test", 4) + newstring.should == "test" + newstring.tainted?.should be_true + end + end + + describe "rb_tainted_str_new2" do + it "creates a new tainted String" do + newstring = @s.rb_tainted_str_new2("test") + newstring.should == "test" + newstring.tainted?.should be_true + end + end + end + describe "rb_str_append" do it "appends a string to another string" do @s.rb_str_append("Hello", " Goodbye").should == "Hello Goodbye" @@ -380,14 +378,6 @@ describe "C-API String function" do it_behaves_like :string_times, :rb_str_times, -> str, times { @s.rb_str_times(str, times) } end - describe "rb_str_buf_append" do - it "concatenates a string to another string" do - str = "Your house " - @s.rb_str_buf_append(str, "is on fire?").should.equal?(str) - str.should == "Your house is on fire?" - end - end - describe "rb_str_buf_cat" do it "concatenates a C string to a ruby string" do @s.rb_str_buf_cat("Your house is on fire").should == "Your house is on fire?" @@ -613,17 +603,9 @@ describe "C-API String function" do filename = fixture(__FILE__, "read.txt") str = "" capacities = @s.RSTRING_PTR_read(str, filename) - capacities[0].should >= 30 - capacities[1].should >= 53 - capacities[0].should < capacities[1] + capacities.should == [30, 53] str.should == "fixture file contents to test read() with RSTRING_PTR" end - - it "terminates the string with at least (encoding min length) \\0 bytes" do - @s.RSTRING_PTR_null_terminate("abc", 1).should == "\x00" - @s.RSTRING_PTR_null_terminate("abc".encode("UTF-16BE"), 2).should == "\x00\x00" - @s.RSTRING_PTR_null_terminate("abc".encode("UTF-32BE"), 4).should == "\x00\x00\x00\x00" - end end describe "RSTRING_LEN" do @@ -673,6 +655,22 @@ describe "C-API String function" do end describe "SafeStringValue" do + ruby_version_is ''...'2.7' do + it "raises for tained string when $SAFE is 1" do + begin + Thread.new { + $SAFE = 1 + -> { + @s.SafeStringValue("str".taint) + }.should raise_error(SecurityError) + }.join + ensure + $SAFE = 0 + end + end + + it_behaves_like :string_value_macro, :SafeStringValue + end end describe "rb_str_modify" do @@ -802,6 +800,12 @@ describe :rb_external_str_new, shared: true do x80 = [0x80].pack('C') @s.send(@method, "#{x80}abc").encoding.should == Encoding::BINARY end + + ruby_version_is ''...'2.7' do + it "returns a tainted String" do + @s.send(@method, "abc").tainted?.should be_true + end + end end describe "C-API String function" do @@ -881,6 +885,13 @@ describe "C-API String function" do s.should == x s.encoding.should equal(Encoding::EUC_JP) end + + ruby_version_is ''...'2.7' do + it "returns a tainted String" do + s = @s.rb_external_str_new_with_enc("abc", 3, Encoding::US_ASCII) + s.tainted?.should be_true + end + end end describe "rb_locale_str_new" do @@ -1040,11 +1051,9 @@ end @s.rb_sprintf3(true.class).should == s end - ruby_bug "#19167", ""..."3.2" do - it "formats a TrueClass VALUE as 'true' if sign specified in format" do - s = 'Result: TrueClass.' - @s.rb_sprintf4(true.class).should == s - end + it "formats a TrueClass VALUE as 'true' if sign specified in format" do + s = 'Result: true.' + @s.rb_sprintf4(true.class).should == s end it "truncates a string to a supplied precision if that is shorter than the string" do diff --git a/spec/ruby/optional/capi/symbol_spec.rb b/spec/ruby/optional/capi/symbol_spec.rb index 12c93c9f27..b8fda34c0e 100644 --- a/spec/ruby/optional/capi/symbol_spec.rb +++ b/spec/ruby/optional/capi/symbol_spec.rb @@ -61,10 +61,6 @@ describe "C-API Symbol function" do it "converts a symbol to a C char array" do @s.rb_id2name(:test_symbol).should == "test_symbol" end - - it "returns (char*) NULL for (ID) 0" do - @s.rb_id2name_id_zero.should == nil - end end describe "rb_id2str" do @@ -76,10 +72,6 @@ describe "C-API Symbol function" do str = "test_symbol".encode(Encoding::UTF_16LE) @s.rb_id2str(str.to_sym).encoding.should == Encoding::UTF_16LE end - - it "returns (VALUE) 0 = Qfalse for (ID) 0" do - @s.rb_id2str_id_zero.should == false - end end describe "rb_intern_str" do diff --git a/spec/ruby/optional/capi/thread_spec.rb b/spec/ruby/optional/capi/thread_spec.rb index af641f0564..30e29681eb 100644 --- a/spec/ruby/optional/capi/thread_spec.rb +++ b/spec/ruby/optional/capi/thread_spec.rb @@ -101,16 +101,6 @@ describe "C-API Thread function" do end end - describe "ruby_native_thread_p" do - it "returns non-zero for a ruby thread" do - @t.ruby_native_thread_p.should be_true - end - - it "returns zero for a non ruby thread" do - @t.ruby_native_thread_p_new_thread.should be_false - end - end - describe "rb_thread_call_without_gvl" do it "runs a C function with the global lock unlocked and can be woken by Thread#wakeup" do thr = Thread.new do @@ -165,23 +155,25 @@ describe "C-API Thread function" do end end - it "runs a C function with the global lock unlocked and unlocks IO with the generic RUBY_UBF_IO" do - thr = Thread.new do - @t.rb_thread_call_without_gvl_with_ubf_io - end + platform_is_not :mingw do + it "runs a C function with the global lock unlocked and unlocks IO with the generic RUBY_UBF_IO" do + thr = Thread.new do + @t.rb_thread_call_without_gvl_with_ubf_io + end - # Wait until it's blocking... - Thread.pass until thr.stop? + # Wait until it's blocking... + Thread.pass until thr.stop? - # The thread status is set to sleep by rb_thread_call_without_gvl(), - # but the thread might not be in the blocking read(2) yet, so wait a bit. - sleep 0.1 + # The thread status is set to sleep by rb_thread_call_without_gvl(), + # but the thread might not be in the blocking read(2) yet, so wait a bit. + sleep 0.1 - # Wake it up, causing the unblock function to be run. - thr.wakeup + # Wake it up, causing the unblock function to be run. + thr.wakeup - # Make sure it stopped and we got a proper value - thr.value.should be_true + # Make sure it stopped and we got a proper value + thr.value.should be_true + end end end end diff --git a/spec/ruby/optional/capi/time_spec.rb b/spec/ruby/optional/capi/time_spec.rb index ca5fc5952a..579e81fc19 100644 --- a/spec/ruby/optional/capi/time_spec.rb +++ b/spec/ruby/optional/capi/time_spec.rb @@ -283,11 +283,6 @@ describe "CApiTimeSpecs" do -> { @s.rb_time_timespec_new(1447087832, 476451125, 86400) }.should raise_error(ArgumentError) -> { @s.rb_time_timespec_new(1447087832, 476451125, -86400) }.should raise_error(ArgumentError) end - - it "doesn't call Time.at directly" do - Time.should_not_receive(:at) - @s.rb_time_timespec_new(1447087832, 476451125, 32400).should be_kind_of(Time) - end end describe "rb_timespec_now" do diff --git a/spec/ruby/optional/capi/typed_data_spec.rb b/spec/ruby/optional/capi/typed_data_spec.rb index 6d1398a1a0..23b7c157ef 100644 --- a/spec/ruby/optional/capi/typed_data_spec.rb +++ b/spec/ruby/optional/capi/typed_data_spec.rb @@ -85,16 +85,4 @@ describe "CApiWrappedTypedStruct" do -> { @s.rb_check_typeddata_different_type(a) }.should raise_error(TypeError) end end - - describe "RTYPEDDATA_P" do - it "returns true for a typed data" do - a = @s.typed_wrap_struct(1024) - @s.RTYPEDDATA_P(a).should == true - end - - it "returns false for an untyped data object" do - a = @s.untyped_wrap_struct(1024) - @s.RTYPEDDATA_P(a).should == false - end - end end diff --git a/spec/ruby/optional/capi/util_spec.rb b/spec/ruby/optional/capi/util_spec.rb index 2c16999cdc..a90c28a78e 100644 --- a/spec/ruby/optional/capi/util_spec.rb +++ b/spec/ruby/optional/capi/util_spec.rb @@ -11,13 +11,13 @@ describe "C-API Util function" do before :each do @prc = -> { 1 } @acc = [] + @keyword_prefix = 'k' if RUBY_VERSION >= '2.7' ScratchPad.record @acc end it "assigns the required arguments scanned" do - obj = Object.new - @o.rb_scan_args([obj, 2], "2", 2, @acc).should == 2 - ScratchPad.recorded.should == [obj, 2] + @o.rb_scan_args([1, 2], "2", 2, @acc).should == 2 + ScratchPad.recorded.should == [1, 2] end it "raises an ArgumentError if there are insufficient arguments" do @@ -100,13 +100,13 @@ describe "C-API Util function" do it "assigns Hash arguments" do h = {a: 1, b: 2} - @o.rb_scan_args([h], "k0:", 1, @acc).should == 0 + @o.rb_scan_args([h], "#{@keyword_prefix}0:", 1, @acc).should == 0 ScratchPad.recorded.should == [h] end it "assigns required and Hash arguments" do h = {a: 1, b: 2} - @o.rb_scan_args([1, h], "k1:", 2, @acc).should == 1 + @o.rb_scan_args([1, h], "#{@keyword_prefix}1:", 2, @acc).should == 1 ScratchPad.recorded.should == [1, h] end @@ -115,11 +115,22 @@ describe "C-API Util function" do ScratchPad.recorded.should == [1, nil] end - it "rejects the use of nil as a hash" do - -> { - @o.rb_scan_args([1, nil], "1:", 2, @acc).should == 1 - }.should raise_error(ArgumentError) - ScratchPad.recorded.should == [] + ruby_version_is ''...'3.0' do + it "assigns required and Hash arguments with nil Hash" do + suppress_warning do + @o.rb_scan_args([1, nil], "1:", 2, @acc).should == 1 + end + ScratchPad.recorded.should == [1, nil] + end + end + + ruby_version_is '3.0' do + it "rejects the use of nil as a hash" do + -> { + @o.rb_scan_args([1, nil], "1:", 2, @acc).should == 1 + }.should raise_error(ArgumentError) + ScratchPad.recorded.should == [] + end end it "assigns required and optional arguments with no hash argument given" do @@ -127,41 +138,61 @@ describe "C-API Util function" do ScratchPad.recorded.should == [1, 7, 4] end - it "assigns optional arguments with no hash argument given" do - @o.rb_scan_args([1, 7], "02:", 3, @acc).should == 2 - ScratchPad.recorded.should == [1, 7, nil] - end - - it "assigns optional arguments with no hash argument given and rejects the use of optional nil argument as a hash" do - -> { - @o.rb_scan_args([1, nil], "02:", 3, @acc).should == 2 - }.should_not complain - - ScratchPad.recorded.should == [1, nil, nil] - end - it "assigns required, optional, splat, post-splat, Hash and block arguments" do h = {a: 1, b: 2} - @o.rb_scan_args([1, 2, 3, 4, 5, h], "k11*1:&", 6, @acc, &@prc).should == 5 + @o.rb_scan_args([1, 2, 3, 4, 5, h], "#{@keyword_prefix}11*1:&", 6, @acc, &@prc).should == 5 ScratchPad.recorded.should == [1, 2, [3, 4], 5, h, @prc] end - it "does not reject non-symbol keys in keyword arguments" do - h = {1 => 2, 3 => 4} - @o.rb_scan_args([h], "k0:", 1, @acc).should == 0 - ScratchPad.recorded.should == [h] - end + ruby_version_is ''...'3.0' do + # r43934 + it "rejects non-keyword arguments" do + h = {1 => 2, 3 => 4} + -> { + suppress_warning do + @o.rb_scan_args([h], "#{@keyword_prefix}0:", 1, @acc) + end + }.should raise_error(ArgumentError) + ScratchPad.recorded.should == [] + end - it "does not reject non-symbol keys in keyword arguments with required argument" do - h = {1 => 2, 3 => 4} - @o.rb_scan_args([1, h], "k1:", 2, @acc).should == 1 - ScratchPad.recorded.should == [1, h] + it "rejects required and non-keyword arguments" do + h = {1 => 2, 3 => 4} + -> { + suppress_warning do + @o.rb_scan_args([1, h], "#{@keyword_prefix}1:", 2, @acc) + end + }.should raise_error(ArgumentError) + ScratchPad.recorded.should == [] + end + + it "considers the hash as a post argument when there is a splat" do + h = {1 => 2, 3 => 4} + suppress_warning do + @o.rb_scan_args([1, 2, 3, 4, 5, h], "#{@keyword_prefix}11*1:&", 6, @acc, &@prc).should == 6 + end + ScratchPad.recorded.should == [1, 2, [3, 4, 5], h, nil, @prc] + end end - it "considers keyword arguments with non-symbol keys as keywords when using splat and post arguments" do - h = {1 => 2, 3 => 4} - @o.rb_scan_args([1, 2, 3, 4, 5, h], "k11*1:&", 6, @acc, &@prc).should == 5 - ScratchPad.recorded.should == [1, 2, [3, 4], 5, h, @prc] + ruby_version_is '3.0' do + it "does not reject non-symbol keys in keyword arguments" do + h = {1 => 2, 3 => 4} + @o.rb_scan_args([h], "#{@keyword_prefix}0:", 1, @acc).should == 0 + ScratchPad.recorded.should == [h] + end + + it "does not reject non-symbol keys in keyword arguments with required argument" do + h = {1 => 2, 3 => 4} + @o.rb_scan_args([1, h], "#{@keyword_prefix}1:", 2, @acc).should == 1 + ScratchPad.recorded.should == [1, h] + end + + it "considers keyword arguments with non-symbol keys as keywords when using splat and post arguments" do + h = {1 => 2, 3 => 4} + @o.rb_scan_args([1, 2, 3, 4, 5, h], "#{@keyword_prefix}11*1:&", 6, @acc, &@prc).should == 5 + ScratchPad.recorded.should == [1, 2, [3, 4], 5, h, @prc] + end end end diff --git a/spec/ruby/security/cve_2014_8080_spec.rb b/spec/ruby/security/cve_2014_8080_spec.rb new file mode 100644 index 0000000000..23770f94b1 --- /dev/null +++ b/spec/ruby/security/cve_2014_8080_spec.rb @@ -0,0 +1,34 @@ +require_relative '../spec_helper' + +ruby_version_is ''...'3.0' do + require 'rexml/document' + + describe "REXML::Document.new" do + + it "resists CVE-2014-8080 by raising an exception when entity expansion has grown too large" do + xml = <<XML + <?xml version="1.0" encoding="UTF-8" ?> + <!DOCTYPE x [ + <!ENTITY % x0 "xxxxxxxxxx"> + <!ENTITY % x1 "%x0;%x0;%x0;%x0;%x0;%x0;%x0;%x0;%x0;%x0;"> + <!ENTITY % x2 "%x1;%x1;%x1;%x1;%x1;%x1;%x1;%x1;%x1;%x1;"> + <!ENTITY % x3 "%x2;%x2;%x2;%x2;%x2;%x2;%x2;%x2;%x2;%x2;"> + <!ENTITY % x4 "%x3;%x3;%x3;%x3;%x3;%x3;%x3;%x3;%x3;%x3;"> + <!ENTITY % x5 "%x4;%x4;%x4;%x4;%x4;%x4;%x4;%x4;%x4;%x4;"> + <!ENTITY % x6 "%x5;%x5;%x5;%x5;%x5;%x5;%x5;%x5;%x5;%x5;"> + <!ENTITY % x7 "%x6;%x6;%x6;%x6;%x6;%x6;%x6;%x6;%x6;%x6;"> + <!ENTITY % x8 "%x7;%x7;%x7;%x7;%x7;%x7;%x7;%x7;%x7;%x7;"> + <!ENTITY % x9 "%x8;%x8;%x8;%x8;%x8;%x8;%x8;%x8;%x8;%x8;"> + ]> + <x> + %x9;%x9;%x9;%x9;%x9;%x9;%x9;%x9;%x9;%x9; + </x> +XML + + -> { + REXML::Document.new(xml).doctype.entities['x9'].value + }.should raise_error(REXML::ParseException, /entity expansion has grown too large/) + end + + end +end diff --git a/spec/ruby/security/cve_2017_17742_spec.rb b/spec/ruby/security/cve_2017_17742_spec.rb new file mode 100644 index 0000000000..b0d93e42b8 --- /dev/null +++ b/spec/ruby/security/cve_2017_17742_spec.rb @@ -0,0 +1,37 @@ +require_relative '../spec_helper' + +# webrick is no longer in stdlib in Ruby 3+ +ruby_version_is ""..."3.0" do + require "webrick" + require "stringio" + require "net/http" + + describe "WEBrick" do + describe "resists CVE-2017-17742" do + it "for a response splitting headers" do + config = WEBrick::Config::HTTP + res = WEBrick::HTTPResponse.new config + res['X-header'] = "malicious\r\nCookie: hack" + io = StringIO.new + res.send_response io + io.rewind + res = Net::HTTPResponse.read_new(Net::BufferedIO.new(io)) + res.code.should == '500' + io.string.should_not =~ /hack/ + end + + it "for a response splitting cookie headers" do + user_input = "malicious\r\nCookie: hack" + config = WEBrick::Config::HTTP + res = WEBrick::HTTPResponse.new config + res.cookies << WEBrick::Cookie.new('author', user_input) + io = StringIO.new + res.send_response io + io.rewind + res = Net::HTTPResponse.read_new(Net::BufferedIO.new(io)) + res.code.should == '500' + io.string.should_not =~ /hack/ + end + end + end +end diff --git a/spec/ruby/security/cve_2018_16396_spec.rb b/spec/ruby/security/cve_2018_16396_spec.rb index 6f8a5d2f5d..c9624e9c63 100644 --- a/spec/ruby/security/cve_2018_16396_spec.rb +++ b/spec/ruby/security/cve_2018_16396_spec.rb @@ -1,7 +1,21 @@ require_relative '../spec_helper' describe "Array#pack" do + ruby_version_is ''...'2.7' do + it "resists CVE-2018-16396 by tainting output based on input" do + "aAZBbHhuMmPp".each_char do |f| + ["123456".taint].pack(f).tainted?.should be_true + end + end + end end describe "String#unpack" do + ruby_version_is ''...'2.7' do + it "resists CVE-2018-16396 by tainting output based on input" do + "aAZBbHhuMm".each_char do |f| + "123456".taint.unpack(f).first.tainted?.should be_true + end + end + end end diff --git a/spec/ruby/security/cve_2019_8323_spec.rb b/spec/ruby/security/cve_2019_8323_spec.rb index 49a31a6682..3632d3b028 100644 --- a/spec/ruby/security/cve_2019_8323_spec.rb +++ b/spec/ruby/security/cve_2019_8323_spec.rb @@ -1,46 +1,38 @@ require_relative '../spec_helper' -require 'optparse' +platform_is_not :darwin do # frequent timeout/hang on macOS + require 'optparse' -require 'rubygems' -require 'rubygems/gemcutter_utilities' + require 'rubygems' + require 'rubygems/gemcutter_utilities' -describe "CVE-2019-8323 is resisted by" do - describe "sanitising the body" do - it "for success codes" do - cutter = Class.new { - include Gem::GemcutterUtilities - }.new - klass = if defined?(Gem::Net::HTTPSuccess) - Gem::Net::HTTPSuccess - else - Net::HTTPSuccess - end - response = klass.new(nil, nil, nil) - def response.body - "\e]2;nyan\a" + describe "CVE-2019-8323 is resisted by" do + describe "sanitising the body" do + it "for success codes" do + cutter = Class.new { + include Gem::GemcutterUtilities + }.new + response = Net::HTTPSuccess.new(nil, nil, nil) + def response.body + "\e]2;nyan\a" + end + cutter.should_receive(:say).with(".]2;nyan.") + cutter.with_response response end - cutter.should_receive(:say).with(".]2;nyan.") - cutter.with_response response - end - it "for error codes" do - cutter = Class.new { - include Gem::GemcutterUtilities - }.new - def cutter.terminate_interaction(n) - end - klass = if defined?(Gem::Net::HTTPNotFound) - Gem::Net::HTTPNotFound - else - Net::HTTPNotFound - end - response = klass.new(nil, nil, nil) - def response.body - "\e]2;nyan\a" + it "for error codes" do + cutter = Class.new { + include Gem::GemcutterUtilities + }.new + def cutter.terminate_interaction(n) + end + response = Net::HTTPNotFound.new(nil, nil, nil) + def response.body + "\e]2;nyan\a" + end + cutter.should_receive(:say).with(".]2;nyan.") + cutter.with_response response end - cutter.should_receive(:say).with(".]2;nyan.") - cutter.with_response response end end end diff --git a/spec/ruby/security/cve_2019_8325_spec.rb b/spec/ruby/security/cve_2019_8325_spec.rb index bbddb3a6ce..309445a50f 100644 --- a/spec/ruby/security/cve_2019_8325_spec.rb +++ b/spec/ruby/security/cve_2019_8325_spec.rb @@ -1,46 +1,38 @@ require_relative '../spec_helper' -require 'rubygems' -require 'rubygems/command_manager' +platform_is_not :darwin do # frequent timeout/hang on macOS + require 'rubygems' + require 'rubygems/command_manager' -describe "CVE-2019-8325 is resisted by" do - describe "sanitising error message components" do - before :each do - @ui = Gem::SilentUI.new - end - - after :each do - @ui.close - end - - it "for the 'while executing' message" do - manager = Gem::CommandManager.new - manager.ui = @ui - def manager.process_args(args, build_args) - raise StandardError, "\e]2;nyan\a" + describe "CVE-2019-8325 is resisted by" do + describe "sanitising error message components" do + it "for the 'while executing' message" do + manager = Gem::CommandManager.new + def manager.process_args(args, build_args) + raise StandardError, "\e]2;nyan\a" + end + def manager.terminate_interaction(n) + end + manager.should_receive(:alert_error).with("While executing gem ... (StandardError)\n .]2;nyan.") + manager.run nil, nil end - def manager.terminate_interaction(n) - end - manager.should_receive(:alert_error).with("While executing gem ... (StandardError)\n .]2;nyan.") - manager.run nil, nil - end - it "for the 'invalid option' message" do - manager = Gem::CommandManager.new - def manager.terminate_interaction(n) + it "for the 'invalid option' message" do + manager = Gem::CommandManager.new + def manager.terminate_interaction(n) + end + manager.should_receive(:alert_error).with("Invalid option: --.]2;nyan.. See 'gem --help'.") + manager.process_args ["--\e]2;nyan\a"], nil end - manager.should_receive(:alert_error).with("Invalid option: --.]2;nyan.. See 'gem --help'.") - manager.process_args ["--\e]2;nyan\a"], nil - end - it "for the 'loading command' message" do - manager = Gem::CommandManager.new - manager.ui = @ui - def manager.require(x) - raise 'foo' + it "for the 'loading command' message" do + manager = Gem::CommandManager.new + def manager.require(x) + raise 'foo' + end + manager.should_receive(:alert_error).with("Loading command: .]2;nyan. (RuntimeError)\n\tfoo") + manager.send :load_and_instantiate, "\e]2;nyan\a" end - manager.should_receive(:alert_error).with("Loading command: .]2;nyan. (RuntimeError)\n\tfoo") - manager.send :load_and_instantiate, "\e]2;nyan\a" end end end diff --git a/spec/ruby/security/cve_2020_10663_spec.rb b/spec/ruby/security/cve_2020_10663_spec.rb index cce1beb012..766590d501 100644 --- a/spec/ruby/security/cve_2020_10663_spec.rb +++ b/spec/ruby/security/cve_2020_10663_spec.rb @@ -18,22 +18,25 @@ module JSONSpecs end guard -> { + ruby_version_is "2.6.6" or JSON.const_defined?(:Pure) or version_is(JSON::VERSION, '2.3.0') } do - describe "CVE-2020-10663 is resisted by" do - it "only creating custom objects if passed create_additions: true or using JSON.load" do - obj = JSONSpecs::MyClass.new("bar") - JSONSpecs::MyClass.should.json_creatable? - json = JSON.dump(obj) + platform_is_not :darwin do # frequent timeout/hang on macOS + describe "CVE-2020-10663 is resisted by" do + it "only creating custom objects if passed create_additions: true or using JSON.load" do + obj = JSONSpecs::MyClass.new("bar") + JSONSpecs::MyClass.should.json_creatable? + json = JSON.dump(obj) - JSON.parse(json, create_additions: true).class.should == JSONSpecs::MyClass - JSON(json, create_additions: true).class.should == JSONSpecs::MyClass - JSON.load(json).class.should == JSONSpecs::MyClass + JSON.parse(json, create_additions: true).class.should == JSONSpecs::MyClass + JSON(json, create_additions: true).class.should == JSONSpecs::MyClass + JSON.load(json).class.should == JSONSpecs::MyClass - JSON.parse(json).class.should == Hash - JSON.parse(json, nil).class.should == Hash - JSON(json).class.should == Hash + JSON.parse(json).class.should == Hash + JSON.parse(json, nil).class.should == Hash + JSON(json).class.should == Hash + end end end end diff --git a/spec/ruby/shared/file/executable.rb b/spec/ruby/shared/file/executable.rb index baa156de98..7b5c4c580c 100644 --- a/spec/ruby/shared/file/executable.rb +++ b/spec/ruby/shared/file/executable.rb @@ -39,41 +39,6 @@ describe :file_executable, shared: true do -> { @object.send(@method, nil) }.should raise_error(TypeError) -> { @object.send(@method, false) }.should raise_error(TypeError) end - - platform_is_not :windows do - as_superuser do - context "when run by a superuser" do - before :each do - @file = tmp('temp3.txt') - touch @file - end - - after :each do - rm_r @file - end - - it "returns true if file owner has permission to execute" do - File.chmod(0766, @file) - @object.send(@method, @file).should == true - end - - it "returns true if group has permission to execute" do - File.chmod(0676, @file) - @object.send(@method, @file).should == true - end - - it "returns true if other have permission to execute" do - File.chmod(0667, @file) - @object.send(@method, @file).should == true - end - - it "return false if nobody has permission to execute" do - File.chmod(0666, @file) - @object.send(@method, @file).should == false - end - end - end - end end describe :file_executable_missing, shared: true do diff --git a/spec/ruby/shared/file/executable_real.rb b/spec/ruby/shared/file/executable_real.rb index bf2734ea07..ce3d5ca176 100644 --- a/spec/ruby/shared/file/executable_real.rb +++ b/spec/ruby/shared/file/executable_real.rb @@ -37,41 +37,6 @@ describe :file_executable_real, shared: true do -> { @object.send(@method, nil) }.should raise_error(TypeError) -> { @object.send(@method, false) }.should raise_error(TypeError) end - - platform_is_not :windows do - as_real_superuser do - context "when run by a real superuser" do - before :each do - @file = tmp('temp3.txt') - touch @file - end - - after :each do - rm_r @file - end - - it "returns true if file owner has permission to execute" do - File.chmod(0766, @file) - @object.send(@method, @file).should == true - end - - it "returns true if group has permission to execute" do - File.chmod(0676, @file) - @object.send(@method, @file).should == true - end - - it "returns true if other have permission to execute" do - File.chmod(0667, @file) - @object.send(@method, @file).should == true - end - - it "return false if nobody has permission to execute" do - File.chmod(0666, @file) - @object.send(@method, @file).should == false - end - end - end - end end describe :file_executable_real_missing, shared: true do diff --git a/spec/ruby/shared/file/exist.rb b/spec/ruby/shared/file/exist.rb index 67424146c5..3bd97711b4 100644 --- a/spec/ruby/shared/file/exist.rb +++ b/spec/ruby/shared/file/exist.rb @@ -4,6 +4,11 @@ describe :file_exist, shared: true do @object.send(@method, 'a_fake_file').should == false end + it "returns true if the file exist using the alias exists?" do + @object.send(@method, __FILE__).should == true + @object.send(@method, 'a_fake_file').should == false + end + it "raises an ArgumentError if not passed one argument" do -> { @object.send(@method) }.should raise_error(ArgumentError) -> { @object.send(@method, __FILE__, __FILE__) }.should raise_error(ArgumentError) diff --git a/spec/ruby/shared/file/readable.rb b/spec/ruby/shared/file/readable.rb index 7b45e23e36..eb2ca06812 100644 --- a/spec/ruby/shared/file/readable.rb +++ b/spec/ruby/shared/file/readable.rb @@ -24,22 +24,6 @@ describe :file_readable, shared: true do it "accepts an object that has a #to_path method" do @object.send(@method, mock_to_path(@file2)).should == true end - - platform_is_not :windows do - as_superuser do - context "when run by a superuser" do - it "returns true unconditionally" do - file = tmp('temp.txt') - touch file - - File.chmod(0333, file) - @object.send(@method, file).should == true - - rm_r file - end - end - end - end end describe :file_readable_missing, shared: true do diff --git a/spec/ruby/shared/file/readable_real.rb b/spec/ruby/shared/file/readable_real.rb index 32d38bc7a2..b6e53ac76d 100644 --- a/spec/ruby/shared/file/readable_real.rb +++ b/spec/ruby/shared/file/readable_real.rb @@ -14,22 +14,6 @@ describe :file_readable_real, shared: true do it "accepts an object that has a #to_path method" do File.open(@file,'w') { @object.send(@method, mock_to_path(@file)).should == true } end - - platform_is_not :windows do - as_real_superuser do - context "when run by a real superuser" do - it "returns true unconditionally" do - file = tmp('temp.txt') - touch file - - File.chmod(0333, file) - @object.send(@method, file).should == true - - rm_r file - end - end - end - end end describe :file_readable_real_missing, shared: true do diff --git a/spec/ruby/shared/file/writable.rb b/spec/ruby/shared/file/writable.rb index 65ea2c1781..4bb8aedce6 100644 --- a/spec/ruby/shared/file/writable.rb +++ b/spec/ruby/shared/file/writable.rb @@ -19,22 +19,6 @@ describe :file_writable, shared: true do it "accepts an object that has a #to_path method" do File.open(@file,'w') { @object.send(@method, mock_to_path(@file)).should == true } end - - platform_is_not :windows do - as_superuser do - context "when run by a superuser" do - it "returns true unconditionally" do - file = tmp('temp.txt') - touch file - - File.chmod(0555, file) - @object.send(@method, file).should == true - - rm_r file - end - end - end - end end describe :file_writable_missing, shared: true do diff --git a/spec/ruby/shared/file/writable_real.rb b/spec/ruby/shared/file/writable_real.rb index b4a0a58c6e..e9721fd379 100644 --- a/spec/ruby/shared/file/writable_real.rb +++ b/spec/ruby/shared/file/writable_real.rb @@ -24,22 +24,6 @@ describe :file_writable_real, shared: true do -> { @object.send(@method, nil) }.should raise_error(TypeError) -> { @object.send(@method, false) }.should raise_error(TypeError) end - - platform_is_not :windows do - as_real_superuser do - context "when run by a real superuser" do - it "returns true unconditionally" do - file = tmp('temp.txt') - touch file - - File.chmod(0555, file) - @object.send(@method, file).should == true - - rm_r file - end - end - end - end end describe :file_writable_real_missing, shared: true do diff --git a/spec/ruby/shared/kernel/at_exit.rb b/spec/ruby/shared/kernel/at_exit.rb deleted file mode 100644 index 26ad361a5b..0000000000 --- a/spec/ruby/shared/kernel/at_exit.rb +++ /dev/null @@ -1,67 +0,0 @@ -describe :kernel_at_exit, shared: true do - it "runs after all other code" do - ruby_exe("#{@method} { print 5 }; print 6").should == "65" - end - - it "runs in reverse order of registration" do - code = "#{@method} { print 4 }; #{@method} { print 5 }; print 6; #{@method} { print 7 }" - ruby_exe(code).should == "6754" - end - - it "allows calling exit inside a handler" do - code = "#{@method} { print 3 }; #{@method} { print 4; exit; print 5 }; #{@method} { print 6 }" - ruby_exe(code).should == "643" - end - - it "gives access to the last raised exception - global variables $! and $@" do - code = <<-EOC - #{@method} { - puts "The exception matches: \#{$! == $exception && $@ == $exception.backtrace} (message=\#{$!.message})" - } - - begin - raise "foo" - rescue => $exception - raise - end - EOC - - result = ruby_exe(code, args: "2>&1", exit_status: 1) - result.lines.should.include?("The exception matches: true (message=foo)\n") - end - - it "both exceptions in a handler and in the main script are printed" do - code = "#{@method} { raise 'at_exit_error' }; raise 'main_script_error'" - result = ruby_exe(code, args: "2>&1", exit_status: 1) - result.should.include?('at_exit_error (RuntimeError)') - result.should.include?('main_script_error (RuntimeError)') - end - - it "decides the exit status if both at_exit and the main script raise SystemExit" do - ruby_exe("#{@method} { exit 43 }; exit 42", args: "2>&1", exit_status: 43) - $?.exitstatus.should == 43 - end - - it "runs all handlers even if some raise exceptions" do - code = "#{@method} { STDERR.puts 'last' }; #{@method} { exit 43 }; #{@method} { STDERR.puts 'first' }; exit 42" - result = ruby_exe(code, args: "2>&1", exit_status: 43) - result.should == "first\nlast\n" - $?.exitstatus.should == 43 - end - - it "runs handlers even if the main script fails to parse" do - script = fixture(__FILE__, "#{@method}.rb") - result = ruby_exe('{', options: "-r#{script}", args: "2>&1", exit_status: 1) - $?.should_not.success? - result.should.include?("handler ran\n") - result.should.include?("syntax error") - end - - it "calls the nested handler right after the outer one if a handler is nested into another handler" do - ruby_exe(<<~ruby).should == "last\nbefore\nafter\nnested\nfirst\n" - #{@method} { puts :first } - #{@method} { puts :before; #{@method} { puts :nested }; puts :after }; - #{@method} { puts :last } - ruby - end -end diff --git a/spec/ruby/shared/kernel/complex.rb b/spec/ruby/shared/kernel/complex.rb deleted file mode 100644 index 98ee0b2b3f..0000000000 --- a/spec/ruby/shared/kernel/complex.rb +++ /dev/null @@ -1,133 +0,0 @@ -# Specs shared by Kernel#Complex() and String#to_c() -describe :kernel_complex, shared: true do - - it "returns a Complex object" do - @object.send(@method, '9').should be_an_instance_of(Complex) - end - - it "understands integers" do - @object.send(@method, '20').should == Complex(20) - end - - it "understands negative integers" do - @object.send(@method, '-3').should == Complex(-3) - end - - it "understands fractions (numerator/denominator) for the real part" do - @object.send(@method, '2/3').should == Complex(Rational(2, 3)) - end - - it "understands fractions (numerator/denominator) for the imaginary part" do - @object.send(@method, '4+2/3i').should == Complex(4, Rational(2, 3)) - end - - it "understands negative fractions (-numerator/denominator) for the real part" do - @object.send(@method, '-2/3').should == Complex(Rational(-2, 3)) - end - - it "understands negative fractions (-numerator/denominator) for the imaginary part" do - @object.send(@method, '7-2/3i').should == Complex(7, Rational(-2, 3)) - end - - it "understands floats (a.b) for the real part" do - @object.send(@method, '2.3').should == Complex(2.3) - end - - it "understands floats (a.b) for the imaginary part" do - @object.send(@method, '4+2.3i').should == Complex(4, 2.3) - end - - it "understands negative floats (-a.b) for the real part" do - @object.send(@method, '-2.33').should == Complex(-2.33) - end - - it "understands negative floats (-a.b) for the imaginary part" do - @object.send(@method, '7-28.771i').should == Complex(7, -28.771) - end - - it "understands an integer followed by 'i' to mean that integer is the imaginary part" do - @object.send(@method, '35i').should == Complex(0,35) - end - - it "understands a negative integer followed by 'i' to mean that negative integer is the imaginary part" do - @object.send(@method, '-29i').should == Complex(0,-29) - end - - it "understands an 'i' by itself as denoting a complex number with an imaginary part of 1" do - @object.send(@method, 'i').should == Complex(0,1) - end - - it "understands a '-i' by itself as denoting a complex number with an imaginary part of -1" do - @object.send(@method, '-i').should == Complex(0,-1) - end - - it "understands 'a+bi' to mean a complex number with 'a' as the real part, 'b' as the imaginary" do - @object.send(@method, '79+4i').should == Complex(79,4) - end - - it "understands 'a-bi' to mean a complex number with 'a' as the real part, '-b' as the imaginary" do - @object.send(@method, '79-4i').should == Complex(79,-4) - end - - it "understands 'a+i' to mean a complex number with 'a' as the real part, 1i as the imaginary" do - @object.send(@method, '79+i').should == Complex(79, 1) - end - - it "understands 'a-i' to mean a complex number with 'a' as the real part, -1i as the imaginary" do - @object.send(@method, '79-i').should == Complex(79, -1) - end - - it "understands i, I, j, and J imaginary units" do - @object.send(@method, '79+4i').should == Complex(79, 4) - @object.send(@method, '79+4I').should == Complex(79, 4) - @object.send(@method, '79+4j').should == Complex(79, 4) - @object.send(@method, '79+4J').should == Complex(79, 4) - end - - it "understands scientific notation for the real part" do - @object.send(@method, '2e3+4i').should == Complex(2e3,4) - end - - it "understands negative scientific notation for the real part" do - @object.send(@method, '-2e3+4i').should == Complex(-2e3,4) - end - - it "understands scientific notation for the imaginary part" do - @object.send(@method, '4+2e3i').should == Complex(4, 2e3) - end - - it "understands negative scientific notation for the imaginary part" do - @object.send(@method, '4-2e3i').should == Complex(4, -2e3) - end - - it "understands scientific notation for the real and imaginary part in the same String" do - @object.send(@method, '2e3+2e4i').should == Complex(2e3,2e4) - end - - it "understands negative scientific notation for the real and imaginary part in the same String" do - @object.send(@method, '-2e3-2e4i').should == Complex(-2e3,-2e4) - end - - it "understands scientific notation with e and E" do - @object.send(@method, '2e3+2e4i').should == Complex(2e3, 2e4) - @object.send(@method, '2E3+2E4i').should == Complex(2e3, 2e4) - end - - it "understands 'm@a' to mean a complex number in polar form with 'm' as the modulus, 'a' as the argument" do - @object.send(@method, '79@4').should == Complex.polar(79, 4) - @object.send(@method, '-79@4').should == Complex.polar(-79, 4) - @object.send(@method, '79@-4').should == Complex.polar(79, -4) - end - - it "ignores leading whitespaces" do - @object.send(@method, ' 79+4i').should == Complex(79, 4) - end - - it "ignores trailing whitespaces" do - @object.send(@method, '79+4i ').should == Complex(79, 4) - end - - it "understands _" do - @object.send(@method, '7_9+4_0i').should == Complex(79, 40) - end -end diff --git a/spec/ruby/shared/kernel/fixtures/END.rb b/spec/ruby/shared/kernel/fixtures/END.rb deleted file mode 100644 index cc8ac17c36..0000000000 --- a/spec/ruby/shared/kernel/fixtures/END.rb +++ /dev/null @@ -1,3 +0,0 @@ -END { - STDERR.puts "handler ran" -} diff --git a/spec/ruby/shared/kernel/fixtures/at_exit.rb b/spec/ruby/shared/kernel/fixtures/at_exit.rb deleted file mode 100644 index e7bc8baf52..0000000000 --- a/spec/ruby/shared/kernel/fixtures/at_exit.rb +++ /dev/null @@ -1,3 +0,0 @@ -at_exit do - STDERR.puts "handler ran" -end diff --git a/spec/ruby/shared/kernel/raise.rb b/spec/ruby/shared/kernel/raise.rb index 82fb0333c8..765ba0f929 100644 --- a/spec/ruby/shared/kernel/raise.rb +++ b/spec/ruby/shared/kernel/raise.rb @@ -29,41 +29,11 @@ describe :kernel_raise, shared: true do @data = data end end - - -> { @object.raise(data_error, {data: 42}) }.should raise_error(data_error) do |ex| - ex.data.should == {data: 42} - end - end - - # https://bugs.ruby-lang.org/issues/8257#note-36 - it "allows extra keyword arguments for compatibility" do - data_error = Class.new(StandardError) do - attr_reader :data - def initialize(data) - @data = data - end - end - - -> { @object.raise(data_error, data: 42) }.should raise_error(data_error) do |ex| - ex.data.should == {data: 42} + -> { @object.raise(data_error, {:data => 42}) }.should raise_error(data_error) do |ex| + ex.data.should == {:data => 42} end end - it "does not allow message and extra keyword arguments" do - data_error = Class.new(StandardError) do - attr_reader :data - def initialize(data) - @data = data - end - end - - -> { @object.raise(data_error, {a: 1}, b: 2) }.should raise_error(StandardError) do |e| - [TypeError, ArgumentError].should.include?(e.class) - end - - -> { @object.raise(data_error, {a: 1}, [], b: 2) }.should raise_error(ArgumentError) - end - it "raises RuntimeError if no exception class is given" do -> { @object.raise }.should raise_error(RuntimeError, "") end diff --git a/spec/ruby/shared/process/exit.rb b/spec/ruby/shared/process/exit.rb index 1e073614a3..ae8abaea40 100644 --- a/spec/ruby/shared/process/exit.rb +++ b/spec/ruby/shared/process/exit.rb @@ -21,12 +21,6 @@ describe :process_exit, shared: true do end end - it "raises a SystemExit with message 'exit'" do - -> { @object.exit }.should raise_error(SystemExit) { |e| - e.message.should == "exit" - } - end - it "tries to convert the passed argument to an Integer using #to_int" do obj = mock('5') obj.should_receive(:to_int).and_return(5) @@ -104,12 +98,6 @@ describe :process_exit!, shared: true do $?.exitstatus.should == 21 end - it "skips ensure clauses" do - out = ruby_exe("begin; STDERR.puts 'before'; #{@object}.send(:exit!, 21); ensure; STDERR.puts 'ensure'; end", args: '2>&1', exit_status: 21) - out.should == "before\n" - $?.exitstatus.should == 21 - end - it "overrides the original exception and exit status when called from #at_exit" do code = <<-RUBY at_exit do diff --git a/spec/ruby/shared/queue/deque.rb b/spec/ruby/shared/queue/deque.rb index 9e6b45009d..8b755dd9b7 100644 --- a/spec/ruby/shared/queue/deque.rb +++ b/spec/ruby/shared/queue/deque.rb @@ -37,15 +37,6 @@ describe :queue_deq, shared: true do q.send(@method).should == 1 end - it "converts false-ish for non_blocking to boolean" do - q = @object.call - q << 1 - q << 2 - - q.send(@method, false).should == 1 - q.send(@method, nil).should == 2 - end - it "returns nil for a closed empty queue" do q = @object.call q.close @@ -64,74 +55,6 @@ describe :queue_deq, shared: true do t.join end - describe "with a timeout" do - ruby_version_is "3.2" do - it "returns an item if one is available in time" do - q = @object.call - - t = Thread.new { - q.send(@method, timeout: 1).should == 1 - } - Thread.pass until t.status == "sleep" && q.num_waiting == 1 - q << 1 - t.join - end - - it "returns nil if no item is available in time" do - q = @object.call - - t = Thread.new { - q.send(@method, timeout: 0.1).should == nil - } - t.join - end - - it "does nothing if the timeout is nil" do - q = @object.call - t = Thread.new { - q.send(@method, timeout: nil).should == 1 - } - t.join(0.2).should == nil - q << 1 - t.join - end - - it "immediately returns nil if no item is available and the timeout is 0" do - q = @object.call - q << 1 - q.send(@method, timeout: 0).should == 1 - q.send(@method, timeout: 0).should == nil - end - - it "raise TypeError if timeout is not a valid numeric" do - q = @object.call - -> { q.send(@method, timeout: "1") }.should raise_error( - TypeError, - "no implicit conversion to float from string", - ) - - -> { q.send(@method, timeout: false) }.should raise_error( - TypeError, - "no implicit conversion to float from false", - ) - end - - it "raise ArgumentError if non_block = true is passed too" do - q = @object.call - -> { q.send(@method, true, timeout: 1) }.should raise_error( - ArgumentError, - "can't set a timeout if non_block is enabled", - ) - end - - it "returns nil for a closed empty queue" do - q = @object.call - q.close - q.send(@method, timeout: 0).should == nil - end - end - end - describe "in non-blocking mode" do it "removes an item from the queue" do q = @object.call @@ -158,13 +81,5 @@ describe :queue_deq, shared: true do q.close -> { q.send(@method, true) }.should raise_error(ThreadError) end - - it "converts true-ish non_blocking argument to true" do - q = @object.call - - -> { q.send(@method, true) }.should raise_error(ThreadError) - -> { q.send(@method, 1) }.should raise_error(ThreadError) - -> { q.send(@method, "") }.should raise_error(ThreadError) - end end end diff --git a/spec/ruby/shared/rational/Rational.rb b/spec/ruby/shared/rational/Rational.rb index 500f7ed271..936a90c086 100644 --- a/spec/ruby/shared/rational/Rational.rb +++ b/spec/ruby/shared/rational/Rational.rb @@ -65,45 +65,40 @@ describe :kernel_Rational, shared: true do r_s.should == r r_s.should_not == f_r end - end - describe "when passed a Numeric" do - it "calls #to_r to convert the first argument to a Rational" do - num = RationalSpecs::SubNumeric.new(2) + describe "when passed a Numeric" do + it "calls #to_r to convert the first argument to a Rational" do + num = RationalSpecs::SubNumeric.new(2) - Rational(num).should == Rational(2) + Rational(num).should == Rational(2) + end end - end - describe "when passed a Complex" do - it "returns a Rational from the real part if the imaginary part is 0" do - Rational(Complex(1, 0)).should == Rational(1) - end + describe "when passed a Complex" do + it "returns a Rational from the real part if the imaginary part is 0" do + Rational(Complex(1, 0)).should == Rational(1) + end - it "raises a RangeError if the imaginary part is not 0" do - -> { Rational(Complex(1, 2)) }.should raise_error(RangeError) + it "raises a RangeError if the imaginary part is not 0" do + -> { Rational(Complex(1, 2)) }.should raise_error(RangeError) + end end - end - - it "raises a ZeroDivisionError if the second argument is 0" do - -> { Rational(1, 0) }.should raise_error(ZeroDivisionError, "divided by 0") - -> { Rational(1, 0.0) }.should raise_error(ZeroDivisionError, "divided by 0") - end - it "raises a TypeError if the first argument is nil" do - -> { Rational(nil) }.should raise_error(TypeError) - end + it "raises a TypeError if the first argument is nil" do + -> { Rational(nil) }.should raise_error(TypeError) + end - it "raises a TypeError if the second argument is nil" do - -> { Rational(1, nil) }.should raise_error(TypeError) - end + it "raises a TypeError if the second argument is nil" do + -> { Rational(1, nil) }.should raise_error(TypeError) + end - it "raises a TypeError if the first argument is a Symbol" do - -> { Rational(:sym) }.should raise_error(TypeError) - end + it "raises a TypeError if the first argument is a Symbol" do + -> { Rational(:sym) }.should raise_error(TypeError) + end - it "raises a TypeError if the second argument is a Symbol" do - -> { Rational(1, :sym) }.should raise_error(TypeError) + it "raises a TypeError if the second argument is a Symbol" do + -> { Rational(1, :sym) }.should raise_error(TypeError) + end end describe "when passed exception: false" do @@ -143,8 +138,4 @@ describe :kernel_Rational, shared: true do end end end - - it "freezes its result" do - Rational(1).frozen?.should == true - end end diff --git a/spec/ruby/shared/rational/divmod.rb b/spec/ruby/shared/rational/divmod.rb index 9e23a18186..471cd7a967 100644 --- a/spec/ruby/shared/rational/divmod.rb +++ b/spec/ruby/shared/rational/divmod.rb @@ -6,7 +6,7 @@ describe :rational_divmod_rat, shared: true do Rational(7, 4).divmod(Rational(-1, 2)).should eql([-4, Rational(-1, 4)]) Rational(0, 4).divmod(Rational(4, 3)).should eql([0, Rational(0, 1)]) - Rational(bignum_value, 4).divmod(Rational(4, 3)).should eql([3458764513820540928, Rational(0, 1)]) + Rational(bignum_value, 4).divmod(Rational(4, 3)).should eql([1729382256910270464, Rational(0, 1)]) end it "raises a ZeroDivisionError when passed a Rational with a numerator of 0" do @@ -19,7 +19,7 @@ describe :rational_divmod_int, shared: true do Rational(7, 4).divmod(2).should eql([0, Rational(7, 4)]) Rational(7, 4).divmod(-2).should eql([-1, Rational(-1, 4)]) - Rational(bignum_value, 4).divmod(3).should eql([1537228672809129301, Rational(1, 1)]) + Rational(bignum_value, 4).divmod(3).should == [768614336404564650, Rational(2, 1)] end it "raises a ZeroDivisionError when passed 0" do diff --git a/spec/ruby/shared/rational/exponent.rb b/spec/ruby/shared/rational/exponent.rb index b0e9b23574..3fd02de08f 100644 --- a/spec/ruby/shared/rational/exponent.rb +++ b/spec/ruby/shared/rational/exponent.rb @@ -40,10 +40,10 @@ describe :rational_exponent, shared: true do (Rational(-3, 4) ** -4).should == Rational(256, 81) (Rational(3, -4) ** -4).should == Rational(256, 81) - (Rational(bignum_value, 4) ** 4).should == Rational(452312848583266388373324160190187140051835877600158453279131187530910662656, 1) - (Rational(3, bignum_value) ** -4).should == Rational(115792089237316195423570985008687907853269984665640564039457584007913129639936, 81) - (Rational(-bignum_value, 4) ** -4).should == Rational(1, 452312848583266388373324160190187140051835877600158453279131187530910662656) - (Rational(3, -bignum_value) ** -4).should == Rational(115792089237316195423570985008687907853269984665640564039457584007913129639936, 81) + (Rational(bignum_value, 4) ** 4).should == Rational(28269553036454149273332760011886696253239742350009903329945699220681916416, 1) + (Rational(3, bignum_value) ** -4).should == Rational(7237005577332262213973186563042994240829374041602535252466099000494570602496, 81) + (Rational(-bignum_value, 4) ** -4).should == Rational(1, 28269553036454149273332760011886696253239742350009903329945699220681916416) + (Rational(3, -bignum_value) ** -4).should == Rational(7237005577332262213973186563042994240829374041602535252466099000494570602496, 81) end # Guard against the Mathn library diff --git a/spec/ruby/shared/rational/marshal_dump.rb b/spec/ruby/shared/rational/marshal_dump.rb new file mode 100644 index 0000000000..09782b45a5 --- /dev/null +++ b/spec/ruby/shared/rational/marshal_dump.rb @@ -0,0 +1,5 @@ +require_relative '../../spec_helper' + +describe :rational_marshal_dump, shared: true do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/shared/rational/marshal_load.rb b/spec/ruby/shared/rational/marshal_load.rb new file mode 100644 index 0000000000..20bdd6fdf4 --- /dev/null +++ b/spec/ruby/shared/rational/marshal_load.rb @@ -0,0 +1,5 @@ +require_relative '../../spec_helper' + +describe :rational_marshal_load, shared: true do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/shared/rational/minus.rb b/spec/ruby/shared/rational/minus.rb new file mode 100644 index 0000000000..0a0946fdb9 --- /dev/null +++ b/spec/ruby/shared/rational/minus.rb @@ -0,0 +1,48 @@ +require_relative '../../spec_helper' + +describe :rational_minus_rat, shared: true 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_minus_int, shared: true 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 + +describe :rational_minus_float, shared: true 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_minus, shared: true do + 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 diff --git a/spec/ruby/shared/rational/quo.rb b/spec/ruby/shared/rational/quo.rb new file mode 100644 index 0000000000..53b32fed2f --- /dev/null +++ b/spec/ruby/shared/rational/quo.rb @@ -0,0 +1,5 @@ +require_relative '../../spec_helper' + +describe :rational_quo, shared: true do + it "needs to be reviewed for spec completeness" +end diff --git a/spec/ruby/shared/rational/to_f.rb b/spec/ruby/shared/rational/to_f.rb index 472a585daa..56e0b61d68 100644 --- a/spec/ruby/shared/rational/to_f.rb +++ b/spec/ruby/shared/rational/to_f.rb @@ -7,10 +7,4 @@ describe :rational_to_f, shared: true do Rational(-1, 4).to_f.should eql(-0.25) Rational(-1, -4).to_f.should eql(0.25) end - - it "converts to a Float for large numerator and denominator" do - num = 1000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146010000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146010000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146009 - den = 2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 - Rational(num, den).to_f.should == 500.0 - end end diff --git a/spec/ruby/shared/rational/truncate.rb b/spec/ruby/shared/rational/truncate.rb index df5198ca02..761dd3113a 100644 --- a/spec/ruby/shared/rational/truncate.rb +++ b/spec/ruby/shared/rational/truncate.rb @@ -17,18 +17,6 @@ describe :rational_truncate, shared: true do end end - describe "with an explicit precision = 0" do - it "returns an integer" do - @rational.truncate(0).should be_kind_of(Integer) - end - - it "returns the truncated value toward 0" do - @rational.truncate(0).should == 314 - Rational(1, 2).truncate(0).should == 0 - Rational(-1, 2).truncate(0).should == 0 - end - end - describe "with a precision < 0" do it "returns an integer" do @rational.truncate(-2).should be_kind_of(Integer) @@ -54,18 +42,4 @@ describe :rational_truncate, shared: true do @rational.truncate(3).should == Rational(62857, 200) end end - - describe "with an invalid value for precision" do - it "raises a TypeError" do - -> { @rational.truncate(nil) }.should raise_error(TypeError, "not an integer") - -> { @rational.truncate(1.0) }.should raise_error(TypeError, "not an integer") - -> { @rational.truncate('') }.should raise_error(TypeError, "not an integer") - end - - it "does not call to_int on the argument" do - object = Object.new - object.should_not_receive(:to_int) - -> { @rational.truncate(object) }.should raise_error(TypeError, "not an integer") - end - end end diff --git a/spec/ruby/shared/sizedqueue/enque.rb b/spec/ruby/shared/sizedqueue/enque.rb index 6307f3c3ca..6ef12349f8 100644 --- a/spec/ruby/shared/sizedqueue/enque.rb +++ b/spec/ruby/shared/sizedqueue/enque.rb @@ -37,7 +37,7 @@ describe :sizedqueue_enq, shared: true do q << 1 t = Thread.new { - -> { q.send(@method, 2) }.should raise_error(ClosedQueueError, "queue closed") + -> { q.send(@method, 2) }.should raise_error(ClosedQueueError) } Thread.pass until q.num_waiting == 1 @@ -47,89 +47,4 @@ describe :sizedqueue_enq, shared: true do t.join q.pop.should == 1 end - - describe "with a timeout" do - ruby_version_is "3.2" do - it "returns self if the item was pushed in time" do - q = @object.call(1) - q << 1 - - t = Thread.new { - q.send(@method, 2, timeout: 1).should == q - } - Thread.pass until t.status == "sleep" && q.num_waiting == 1 - q.pop - t.join - end - - it "does nothing if the timeout is nil" do - q = @object.call(1) - q << 1 - t = Thread.new { - q.send(@method, 2, timeout: nil).should == q - } - t.join(0.2).should == nil - q.pop - t.join - end - - it "returns nil if no space is available and timeout is 0" do - q = @object.call(1) - q.send(@method, 1, timeout: 0).should == q - q.send(@method, 2, timeout: 0).should == nil - end - - it "returns nil if no space is available in time" do - q = @object.call(1) - q << 1 - t = Thread.new { - q.send(@method, 2, timeout: 0.1).should == nil - } - t.join - end - - it "raise TypeError if timeout is not a valid numeric" do - q = @object.call(1) - -> { q.send(@method, 2, timeout: "1") }.should raise_error( - TypeError, - "no implicit conversion to float from string", - ) - - -> { q.send(@method, 2, timeout: false) }.should raise_error( - TypeError, - "no implicit conversion to float from false", - ) - end - - it "raise ArgumentError if non_block = true is passed too" do - q = @object.call(1) - -> { q.send(@method, 2, true, timeout: 1) }.should raise_error( - ArgumentError, - "can't set a timeout if non_block is enabled", - ) - end - - it "raise ClosedQueueError when closed before enqueued" do - q = @object.call(1) - q.close - -> { q.send(@method, 2, timeout: 1) }.should raise_error(ClosedQueueError, "queue closed") - end - - it "interrupts enqueuing threads with ClosedQueueError when the queue is closed" do - q = @object.call(1) - q << 1 - - t = Thread.new { - -> { q.send(@method, 1, timeout: 10) }.should raise_error(ClosedQueueError, "queue closed") - } - - Thread.pass until q.num_waiting == 1 - - q.close - - t.join - q.pop.should == 1 - end - end - end end diff --git a/spec/ruby/shared/sizedqueue/new.rb b/spec/ruby/shared/sizedqueue/new.rb index 2573194efb..713785fb50 100644 --- a/spec/ruby/shared/sizedqueue/new.rb +++ b/spec/ruby/shared/sizedqueue/new.rb @@ -1,12 +1,7 @@ describe :sizedqueue_new, shared: true do - it "raises a TypeError when the given argument doesn't respond to #to_int" do - -> { @object.call("12") }.should raise_error(TypeError) + it "raises a TypeError when the given argument is not Numeric" do + -> { @object.call("foo") }.should raise_error(TypeError) -> { @object.call(Object.new) }.should raise_error(TypeError) - - @object.call(12.9).max.should == 12 - object = Object.new - object.define_singleton_method(:to_int) { 42 } - @object.call(object).max.should == 42 end it "raises an argument error when no argument is given" do diff --git a/spec/ruby/shared/string/end_with.rb b/spec/ruby/shared/string/end_with.rb index 0e4c1386e8..5f2a011235 100644 --- a/spec/ruby/shared/string/end_with.rb +++ b/spec/ruby/shared/string/end_with.rb @@ -38,7 +38,7 @@ describe :end_with, shared: true do it "uses only the needed arguments" do find = mock('h') find.should_not_receive(:to_str) - "hello".send(@method).should.end_with?("o", find) + "hello".send(@method).should.end_with?("o",find) end it "works for multibyte strings" do @@ -51,11 +51,4 @@ describe :end_with, shared: true do "あれ".send(@method).end_with?(pat) end.should raise_error(Encoding::CompatibilityError) end - - it "checks that we are starting to match at the head of a character" do - "\xC3\xA9".send(@method).should_not.end_with?("\xA9") - "\xe3\x81\x82".send(@method).should_not.end_with?("\x82") - "ab".force_encoding("UTF-16BE").send(@method).should_not.end_with?( - "b".force_encoding("UTF-16BE")) - end end diff --git a/spec/ruby/shared/string/start_with.rb b/spec/ruby/shared/string/start_with.rb index 4b947a3bbf..d8d6e13f6a 100644 --- a/spec/ruby/shared/string/start_with.rb +++ b/spec/ruby/shared/string/start_with.rb @@ -69,16 +69,4 @@ describe :start_with, shared: true do Regexp.last_match.should be_nil $1.should be_nil end - - ruby_version_is ""..."3.3" do - it "does not check that we are not matching part of a character" do - "\xC3\xA9".send(@method).should.start_with?("\xC3") - end - end - - ruby_version_is "3.3" do # #19784 - it "checks that we are not matching part of a character" do - "\xC3\xA9".send(@method).should_not.start_with?("\xC3") - end - end end diff --git a/spec/ruby/shared/string/times.rb b/spec/ruby/shared/string/times.rb index be3b622f73..cd4edf5340 100644 --- a/spec/ruby/shared/string/times.rb +++ b/spec/ruby/shared/string/times.rb @@ -32,10 +32,32 @@ describe :string_times, shared: true do @object.call("", max_long).should == "" end - it "returns String instances" do - @object.call(MyString.new("cool"), 0).should be_an_instance_of(String) - @object.call(MyString.new("cool"), 1).should be_an_instance_of(String) - @object.call(MyString.new("cool"), 2).should be_an_instance_of(String) + ruby_version_is ''...'3.0' do + it "returns subclass instances" do + @object.call(MyString.new("cool"), 0).should be_an_instance_of(MyString) + @object.call(MyString.new("cool"), 1).should be_an_instance_of(MyString) + @object.call(MyString.new("cool"), 2).should be_an_instance_of(MyString) + end + end + + ruby_version_is '3.0' do + it "returns String instances" do + @object.call(MyString.new("cool"), 0).should be_an_instance_of(String) + @object.call(MyString.new("cool"), 1).should be_an_instance_of(String) + @object.call(MyString.new("cool"), 2).should be_an_instance_of(String) + end + end + + ruby_version_is ''...'2.7' do + it "always taints the result when self is tainted" do + ["", "OK", MyString.new(""), MyString.new("OK")].each do |str| + str.taint + + [0, 1, 2].each do |arg| + @object.call(str, arg).should.tainted? + end + end + end end it "returns a String in the same encoding as self" do diff --git a/spec/ruby/shared/types/rb_num2dbl_fails.rb b/spec/ruby/shared/types/rb_num2dbl_fails.rb deleted file mode 100644 index ec7cc11986..0000000000 --- a/spec/ruby/shared/types/rb_num2dbl_fails.rb +++ /dev/null @@ -1,17 +0,0 @@ -# -# Shared tests for rb_num2dbl related conversion failures. -# -# Usage example: -# it_behaves_like :rb_num2dbl_fails, nil, -> v { o = A.new; o.foo(v) } -# - -describe :rb_num2dbl_fails, shared: true do - it "fails if string is provided" do - -> { @object.call("123") }.should raise_error(TypeError, "no implicit conversion to float from string") - end - - it "fails if boolean is provided" do - -> { @object.call(true) }.should raise_error(TypeError, "no implicit conversion to float from true") - -> { @object.call(false) }.should raise_error(TypeError, "no implicit conversion to float from false") - end -end diff --git a/spec/ruby/spec_helper.rb b/spec/ruby/spec_helper.rb index af1c385878..c38965d3c5 100644 --- a/spec/ruby/spec_helper.rb +++ b/spec/ruby/spec_helper.rb @@ -1,5 +1,5 @@ use_realpath = File.respond_to?(:realpath) -root = __dir__ +root = File.dirname(__FILE__) dir = "fixtures/code" CODE_LOADING_DIR = use_realpath ? File.realpath(dir, root) : File.expand_path(dir, root) @@ -14,7 +14,8 @@ else end end -unless ENV['MSPEC_RUNNER'] # Running directly with ruby some_spec.rb +# Running directly with ruby some_spec.rb +unless ENV['MSPEC_RUNNER'] mspec_lib = File.expand_path("../../mspec/lib", __FILE__) $LOAD_PATH << mspec_lib if File.directory?(mspec_lib) @@ -25,14 +26,7 @@ unless ENV['MSPEC_RUNNER'] # Running directly with ruby some_spec.rb puts "Please add -Ipath/to/mspec/lib or clone mspec as a sibling to run the specs." exit 1 end -end - -# Compare with SpecVersion directly here so it works even with --unguarded -if VersionGuard::FULL_RUBY_VERSION < SpecVersion.new('2.7') - abort "This version of ruby/spec requires Ruby 2.7+" -end -unless ENV['MSPEC_RUNNER'] # Running directly with ruby some_spec.rb ARGV.unshift $0 MSpecRun.main end |
