diff --git a/.github/workflows/spec_guards.yml b/.github/workflows/spec_guards.yml
index 856d6f61eb9303..0a5104f1419298 100644
--- a/.github/workflows/spec_guards.yml
+++ b/.github/workflows/spec_guards.yml
@@ -39,7 +39,6 @@ jobs:
# Specs from ruby/spec should still run on all supported Ruby versions.
# This also ensures the needed ruby_version_is guards are there, see spec/README.md.
ruby:
- - ruby-3.2
- ruby-3.3
- ruby-3.4
- ruby-4.0
diff --git a/ext/coverage/coverage.c b/ext/coverage/coverage.c
index 93acdb24806f78..41f33f4fb8c9f3 100644
--- a/ext/coverage/coverage.c
+++ b/ext/coverage/coverage.c
@@ -70,7 +70,7 @@ rb_coverage_supported(VALUE self, VALUE _mode)
* If +lines+ is enabled, +oneshot_lines+ cannot be enabled.
* See {Lines Coverage}[rdoc-ref:Coverage@Lines+Coverage].
* - +branches+: Enables branch coverage that records the number of times each
- * branch in each conditional was executed. See {Branches Coverage}[rdoc-ref:Coverage@Branch+Coverage].
+ * branch in each conditional was executed. See {Branches Coverage}[rdoc-ref:Coverage@Branches+Coverage].
* - +methods+: Enables method coverage that records the number of times each method was exectued.
* See {Methods Coverage}[rdoc-ref:Coverage@Methods+Coverage].
* - +eval+: Enables coverage for evaluations (e.g. Kernel#eval, Module#class_eval).
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index 5ab577f504c39d..639740e46b6b04 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -1077,7 +1077,7 @@ def converge_specs(specs)
end
end
- if parent_dep
+ if parent_dep && parent_dep.source.is_a?(Source::Path)
replacement_source = parent_dep.source
else
replacement_source = sources.get(lockfile_source)
diff --git a/lib/net/http/requests.rb b/lib/net/http/requests.rb
index 939d413f91961c..8dc79a9f665d52 100644
--- a/lib/net/http/requests.rb
+++ b/lib/net/http/requests.rb
@@ -19,9 +19,9 @@
#
# - Request body: optional.
# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: yes.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
#
# Related:
#
@@ -52,9 +52,9 @@ class Net::HTTP::Get < Net::HTTPRequest
#
# - Request body: optional.
# - Response body: no.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: yes.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
#
# Related:
#
@@ -87,9 +87,9 @@ class Net::HTTP::Head < Net::HTTPRequest
#
# - Request body: yes.
# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: no.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: yes.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: no.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: yes.
#
# Related:
#
@@ -123,9 +123,9 @@ class Net::HTTP::Post < Net::HTTPRequest
#
# - Request body: yes.
# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
@@ -157,9 +157,9 @@ class Net::HTTP::Put < Net::HTTPRequest
#
# - Request body: optional.
# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
@@ -189,9 +189,9 @@ class Net::HTTP::Delete < Net::HTTPRequest
#
# - Request body: optional.
# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
@@ -221,9 +221,9 @@ class Net::HTTP::Options < Net::HTTPRequest
#
# - Request body: no.
# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: yes.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: yes.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: yes.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: yes.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
@@ -256,9 +256,9 @@ class Net::HTTP::Trace < Net::HTTPRequest
#
# - Request body: yes.
# - Response body: yes.
-# - {Safe}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Safe_methods]: no.
-# - {Idempotent}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Idempotent_methods]: no.
-# - {Cacheable}[https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Cacheable_methods]: no.
+# - {Safe}[https://en.wikipedia.org/wiki/HTTP#Safe_method]: no.
+# - {Idempotent}[https://en.wikipedia.org/wiki/HTTP#Idempotent_method]: no.
+# - {Cacheable}[https://en.wikipedia.org/wiki/HTTP#Cacheable_method]: no.
#
# Related:
#
diff --git a/lib/open-uri.rb b/lib/open-uri.rb
index 5983c7368b1d35..844865b13ac0a1 100644
--- a/lib/open-uri.rb
+++ b/lib/open-uri.rb
@@ -4,22 +4,25 @@
require 'time'
module URI
- # Allows the opening of various resources including URIs.
+ # Allows the opening of various resources including URIs. Example:
#
- # If the first argument responds to the 'open' method, 'open' is called on
+ # require "open-uri"
+ # URI.open("http://example.com") { |f| f.read }
+ #
+ # If the first argument responds to the +open+ method, +open+ is called on
# it with the rest of the arguments.
#
# If the first argument is a string that begins with (protocol)://, it is parsed by
- # URI.parse. If the parsed object responds to the 'open' method,
- # 'open' is called on it with the rest of the arguments.
+ # URI.parse. If the parsed object responds to the +open+ method,
+ # +open+ is called on it with the rest of the arguments.
#
# Otherwise, Kernel#open is called.
#
# OpenURI::OpenRead#open provides URI::HTTP#open, URI::HTTPS#open and
# URI::FTP#open, Kernel#open.
#
- # We can accept URIs and strings that begin with http://, https:// and
- # ftp://. In these cases, the opened file object is extended by OpenURI::Meta.
+ # We can accept URIs and strings that begin with http://, https:// and
+ # ftp://. In these cases, the opened file object is extended by OpenURI::Meta.
def self.open(name, *rest, &block)
if name.respond_to?(:open)
name.open(*rest, &block)
diff --git a/lib/prism/ffi.rb b/lib/prism/ffi.rb
index d4c9d60c9aa2a4..57d878a33fa299 100644
--- a/lib/prism/ffi.rb
+++ b/lib/prism/ffi.rb
@@ -423,10 +423,26 @@ def dump_options_command_line(options)
# Return the value that should be dumped for the version option.
def dump_options_version(version)
- current = version == "current"
+ checking =
+ case version
+ when "current"
+ RUBY_VERSION
+ when "latest"
+ nil
+ when "nearest"
+ if RUBY_VERSION <= "3.3"
+ "3.3"
+ elsif RUBY_VERSION >= "4.1"
+ "4.1"
+ else
+ RUBY_VERSION
+ end
+ else
+ version
+ end
- case current ? RUBY_VERSION : version
- when nil, "latest"
+ case checking
+ when nil
0 # Handled in pm_parser_init
when /\A3\.3(\.\d+)?\z/
1
@@ -437,7 +453,7 @@ def dump_options_version(version)
when /\A4\.1(\.\d+)?\z/
4
else
- if current
+ if version == "current"
raise CurrentVersionError, RUBY_VERSION
else
raise ArgumentError, "invalid version: #{version}"
diff --git a/lib/rubygems/remote_fetcher.rb b/lib/rubygems/remote_fetcher.rb
index 805f7aaf82ed1a..151c6fd4d8bbdf 100644
--- a/lib/rubygems/remote_fetcher.rb
+++ b/lib/rubygems/remote_fetcher.rb
@@ -174,7 +174,7 @@ def download(spec, source_uri, install_dir = Gem.dir)
end
verbose "Using local gem #{local_gem_path}"
- when nil then # TODO: test for local overriding cache
+ when nil then
source_path = if Gem.win_platform? && source_uri.scheme &&
!source_uri.path.include?(":")
"#{source_uri.scheme}:#{source_uri.path}"
diff --git a/prism/extension.c b/prism/extension.c
index 400546a4ce0364..cde10bf360df2a 100644
--- a/prism/extension.c
+++ b/prism/extension.c
@@ -201,9 +201,24 @@ build_options_i(VALUE key, VALUE value, VALUE argument) {
const char *version = check_string(value);
if (RSTRING_LEN(value) == 7 && strncmp(version, "current", 7) == 0) {
- const char *current_version = RSTRING_PTR(rb_const_get(rb_cObject, rb_intern("RUBY_VERSION")));
- if (!pm_options_version_set(options, current_version, 3)) {
- rb_exc_raise(rb_exc_new_cstr(rb_cPrismCurrentVersionError, current_version));
+ const char *ruby_version = RSTRING_PTR(rb_const_get(rb_cObject, rb_intern("RUBY_VERSION")));
+ if (!pm_options_version_set(options, ruby_version, 3)) {
+ rb_exc_raise(rb_exc_new_cstr(rb_cPrismCurrentVersionError, ruby_version));
+ }
+ } else if (RSTRING_LEN(value) == 7 && strncmp(version, "nearest", 7) == 0) {
+ const char *ruby_version = RSTRING_PTR(rb_const_get(rb_cObject, rb_intern("RUBY_VERSION")));
+ const char *nearest_version;
+
+ if (ruby_version[0] < '3' || (ruby_version[0] == '3' && ruby_version[2] < '3')) {
+ nearest_version = "3.3";
+ } else if (ruby_version[0] > '4' || (ruby_version[0] == '4' && ruby_version[2] > '1')) {
+ nearest_version = "4.1";
+ } else {
+ nearest_version = ruby_version;
+ }
+
+ if (!pm_options_version_set(options, nearest_version, 3)) {
+ rb_raise(rb_eArgError, "invalid nearest version: %s", nearest_version);
}
} else if (!pm_options_version_set(options, version, RSTRING_LEN(value))) {
rb_raise(rb_eArgError, "invalid version: %" PRIsVALUE, value);
@@ -894,8 +909,10 @@ parse_input(pm_string_t *input, const pm_options_t *options) {
* version of Ruby syntax (which you can trigger with `nil` or
* `"latest"`). You may also restrict the syntax to a specific version of
* Ruby, e.g., with `"3.3.0"`. To parse with the same syntax version that
- * the current Ruby is running use `version: "current"`. Raises
- * ArgumentError if the version is not currently supported by Prism.
+ * the current Ruby is running use `version: "current"`. To parse with the
+ * nearest version to the current Ruby that is running, use
+ * `version: "nearest"`. Raises ArgumentError if the version is not
+ * currently supported by Prism.
*/
static VALUE
parse(int argc, VALUE *argv, VALUE self) {
diff --git a/prism/options.h b/prism/options.h
index c00c7bf7553a4f..9a19a2aeadf31a 100644
--- a/prism/options.h
+++ b/prism/options.h
@@ -82,7 +82,10 @@ typedef void (*pm_options_shebang_callback_t)(struct pm_options *options, const
* parse in the same way as a specific version of CRuby would have.
*/
typedef enum {
- /** If an explicit version is not provided, the current version of prism will be used. */
+ /**
+ * If an explicit version is not provided, the current version of prism will
+ * be used.
+ */
PM_OPTIONS_VERSION_UNSET = 0,
/** The vendored version of prism in CRuby 3.3.x. */
@@ -452,6 +455,9 @@ PRISM_EXPORTED_FUNCTION void pm_options_free(pm_options_t *options);
* | ----- | ------------------------- |
* | `0` | use the latest version of prism |
* | `1` | use the version of prism that is vendored in CRuby 3.3.0 |
+ * | `2` | use the version of prism that is vendored in CRuby 3.4.0 |
+ * | `3` | use the version of prism that is vendored in CRuby 4.0.0 |
+ * | `4` | use the version of prism that is vendored in CRuby 4.1.0 |
*
* Each scope is laid out as follows:
*
diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb
index 90f87ed0c5daea..69b0816a18999e 100644
--- a/spec/bundler/install/gemfile/sources_spec.rb
+++ b/spec/bundler/install/gemfile/sources_spec.rb
@@ -1195,4 +1195,45 @@
expect(gem_section).not_to include("activerecord (7.0.0)")
end
end
+
+ context "when a scoped rubygems source is missing a transitive dependency" do
+ before do
+ build_repo2 do
+ build_gem "fallback_dep", "1.0.0"
+ build_gem "foo", "1.0.0"
+ end
+
+ build_repo3 do
+ build_gem "private_parent", "1.0.0" do |s|
+ s.add_dependency "fallback_dep"
+ end
+ end
+
+ gemfile <<-G
+ source "https://gem.repo2"
+
+ gem "foo"
+
+ source "https://gem.repo3" do
+ gem "private_parent", "1.0.0"
+ end
+ G
+
+ bundle :install, artifice: "compact_index"
+ end
+
+ it "falls back to the default rubygems source for that dependency" do
+ build_repo2 do
+ build_gem "foo", "2.0.0"
+ end
+
+ system_gems []
+
+ bundle "update foo", artifice: "compact_index"
+
+ expect(the_bundle).to include_gems("private_parent 1.0.0", "fallback_dep 1.0.0", "foo 2.0.0")
+ expect(the_bundle).to include_gems("private_parent 1.0.0", source: "remote3")
+ expect(the_bundle).to include_gems("fallback_dep 1.0.0", source: "remote2")
+ end
+ end
end
diff --git a/spec/mspec/tool/sync/sync-rubyspec.rb b/spec/mspec/tool/sync/sync-rubyspec.rb
index 617123733e5442..122de0decba9f6 100644
--- a/spec/mspec/tool/sync/sync-rubyspec.rb
+++ b/spec/mspec/tool/sync/sync-rubyspec.rb
@@ -190,20 +190,20 @@ def test_new_specs
Dir.chdir(SOURCE_REPO) do
workflow = YAML.load_file(".github/workflows/ci.yml")
job_name = MSPEC ? "test" : "specs"
- versions = workflow.dig("jobs", job_name, "strategy", "matrix", "ruby")
+ versions = workflow.dig("jobs", job_name, "strategy", "matrix", "ruby").map(&:to_s)
versions = versions.grep(/^\d+\./) # Test on MRI
min_version, max_version = versions.minmax
test_command = MSPEC ? "bundle install && bundle exec rspec" : "../mspec/bin/mspec -j"
run_test = -> version {
- command = "chruby #{version} && #{test_command}"
+ command = "chruby ruby-#{version} && #{test_command}"
sh ENV["SHELL"], "-c", command
}
run_test[min_version]
run_test[max_version]
- run_test["ruby-master"] if TEST_MASTER
+ run_test["master"] if TEST_MASTER
end
end
diff --git a/spec/mspec/tool/tag_from_output.rb b/spec/mspec/tool/tag_from_output.rb
index b6b46038556ae1..41aa70f932057f 100755
--- a/spec/mspec/tool/tag_from_output.rb
+++ b/spec/mspec/tool/tag_from_output.rb
@@ -20,7 +20,7 @@
NUMBER = /^\d+\)$/
ERROR_OR_FAILED = / (ERROR|FAILED)$/
-SPEC_FILE = /^(\/.+_spec\.rb)\:\d+/
+SPEC_FILE = /^((?:\/|[CD]:\/).+_spec\.rb)\:\d+/
output.slice_before(NUMBER).select { |number, *rest|
number =~ NUMBER and rest.any? { |line| line =~ ERROR_OR_FAILED }
diff --git a/spec/ruby/README.md b/spec/ruby/README.md
index 674ada4c9e4cc9..14a0068346fe3d 100644
--- a/spec/ruby/README.md
+++ b/spec/ruby/README.md
@@ -64,6 +64,7 @@ For older specs try these commits:
* Ruby 2.7.8 - [Suite](https://github.com/ruby/spec/commit/93787e6035c925b593a9c0c6fb0e7e07a6f1df1f) using [MSpec](https://github.com/ruby/mspec/commit/1d8cf64722d8a7529f7cd205be5f16a89b7a67fd)
* Ruby 3.0.7 - [Suite](https://github.com/ruby/spec/commit/affef93d9940f615e4836f64b011da211f570913) using [MSpec](https://github.com/ruby/mspec/commit/0aabb3e548eb5ea6cad0125f8f46cee34542b6b7)
* Ruby 3.1.6 - [Suite](https://github.com/ruby/spec/commit/ec960f2389d1c2265d32397fa8afa6d462014efc) using [MSpec](https://github.com/ruby/mspec/commit/484310dbed35b84c74484fd674602f88c42d063a)
+* Ruby 3.2.9 - [Suite](https://github.com/ruby/spec/commit/97f076242b7fc6e60703e6a6053365065cd6fc30) using [MSpec](https://github.com/ruby/mspec/commit/54704795e21128a930af2021c72c49cb87065134)
### Running the specs
diff --git a/spec/ruby/command_line/dash_r_spec.rb b/spec/ruby/command_line/dash_r_spec.rb
index 9f673c53dcc097..62b8dc001452a7 100644
--- a/spec/ruby/command_line/dash_r_spec.rb
+++ b/spec/ruby/command_line/dash_r_spec.rb
@@ -16,10 +16,7 @@
out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), options: "-r #{@test_file}", args: "2>&1", exit_status: 1)
$?.should_not.success?
out.should include("REQUIRED")
-
- # it's tempting not to rely on error message and rely only on exception class name,
- # but CRuby before 3.2 doesn't print class name for syntax error
- out.should include_any_of("syntax error", "SyntaxError")
+ out.should include("SyntaxError")
end
it "does not require the file if the main script file does not exist" do
diff --git a/spec/ruby/command_line/syntax_error_spec.rb b/spec/ruby/command_line/syntax_error_spec.rb
index 9ba87b9e22795b..88864c048ebfee 100644
--- a/spec/ruby/command_line/syntax_error_spec.rb
+++ b/spec/ruby/command_line/syntax_error_spec.rb
@@ -3,17 +3,11 @@
describe "The interpreter" do
it "prints an error when given a file with invalid syntax" do
out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), args: "2>&1", exit_status: 1)
-
- # it's tempting not to rely on error message and rely only on exception class name,
- # but CRuby before 3.2 doesn't print class name for syntax error
- out.should include_any_of("syntax error", "SyntaxError")
+ out.should.include?("SyntaxError")
end
it "prints an error when given code via -e with invalid syntax" do
out = ruby_exe(nil, args: "-e 'a{' 2>&1", exit_status: 1)
-
- # it's tempting not to rely on error message and rely only on exception class name,
- # but CRuby before 3.2 doesn't print class name for syntax error
- out.should include_any_of("syntax error", "SyntaxError")
+ out.should.include?("SyntaxError")
end
end
diff --git a/spec/ruby/core/array/fetch_spec.rb b/spec/ruby/core/array/fetch_spec.rb
index b81c0b48d7296d..598b481ba46a11 100644
--- a/spec/ruby/core/array/fetch_spec.rb
+++ b/spec/ruby/core/array/fetch_spec.rb
@@ -12,9 +12,9 @@
end
it "raises an IndexError if there is no element at index" do
- -> { [1, 2, 3].fetch(3) }.should raise_error(IndexError)
- -> { [1, 2, 3].fetch(-4) }.should raise_error(IndexError)
- -> { [].fetch(0) }.should raise_error(IndexError)
+ -> { [1, 2, 3].fetch(3) }.should raise_error(IndexError, "index 3 outside of array bounds: -3...3")
+ -> { [1, 2, 3].fetch(-4) }.should raise_error(IndexError, "index -4 outside of array bounds: -3...3")
+ -> { [].fetch(0) }.should raise_error(IndexError, "index 0 outside of array bounds: 0...0")
end
it "returns default if there is no element at index if passed a default value" do
@@ -50,6 +50,6 @@ def o.to_int(); 5; end
end
it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { [].fetch("cat") }.should raise_error(TypeError)
+ -> { [].fetch("cat") }.should raise_error(TypeError, "no implicit conversion of String into Integer")
end
end
diff --git a/spec/ruby/core/array/pack/c_spec.rb b/spec/ruby/core/array/pack/c_spec.rb
index 47b71b663d6a98..7a2b95def87f7f 100644
--- a/spec/ruby/core/array/pack/c_spec.rb
+++ b/spec/ruby/core/array/pack/c_spec.rb
@@ -45,20 +45,10 @@
[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 "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 spaces between directives" do
diff --git a/spec/ruby/core/array/pack/shared/basic.rb b/spec/ruby/core/array/pack/shared/basic.rb
index a63f64d296a312..2ebd75f6c5ed79 100644
--- a/spec/ruby/core/array/pack/shared/basic.rb
+++ b/spec/ruby/core/array/pack/shared/basic.rb
@@ -32,22 +32,11 @@
[@obj, @obj, @obj, @obj].pack("aa #{pack_format} # some comment \n#{pack_format}").should be_an_instance_of(String)
end
- ruby_version_is ""..."3.3" do
- it "warns that a directive is unknown" do
- # additional directive ('a') is required for the X directive
- -> { [@obj, @obj].pack("a K" + pack_format) }.should complain(/unknown pack directive 'K' in 'a K#{pack_format}'/)
- -> { [@obj, @obj].pack("a 0" + pack_format) }.should complain(/unknown pack directive '0' in 'a 0#{pack_format}'/)
- -> { [@obj, @obj].pack("a :" + pack_format) }.should complain(/unknown pack directive ':' in 'a :#{pack_format}'/)
- end
- end
-
- ruby_version_is "3.3" do
- 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, /unknown pack directive 'R'/)
- -> { [@obj, @obj].pack("a 0" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive '0'/)
- -> { [@obj, @obj].pack("a :" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive ':'/)
- end
+ 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, /unknown pack directive 'R'/)
+ -> { [@obj, @obj].pack("a 0" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive '0'/)
+ -> { [@obj, @obj].pack("a :" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive ':'/)
end
it "calls #to_str to coerce the directives string" do
diff --git a/spec/ruby/core/array/pack/shared/float.rb b/spec/ruby/core/array/pack/shared/float.rb
index 76c800b74dc5f1..3f60fee2150b48 100644
--- a/spec/ruby/core/array/pack/shared/float.rb
+++ b/spec/ruby/core/array/pack/shared/float.rb
@@ -25,20 +25,10 @@
[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 "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 spaces between directives" do
@@ -105,20 +95,10 @@
[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 "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 spaces between directives" do
@@ -177,20 +157,10 @@
[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 "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 spaces between directives" do
@@ -248,20 +218,10 @@
[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 "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 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 61f7cca184a9b0..ff2ee492016cc4 100644
--- a/spec/ruby/core/array/pack/shared/integer.rb
+++ b/spec/ruby/core/array/pack/shared/integer.rb
@@ -41,21 +41,10 @@
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 "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 spaces between directives" do
@@ -105,21 +94,10 @@
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 "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 spaces between directives" do
@@ -169,21 +147,10 @@
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 "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 spaces between directives" do
@@ -233,21 +200,10 @@
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 "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 spaces between directives" do
@@ -357,21 +313,10 @@
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 "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 spaces between directives" do
@@ -429,21 +374,10 @@
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 "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 spaces between directives" do
diff --git a/spec/ruby/core/array/pack/shared/unicode.rb b/spec/ruby/core/array/pack/shared/unicode.rb
index 4d8eaef3231067..0eccc7098c7cbf 100644
--- a/spec/ruby/core/array/pack/shared/unicode.rb
+++ b/spec/ruby/core/array/pack/shared/unicode.rb
@@ -67,20 +67,10 @@
-> { [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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [1, 2, 3].pack("U\x00U")
+ }.should raise_error(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/array/pack/w_spec.rb b/spec/ruby/core/array/pack/w_spec.rb
index e770288d67b4d2..ebadb94cab0504 100644
--- a/spec/ruby/core/array/pack/w_spec.rb
+++ b/spec/ruby/core/array/pack/w_spec.rb
@@ -24,20 +24,10 @@
[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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [1, 2, 3].pack("w\x00w")
+ }.should raise_error(ArgumentError, /unknown pack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/array/rassoc_spec.rb b/spec/ruby/core/array/rassoc_spec.rb
index 632a05e8b3778b..a7ffb75fb53521 100644
--- a/spec/ruby/core/array/rassoc_spec.rb
+++ b/spec/ruby/core/array/rassoc_spec.rb
@@ -36,17 +36,15 @@ def o.==(other); other == 'foobar'; end
[[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
+ 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
diff --git a/spec/ruby/core/array/sum_spec.rb b/spec/ruby/core/array/sum_spec.rb
index 06abe061359faa..1886d692faaddc 100644
--- a/spec/ruby/core/array/sum_spec.rb
+++ b/spec/ruby/core/array/sum_spec.rb
@@ -74,13 +74,11 @@
[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
+ 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
diff --git a/spec/ruby/core/basicobject/instance_eval_spec.rb b/spec/ruby/core/basicobject/instance_eval_spec.rb
index 633b5c2cb1d9bb..f8d9d7505920d1 100644
--- a/spec/ruby/core/basicobject/instance_eval_spec.rb
+++ b/spec/ruby/core/basicobject/instance_eval_spec.rb
@@ -84,11 +84,9 @@ def foo
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
+ it "uses the caller location as default location" do
+ f = Object.new
+ f.instance_eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
end
it "has access to receiver's instance variables" do
diff --git a/spec/ruby/core/binding/eval_spec.rb b/spec/ruby/core/binding/eval_spec.rb
index bb2036f73911c4..7852e1c93936b4 100644
--- a/spec/ruby/core/binding/eval_spec.rb
+++ b/spec/ruby/core/binding/eval_spec.rb
@@ -60,14 +60,6 @@
bind.eval("#foo\n__LINE__", "(test)", 88).should == 89
end
- ruby_version_is ""..."3.3" 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
@@ -107,9 +99,7 @@
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
+ it "uses the caller location as default filename" do
+ binding.eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
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 13e066cc7f1664..2c71b416679749 100644
--- a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb
+++ b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb
@@ -87,65 +87,63 @@
end
ruby_version_is "4.0" do
- context "The constant" do
- describe "Ruby" do
- it "is a Module" do
- Ruby.should.instance_of?(Module)
- end
+ describe "Ruby" do
+ it "is a Module" do
+ Ruby.should.instance_of?(Module)
end
+ end
- describe "Ruby::VERSION" do
- it "is equal to RUBY_VERSION" do
- Ruby::VERSION.should equal(RUBY_VERSION)
- end
+ describe "Ruby::VERSION" do
+ it "is equal to RUBY_VERSION" do
+ Ruby::VERSION.should equal(RUBY_VERSION)
end
+ end
- describe "RUBY::PATCHLEVEL" do
- it "is equal to RUBY_PATCHLEVEL" do
- Ruby::PATCHLEVEL.should equal(RUBY_PATCHLEVEL)
- end
+ describe "RUBY::PATCHLEVEL" do
+ it "is equal to RUBY_PATCHLEVEL" do
+ Ruby::PATCHLEVEL.should equal(RUBY_PATCHLEVEL)
end
+ end
- describe "Ruby::COPYRIGHT" do
- it "is equal to RUBY_COPYRIGHT" do
- Ruby::COPYRIGHT.should equal(RUBY_COPYRIGHT)
- end
+ describe "Ruby::COPYRIGHT" do
+ it "is equal to RUBY_COPYRIGHT" do
+ Ruby::COPYRIGHT.should equal(RUBY_COPYRIGHT)
end
+ end
- describe "Ruby::DESCRIPTION" do
- it "is equal to RUBY_DESCRIPTION" do
- Ruby::DESCRIPTION.should equal(RUBY_DESCRIPTION)
- end
+ describe "Ruby::DESCRIPTION" do
+ it "is equal to RUBY_DESCRIPTION" do
+ Ruby::DESCRIPTION.should equal(RUBY_DESCRIPTION)
end
+ end
- describe "Ruby::ENGINE" do
- it "is equal to RUBY_ENGINE" do
- Ruby::ENGINE.should equal(RUBY_ENGINE)
- end
+ describe "Ruby::ENGINE" do
+ it "is equal to RUBY_ENGINE" do
+ Ruby::ENGINE.should equal(RUBY_ENGINE)
end
+ end
- describe "Ruby::ENGINE_VERSION" do
- it "is equal to RUBY_ENGINE_VERSION" do
- Ruby::ENGINE_VERSION.should equal(RUBY_ENGINE_VERSION)
- end
+ describe "Ruby::ENGINE_VERSION" do
+ it "is equal to RUBY_ENGINE_VERSION" do
+ Ruby::ENGINE_VERSION.should equal(RUBY_ENGINE_VERSION)
end
+ end
- describe "Ruby::PLATFORM" do
- it "is equal to RUBY_PLATFORM" do
- Ruby::PLATFORM.should equal(RUBY_PLATFORM)
- end
+ describe "Ruby::PLATFORM" do
+ it "is equal to RUBY_PLATFORM" do
+ Ruby::PLATFORM.should equal(RUBY_PLATFORM)
end
+ end
- describe "Ruby::RELEASE_DATE" do
- it "is equal to RUBY_RELEASE_DATE" do
- Ruby::RELEASE_DATE.should equal(RUBY_RELEASE_DATE)
- end
+ describe "Ruby::RELEASE_DATE" do
+ it "is equal to RUBY_RELEASE_DATE" do
+ Ruby::RELEASE_DATE.should equal(RUBY_RELEASE_DATE)
end
+ end
- describe "Ruby::REVISION" do
- it "is equal to RUBY_REVISION" do
- Ruby::REVISION.should equal(RUBY_REVISION)
- end
+ describe "Ruby::REVISION" do
+ it "is equal to RUBY_REVISION" do
+ Ruby::REVISION.should equal(RUBY_REVISION)
end
end
end
diff --git a/spec/ruby/core/data/with_spec.rb b/spec/ruby/core/data/with_spec.rb
index fd0a99d1fadaab..83cb97fa60777b 100644
--- a/spec/ruby/core/data/with_spec.rb
+++ b/spec/ruby/core/data/with_spec.rb
@@ -44,14 +44,12 @@ def subclass.new(*)
data_copy.unit.should == "m"
end
- ruby_version_is "3.3" do
- it "calls #initialize" do
- data = DataSpecs::DataWithOverriddenInitialize.new(42, "m")
- ScratchPad.clear
+ it "calls #initialize" do
+ data = DataSpecs::DataWithOverriddenInitialize.new(42, "m")
+ ScratchPad.clear
- data.with(amount: 0)
+ data.with(amount: 0)
- ScratchPad.recorded.should == [:initialize, [], {amount: 0, unit: "m"}]
- end
+ ScratchPad.recorded.should == [:initialize, [], {amount: 0, unit: "m"}]
end
end
diff --git a/spec/ruby/core/dir/chdir_spec.rb b/spec/ruby/core/dir/chdir_spec.rb
index 015386a9026cf3..fd277e4e1d64fc 100644
--- a/spec/ruby/core/dir/chdir_spec.rb
+++ b/spec/ruby/core/dir/chdir_spec.rb
@@ -125,96 +125,94 @@ def to_str; DirSpecs.mock_dir; end
end
end
-ruby_version_is '3.3' do
- describe "Dir#chdir" do
- before :all do
- DirSpecs.create_mock_dirs
- end
+describe "Dir#chdir" do
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
- after :all do
- DirSpecs.delete_mock_dirs
- end
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
- before :each do
- @original = Dir.pwd
- end
+ before :each do
+ @original = Dir.pwd
+ end
- after :each do
- Dir.chdir(@original)
- end
+ after :each do
+ Dir.chdir(@original)
+ end
- it "changes the current working directory to self" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir.chdir
- Dir.pwd.should == DirSpecs.mock_dir
- ensure
- dir.close
- end
+ it "changes the current working directory to self" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir.chdir
+ Dir.pwd.should == DirSpecs.mock_dir
+ ensure
+ dir.close
+ end
- it "changes the current working directory to self for duration of the block when a block is given" do
- dir = Dir.new(DirSpecs.mock_dir)
- pwd_in_block = nil
+ it "changes the current working directory to self for duration of the block when a block is given" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ pwd_in_block = nil
- dir.chdir { pwd_in_block = Dir.pwd }
+ dir.chdir { pwd_in_block = Dir.pwd }
- pwd_in_block.should == DirSpecs.mock_dir
- Dir.pwd.should == @original
- ensure
- dir.close
- end
+ pwd_in_block.should == DirSpecs.mock_dir
+ Dir.pwd.should == @original
+ ensure
+ dir.close
+ end
- it "returns 0 when successfully changing directory" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir.chdir.should == 0
- ensure
- dir.close
- end
+ it "returns 0 when successfully changing directory" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir.chdir.should == 0
+ ensure
+ dir.close
+ end
- it "returns the value of the block when a block is given" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir.chdir { :block_value }.should == :block_value
- ensure
- dir.close
- end
+ it "returns the value of the block when a block is given" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir.chdir { :block_value }.should == :block_value
+ ensure
+ dir.close
+ end
+
+ platform_is_not :windows do
+ it "does not raise an Errno::ENOENT if the original directory no longer exists" do
+ dir_name1 = tmp('testdir1')
+ dir_name2 = tmp('testdir2')
+ Dir.should_not.exist?(dir_name1)
+ Dir.should_not.exist?(dir_name2)
+ Dir.mkdir dir_name1
+ Dir.mkdir dir_name2
- platform_is_not :windows do
- it "does not raise an Errno::ENOENT if the original directory no longer exists" do
- dir_name1 = tmp('testdir1')
- dir_name2 = tmp('testdir2')
- Dir.should_not.exist?(dir_name1)
- Dir.should_not.exist?(dir_name2)
- Dir.mkdir dir_name1
- Dir.mkdir dir_name2
-
- dir2 = Dir.new(dir_name2)
-
- begin
- Dir.chdir(dir_name1) do
- dir2.chdir { Dir.unlink dir_name1 }
- end
- Dir.pwd.should == @original
- ensure
- Dir.unlink dir_name1 if Dir.exist?(dir_name1)
- Dir.unlink dir_name2 if Dir.exist?(dir_name2)
+ dir2 = Dir.new(dir_name2)
+
+ begin
+ Dir.chdir(dir_name1) do
+ dir2.chdir { Dir.unlink dir_name1 }
end
+ Dir.pwd.should == @original
ensure
- dir2.close
+ Dir.unlink dir_name1 if Dir.exist?(dir_name1)
+ Dir.unlink dir_name2 if Dir.exist?(dir_name2)
end
+ ensure
+ dir2.close
end
+ end
- it "always returns to the original directory when given a block" do
- dir = Dir.new(DirSpecs.mock_dir)
+ it "always returns to the original directory when given a block" do
+ dir = Dir.new(DirSpecs.mock_dir)
- begin
- dir.chdir do
- raise StandardError, "something bad happened"
- end
- rescue StandardError
+ begin
+ dir.chdir do
+ raise StandardError, "something bad happened"
end
-
- Dir.pwd.should == @original
- ensure
- dir.close
+ rescue StandardError
end
+
+ Dir.pwd.should == @original
+ ensure
+ dir.close
end
end
diff --git a/spec/ruby/core/dir/close_spec.rb b/spec/ruby/core/dir/close_spec.rb
index f7cce318b8b17d..10ad1369c84d2f 100644
--- a/spec/ruby/core/dir/close_spec.rb
+++ b/spec/ruby/core/dir/close_spec.rb
@@ -24,7 +24,7 @@
dir.close.should == nil
end
- ruby_version_is '3.3'...'3.4' do
+ ruby_version_is ''...'3.4' do
platform_is_not :windows do
it "does not raise an error even if the file descriptor is closed with another Dir instance" do
dir = Dir.open DirSpecs.mock_dir
diff --git a/spec/ruby/core/dir/fchdir_spec.rb b/spec/ruby/core/dir/fchdir_spec.rb
index 52600a95f2b80c..d5e77f7f03f372 100644
--- a/spec/ruby/core/dir/fchdir_spec.rb
+++ b/spec/ruby/core/dir/fchdir_spec.rb
@@ -1,73 +1,71 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
-ruby_version_is '3.3' do
- platform_is_not :windows do
- describe "Dir.fchdir" do
- before :all do
- DirSpecs.create_mock_dirs
- end
+platform_is_not :windows do
+ describe "Dir.fchdir" do
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
- after :all do
- DirSpecs.delete_mock_dirs
- end
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
- before :each do
- @original = Dir.pwd
- end
+ before :each do
+ @original = Dir.pwd
+ end
- after :each do
- Dir.chdir(@original)
- end
+ after :each do
+ Dir.chdir(@original)
+ end
- it "changes the current working directory to the directory specified by the integer file descriptor" do
- dir = Dir.new(DirSpecs.mock_dir)
- Dir.fchdir dir.fileno
- Dir.pwd.should == DirSpecs.mock_dir
- ensure
- dir.close
- end
+ it "changes the current working directory to the directory specified by the integer file descriptor" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ Dir.fchdir dir.fileno
+ Dir.pwd.should == DirSpecs.mock_dir
+ ensure
+ dir.close
+ end
- it "returns 0 when successfully changing directory" do
- dir = Dir.new(DirSpecs.mock_dir)
- Dir.fchdir(dir.fileno).should == 0
- ensure
- dir.close
- end
+ it "returns 0 when successfully changing directory" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ Dir.fchdir(dir.fileno).should == 0
+ ensure
+ dir.close
+ end
- it "returns the value of the block when a block is given" do
- dir = Dir.new(DirSpecs.mock_dir)
- Dir.fchdir(dir.fileno) { :block_value }.should == :block_value
- ensure
- dir.close
- end
+ it "returns the value of the block when a block is given" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ Dir.fchdir(dir.fileno) { :block_value }.should == :block_value
+ ensure
+ dir.close
+ end
- it "changes to the specified directory for the duration of the block" do
- dir = Dir.new(DirSpecs.mock_dir)
- Dir.fchdir(dir.fileno) { Dir.pwd }.should == DirSpecs.mock_dir
- Dir.pwd.should == @original
- ensure
- dir.close
- end
+ it "changes to the specified directory for the duration of the block" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ Dir.fchdir(dir.fileno) { Dir.pwd }.should == DirSpecs.mock_dir
+ Dir.pwd.should == @original
+ ensure
+ dir.close
+ end
- it "raises a SystemCallError if the file descriptor given is not valid" do
- -> { Dir.fchdir(-1) }.should raise_error(SystemCallError, "Bad file descriptor - fchdir")
- -> { Dir.fchdir(-1) { } }.should raise_error(SystemCallError, "Bad file descriptor - fchdir")
- end
+ it "raises a SystemCallError if the file descriptor given is not valid" do
+ -> { Dir.fchdir(-1) }.should raise_error(SystemCallError, "Bad file descriptor - fchdir")
+ -> { Dir.fchdir(-1) { } }.should raise_error(SystemCallError, "Bad file descriptor - fchdir")
+ end
- it "raises a SystemCallError if the file descriptor given is not for a directory" do
- -> { Dir.fchdir $stdout.fileno }.should raise_error(SystemCallError, /(Not a directory|Invalid argument) - fchdir/)
- -> { Dir.fchdir($stdout.fileno) { } }.should raise_error(SystemCallError, /(Not a directory|Invalid argument) - fchdir/)
- end
+ it "raises a SystemCallError if the file descriptor given is not for a directory" do
+ -> { Dir.fchdir $stdout.fileno }.should raise_error(SystemCallError, /(Not a directory|Invalid argument) - fchdir/)
+ -> { Dir.fchdir($stdout.fileno) { } }.should raise_error(SystemCallError, /(Not a directory|Invalid argument) - fchdir/)
end
end
+end
- platform_is :windows do
- describe "Dir.fchdir" do
- it "raises NotImplementedError" do
- -> { Dir.fchdir 1 }.should raise_error(NotImplementedError)
- -> { Dir.fchdir(1) { } }.should raise_error(NotImplementedError)
- end
+platform_is :windows 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
diff --git a/spec/ruby/core/dir/for_fd_spec.rb b/spec/ruby/core/dir/for_fd_spec.rb
index ba467f2f86d928..1559e1baa43a6c 100644
--- a/spec/ruby/core/dir/for_fd_spec.rb
+++ b/spec/ruby/core/dir/for_fd_spec.rb
@@ -2,77 +2,75 @@
require_relative 'fixtures/common'
quarantine! do # leads to "Errno::EBADF: Bad file descriptor - closedir" in DirSpecs.delete_mock_dirs
-ruby_version_is '3.3' do
- platform_is_not :windows do
- describe "Dir.for_fd" do
- before :all do
- DirSpecs.create_mock_dirs
- end
+platform_is_not :windows do
+ describe "Dir.for_fd" do
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
- after :all do
- DirSpecs.delete_mock_dirs
- end
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
- before :each do
- @original = Dir.pwd
- end
+ before :each do
+ @original = Dir.pwd
+ end
- after :each do
- Dir.chdir(@original)
- end
+ after :each do
+ Dir.chdir(@original)
+ end
- it "returns a new Dir object representing the directory specified by the given integer directory file descriptor" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir_new = Dir.for_fd(dir.fileno)
+ it "returns a new Dir object representing the directory specified by the given integer directory file descriptor" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir_new = Dir.for_fd(dir.fileno)
- dir_new.should.instance_of?(Dir)
- dir_new.children.should == dir.children
- dir_new.fileno.should == dir.fileno
- ensure
- dir.close
- end
+ dir_new.should.instance_of?(Dir)
+ dir_new.children.should == dir.children
+ dir_new.fileno.should == dir.fileno
+ ensure
+ dir.close
+ end
- it "returns a new Dir object without associated path" do
- dir = Dir.new(DirSpecs.mock_dir)
- dir_new = Dir.for_fd(dir.fileno)
+ it "returns a new Dir object without associated path" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir_new = Dir.for_fd(dir.fileno)
- dir_new.path.should == nil
- ensure
- dir.close
- end
+ dir_new.path.should == nil
+ ensure
+ dir.close
+ end
- it "calls #to_int to convert a value to an Integer" do
- dir = Dir.new(DirSpecs.mock_dir)
- obj = mock("fd")
- obj.should_receive(:to_int).and_return(dir.fileno)
+ it "calls #to_int to convert a value to an Integer" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ obj = mock("fd")
+ obj.should_receive(:to_int).and_return(dir.fileno)
- dir_new = Dir.for_fd(obj)
- dir_new.fileno.should == dir.fileno
- ensure
- dir.close
- end
+ dir_new = Dir.for_fd(obj)
+ dir_new.fileno.should == dir.fileno
+ ensure
+ dir.close
+ end
- it "raises TypeError when value cannot be converted to Integer" do
- -> {
- Dir.for_fd(nil)
- }.should raise_error(TypeError, "no implicit conversion from nil to integer")
- end
+ it "raises TypeError when value cannot be converted to Integer" do
+ -> {
+ Dir.for_fd(nil)
+ }.should raise_error(TypeError, "no implicit conversion from nil to integer")
+ end
- it "raises a SystemCallError if the file descriptor given is not valid" do
- -> { Dir.for_fd(-1) }.should raise_error(SystemCallError, "Bad file descriptor - fdopendir")
- end
+ it "raises a SystemCallError if the file descriptor given is not valid" do
+ -> { Dir.for_fd(-1) }.should raise_error(SystemCallError, "Bad file descriptor - fdopendir")
+ end
- it "raises a SystemCallError if the file descriptor given is not for a directory" do
- -> { Dir.for_fd $stdout.fileno }.should raise_error(SystemCallError, "Not a directory - fdopendir")
- end
+ it "raises a SystemCallError if the file descriptor given is not for a directory" do
+ -> { Dir.for_fd $stdout.fileno }.should raise_error(SystemCallError, "Not a directory - fdopendir")
end
end
+end
- platform_is :windows do
- describe "Dir.for_fd" do
- it "raises NotImplementedError" do
- -> { Dir.for_fd 1 }.should raise_error(NotImplementedError)
- end
+platform_is :windows do
+ describe "Dir.for_fd" do
+ it "raises NotImplementedError" do
+ -> { Dir.for_fd 1 }.should raise_error(NotImplementedError)
end
end
end
diff --git a/spec/ruby/core/encoding/ascii_compatible_spec.rb b/spec/ruby/core/encoding/ascii_compatible_spec.rb
index 4804300e855dff..bbcc6add9e4e1b 100644
--- a/spec/ruby/core/encoding/ascii_compatible_spec.rb
+++ b/spec/ruby/core/encoding/ascii_compatible_spec.rb
@@ -8,4 +8,15 @@
it "returns false if self does not represent an ASCII-compatible encoding" do
Encoding::UTF_16LE.ascii_compatible?.should be_false
end
+
+ it "returns false for UTF_16 and UTF_32" do
+ Encoding::UTF_16.should_not.ascii_compatible?
+ Encoding::UTF_32.should_not.ascii_compatible?
+ end
+
+ it "is always false for dummy encodings" do
+ Encoding.list.select(&:dummy?).each do |encoding|
+ encoding.should_not.ascii_compatible?
+ end
+ end
end
diff --git a/spec/ruby/core/encoding/dummy_spec.rb b/spec/ruby/core/encoding/dummy_spec.rb
index 75ffcd5a4ec093..77caebca9a2871 100644
--- a/spec/ruby/core/encoding/dummy_spec.rb
+++ b/spec/ruby/core/encoding/dummy_spec.rb
@@ -11,4 +11,15 @@
Encoding::CP50221.dummy?.should be_true
Encoding::UTF_7.dummy?.should be_true
end
+
+ it "returns true for UTF_16 and UTF_32" do
+ Encoding::UTF_16.should.dummy?
+ Encoding::UTF_32.should.dummy?
+ end
+
+ it "implies not #ascii_compatible?" do
+ Encoding.list.select(&:dummy?).each do |encoding|
+ encoding.should_not.ascii_compatible?
+ end
+ end
end
diff --git a/spec/ruby/core/encoding/replicate_spec.rb b/spec/ruby/core/encoding/replicate_spec.rb
index 2da998837f866b..9fe0ba87478bd0 100644
--- a/spec/ruby/core/encoding/replicate_spec.rb
+++ b/spec/ruby/core/encoding/replicate_spec.rb
@@ -2,87 +2,7 @@
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
-
- "a".dup.force_encoding(e).valid_encoding?.should be_true
- "\x80".dup.force_encoding(e).valid_encoding?.should be_false
- 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
-
- "a".dup.force_encoding(e).valid_encoding?.should be_true
- "\u3042".dup.force_encoding(e).valid_encoding?.should be_true
- "\x80".dup.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
-
- "a".dup.force_encoding(e).valid_encoding?.should be_false
- "\x30\x42".dup.force_encoding(e).valid_encoding?.should be_true
- "\x80".dup.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
-
- e.name.should == name
- e.dummy?.should be_true
- 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
-
- s = "abc".dup.force_encoding(e)
- s.encoding.should == e
- s.encoding.name.should == name
- end
- end
-
- ruby_version_is ""..."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
-
- it "raises EncodingError if too many encodings" do
- code = '1_000.times {|i| Encoding::US_ASCII.replicate("R_#{i}") }'
- ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
- end
- end
-
- ruby_version_is "3.3" do
- it "has been removed" do
- Encoding::US_ASCII.should_not.respond_to?(:replicate, true)
- end
+ it "has been removed" do
+ Encoding::US_ASCII.should_not.respond_to?(:replicate, true)
end
end
diff --git a/spec/ruby/core/enumerator/each_spec.rb b/spec/ruby/core/enumerator/each_spec.rb
index 3af16e5587e466..8c9785cc85fe37 100644
--- a/spec/ruby/core/enumerator/each_spec.rb
+++ b/spec/ruby/core/enumerator/each_spec.rb
@@ -86,4 +86,19 @@ def object_each_with_arguments.each_with_arguments(arg, *args)
ret.should be_an_instance_of(Enumerator)
ret.should_not equal(@enum_with_arguments)
end
+
+ it "does not destructure yielded array values when chaining each.map" do
+ result = [[[1]]].each.map { |a, b| [a, b] }
+ result.should == [[[1], nil]]
+ end
+
+ it "preserves array values yielded from the enumerator" do
+ result = [[1, 2]].each.map { |a| a }
+ result.should == [[1, 2]]
+ end
+
+ it "allows destructuring to occur in the block, not the enumerator" do
+ result = [[1, 2]].each.map { |a, b| a }
+ result.should == [1]
+ 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 772c569f67963e..d20878c6e3328d 100644
--- a/spec/ruby/core/exception/no_method_error_spec.rb
+++ b/spec/ruby/core/exception/no_method_error_spec.rb
@@ -66,204 +66,145 @@
end
end
- ruby_version_is ""..."3.3" do
- it "calls #inspect when calling Exception#message" do
- ScratchPad.record []
- test_class = Class.new do
- def inspect
- ScratchPad << :inspect_called
- ""
- end
- end
- instance = test_class.new
-
- begin
- instance.bar
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for :#$/
- ScratchPad.recorded.should == [:inspect_called]
- end
- end
-
- it "fallbacks to a simpler representation of the receiver when receiver.inspect raises an exception" do
- test_class = Class.new do
- def inspect
- raise NoMethodErrorSpecs::InstanceException
- end
- end
- instance = test_class.new
-
- begin
- instance.bar
- rescue NoMethodError => error
- message = error.message
- message.should =~ /undefined method.+\bbar\b/
- message.should include test_class.inspect
- end
- end
-
- it "uses #name to display the receiver if it is a class" do
- klass = Class.new { def self.name; "MyClass"; end }
-
- begin
- klass.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for MyClass:Class$/
- end
+ it "uses a literal name when receiver is nil" do
+ begin
+ nil.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for nil\Z/
end
+ end
- it "uses #name to display the receiver if it is a module" do
- mod = Module.new { def self.name; "MyModule"; end }
-
- begin
- mod.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for MyModule:Module$/
- end
+ it "uses a literal name when receiver is true" do
+ begin
+ true.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for true\Z/
end
end
- ruby_version_is "3.3" do
- it "uses a literal name when receiver is nil" do
- begin
- nil.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for nil\Z/
- end
+ it "uses a literal name when receiver is false" do
+ begin
+ false.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for false\Z/
end
+ end
- it "uses a literal name when receiver is true" do
- begin
- true.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for true\Z/
- end
- end
+ it "uses #name when receiver is a class" do
+ klass = Class.new { def self.name; "MyClass"; end }
- it "uses a literal name when receiver is false" do
- begin
- false.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for false\Z/
- end
+ begin
+ klass.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for class MyClass\Z/
end
+ end
- it "uses #name when receiver is a class" do
- klass = Class.new { def self.name; "MyClass"; end }
+ it "uses class' string representation when receiver is an anonymous class" do
+ klass = Class.new
- begin
- klass.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for class MyClass\Z/
- end
+ begin
+ klass.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for class #\Z/
end
+ end
- it "uses class' string representation when receiver is an anonymous class" do
- klass = Class.new
+ it "uses class' string representation when receiver is a singleton class" do
+ obj = Object.new
+ singleton_class = obj.singleton_class
- begin
- klass.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for class #\Z/
- end
+ begin
+ singleton_class.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for class #>\Z/
end
+ end
- it "uses class' string representation when receiver is a singleton class" do
- obj = Object.new
- singleton_class = obj.singleton_class
+ it "uses #name when receiver is a module" do
+ mod = Module.new { def self.name; "MyModule"; end }
- begin
- singleton_class.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for class #>\Z/
- end
+ begin
+ mod.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for module MyModule\Z/
end
+ end
- it "uses #name when receiver is a module" do
- mod = Module.new { def self.name; "MyModule"; end }
+ it "uses module's string representation when receiver is an anonymous module" do
+ m = Module.new
- begin
- mod.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for module MyModule\Z/
- end
+ begin
+ m.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for module #\Z/
end
+ end
- it "uses module's string representation when receiver is an anonymous module" do
- m = Module.new
+ it "uses class #name when receiver is an ordinary object" do
+ klass = Class.new { def self.name; "MyClass"; end }
+ instance = klass.new
- begin
- m.foo
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for module #\Z/
- end
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for an instance of MyClass\Z/
end
+ end
- it "uses class #name when receiver is an ordinary object" do
- klass = Class.new { def self.name; "MyClass"; end }
- instance = klass.new
+ it "uses class string representation when receiver is an instance of anonymous class" do
+ klass = Class.new
+ instance = klass.new
- begin
- instance.bar
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for an instance of MyClass\Z/
- end
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for an instance of #\Z/
end
+ end
- it "uses class string representation when receiver is an instance of anonymous class" do
- klass = Class.new
- instance = klass.new
+ it "uses class name when receiver has a singleton class" do
+ instance = NoMethodErrorSpecs::NoMethodErrorA.new
+ def instance.foo; end
- begin
- instance.bar
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for an instance of #\Z/
- end
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for #\Z/
end
+ end
- it "uses class name when receiver has a singleton class" do
- instance = NoMethodErrorSpecs::NoMethodErrorA.new
- def instance.foo; end
-
- begin
- instance.bar
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for #\Z/
+ it "does not call #inspect when calling Exception#message" do
+ ScratchPad.record []
+ test_class = Class.new do
+ def inspect
+ ScratchPad << :inspect_called
+ ""
end
end
+ instance = test_class.new
- it "does not call #inspect when calling Exception#message" do
- ScratchPad.record []
- test_class = Class.new do
- def inspect
- ScratchPad << :inspect_called
- ""
- end
- end
- instance = test_class.new
-
- begin
- instance.bar
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']bar' for an instance of #\Z/
- ScratchPad.recorded.should == []
- end
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for an instance of #\Z/
+ ScratchPad.recorded.should == []
end
+ end
- it "does not truncate long class names" do
- class_name = 'ExceptionSpecs::A' + 'a'*100
+ it "does not truncate long class names" do
+ class_name = 'ExceptionSpecs::A' + 'a'*100
- begin
- eval <<~RUBY
- class #{class_name}
- end
+ begin
+ eval <<~RUBY
+ class #{class_name}
+ end
- obj = #{class_name}.new
- obj.foo
- RUBY
- rescue NoMethodError => error
- error.message.should =~ /\Aundefined method [`']foo' for an instance of #{class_name}\Z/
- end
+ obj = #{class_name}.new
+ obj.foo
+ RUBY
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for an instance of #{class_name}\Z/
end
end
end
diff --git a/spec/ruby/core/false/singleton_method_spec.rb b/spec/ruby/core/false/singleton_method_spec.rb
index 738794b46c26f8..16dc85d67c64b7 100644
--- a/spec/ruby/core/false/singleton_method_spec.rb
+++ b/spec/ruby/core/false/singleton_method_spec.rb
@@ -1,15 +1,13 @@
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
+ 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)
- begin
- def (false).foo; end
- -> { false.singleton_method(:foo) }.should raise_error(NameError)
- ensure
- FalseClass.send(:remove_method, :foo)
- end
+ ensure
+ FalseClass.send(:remove_method, :foo)
end
end
end
diff --git a/spec/ruby/core/fiber/kill_spec.rb b/spec/ruby/core/fiber/kill_spec.rb
index 2f4c499280f400..abf23ff17621fa 100644
--- a/spec/ruby/core/fiber/kill_spec.rb
+++ b/spec/ruby/core/fiber/kill_spec.rb
@@ -2,89 +2,87 @@
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{}
+describe "Fiber#kill" do
+ it "kills a non-resumed fiber" do
+ fiber = Fiber.new{}
- fiber.alive?.should == true
+ 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
- fiber.kill
- fiber.alive?.should == false
- end
+ it "kills a resumed fiber" do
+ fiber = Fiber.new{while true; Fiber.yield; end}
+ fiber.resume
- it "can kill itself" do
- fiber = Fiber.new do
- Fiber.current.kill
- end
+ fiber.alive?.should == true
- fiber.alive?.should == true
+ fiber.kill
+ fiber.alive?.should == false
+ end
- fiber.resume
- fiber.alive?.should == false
+ it "can kill itself" do
+ fiber = Fiber.new do
+ Fiber.current.kill
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
+ fiber.alive?.should == true
+
+ fiber.resume
+ fiber.alive?.should == false
+ end
- child.resume
+ it "kills a resumed fiber from a child" do
+ parent = Fiber.new do
+ child = Fiber.new do
+ parent.kill
+ parent.alive?.should == true
end
- parent.resume
- parent.alive?.should == false
+ child.resume
end
- it "executes the ensure block" do
- ensure_executed = false
+ parent.resume
+ parent.alive?.should == false
+ end
- fiber = Fiber.new do
- while true; Fiber.yield; end
- ensure
- ensure_executed = true
- end
+ it "executes the ensure block" do
+ ensure_executed = false
- fiber.resume
- fiber.kill
- ensure_executed.should == true
+ fiber = Fiber.new do
+ while true; Fiber.yield; end
+ ensure
+ ensure_executed = true
end
- it "does not execute rescue block" do
- rescue_executed = false
+ fiber.resume
+ fiber.kill
+ ensure_executed.should == true
+ end
- fiber = Fiber.new do
- while true; Fiber.yield; end
- rescue Exception
- rescue_executed = true
- end
+ it "does not execute rescue block" do
+ rescue_executed = false
- fiber.resume
- fiber.kill
- rescue_executed.should == false
+ fiber = Fiber.new do
+ while true; Fiber.yield; end
+ rescue Exception
+ rescue_executed = true
end
- it "repeatedly kills a fiber" do
- fiber = Fiber.new do
- while true; Fiber.yield; end
- ensure
- while true; Fiber.yield; end
- end
+ fiber.resume
+ fiber.kill
+ rescue_executed.should == false
+ end
- fiber.kill
- fiber.alive?.should == false
+ 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
diff --git a/spec/ruby/core/fiber/storage_spec.rb b/spec/ruby/core/fiber/storage_spec.rb
index 015caaf3bbff48..6ffc13ee283bec 100644
--- a/spec/ruby/core/fiber/storage_spec.rb
+++ b/spec/ruby/core/fiber/storage_spec.rb
@@ -161,13 +161,11 @@ def key.to_str; "Foo"; end
-> { 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
+ 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
diff --git a/spec/ruby/core/file/basename_spec.rb b/spec/ruby/core/file/basename_spec.rb
index 87695ab97be3ca..66a5b56ed9a11a 100644
--- a/spec/ruby/core/file/basename_spec.rb
+++ b/spec/ruby/core/file/basename_spec.rb
@@ -162,11 +162,7 @@
it "rejects strings encoded with non ASCII-compatible encodings" do
Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |enc|
- begin
- path = "/foo/bar".encode(enc)
- rescue Encoding::ConverterNotFoundError
- next
- end
+ path = "/foo/bar".encode(enc)
-> {
File.basename(path)
diff --git a/spec/ruby/core/file/dirname_spec.rb b/spec/ruby/core/file/dirname_spec.rb
index 8e6016ce6fef5b..1b006af7839f17 100644
--- a/spec/ruby/core/file/dirname_spec.rb
+++ b/spec/ruby/core/file/dirname_spec.rb
@@ -78,7 +78,33 @@ def object.to_int; 2; end
File.dirname("foo/../").should == "foo"
end
+ it "rejects strings encoded with non ASCII-compatible encodings" do
+ Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |enc|
+ path = "/foo/bar".encode(enc)
+ -> {
+ File.dirname(path)
+ }.should raise_error(Encoding::CompatibilityError)
+ end
+ end
+
+ it "works with all ASCII-compatible encodings" do
+ Encoding.list.select(&:ascii_compatible?).each do |enc|
+ File.dirname("/foo/bar".encode(enc)).should == "/foo".encode(enc)
+ end
+ end
+
+ it "handles Shift JIS 0x5C (\\) as second byte of a multi-byte sequence" do
+ # dir/fileソname.txt
+ path = "dir/file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS)
+ path.valid_encoding?.should be_true
+ File.dirname(path).should == "dir"
+ end
+
platform_is_not :windows do
+ it "ignores repeated leading / (edge cases on non-windows)" do
+ File.dirname("/////foo/bar/").should == "/foo"
+ end
+
it "returns all the components of filename except the last one (edge cases on non-windows)" do
File.dirname('/////').should == '/'
File.dirname("//foo//").should == "/"
@@ -94,6 +120,13 @@ def object.to_int; 2; end
File.dirname("//foo//").should == "//foo"
File.dirname('/////').should == '//'
end
+
+ it "handles Shift JIS 0x5C (\\) as second byte of a multi-byte sequence (windows)" do
+ # dir\fileソname.txt
+ path = "dir\\file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS)
+ path.valid_encoding?.should be_true
+ File.dirname(path).should == "dir"
+ end
end
it "accepts an object that has a #to_path method" do
diff --git a/spec/ruby/core/float/ceil_spec.rb b/spec/ruby/core/float/ceil_spec.rb
index 75f56102922e82..5236a133f5de18 100644
--- a/spec/ruby/core/float/ceil_spec.rb
+++ b/spec/ruby/core/float/ceil_spec.rb
@@ -2,7 +2,7 @@
require_relative '../integer/shared/integer_ceil_precision'
describe "Float#ceil" do
- context "with precision" do
+ context "with values equal to integers" do
it_behaves_like :integer_ceil_precision, :Float
end
@@ -20,7 +20,9 @@
2.1679.ceil(0).should eql(3)
214.94.ceil(-1).should eql(220)
7.0.ceil(1).should eql(7.0)
+ 200.0.ceil(-2).should eql(200)
-1.234.ceil(2).should eql(-1.23)
5.123812.ceil(4).should eql(5.1239)
+ 10.00001.ceil(5).should eql(10.00001)
end
end
diff --git a/spec/ruby/core/float/floor_spec.rb b/spec/ruby/core/float/floor_spec.rb
index 8b492ef4732fb7..1fafdadee9b6d7 100644
--- a/spec/ruby/core/float/floor_spec.rb
+++ b/spec/ruby/core/float/floor_spec.rb
@@ -2,7 +2,7 @@
require_relative '../integer/shared/integer_floor_precision'
describe "Float#floor" do
- context "with precision" do
+ context "with values equal to integers" do
it_behaves_like :integer_floor_precision, :Float
end
@@ -20,7 +20,9 @@
2.1679.floor(0).should eql(2)
214.94.floor(-1).should eql(210)
7.0.floor(1).should eql(7.0)
+ 200.0.floor(-2).should eql(200)
-1.234.floor(2).should eql(-1.24)
5.123812.floor(4).should eql(5.1238)
+ 10.00001.floor(5).should eql(10.00001)
end
end
diff --git a/spec/ruby/core/float/round_spec.rb b/spec/ruby/core/float/round_spec.rb
index 7e8c792051b9d5..3e6575100bd52a 100644
--- a/spec/ruby/core/float/round_spec.rb
+++ b/spec/ruby/core/float/round_spec.rb
@@ -66,6 +66,7 @@
it "works for corner cases" do
42.0.round(308).should eql(42.0)
1.0e307.round(2).should eql(1.0e307)
+ 120.0.round(-1).should eql(120)
end
# redmine:5271
@@ -145,37 +146,35 @@
-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
+ # 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
it "raises FloatDomainError for exceptional values with a half option" do
@@ -197,7 +196,13 @@
it "returns 0 for 0 or undefined ndigits" do
(0.0).round.should == 0
(-0.0).round(0).should == 0
- (0.0).round(half: :up) == 0
+ (0.0).round(half: :up).should == 0
+ end
+
+ it "returns 0 for negative ndigits" do
+ (0.0).round(-1).should == 0
+ (-0.0).round(-1).should == 0
+ (0.0).round(-1, half: :up).should == 0
end
end
end
diff --git a/spec/ruby/core/gc/config_spec.rb b/spec/ruby/core/gc/config_spec.rb
index e20e8e4a16a97f..db452b0907f58b 100644
--- a/spec/ruby/core/gc/config_spec.rb
+++ b/spec/ruby/core/gc/config_spec.rb
@@ -40,6 +40,20 @@
GC.config.should == previous
end
+ ruby_version_is ""..."4.0" do
+ it "returns the same as GC.config but without the :implementation key" do
+ previous = GC.config
+ GC.config({}).should == previous.except(:implementation)
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "returns the same as GC.config, including the :implementation key" do
+ previous = GC.config
+ GC.config({}).should == previous
+ end
+ end
+
it "raises an ArgumentError if options include global keys" do
-> { GC.config(implementation: "default") }.should raise_error(ArgumentError, 'Attempting to set read-only key "Implementation"')
end
diff --git a/spec/ruby/core/hash/compact_spec.rb b/spec/ruby/core/hash/compact_spec.rb
index 13371bce434fc9..48f8bb7cae166c 100644
--- a/spec/ruby/core/hash/compact_spec.rb
+++ b/spec/ruby/core/hash/compact_spec.rb
@@ -19,28 +19,26 @@
@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 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 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
+ 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
diff --git a/spec/ruby/core/hash/constructor_spec.rb b/spec/ruby/core/hash/constructor_spec.rb
index 0f97f7b40e9c2c..301f8675ce27be 100644
--- a/spec/ruby/core/hash/constructor_spec.rb
+++ b/spec/ruby/core/hash/constructor_spec.rb
@@ -44,23 +44,23 @@
it "raises for elements that are not arrays" do
-> {
- Hash[[:a]].should == {}
- }.should raise_error(ArgumentError)
+ Hash[[:a]]
+ }.should raise_error(ArgumentError, "wrong element type Symbol at 0 (expected array)")
-> {
- Hash[[:nil]].should == {}
- }.should raise_error(ArgumentError)
+ Hash[[nil]]
+ }.should raise_error(ArgumentError, "wrong element type nil at 0 (expected array)")
end
it "raises an ArgumentError for arrays of more than 2 elements" do
- ->{ Hash[[[:a, :b, :c]]].should == {} }.should raise_error(ArgumentError)
+ ->{
+ Hash[[[:a, :b, :c]]]
+ }.should raise_error(ArgumentError, "invalid number of elements (3 for 1..2)")
end
it "raises an ArgumentError when passed a list of value-invalid-pairs in an array" do
-> {
- -> {
- Hash[[[:a, 1], [:b], 42, [:d, 2], [:e, 2, 3], []]]
- }.should complain(/ignoring wrong elements/)
- }.should raise_error(ArgumentError)
+ Hash[[[:a, 1], [:b], 42, [:d, 2], [:e, 2, 3], []]]
+ }.should raise_error(ArgumentError, "wrong element type Integer at 2 (expected array)")
end
describe "passed a single argument which responds to #to_hash" do
@@ -117,13 +117,11 @@ def obj.to_hash() { 1 => 2, 3 => 4 } end
Hash[hash].default_proc.should be_nil
end
- ruby_version_is '3.3' do
- it "does not retain compare_by_identity flag" do
- hash = { a: 1 }.compare_by_identity
- Hash[hash].compare_by_identity?.should == false
+ it "does not retain compare_by_identity flag" do
+ hash = { a: 1 }.compare_by_identity
+ Hash[hash].compare_by_identity?.should == false
- hash = {}.compare_by_identity
- Hash[hash].compare_by_identity?.should == false
- end
+ hash = {}.compare_by_identity
+ Hash[hash].compare_by_identity?.should == false
end
end
diff --git a/spec/ruby/core/hash/new_spec.rb b/spec/ruby/core/hash/new_spec.rb
index 5ae3e1f98d6205..8de44ec9411deb 100644
--- a/spec/ruby/core/hash/new_spec.rb
+++ b/spec/ruby/core/hash/new_spec.rb
@@ -34,7 +34,7 @@
-> { Hash.new(nil) { 0 } }.should raise_error(ArgumentError)
end
- ruby_version_is "3.3"..."3.4" do
+ ruby_version_is ""..."3.4" 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"))
diff --git a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb
index 7dbb9c0a98351d..ddf9038800005f 100644
--- a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb
+++ b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb
@@ -72,12 +72,10 @@
Hash.ruby2_keywords_hash(hash).default_proc.should == pr
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
- end
+ 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
end
end
diff --git a/spec/ruby/core/hash/shared/to_s.rb b/spec/ruby/core/hash/shared/to_s.rb
index e116b8878b9699..38dd2c44360a95 100644
--- a/spec/ruby/core/hash/shared/to_s.rb
+++ b/spec/ruby/core/hash/shared/to_s.rb
@@ -89,5 +89,36 @@
it "adds quotes to symbol keys that are not valid symbol literals" do
{ "needs-quotes": 1 }.send(@method).should == '{"needs-quotes": 1}'
end
+
+ it "can be evaled" do
+ no_quote = '{a: 1, a!: 1, a?: 1}'
+ eval(no_quote).inspect.should == no_quote
+ [
+ '{"": 1}',
+ '{"0": 1, "!": 1, "%": 1, "&": 1, "*": 1, "+": 1, "-": 1, "/": 1, "<": 1, ">": 1, "^": 1, "`": 1, "|": 1, "~": 1}',
+ '{"@a": 1, "$a": 1, "+@": 1, "a=": 1, "[]": 1}',
+ '{"a\"b": 1, "@@a": 1, "<=>": 1, "===": 1, "[]=": 1}',
+ ].each do |quote|
+ eval(quote).inspect.should == quote
+ end
+ end
+
+ it "can be evaled when Encoding.default_external is changed" do
+ external = Encoding.default_external
+
+ Encoding.default_external = Encoding::ASCII
+ utf8_ascii_hash = '{"\\u3042": 1}'
+ eval(utf8_ascii_hash).inspect.should == utf8_ascii_hash
+
+ Encoding.default_external = Encoding::UTF_8
+ utf8_hash = "{\u3042: 1}"
+ eval(utf8_hash).inspect.should == utf8_hash
+
+ Encoding.default_external = Encoding::Windows_31J
+ sjis_hash = "{\x87]: 1}".dup.force_encoding('sjis')
+ eval(sjis_hash).inspect.should == sjis_hash
+ ensure
+ Encoding.default_external = external
+ end
end
end
diff --git a/spec/ruby/core/integer/ceil_spec.rb b/spec/ruby/core/integer/ceil_spec.rb
index eb633fba78432f..395be58fbd3f48 100644
--- a/spec/ruby/core/integer/ceil_spec.rb
+++ b/spec/ruby/core/integer/ceil_spec.rb
@@ -10,15 +10,4 @@
context "with precision" do
it_behaves_like :integer_ceil_precision, :Integer
end
-
- context "precision argument specified as part of the ceil method is negative" do
- it "returns the smallest integer greater than self with at least precision.abs trailing zeros" do
- 18.ceil(-1).should eql(20)
- 18.ceil(-2).should eql(100)
- 18.ceil(-3).should eql(1000)
- -1832.ceil(-1).should eql(-1830)
- -1832.ceil(-2).should eql(-1800)
- -1832.ceil(-3).should eql(-1000)
- end
- end
end
diff --git a/spec/ruby/core/integer/shared/integer_ceil_precision.rb b/spec/ruby/core/integer/shared/integer_ceil_precision.rb
index 9f31c2cf615ed0..b23c17937faf0c 100644
--- a/spec/ruby/core/integer/shared/integer_ceil_precision.rb
+++ b/spec/ruby/core/integer/shared/integer_ceil_precision.rb
@@ -1,6 +1,6 @@
describe :integer_ceil_precision, shared: true do
context "precision is zero" do
- it "returns integer self" do
+ it "returns Integer equal to self" do
send(@method, 0).ceil(0).should.eql?(0)
send(@method, 123).ceil(0).should.eql?(123)
send(@method, -123).ceil(0).should.eql?(-123)
@@ -23,7 +23,16 @@
send(@method, 0).ceil(-10).should.eql?(0)
end
- it "returns largest integer less than self with at least precision.abs trailing zeros" do
+ it "returns Integer equal to self if there are already at least precision.abs trailing zeros" do
+ send(@method, 10).ceil(-1).should.eql?(10)
+ send(@method, 100).ceil(-1).should.eql?(100)
+ send(@method, 100).ceil(-2).should.eql?(100)
+ send(@method, -10).ceil(-1).should.eql?(-10)
+ send(@method, -100).ceil(-1).should.eql?(-100)
+ send(@method, -100).ceil(-2).should.eql?(-100)
+ end
+
+ it "returns smallest Integer greater than self with at least precision.abs trailing zeros" do
send(@method, 123).ceil(-1).should.eql?(130)
send(@method, 123).ceil(-2).should.eql?(200)
send(@method, 123).ceil(-3).should.eql?(1000)
@@ -31,13 +40,15 @@
send(@method, -123).ceil(-1).should.eql?(-120)
send(@method, -123).ceil(-2).should.eql?(-100)
send(@method, -123).ceil(-3).should.eql?(0)
+
+ send(@method, 100).ceil(-3).should.eql?(1000)
+ send(@method, -100).ceil(-3).should.eql?(0)
end
- ruby_bug "#20654", ""..."3.4" do
- it "returns 10**precision.abs when precision.abs is larger than the number digits of self" do
- send(@method, 123).ceil(-20).should.eql?(100000000000000000000)
- send(@method, 123).ceil(-50).should.eql?(100000000000000000000000000000000000000000000000000)
- end
+ # Bug #20654
+ it "returns 10**precision.abs when precision.abs has more digits than self" do
+ send(@method, 123).ceil(-20).should.eql?(100000000000000000000)
+ send(@method, 123).ceil(-50).should.eql?(100000000000000000000000000000000000000000000000000)
end
end
end
diff --git a/spec/ruby/core/integer/shared/integer_floor_precision.rb b/spec/ruby/core/integer/shared/integer_floor_precision.rb
index 4c5888c6c4818d..6247907d4cd0b8 100644
--- a/spec/ruby/core/integer/shared/integer_floor_precision.rb
+++ b/spec/ruby/core/integer/shared/integer_floor_precision.rb
@@ -33,11 +33,10 @@
send(@method, -123).floor(-3).should.eql?(-1000)
end
- ruby_bug "#20654", ""..."3.4" do
- it "returns -(10**precision.abs) when self is negative and precision.abs is larger than the number digits of self" do
- send(@method, -123).floor(-20).should.eql?(-100000000000000000000)
- send(@method, -123).floor(-50).should.eql?(-100000000000000000000000000000000000000000000000000)
- end
+ # Bug #20654
+ it "returns -(10**precision.abs) when self is negative and precision.abs is larger than the number digits of self" do
+ send(@method, -123).floor(-20).should.eql?(-100000000000000000000)
+ send(@method, -123).floor(-50).should.eql?(-100000000000000000000000000000000000000000000000000)
end
end
end
diff --git a/spec/ruby/core/io/binread_spec.rb b/spec/ruby/core/io/binread_spec.rb
index 9e36b84da97350..e4576c1aa1e4f3 100644
--- a/spec/ruby/core/io/binread_spec.rb
+++ b/spec/ruby/core/io/binread_spec.rb
@@ -45,7 +45,7 @@
-> { IO.binread @fname, 0, -1 }.should raise_error(Errno::EINVAL)
end
- ruby_version_is "3.3"..."4.0" do
+ ruby_version_is ""..."4.0" do
# https://bugs.ruby-lang.org/issues/19630
it "warns about deprecation given a path with a pipe" do
cmd = "|echo ok"
diff --git a/spec/ruby/core/io/buffer/empty_spec.rb b/spec/ruby/core/io/buffer/empty_spec.rb
index e1fd4ab6a23268..788b23f88f0a48 100644
--- a/spec/ruby/core/io/buffer/empty_spec.rb
+++ b/spec/ruby/core/io/buffer/empty_spec.rb
@@ -14,11 +14,9 @@
@buffer.empty?.should be_true
end
- ruby_version_is "3.3" do
- it "is true for a 0-length String-backed buffer created with .string" do
- IO::Buffer.string(0) do |buffer|
- buffer.empty?.should be_true
- end
+ it "is true for a 0-length String-backed buffer created with .string" do
+ IO::Buffer.string(0) do |buffer|
+ buffer.empty?.should be_true
end
end
diff --git a/spec/ruby/core/io/buffer/external_spec.rb b/spec/ruby/core/io/buffer/external_spec.rb
index 4377a383578167..10bb51053d422d 100644
--- a/spec/ruby/core/io/buffer/external_spec.rb
+++ b/spec/ruby/core/io/buffer/external_spec.rb
@@ -6,103 +6,18 @@
@buffer = nil
end
- context "with a buffer created with .new" do
- it "is false for an internal buffer" do
- @buffer = IO::Buffer.new(4)
- @buffer.external?.should be_false
- end
-
- it "is false for a mapped buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
- @buffer.external?.should be_false
- end
- end
-
- context "with a file-backed buffer created with .map" do
- it "is true for a regular mapping" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
- @buffer.external?.should be_true
- end
- end
-
- ruby_version_is "3.3" do
- it "is false for a private mapping" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE)
- @buffer.external?.should be_false
- end
- end
- end
- end
-
- context "with a String-backed buffer created with .for" do
- it "is true for a buffer created without a block" do
- @buffer = IO::Buffer.for("test")
- @buffer.external?.should be_true
- end
-
- it "is true for a buffer created with a block" do
- IO::Buffer.for(+"test") do |buffer|
- buffer.external?.should be_true
- end
- end
+ it "is true for a buffer with externally-managed memory" do
+ @buffer = IO::Buffer.for("string")
+ @buffer.external?.should be_true
end
- ruby_version_is "3.3" do
- context "with a String-backed buffer created with .string" do
- it "is true" do
- IO::Buffer.string(4) do |buffer|
- buffer.external?.should be_true
- end
- end
- end
+ it "is false for a buffer with self-managed memory" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::MAPPED)
+ @buffer.external?.should be_false
end
- # Always false for slices
- context "with a slice of a buffer" do
- context "created with .new" do
- it "is false when slicing an internal buffer" do
- @buffer = IO::Buffer.new(4)
- @buffer.slice.external?.should be_false
- end
-
- it "is false when slicing a mapped buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
- @buffer.slice.external?.should be_false
- end
- end
-
- context "created with .map" do
- it "is false" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
- @buffer.slice.external?.should be_false
- end
- end
- end
-
- context "created with .for" do
- it "is false when slicing a buffer created without a block" do
- @buffer = IO::Buffer.for("test")
- @buffer.slice.external?.should be_false
- end
-
- it "is false when slicing a buffer created with a block" do
- IO::Buffer.for(+"test") do |buffer|
- buffer.slice.external?.should be_false
- end
- end
- end
-
- ruby_version_is "3.3" do
- context "created with .string" do
- it "is false" do
- IO::Buffer.string(4) do |buffer|
- buffer.slice.external?.should be_false
- end
- end
- end
- end
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.external?.should be_false
end
end
diff --git a/spec/ruby/core/io/buffer/for_spec.rb b/spec/ruby/core/io/buffer/for_spec.rb
new file mode 100644
index 00000000000000..d59a2a033afb3b
--- /dev/null
+++ b/spec/ruby/core/io/buffer/for_spec.rb
@@ -0,0 +1,94 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer.for" do
+ before :each do
+ @string = +"för striñg"
+ end
+
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "without a block" do
+ it "copies string's contents, creating a separate read-only buffer" do
+ @buffer = IO::Buffer.for(@string)
+
+ @buffer.size.should == @string.bytesize
+ @buffer.get_string.should == @string.b
+
+ @string[0] = "d"
+ @buffer.get_string(0, 1).should == "f".b
+
+ -> { @buffer.set_string("d") }.should raise_error(IO::Buffer::AccessError, "Buffer is not writable!")
+ end
+
+ it "creates an external, read-only buffer" do
+ @buffer = IO::Buffer.for(@string)
+
+ @buffer.should_not.internal?
+ @buffer.should_not.mapped?
+ @buffer.should.external?
+
+ @buffer.should_not.empty?
+ @buffer.should_not.null?
+
+ @buffer.should_not.shared?
+ @buffer.should_not.private?
+ @buffer.should.readonly?
+
+ @buffer.should_not.locked?
+ @buffer.should.valid?
+ end
+ end
+
+ context "with a block" do
+ it "returns the last value in the block" do
+ value =
+ IO::Buffer.for(@string) do |buffer|
+ buffer.size * 3
+ end
+ value.should == @string.bytesize * 3
+ end
+
+ it "frees the buffer at the end of the block" do
+ IO::Buffer.for(@string) do |buffer|
+ @buffer = buffer
+ @buffer.should_not.null?
+ end
+ @buffer.should.null?
+ end
+
+ context "if string is not frozen" do
+ it "creates a modifiable string-backed buffer" do
+ IO::Buffer.for(@string) do |buffer|
+ buffer.size.should == @string.bytesize
+ buffer.get_string.should == @string.b
+
+ buffer.should_not.readonly?
+
+ buffer.set_string("ghost shell")
+ @string.should == "ghost shellg"
+ end
+ end
+
+ it "locks the original string to prevent modification" do
+ IO::Buffer.for(@string) do |_buffer|
+ -> { @string[0] = "t" }.should raise_error(RuntimeError, "can't modify string; temporarily locked")
+ end
+ @string[1] = "u"
+ @string.should == "fur striñg"
+ end
+ end
+
+ context "if string is frozen" do
+ it "creates a read-only string-backed buffer" do
+ IO::Buffer.for(@string.freeze) do |buffer|
+ buffer.should.readonly?
+
+ -> { buffer.set_string("ghost shell") }.should raise_error(IO::Buffer::AccessError, "Buffer is not writable!")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/free_spec.rb b/spec/ruby/core/io/buffer/free_spec.rb
index f3a491897849ae..9a141e11f6b728 100644
--- a/spec/ruby/core/io/buffer/free_spec.rb
+++ b/spec/ruby/core/io/buffer/free_spec.rb
@@ -49,17 +49,15 @@
end
end
- ruby_version_is "3.3" do
- context "with a String-backed buffer created with .string" do
- it "disassociates the buffer from the string and nullifies the buffer" do
- string =
- IO::Buffer.string(4) do |buffer|
- buffer.set_string("meat")
- buffer.free
- buffer.null?.should be_true
- end
- string.should == "meat"
- end
+ context "with a String-backed buffer created with .string" do
+ it "disassociates the buffer from the string and nullifies the buffer" do
+ string =
+ IO::Buffer.string(4) do |buffer|
+ buffer.set_string("meat")
+ buffer.free
+ buffer.null?.should be_true
+ end
+ string.should == "meat"
end
end
diff --git a/spec/ruby/core/io/buffer/initialize_spec.rb b/spec/ruby/core/io/buffer/initialize_spec.rb
index c86d1e7f1d634a..90b501f53d9a92 100644
--- a/spec/ruby/core/io/buffer/initialize_spec.rb
+++ b/spec/ruby/core/io/buffer/initialize_spec.rb
@@ -14,14 +14,18 @@
it "creates a buffer with default state" do
@buffer = IO::Buffer.new
+
+ @buffer.should_not.external?
+
@buffer.should_not.shared?
+ @buffer.should_not.private?
@buffer.should_not.readonly?
@buffer.should_not.empty?
@buffer.should_not.null?
- # This is run-time state, set by #locked.
@buffer.should_not.locked?
+ @buffer.should.valid?
end
context "with size argument" do
@@ -29,25 +33,24 @@
size = IO::Buffer::PAGE_SIZE - 1
@buffer = IO::Buffer.new(size)
@buffer.size.should == size
+ @buffer.should_not.empty?
+
@buffer.should.internal?
@buffer.should_not.mapped?
- @buffer.should_not.empty?
end
it "creates a new mapped buffer if size is greater than or equal to IO::Buffer::PAGE_SIZE" do
size = IO::Buffer::PAGE_SIZE
@buffer = IO::Buffer.new(size)
@buffer.size.should == size
+ @buffer.should_not.empty?
+
@buffer.should_not.internal?
@buffer.should.mapped?
- @buffer.should_not.empty?
end
it "creates a null buffer if size is 0" do
@buffer = IO::Buffer.new(0)
- @buffer.size.should.zero?
- @buffer.should_not.internal?
- @buffer.should_not.mapped?
@buffer.should.null?
@buffer.should.empty?
end
@@ -77,27 +80,40 @@
@buffer.should_not.empty?
end
+ it "allows extra flags" do
+ @buffer = IO::Buffer.new(10, IO::Buffer::INTERNAL | IO::Buffer::SHARED | IO::Buffer::READONLY)
+ @buffer.should.internal?
+ @buffer.should.shared?
+ @buffer.should.readonly?
+ end
+
+ it "ignores flags if size is 0" do
+ @buffer = IO::Buffer.new(0, 0xffff)
+ @buffer.should.null?
+ @buffer.should.empty?
+
+ @buffer.should_not.internal?
+ @buffer.should_not.mapped?
+ @buffer.should_not.external?
+
+ @buffer.should_not.shared?
+ @buffer.should_not.readonly?
+
+ @buffer.should_not.locked?
+ @buffer.should.valid?
+ end
+
it "raises IO::Buffer::AllocationError if neither IO::Buffer::MAPPED nor IO::Buffer::INTERNAL is given" do
-> { IO::Buffer.new(10, IO::Buffer::READONLY) }.should raise_error(IO::Buffer::AllocationError, "Could not allocate buffer!")
-> { IO::Buffer.new(10, 0) }.should raise_error(IO::Buffer::AllocationError, "Could not allocate buffer!")
end
- ruby_version_is "3.3" do
- it "raises ArgumentError if flags is negative" do
- -> { IO::Buffer.new(10, -1) }.should raise_error(ArgumentError, "Flags can't be negative!")
- end
- end
-
- ruby_version_is ""..."3.3" do
- it "raises IO::Buffer::AllocationError with non-Integer flags" do
- -> { IO::Buffer.new(10, 0.0) }.should raise_error(IO::Buffer::AllocationError, "Could not allocate buffer!")
- end
+ it "raises ArgumentError if flags is negative" do
+ -> { IO::Buffer.new(10, -1) }.should raise_error(ArgumentError, "Flags can't be negative!")
end
- ruby_version_is "3.3" do
- it "raises TypeError with non-Integer flags" do
- -> { IO::Buffer.new(10, 0.0) }.should raise_error(TypeError, "not an Integer")
- end
+ it "raises TypeError with non-Integer flags" do
+ -> { IO::Buffer.new(10, 0.0) }.should raise_error(TypeError, "not an Integer")
end
end
end
diff --git a/spec/ruby/core/io/buffer/internal_spec.rb b/spec/ruby/core/io/buffer/internal_spec.rb
index 409699cc3c9230..40dc633d5d7fd0 100644
--- a/spec/ruby/core/io/buffer/internal_spec.rb
+++ b/spec/ruby/core/io/buffer/internal_spec.rb
@@ -6,103 +6,18 @@
@buffer = nil
end
- context "with a buffer created with .new" do
- it "is true for an internal buffer" do
- @buffer = IO::Buffer.new(4)
- @buffer.internal?.should be_true
- end
-
- it "is false for a mapped buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
- @buffer.internal?.should be_false
- end
- end
-
- context "with a file-backed buffer created with .map" do
- it "is false for a regular mapping" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
- @buffer.internal?.should be_false
- end
- end
-
- ruby_version_is "3.3" do
- it "is false for a private mapping" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE)
- @buffer.internal?.should be_false
- end
- end
- end
- end
-
- context "with a String-backed buffer created with .for" do
- it "is false for a buffer created without a block" do
- @buffer = IO::Buffer.for("test")
- @buffer.internal?.should be_false
- end
-
- it "is false for a buffer created with a block" do
- IO::Buffer.for(+"test") do |buffer|
- buffer.internal?.should be_false
- end
- end
+ it "is true for an internally-allocated buffer" do
+ @buffer = IO::Buffer.new(12)
+ @buffer.internal?.should be_true
end
- ruby_version_is "3.3" do
- context "with a String-backed buffer created with .string" do
- it "is false" do
- IO::Buffer.string(4) do |buffer|
- buffer.internal?.should be_false
- end
- end
- end
+ it "is false for an externally-allocated buffer" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::MAPPED)
+ @buffer.internal?.should be_false
end
- # Always false for slices
- context "with a slice of a buffer" do
- context "created with .new" do
- it "is false when slicing an internal buffer" do
- @buffer = IO::Buffer.new(4)
- @buffer.slice.internal?.should be_false
- end
-
- it "is false when slicing a mapped buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
- @buffer.slice.internal?.should be_false
- end
- end
-
- context "created with .map" do
- it "is false" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
- @buffer.slice.internal?.should be_false
- end
- end
- end
-
- context "created with .for" do
- it "is false when slicing a buffer created without a block" do
- @buffer = IO::Buffer.for("test")
- @buffer.slice.internal?.should be_false
- end
-
- it "is false when slicing a buffer created with a block" do
- IO::Buffer.for(+"test") do |buffer|
- buffer.slice.internal?.should be_false
- end
- end
- end
-
- ruby_version_is "3.3" do
- context "created with .string" do
- it "is false" do
- IO::Buffer.string(4) do |buffer|
- buffer.slice.internal?.should be_false
- end
- end
- end
- end
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.internal?.should be_false
end
end
diff --git a/spec/ruby/core/io/buffer/map_spec.rb b/spec/ruby/core/io/buffer/map_spec.rb
new file mode 100644
index 00000000000000..d980eb0ae0451a
--- /dev/null
+++ b/spec/ruby/core/io/buffer/map_spec.rb
@@ -0,0 +1,357 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer.map" do
+ before :all do
+ @big_file_name = tmp("big_file")
+ # Usually 4 kibibytes + 16 bytes
+ File.write(@big_file_name, "12345678" * (IO::Buffer::PAGE_SIZE / 8 + 2))
+ end
+
+ after :all do
+ File.delete(@big_file_name)
+ end
+
+ def open_fixture
+ File.open("#{__dir__}/../fixtures/read_text.txt", "r+")
+ end
+
+ def open_big_file_fixture
+ File.open(@big_file_name, "r+")
+ end
+
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ @file&.close
+ @file = nil
+ end
+
+ it "creates a new buffer mapped from a file" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file)
+
+ @buffer.size.should == 9
+ @buffer.get_string.should == "abcâdef\n".b
+ end
+
+ it "allows to close the file after creating buffer, retaining mapping" do
+ file = open_fixture
+ @buffer = IO::Buffer.map(file)
+ file.close
+
+ @buffer.get_string.should == "abcâdef\n".b
+ end
+
+ it "creates a mapped, external, shared buffer" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file)
+
+ @buffer.should_not.internal?
+ @buffer.should.mapped?
+ @buffer.should.external?
+
+ @buffer.should_not.empty?
+ @buffer.should_not.null?
+
+ @buffer.should.shared?
+ @buffer.should_not.private?
+ @buffer.should_not.readonly?
+
+ @buffer.should_not.locked?
+ @buffer.should.valid?
+ end
+
+ platform_is_not :windows do
+ it "is shareable across processes" do
+ file_name = tmp("shared_buffer")
+ @file = File.open(file_name, "w+")
+ @file << "I'm private"
+ @file.rewind
+ @buffer = IO::Buffer.map(@file)
+
+ IO.popen("-") do |child_pipe|
+ if child_pipe
+ # Synchronize on child's output.
+ child_pipe.readlines.first.chomp.should == @buffer.to_s
+ @buffer.get_string.should == "I'm shared!"
+
+ @file.read.should == "I'm shared!"
+ else
+ @buffer.set_string("I'm shared!")
+ puts @buffer
+ end
+ ensure
+ child_pipe&.close
+ end
+ ensure
+ File.unlink(file_name)
+ end
+ end
+
+ context "with an empty file" do
+ ruby_version_is ""..."4.0" do
+ it "raises a SystemCallError" do
+ @file = File.open("#{__dir__}/../fixtures/empty.txt", "r+")
+ -> { IO::Buffer.map(@file) }.should raise_error(SystemCallError)
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "raises ArgumentError" do
+ @file = File.open("#{__dir__}/../fixtures/empty.txt", "r+")
+ -> { IO::Buffer.map(@file) }.should raise_error(ArgumentError, "Invalid negative or zero file size!")
+ end
+ end
+ end
+
+ context "with a file opened only for reading" do
+ it "raises a SystemCallError if no flags are used" do
+ @file = File.open("#{__dir__}/../fixtures/read_text.txt", "r")
+ -> { IO::Buffer.map(@file) }.should raise_error(SystemCallError)
+ end
+ end
+
+ context "with size argument" do
+ it "limits the buffer to the specified size in bytes, starting from the start of the file" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, 4)
+
+ @buffer.size.should == 4
+ @buffer.get_string.should == "abc\xC3".b
+ end
+
+ it "maps the whole file if size is nil" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, nil)
+
+ @buffer.size.should == 9
+ end
+
+ context "if size is 0" do
+ ruby_version_is ""..."4.0" do
+ platform_is_not :windows do
+ it "raises a SystemCallError" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 0) }.should raise_error(SystemCallError)
+ end
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "raises ArgumentError" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 0) }.should raise_error(ArgumentError, "Size can't be zero!")
+ end
+ end
+ end
+
+ it "raises TypeError if size is not an Integer or nil" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, "10") }.should raise_error(TypeError, "not an Integer")
+ -> { IO::Buffer.map(@file, 10.0) }.should raise_error(TypeError, "not an Integer")
+ end
+
+ it "raises ArgumentError if size is negative" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, -1) }.should raise_error(ArgumentError, "Size can't be negative!")
+ end
+
+ ruby_version_is ""..."4.0" do
+ # May or may not cause a crash on access.
+ it "is undefined behavior if size is larger than file size"
+ end
+
+ ruby_version_is "4.0" do
+ it "raises ArgumentError if size is larger than file size" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 8192) }.should raise_error(ArgumentError, "Size can't be larger than file size!")
+ end
+ end
+ end
+
+ context "with size and offset arguments" do
+ # Neither Windows nor macOS have clear, stable behavior with non-zero offset.
+ # https://bugs.ruby-lang.org/issues/21700
+ platform_is :linux do
+ context "if offset is an allowed value for system call" do
+ it "maps the span specified by size starting from the offset" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, 14, IO::Buffer::PAGE_SIZE)
+
+ @buffer.size.should == 14
+ @buffer.get_string(0, 14).should == "12345678123456"
+ end
+
+ context "if size is nil" do
+ ruby_version_is ""..."4.0" do
+ it "maps the rest of the file" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE)
+
+ @buffer.get_string(0, 1).should == "1"
+ end
+
+ it "incorrectly sets buffer's size to file's full size" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE)
+
+ @buffer.size.should == @file.size
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "maps the rest of the file" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE)
+
+ @buffer.get_string(0, 1).should == "1"
+ end
+
+ it "sets buffer's size to file's remaining size" do
+ @file = open_big_file_fixture
+ @buffer = IO::Buffer.map(@file, nil, IO::Buffer::PAGE_SIZE)
+
+ @buffer.size.should == (@file.size - IO::Buffer::PAGE_SIZE)
+ end
+ end
+ end
+ end
+ end
+
+ it "maps the file from the start if offset is 0" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, 4, 0)
+
+ @buffer.size.should == 4
+ @buffer.get_string.should == "abc\xC3".b
+ end
+
+ ruby_version_is ""..."4.0" do
+ # May or may not cause a crash on access.
+ it "is undefined behavior if offset+size is larger than file size"
+ end
+
+ ruby_version_is "4.0" do
+ it "raises ArgumentError if offset+size is larger than file size" do
+ @file = open_big_file_fixture
+ -> { IO::Buffer.map(@file, 17, IO::Buffer::PAGE_SIZE) }.should raise_error(ArgumentError, "Offset too large!")
+ ensure
+ # Windows requires the file to be closed before deletion.
+ @file.close unless @file.closed?
+ end
+ end
+
+ it "raises TypeError if offset is not convertible to Integer" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 4, "4096") }.should raise_error(TypeError, /no implicit conversion/)
+ -> { IO::Buffer.map(@file, 4, nil) }.should raise_error(TypeError, /no implicit conversion/)
+ end
+
+ it "raises a SystemCallError if offset is not an allowed value" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 4, 3) }.should raise_error(SystemCallError)
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "raises a SystemCallError if offset is negative" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 4, -1) }.should raise_error(SystemCallError)
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "raises ArgumentError if offset is negative" do
+ @file = open_fixture
+ -> { IO::Buffer.map(@file, 4, -1) }.should raise_error(ArgumentError, "Offset can't be negative!")
+ end
+ end
+ end
+
+ context "with flags argument" do
+ context "when READONLY flag is specified" do
+ it "sets readonly flag on the buffer, allowing only reads" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::READONLY)
+
+ @buffer.should.readonly?
+
+ @buffer.get_string.should == "abc\xC3\xA2def\n".b
+ end
+
+ it "allows mapping read-only files" do
+ @file = File.open("#{__dir__}/../fixtures/read_text.txt", "r")
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::READONLY)
+
+ @buffer.should.readonly?
+
+ @buffer.get_string.should == "abc\xC3\xA2def\n".b
+ end
+
+ it "causes IO::Buffer::AccessError on write" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::READONLY)
+
+ -> { @buffer.set_string("test") }.should raise_error(IO::Buffer::AccessError, "Buffer is not writable!")
+ end
+ end
+
+ context "when PRIVATE is specified" do
+ it "sets private flag on the buffer, making it freely modifiable" do
+ @file = open_fixture
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::PRIVATE)
+
+ @buffer.should.private?
+ @buffer.should_not.shared?
+ @buffer.should_not.external?
+
+ @buffer.get_string.should == "abc\xC3\xA2def\n".b
+ @buffer.set_string("test12345")
+ @buffer.get_string.should == "test12345".b
+
+ @file.read.should == "abcâdef\n"
+ end
+
+ it "allows mapping read-only files and modifying the buffer" do
+ @file = File.open("#{__dir__}/../fixtures/read_text.txt", "r")
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::PRIVATE)
+
+ @buffer.should.private?
+ @buffer.should_not.shared?
+ @buffer.should_not.external?
+
+ @buffer.get_string.should == "abc\xC3\xA2def\n".b
+ @buffer.set_string("test12345")
+ @buffer.get_string.should == "test12345".b
+
+ @file.read.should == "abcâdef\n"
+ end
+
+ platform_is_not :windows do
+ it "is not shared across processes" do
+ file_name = tmp("shared_buffer")
+ @file = File.open(file_name, "w+")
+ @file << "I'm private"
+ @file.rewind
+ @buffer = IO::Buffer.map(@file, nil, 0, IO::Buffer::PRIVATE)
+
+ IO.popen("-") do |child_pipe|
+ if child_pipe
+ # Synchronize on child's output.
+ child_pipe.readlines.first.chomp.should == @buffer.to_s
+ @buffer.get_string.should == "I'm private"
+
+ @file.read.should == "I'm private"
+ else
+ @buffer.set_string("I'm shared!")
+ puts @buffer
+ end
+ ensure
+ child_pipe&.close
+ end
+ ensure
+ File.unlink(file_name)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/mapped_spec.rb b/spec/ruby/core/io/buffer/mapped_spec.rb
index b3610207ffb100..13dc548ed26e72 100644
--- a/spec/ruby/core/io/buffer/mapped_spec.rb
+++ b/spec/ruby/core/io/buffer/mapped_spec.rb
@@ -6,103 +6,18 @@
@buffer = nil
end
- context "with a buffer created with .new" do
- it "is false for an internal buffer" do
- @buffer = IO::Buffer.new(4)
- @buffer.mapped?.should be_false
- end
-
- it "is true for a mapped buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
- @buffer.mapped?.should be_true
- end
- end
-
- context "with a file-backed buffer created with .map" do
- it "is true for a regular mapping" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
- @buffer.mapped?.should be_true
- end
- end
-
- ruby_version_is "3.3" do
- it "is true for a private mapping" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE)
- @buffer.mapped?.should be_true
- end
- end
- end
- end
-
- context "with a String-backed buffer created with .for" do
- it "is false for a buffer created without a block" do
- @buffer = IO::Buffer.for("test")
- @buffer.mapped?.should be_false
- end
-
- it "is false for a buffer created with a block" do
- IO::Buffer.for(+"test") do |buffer|
- buffer.mapped?.should be_false
- end
- end
+ it "is true for a buffer with mapped memory" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::MAPPED)
+ @buffer.mapped?.should be_true
end
- ruby_version_is "3.3" do
- context "with a String-backed buffer created with .string" do
- it "is false" do
- IO::Buffer.string(4) do |buffer|
- buffer.mapped?.should be_false
- end
- end
- end
+ it "is false for a buffer with non-mapped memory" do
+ @buffer = IO::Buffer.for("string")
+ @buffer.mapped?.should be_false
end
- # Always false for slices
- context "with a slice of a buffer" do
- context "created with .new" do
- it "is false when slicing an internal buffer" do
- @buffer = IO::Buffer.new(4)
- @buffer.slice.mapped?.should be_false
- end
-
- it "is false when slicing a mapped buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
- @buffer.slice.mapped?.should be_false
- end
- end
-
- context "created with .map" do
- it "is false" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
- @buffer.slice.mapped?.should be_false
- end
- end
- end
-
- context "created with .for" do
- it "is false when slicing a buffer created without a block" do
- @buffer = IO::Buffer.for("test")
- @buffer.slice.mapped?.should be_false
- end
-
- it "is false when slicing a buffer created with a block" do
- IO::Buffer.for(+"test") do |buffer|
- buffer.slice.mapped?.should be_false
- end
- end
- end
-
- ruby_version_is "3.3" do
- context "created with .string" do
- it "is false" do
- IO::Buffer.string(4) do |buffer|
- buffer.slice.mapped?.should be_false
- end
- end
- end
- end
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.mapped?.should be_false
end
end
diff --git a/spec/ruby/core/io/buffer/null_spec.rb b/spec/ruby/core/io/buffer/null_spec.rb
index 3fb1144d0ed66f..3a0e7f841bf94d 100644
--- a/spec/ruby/core/io/buffer/null_spec.rb
+++ b/spec/ruby/core/io/buffer/null_spec.rb
@@ -14,11 +14,9 @@
@buffer.null?.should be_false
end
- ruby_version_is "3.3" do
- it "is false for a 0-length String-backed buffer created with .string" do
- IO::Buffer.string(0) do |buffer|
- buffer.null?.should be_false
- end
+ it "is false for a 0-length String-backed buffer created with .string" do
+ IO::Buffer.string(0) do |buffer|
+ buffer.null?.should be_false
end
end
diff --git a/spec/ruby/core/io/buffer/private_spec.rb b/spec/ruby/core/io/buffer/private_spec.rb
index 7aa308997b1939..86b7a7a0d0b391 100644
--- a/spec/ruby/core/io/buffer/private_spec.rb
+++ b/spec/ruby/core/io/buffer/private_spec.rb
@@ -1,111 +1,23 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.3" do
- describe "IO::Buffer#private?" do
- after :each do
- @buffer&.free
- @buffer = nil
- end
-
- context "with a buffer created with .new" do
- it "is false for an internal buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::INTERNAL)
- @buffer.private?.should be_false
- end
-
- it "is false for a mapped buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
- @buffer.private?.should be_false
- end
- end
-
- context "with a file-backed buffer created with .map" do
- it "is false for a regular mapping" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
- @buffer.private?.should be_false
- end
- end
-
- it "is true for a private mapping" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE)
- @buffer.private?.should be_true
- end
- end
- end
-
- context "with a String-backed buffer created with .for" do
- it "is false for a buffer created without a block" do
- @buffer = IO::Buffer.for("test")
- @buffer.private?.should be_false
- end
-
- it "is false for a buffer created with a block" do
- IO::Buffer.for(+"test") do |buffer|
- buffer.private?.should be_false
- end
- end
- end
-
- context "with a String-backed buffer created with .string" do
- it "is false" do
- IO::Buffer.string(4) do |buffer|
- buffer.private?.should be_false
- end
- end
- end
-
- # Always false for slices
- context "with a slice of a buffer" do
- context "created with .new" do
- it "is false when slicing an internal buffer" do
- @buffer = IO::Buffer.new(4)
- @buffer.slice.private?.should be_false
- end
-
- it "is false when slicing a mapped buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
- @buffer.slice.private?.should be_false
- end
- end
-
- context "created with .map" do
- it "is false when slicing a regular file-backed buffer" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
- @buffer.slice.private?.should be_false
- end
- end
-
- it "is false when slicing a private file-backed buffer" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE)
- @buffer.slice.private?.should be_false
- end
- end
- end
+describe "IO::Buffer#private?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
- context "created with .for" do
- it "is false when slicing a buffer created without a block" do
- @buffer = IO::Buffer.for("test")
- @buffer.slice.private?.should be_false
- end
+ it "is true for a buffer created with PRIVATE flag" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL | IO::Buffer::PRIVATE)
+ @buffer.private?.should be_true
+ end
- it "is false when slicing a buffer created with a block" do
- IO::Buffer.for(+"test") do |buffer|
- buffer.slice.private?.should be_false
- end
- end
- end
+ it "is false for a buffer created without PRIVATE flag" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL)
+ @buffer.private?.should be_false
+ end
- context "created with .string" do
- it "is false" do
- IO::Buffer.string(4) do |buffer|
- buffer.slice.private?.should be_false
- end
- end
- end
- end
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.private?.should be_false
end
end
diff --git a/spec/ruby/core/io/buffer/readonly_spec.rb b/spec/ruby/core/io/buffer/readonly_spec.rb
index 0014a876ed743e..2fc7d340b77b80 100644
--- a/spec/ruby/core/io/buffer/readonly_spec.rb
+++ b/spec/ruby/core/io/buffer/readonly_spec.rb
@@ -6,138 +6,23 @@
@buffer = nil
end
- context "with a buffer created with .new" do
- it "is false for an internal buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::INTERNAL)
- @buffer.readonly?.should be_false
- end
-
- it "is false for a mapped buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
- @buffer.readonly?.should be_false
- end
- end
-
- context "with a file-backed buffer created with .map" do
- it "is false for a writable mapping" do
- File.open(__FILE__, "r+") do |file|
- @buffer = IO::Buffer.map(file)
- @buffer.readonly?.should be_false
- end
- end
-
- it "is true for a readonly mapping" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
- @buffer.readonly?.should be_true
- end
- end
-
- ruby_version_is "3.3" do
- it "is false for a private mapping" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE)
- @buffer.readonly?.should be_false
- end
- end
- end
+ it "is true for a buffer created with READONLY flag" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL | IO::Buffer::READONLY)
+ @buffer.readonly?.should be_true
end
- context "with a String-backed buffer created with .for" do
- it "is true for a buffer created without a block" do
- @buffer = IO::Buffer.for(+"test")
- @buffer.readonly?.should be_true
- end
-
- it "is false for a buffer created with a block" do
- IO::Buffer.for(+"test") do |buffer|
- buffer.readonly?.should be_false
- end
- end
-
- it "is true for a buffer created with a block from a frozen string" do
- IO::Buffer.for(-"test") do |buffer|
- buffer.readonly?.should be_true
- end
- end
+ it "is true for a buffer that is non-writable" do
+ @buffer = IO::Buffer.for("string")
+ @buffer.readonly?.should be_true
end
- ruby_version_is "3.3" do
- context "with a String-backed buffer created with .string" do
- it "is false" do
- IO::Buffer.string(4) do |buffer|
- buffer.readonly?.should be_false
- end
- end
- end
+ it "is false for a modifiable buffer" do
+ @buffer = IO::Buffer.new(12)
+ @buffer.readonly?.should be_false
end
- # This seems to be the only flag propagated from the source buffer to the slice.
- context "with a slice of a buffer" do
- context "created with .new" do
- it "is false when slicing an internal buffer" do
- @buffer = IO::Buffer.new(4)
- @buffer.slice.readonly?.should be_false
- end
-
- it "is false when slicing a mapped buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
- @buffer.slice.readonly?.should be_false
- end
- end
-
- context "created with .map" do
- it "is false when slicing a read-write file-backed buffer" do
- File.open(__FILE__, "r+") do |file|
- @buffer = IO::Buffer.map(file)
- @buffer.slice.readonly?.should be_false
- end
- end
-
- it "is true when slicing a readonly file-backed buffer" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
- @buffer.slice.readonly?.should be_true
- end
- end
-
- ruby_version_is "3.3" do
- it "is false when slicing a private file-backed buffer" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE)
- @buffer.slice.readonly?.should be_false
- end
- end
- end
- end
-
- context "created with .for" do
- it "is true when slicing a buffer created without a block" do
- @buffer = IO::Buffer.for(+"test")
- @buffer.slice.readonly?.should be_true
- end
-
- it "is false when slicing a buffer created with a block" do
- IO::Buffer.for(+"test") do |buffer|
- buffer.slice.readonly?.should be_false
- end
- end
-
- it "is true when slicing a buffer created with a block from a frozen string" do
- IO::Buffer.for(-"test") do |buffer|
- buffer.slice.readonly?.should be_true
- end
- end
- end
-
- ruby_version_is "3.3" do
- context "created with .string" do
- it "is false" do
- IO::Buffer.string(4) do |buffer|
- buffer.slice.readonly?.should be_false
- end
- end
- end
- end
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.readonly?.should be_false
end
end
diff --git a/spec/ruby/core/io/buffer/resize_spec.rb b/spec/ruby/core/io/buffer/resize_spec.rb
index 0da3a23356c0dc..a5e80439dac653 100644
--- a/spec/ruby/core/io/buffer/resize_spec.rb
+++ b/spec/ruby/core/io/buffer/resize_spec.rb
@@ -44,17 +44,15 @@
end
end
- ruby_version_is "3.3" do
- it "resizes private buffer, discarding excess contents" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE)
- @buffer.resize(10)
- @buffer.size.should == 10
- @buffer.get_string.should == "require_re"
- @buffer.resize(12)
- @buffer.size.should == 12
- @buffer.get_string.should == "require_re\0\0"
- end
+ it "resizes private buffer, discarding excess contents" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE)
+ @buffer.resize(10)
+ @buffer.size.should == 10
+ @buffer.get_string.should == "require_re"
+ @buffer.resize(12)
+ @buffer.size.should == 12
+ @buffer.get_string.should == "require_re\0\0"
end
end
end
@@ -76,12 +74,10 @@
end
end
- ruby_version_is "3.3" do
- context "with a String-backed buffer created with .string" do
- it "disallows resizing, raising IO::Buffer::AccessError" do
- IO::Buffer.string(4) do |buffer|
- -> { buffer.resize(10) }.should raise_error(IO::Buffer::AccessError, "Cannot resize external buffer!")
- end
+ context "with a String-backed buffer created with .string" do
+ it "disallows resizing, raising IO::Buffer::AccessError" do
+ IO::Buffer.string(4) do |buffer|
+ -> { buffer.resize(10) }.should raise_error(IO::Buffer::AccessError, "Cannot resize external buffer!")
end
end
end
diff --git a/spec/ruby/core/io/buffer/shared/null_and_empty.rb b/spec/ruby/core/io/buffer/shared/null_and_empty.rb
index c8fe9e5e46ca9b..2ff5cf8f410db7 100644
--- a/spec/ruby/core/io/buffer/shared/null_and_empty.rb
+++ b/spec/ruby/core/io/buffer/shared/null_and_empty.rb
@@ -21,11 +21,9 @@
@buffer.send(@method).should be_false
end
- ruby_version_is "3.3" do
- it "is false for a non-empty String-backed buffer created with .string" do
- IO::Buffer.string(4) do |buffer|
- buffer.send(@method).should be_false
- end
+ it "is false for a non-empty String-backed buffer created with .string" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.send(@method).should be_false
end
end
diff --git a/spec/ruby/core/io/buffer/shared_spec.rb b/spec/ruby/core/io/buffer/shared_spec.rb
index f2a638cf39f9b1..4f3bce5448fee0 100644
--- a/spec/ruby/core/io/buffer/shared_spec.rb
+++ b/spec/ruby/core/io/buffer/shared_spec.rb
@@ -6,112 +6,25 @@
@buffer = nil
end
- context "with a buffer created with .new" do
- it "is false for an internal buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::INTERNAL)
- @buffer.shared?.should be_false
- end
-
- it "is false for a mapped buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
- @buffer.shared?.should be_false
- end
- end
-
- context "with a file-backed buffer created with .map" do
- it "is true for a regular mapping" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
- @buffer.shared?.should be_true
- end
- end
-
- ruby_version_is "3.3" do
- it "is false for a private mapping" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE)
- @buffer.shared?.should be_false
- end
- end
- end
+ it "is true for a buffer created with SHARED flag" do
+ @buffer = IO::Buffer.new(12, IO::Buffer::INTERNAL | IO::Buffer::SHARED)
+ @buffer.shared?.should be_true
end
- context "with a String-backed buffer created with .for" do
- it "is false for a buffer created without a block" do
- @buffer = IO::Buffer.for("test")
- @buffer.shared?.should be_false
- end
-
- it "is false for a buffer created with a block" do
- IO::Buffer.for(+"test") do |buffer|
- buffer.shared?.should be_false
- end
- end
+ it "is true for a non-private buffer created with .map" do
+ file = File.open("#{__dir__}/../fixtures/read_text.txt", "r+")
+ @buffer = IO::Buffer.map(file)
+ file.close
+ @buffer.shared?.should be_true
end
- ruby_version_is "3.3" do
- context "with a String-backed buffer created with .string" do
- it "is false" do
- IO::Buffer.string(4) do |buffer|
- buffer.shared?.should be_false
- end
- end
- end
+ it "is false for an unshared buffer" do
+ @buffer = IO::Buffer.new(12)
+ @buffer.shared?.should be_false
end
- # Always false for slices
- context "with a slice of a buffer" do
- context "created with .new" do
- it "is false when slicing an internal buffer" do
- @buffer = IO::Buffer.new(4)
- @buffer.slice.shared?.should be_false
- end
-
- it "is false when slicing a mapped buffer" do
- @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
- @buffer.slice.shared?.should be_false
- end
- end
-
- context "created with .map" do
- it "is false when slicing a regular file-backed buffer" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
- @buffer.slice.shared?.should be_false
- end
- end
-
- ruby_version_is "3.3" do
- it "is false when slicing a private file-backed buffer" do
- File.open(__FILE__, "r") do |file|
- @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE)
- @buffer.slice.shared?.should be_false
- end
- end
- end
- end
-
- context "created with .for" do
- it "is false when slicing a buffer created without a block" do
- @buffer = IO::Buffer.for("test")
- @buffer.slice.shared?.should be_false
- end
-
- it "is false when slicing a buffer created with a block" do
- IO::Buffer.for(+"test") do |buffer|
- buffer.slice.shared?.should be_false
- end
- end
- end
-
- ruby_version_is "3.3" do
- context "created with .string" do
- it "is false" do
- IO::Buffer.string(4) do |buffer|
- buffer.slice.shared?.should be_false
- end
- end
- end
- end
+ it "is false for a null buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.shared?.should be_false
end
end
diff --git a/spec/ruby/core/io/buffer/string_spec.rb b/spec/ruby/core/io/buffer/string_spec.rb
new file mode 100644
index 00000000000000..bc7a73075e3948
--- /dev/null
+++ b/spec/ruby/core/io/buffer/string_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer.string" do
+ it "creates a modifiable buffer for the duration of the block" do
+ IO::Buffer.string(7) do |buffer|
+ @buffer = buffer
+
+ buffer.size.should == 7
+ buffer.get_string.should == "\0\0\0\0\0\0\0".b
+
+ buffer.set_string("test")
+ buffer.get_string.should == "test\0\0\0"
+ end
+ @buffer.should.null?
+ end
+
+ it "returns contents of the buffer as a binary string" do
+ string =
+ IO::Buffer.string(7) do |buffer|
+ buffer.set_string("ä test")
+ end
+ string.should == "\xC3\xA4 test".b
+ end
+
+ it "creates an external buffer" do
+ IO::Buffer.string(8) do |buffer|
+ buffer.should_not.internal?
+ buffer.should_not.mapped?
+ buffer.should.external?
+
+ buffer.should_not.empty?
+ buffer.should_not.null?
+
+ buffer.should_not.shared?
+ buffer.should_not.private?
+ buffer.should_not.readonly?
+
+ buffer.should_not.locked?
+ buffer.should.valid?
+ end
+ end
+
+ it "returns an empty string if size is 0" do
+ string =
+ IO::Buffer.string(0) do |buffer|
+ buffer.size.should == 0
+ end
+ string.should == ""
+ end
+
+ it "raises ArgumentError if size is negative" do
+ -> { IO::Buffer.string(-1) {} }.should raise_error(ArgumentError, "negative string size (or size too big)")
+ end
+
+ it "raises RangeError if size is too large" do
+ -> { IO::Buffer.string(2 ** 232) {} }.should raise_error(RangeError, /\Abignum too big to convert into [`']long'\z/)
+ end
+
+ it "raises LocalJumpError if no block is given" do
+ -> { IO::Buffer.string(7) }.should raise_error(LocalJumpError, "no block given")
+ end
+end
diff --git a/spec/ruby/core/io/buffer/transfer_spec.rb b/spec/ruby/core/io/buffer/transfer_spec.rb
index cb8c843ff24750..5b7b63e3339991 100644
--- a/spec/ruby/core/io/buffer/transfer_spec.rb
+++ b/spec/ruby/core/io/buffer/transfer_spec.rb
@@ -60,17 +60,15 @@
end
end
- ruby_version_is "3.3" do
- context "with a String-backed buffer created with .string" do
- it "transfers memory to a new buffer, breaking the transaction by nullifying the original" do
- IO::Buffer.string(4) do |buffer|
- info = buffer.to_s
- @buffer = buffer.transfer
- @buffer.to_s.should == info
- buffer.null?.should be_true
- end
- @buffer.null?.should be_false
+ context "with a String-backed buffer created with .string" do
+ it "transfers memory to a new buffer, breaking the transaction by nullifying the original" do
+ IO::Buffer.string(4) do |buffer|
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should be_true
end
+ @buffer.null?.should be_false
end
end
diff --git a/spec/ruby/core/io/foreach_spec.rb b/spec/ruby/core/io/foreach_spec.rb
index 6abe8901bac7a0..28d6fef7ae5079 100644
--- a/spec/ruby/core/io/foreach_spec.rb
+++ b/spec/ruby/core/io/foreach_spec.rb
@@ -47,14 +47,12 @@
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
+ # 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
diff --git a/spec/ruby/core/io/gets_spec.rb b/spec/ruby/core/io/gets_spec.rb
index ca64bf860e4148..0587fa07c43289 100644
--- a/spec/ruby/core/io/gets_spec.rb
+++ b/spec/ruby/core/io/gets_spec.rb
@@ -338,23 +338,11 @@
@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 "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
end
diff --git a/spec/ruby/core/io/pread_spec.rb b/spec/ruby/core/io/pread_spec.rb
index dc7bcedf3e5c2f..8f7d9b2521d9c9 100644
--- a/spec/ruby/core/io/pread_spec.rb
+++ b/spec/ruby/core/io/pread_spec.rb
@@ -1,140 +1,138 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
- describe "IO#pread" do
- before :each do
- @fname = tmp("io_pread.txt")
- @contents = "1234567890"
- touch(@fname) { |f| f.write @contents }
- @file = File.open(@fname, "r+")
- end
-
- after :each do
- @file.close
- rm_r @fname
- end
+describe "IO#pread" do
+ before :each do
+ @fname = tmp("io_pread.txt")
+ @contents = "1234567890"
+ touch(@fname) { |f| f.write @contents }
+ @file = File.open(@fname, "r+")
+ end
- it "accepts a length, and an offset" do
- @file.pread(4, 0).should == "1234"
- @file.pread(3, 4).should == "567"
- end
+ after :each do
+ @file.close
+ rm_r @fname
+ end
- it "accepts a length, an offset, and an output buffer" do
- buffer = +"foo"
- @file.pread(3, 4, buffer).should.equal?(buffer)
- buffer.should == "567"
- end
+ it "accepts a length, and an offset" do
+ @file.pread(4, 0).should == "1234"
+ @file.pread(3, 4).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 "accepts a length, an offset, and an output buffer" do
+ buffer = +"foo"
+ @file.pread(3, 4, buffer).should.equal?(buffer)
+ buffer.should == "567"
+ end
- it "grows the buffer in case of more bytes read" do
- buffer = +"foo"
- @file.pread(5, 0, buffer)
- buffer.should == "12345"
- end
+ it "shrinks the buffer in case of less bytes read" do
+ buffer = +"foo"
+ @file.pread(1, 0, buffer)
+ buffer.should == "1"
+ end
- it "preserves the encoding of the given buffer" do
- buffer = ''.encode(Encoding::ISO_8859_1)
- @file.pread(10, 0, buffer)
+ it "grows the buffer in case of more bytes read" do
+ buffer = +"foo"
+ @file.pread(5, 0, buffer)
+ buffer.should == "12345"
+ end
- buffer.encoding.should == Encoding::ISO_8859_1
- end
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @file.pread(10, 0, buffer)
- it "does not advance the file pointer" do
- @file.pread(4, 0).should == "1234"
- @file.read.should == "1234567890"
- end
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
- it "ignores the current offset" do
- @file.pos = 3
- @file.pread(4, 0).should == "1234"
- end
+ it "does not advance the file pointer" do
+ @file.pread(4, 0).should == "1234"
+ @file.read.should == "1234567890"
+ end
- it "returns an empty string for maxlen = 0" do
- @file.pread(0, 4).should == ""
- end
+ it "ignores the current offset" do
+ @file.pos = 3
+ @file.pread(4, 0).should == "1234"
+ end
- it "returns a buffer for maxlen = 0 when buffer specified" do
- buffer = +"foo"
- @file.pread(0, 4, buffer).should.equal?(buffer)
- buffer.should == "foo"
- 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 "returns a buffer for maxlen = 0 when buffer specified" do
+ buffer = +"foo"
+ @file.pread(0, 4, buffer).should.equal?(buffer)
+ buffer.should == "foo"
+ end
- it "does not reset the buffer when reading with maxlen = 0" do
- buffer = +"foo"
- @file.pread(0, 4, buffer)
- buffer.should == "foo"
+ it "ignores the offset for maxlen = 0, even if it is out of file bounds" do
+ @file.pread(0, 400).should == ""
+ end
- @file.pread(0, 400, buffer)
- buffer.should == "foo"
- end
+ it "does not reset the buffer when reading with maxlen = 0" do
+ buffer = +"foo"
+ @file.pread(0, 4, buffer)
+ buffer.should == "foo"
- 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
+ @file.pread(0, 400, buffer)
+ buffer.should == "foo"
+ 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 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 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 "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 "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 "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 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 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 ArgumentError for negative values of maxlen" do
- -> { @file.pread(-4, 0) }.should raise_error(ArgumentError, 'negative string size (or size too big)')
- 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 "raised Errno::EINVAL for negative values of offset" do
- -> { @file.pread(4, -1) }.should raise_error(Errno::EINVAL, /Invalid argument/)
- 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 "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 "raised Errno::EINVAL for negative values of offset" do
+ -> { @file.pread(4, -1) }.should raise_error(Errno::EINVAL, /Invalid argument/)
+ end
- it "raises EOFError if end-of-file is reached" do
- -> { @file.pread(1, 10) }.should raise_error(EOFError)
- 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 IOError when file is not open in read mode" do
- File.open(@fname, "w") do |file|
- -> { file.pread(1, 1) }.should raise_error(IOError)
- end
- end
+ it "raises EOFError if end-of-file is reached" do
+ -> { @file.pread(1, 10) }.should raise_error(EOFError)
+ end
- it "raises IOError when file is closed" do
- file = File.open(@fname, "r+")
- file.close
+ it "raises IOError when file is not open in read mode" do
+ File.open(@fname, "w") do |file|
-> { file.pread(1, 1) }.should raise_error(IOError)
end
end
+
+ it "raises IOError when file is closed" do
+ file = File.open(@fname, "r+")
+ file.close
+ -> { file.pread(1, 1) }.should raise_error(IOError)
+ end
end
diff --git a/spec/ruby/core/io/pwrite_spec.rb b/spec/ruby/core/io/pwrite_spec.rb
index 2bc508b37d1660..fd0b6cf380c463 100644
--- a/spec/ruby/core/io/pwrite_spec.rb
+++ b/spec/ruby/core/io/pwrite_spec.rb
@@ -1,69 +1,67 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
- describe "IO#pwrite" do
- before :each do
- @fname = tmp("io_pwrite.txt")
- @file = File.open(@fname, "w+")
- end
+describe "IO#pwrite" do
+ before :each do
+ @fname = tmp("io_pwrite.txt")
+ @file = File.open(@fname, "w+")
+ end
- after :each do
- @file.close
- rm_r @fname
- end
+ after :each do
+ @file.close
+ rm_r @fname
+ end
- it "returns the number of bytes written" do
- @file.pwrite("foo", 0).should == 3
- end
+ it "returns the number of bytes written" do
+ @file.pwrite("foo", 0).should == 3
+ end
- it "accepts a string and an offset" do
- @file.pwrite("foo", 2)
- @file.pread(3, 2).should == "foo"
- end
+ it "accepts a string and an offset" do
+ @file.pwrite("foo", 2)
+ @file.pread(3, 2).should == "foo"
+ end
- it "does not advance the pointer in the file" do
- @file.pwrite("bar", 3)
- @file.write("foo")
- @file.pread(6, 0).should == "foobar"
- end
+ it "does not advance the pointer in the file" do
+ @file.pwrite("bar", 3)
+ @file.write("foo")
+ @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_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 "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")
- 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")
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 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 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")
- 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")
end
end
diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb
index 988ec2ce30df25..dfb42e09db7681 100644
--- a/spec/ruby/core/io/read_spec.rb
+++ b/spec/ruby/core/io/read_spec.rb
@@ -65,15 +65,6 @@
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
@@ -135,18 +126,9 @@
-> { 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 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 "uses the external encoding specified via the :external_encoding option" do
@@ -232,14 +214,12 @@
end
end
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19630
- it "warns about deprecation" do
- cmd = "|echo ok"
- -> {
- IO.read(cmd)
- }.should complain(/IO process creation with a leading '\|'/)
- end
+ # https://bugs.ruby-lang.org/issues/19630
+ it "warns about deprecation" do
+ cmd = "|echo ok"
+ -> {
+ IO.read(cmd)
+ }.should complain(/IO process creation with a leading '\|'/)
end
end
end
@@ -322,11 +302,9 @@
-> { @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
+ it "raise FrozenError if the output buffer is frozen (2)" do
+ @io.read
+ -> { @io.read(1, ''.freeze) }.should raise_error(FrozenError)
end
it "consumes zero bytes when reading zero bytes" do
diff --git a/spec/ruby/core/io/readlines_spec.rb b/spec/ruby/core/io/readlines_spec.rb
index b4770775d1e813..07d29ea5317f2d 100644
--- a/spec/ruby/core/io/readlines_spec.rb
+++ b/spec/ruby/core/io/readlines_spec.rb
@@ -207,14 +207,12 @@
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
+ # 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
diff --git a/spec/ruby/core/io/select_spec.rb b/spec/ruby/core/io/select_spec.rb
index 3893e7620f9e10..9fdb7e12c932db 100644
--- a/spec/ruby/core/io/select_spec.rb
+++ b/spec/ruby/core/io/select_spec.rb
@@ -149,16 +149,28 @@
end
end
-describe "IO.select when passed nil for timeout" do
- it "sleeps forever and sets the thread status to 'sleep'" do
- t = Thread.new do
- IO.select(nil, nil, nil, nil)
+describe "IO.select with infinite timeout" do
+ describe :io_select_infinite_timeout, shared: true do
+ it "sleeps forever and sets the thread status to 'sleep'" do
+ t = Thread.new do
+ IO.select(nil, nil, nil, @method)
+ end
+
+ Thread.pass while t.status && t.status != "sleep"
+ t.join unless t.status
+ t.status.should == "sleep"
+ t.kill
+ t.join
end
+ end
- Thread.pass while t.status && t.status != "sleep"
- t.join unless t.status
- t.status.should == "sleep"
- t.kill
- t.join
+ describe "IO.select when passed nil for timeout" do
+ it_behaves_like :io_select_infinite_timeout, nil
+ end
+
+ ruby_version_is "4.0" do
+ describe "IO.select when passed Float::INFINITY for timeout" do
+ it_behaves_like :io_select_infinite_timeout, Float::INFINITY
+ end
end
end
diff --git a/spec/ruby/core/io/shared/readlines.rb b/spec/ruby/core/io/shared/readlines.rb
index 6c1fa11a596800..77eb9cbd65cb8f 100644
--- a/spec/ruby/core/io/shared/readlines.rb
+++ b/spec/ruby/core/io/shared/readlines.rb
@@ -83,11 +83,9 @@
-> { 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
+ 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
diff --git a/spec/ruby/core/io/write_spec.rb b/spec/ruby/core/io/write_spec.rb
index e58100f8467d9c..95e6371985bf7c 100644
--- a/spec/ruby/core/io/write_spec.rb
+++ b/spec/ruby/core/io/write_spec.rb
@@ -102,6 +102,13 @@
File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000"
end
+ it "ignores the 'bom|' prefix" do
+ File.open(@filename, "w", encoding: 'bom|utf-8') do |file|
+ file.write("hi")
+ end
+ File.binread(@filename).should == "hi"
+ end
+
it "raises a invalid byte sequence error if invalid bytes are being written" do
# pack "\xFEhi" to avoid utf-8 conflict
xFEhi = ([254].pack('C*') + 'hi').force_encoding('utf-8')
@@ -220,7 +227,7 @@
end
end
- ruby_version_is "3.3"..."4.0" do
+ ruby_version_is ""..."4.0" do
# https://bugs.ruby-lang.org/issues/19630
it "warns about deprecation given a path with a pipe" do
-> {
diff --git a/spec/ruby/core/kernel/Integer_spec.rb b/spec/ruby/core/kernel/Integer_spec.rb
index 74dd3e0dd2ef27..c62b8b08013898 100644
--- a/spec/ruby/core/kernel/Integer_spec.rb
+++ b/spec/ruby/core/kernel/Integer_spec.rb
@@ -586,19 +586,10 @@
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")
- end
+ 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")
end
describe "when passed exception: false" do
diff --git a/spec/ruby/core/kernel/caller_spec.rb b/spec/ruby/core/kernel/caller_spec.rb
index 7cd703de5a3a8d..df051ef07f2d16 100644
--- a/spec/ruby/core/kernel/caller_spec.rb
+++ b/spec/ruby/core/kernel/caller_spec.rb
@@ -84,14 +84,25 @@
end
guard -> { Kernel.instance_method(:tap).source_location } do
- ruby_version_is ""..."4.0" do
+ ruby_version_is ""..."3.4" do
it "includes core library methods defined in Ruby" do
file, line = Kernel.instance_method(:tap).source_location
file.should.start_with?(' { 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/)
- end
+ it "raises when proc isn't a lambda" do
+ -> { lambda(&proc{}) }.should raise_error(ArgumentError, /the lambda method requires a literal block/)
end
it "doesn't warn when proc is lambda" do
diff --git a/spec/ruby/core/kernel/open_spec.rb b/spec/ruby/core/kernel/open_spec.rb
index b967d5044ba92b..9d3f3760b96b3e 100644
--- a/spec/ruby/core/kernel/open_spec.rb
+++ b/spec/ruby/core/kernel/open_spec.rb
@@ -79,14 +79,12 @@
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
+ # 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
diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb
index 52f86f73e50f48..ef5b9486c6157d 100644
--- a/spec/ruby/core/kernel/shared/require.rb
+++ b/spec/ruby/core/kernel/shared/require.rb
@@ -266,15 +266,13 @@
ScratchPad.recorded.should == [:loaded]
end
- ruby_bug "#17340", ''...'3.3' do
- it "loads a file concurrently" do
- path = File.expand_path "concurrent_require_fixture.rb", CODE_LOADING_DIR
- ScratchPad.record(@object)
- -> {
- @object.require(path)
- }.should_not complain(/circular require considered harmful/, verbose: true)
- ScratchPad.recorded.join
- end
+ it "loads a file concurrently" do
+ path = File.expand_path "concurrent_require_fixture.rb", CODE_LOADING_DIR
+ ScratchPad.record(@object)
+ -> {
+ @object.require(path)
+ }.should_not complain(/circular require considered harmful/, verbose: true)
+ ScratchPad.recorded.join
end
end
diff --git a/spec/ruby/core/kernel/sleep_spec.rb b/spec/ruby/core/kernel/sleep_spec.rb
index e9c600aac41107..0b003ad189a48b 100644
--- a/spec/ruby/core/kernel/sleep_spec.rb
+++ b/spec/ruby/core/kernel/sleep_spec.rb
@@ -63,27 +63,19 @@ def o.divmod(*); [0, 0.001]; end
actual_duration.should > 0.01 # 100 * 0.0001 => 0.01
end
- ruby_version_is ""..."3.3" do
- it "raises a TypeError when passed nil" do
- -> { sleep(nil) }.should raise_error(TypeError)
+ it "accepts a nil duration" do
+ running = false
+ t = Thread.new do
+ running = true
+ sleep(nil)
+ 5
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"
+ Thread.pass until running
+ Thread.pass while t.status and t.status != "sleep"
- t.wakeup
- t.value.should == 5
- end
+ t.wakeup
+ t.value.should == 5
end
context "Kernel.sleep with Fiber scheduler" do
diff --git a/spec/ruby/core/marshal/shared/load.rb b/spec/ruby/core/marshal/shared/load.rb
index 204a4d34e3edff..692c14cfa10adb 100644
--- a/spec/ruby/core/marshal/shared/load.rb
+++ b/spec/ruby/core/marshal/shared/load.rb
@@ -127,36 +127,32 @@
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" 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
+ 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
- ruby_bug "#19427", ""..."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 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 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)
+ 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
+ object = Marshal.send(@method, Marshal.dump(object), freeze: true)
+ object.should.frozen?
end
it "does not call freeze method" do
@@ -239,12 +235,10 @@
string.should.frozen?
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
+ 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
it "returns the value of the proc" do
@@ -930,15 +924,13 @@ def io.binmode; raise "binmode"; end
[Meths, UserRegexp, Regexp]
end
- ruby_bug "#19439", ""..."3.3" do
- it "restore the regexp instance variables" do
- obj = Regexp.new("hello")
- obj.instance_variable_set(:@regexp_ivar, [42])
+ it "restore the regexp instance variables" do
+ obj = Regexp.new("hello")
+ obj.instance_variable_set(:@regexp_ivar, [42])
- new_obj = Marshal.send(@method, "\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/")
- new_obj.instance_variables.should == [:@regexp_ivar]
- new_obj.instance_variable_get(:@regexp_ivar).should == [42]
- end
+ new_obj = Marshal.send(@method, "\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/")
+ new_obj.instance_variables.should == [:@regexp_ivar]
+ new_obj.instance_variable_get(:@regexp_ivar).should == [42]
end
it "preserves Regexp encoding" do
diff --git a/spec/ruby/core/matchdata/named_captures_spec.rb b/spec/ruby/core/matchdata/named_captures_spec.rb
index 5e4693d62d662b..10b1f884d6e4c9 100644
--- a/spec/ruby/core/matchdata/named_captures_spec.rb
+++ b/spec/ruby/core/matchdata/named_captures_spec.rb
@@ -13,15 +13,13 @@
/\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
- /(?.)(?.)?/.match('0').named_captures(symbolize_names: true).should == { a: '0', b: nil }
- /(?.)(?.)?/.match('0').named_captures(symbolize_names: "truly").should == { a: '0', b: nil }
- end
+ it 'returns a Hash with Symbol keys when symbolize_names is provided a true value' do
+ /(?.)(?.)?/.match('0').named_captures(symbolize_names: true).should == { a: '0', b: nil }
+ /(?.)(?.)?/.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
- /(?.)(?.)?/.match('02').named_captures(symbolize_names: false).should == { 'a' => '0', 'b' => '2' }
- /(?.)(?.)?/.match('02').named_captures(symbolize_names: nil).should == { 'a' => '0', 'b' => '2' }
- end
+ it 'returns a Hash with String keys when symbolize_names is provided a false value' do
+ /(?.)(?.)?/.match('02').named_captures(symbolize_names: false).should == { 'a' => '0', 'b' => '2' }
+ /(?.)(?.)?/.match('02').named_captures(symbolize_names: nil).should == { 'a' => '0', 'b' => '2' }
end
end
diff --git a/spec/ruby/core/math/log10_spec.rb b/spec/ruby/core/math/log10_spec.rb
index c4daedcd5c9d75..f3bd7fd4b86474 100644
--- a/spec/ruby/core/math/log10_spec.rb
+++ b/spec/ruby/core/math/log10_spec.rb
@@ -23,6 +23,10 @@
-> { Math.log10("test") }.should raise_error(TypeError)
end
+ it "raises a TypeError if passed a numerical argument as a string" do
+ -> { Math.log10("1.0") }.should raise_error(TypeError)
+ end
+
it "returns NaN given NaN" do
Math.log10(nan_value).nan?.should be_true
end
diff --git a/spec/ruby/core/module/set_temporary_name_spec.rb b/spec/ruby/core/module/set_temporary_name_spec.rb
index 46605ed6758877..0b96b869c90c51 100644
--- a/spec/ruby/core/module/set_temporary_name_spec.rb
+++ b/spec/ruby/core/module/set_temporary_name_spec.rb
@@ -1,147 +1,145 @@
require_relative '../../spec_helper'
require_relative 'fixtures/set_temporary_name'
-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
+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("fake_name")
+ m.name.should == "fake_name"
- m.set_temporary_name(nil)
- m.name.should be_nil
- end
+ m.set_temporary_name(nil)
+ m.name.should be_nil
+ end
- it "returns self" do
- m = Module.new
- m.set_temporary_name("fake_name").should.equal? m
- end
+ it "returns self" do
+ m = Module.new
+ m.set_temporary_name("fake_name").should.equal? m
+ end
- it "can assign a temporary name which is not a valid constant path" do
- m = Module.new
+ it "can assign a temporary name which is not a valid constant path" do
+ m = Module.new
- m.set_temporary_name("name")
- m.name.should == "name"
+ m.set_temporary_name("name")
+ m.name.should == "name"
- m.set_temporary_name("Template['foo.rb']")
- m.name.should == "Template['foo.rb']"
+ m.set_temporary_name("Template['foo.rb']")
+ m.name.should == "Template['foo.rb']"
- m.set_temporary_name("a::B")
- m.name.should == "a::B"
+ m.set_temporary_name("a::B")
+ m.name.should == "a::B"
- m.set_temporary_name("A::b")
- m.name.should == "A::b"
+ m.set_temporary_name("A::b")
+ m.name.should == "A::b"
- m.set_temporary_name("A::B::")
- m.name.should == "A::B::"
+ m.set_temporary_name("A::B::")
+ m.name.should == "A::B::"
- m.set_temporary_name("A::::B")
- m.name.should == "A::::B"
+ m.set_temporary_name("A::::B")
+ m.name.should == "A::::B"
- m.set_temporary_name("A=")
- m.name.should == "A="
- end
+ m.set_temporary_name("A=")
+ m.name.should == "A="
+ 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 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 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 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'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 module nested into an anonymous module" do
- m = Module.new
- module m::N; end
- m::N.name.should =~ /\A#::N\z/
+ it "can assign a temporary name to a module nested into an anonymous module" do
+ m = Module.new
+ module m::N; end
+ m::N.name.should =~ /\A#::N\z/
- m::N.set_temporary_name("fake_name")
- m::N.name.should == "fake_name"
+ 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
+ m::N.set_temporary_name(nil)
+ m::N.name.should be_nil
+ end
- it "discards a temporary name when an outer anonymous module gets a permanent name" do
- m = Module.new
- module m::N; end
+ it "discards a temporary name when an outer anonymous module gets a permanent name" do
+ m = Module.new
+ module m::N; end
- m::N.set_temporary_name("fake_name")
- m::N.name.should == "fake_name"
+ m::N.set_temporary_name("fake_name")
+ m::N.name.should == "fake_name"
- ModuleSpecs::SetTemporaryNameSpec::M = m
- m::N.name.should == "ModuleSpecs::SetTemporaryNameSpec::M::N"
- ModuleSpecs::SetTemporaryNameSpec.send :remove_const, :M
- end
+ ModuleSpecs::SetTemporaryNameSpec::M = m
+ m::N.name.should == "ModuleSpecs::SetTemporaryNameSpec::M::N"
+ ModuleSpecs::SetTemporaryNameSpec.send :remove_const, :M
+ end
- it "can update the name when assigned to a constant" do
- m = Module.new
- m::N = Module.new
- m::N.name.should =~ /\A#::N\z/
- m::N.set_temporary_name(nil)
+ it "can update the name when assigned to a constant" do
+ m = Module.new
+ m::N = Module.new
+ m::N.name.should =~ /\A#::N\z/
+ m::N.set_temporary_name(nil)
- m::M = m::N
- m::M.name.should =~ /\A#::M\z/m
- end
+ m::M = m::N
+ m::M.name.should =~ /\A#::M\z/m
+ end
- it "can reassign a temporary name repeatedly" do
- m = Module.new
+ it "can reassign a temporary name repeatedly" do
+ m = Module.new
- m.set_temporary_name("fake_name")
- m.name.should == "fake_name"
+ m.set_temporary_name("fake_name")
+ m.name.should == "fake_name"
- m.set_temporary_name("fake_name_2")
- m.name.should == "fake_name_2"
- end
+ m.set_temporary_name("fake_name_2")
+ m.name.should == "fake_name_2"
+ end
- ruby_bug "#21094", ""..."4.0" do
- it "also updates a name of a nested module" do
- m = Module.new
- m::N = Module.new
- m::N.name.should =~ /\A#::N\z/
+ ruby_bug "#21094", ""..."4.0" do
+ it "also updates a name of a nested module" do
+ m = Module.new
+ m::N = Module.new
+ m::N.name.should =~ /\A#::N\z/
- m.set_temporary_name "m"
- m::N.name.should == "m::N"
+ m.set_temporary_name "m"
+ m::N.name.should == "m::N"
- m.set_temporary_name nil
- m::N.name.should == nil
- end
+ m.set_temporary_name nil
+ m::N.name.should == nil
end
+ end
- it "keeps temporary name when assigned in an anonymous module" do
- outer = Module.new
- m = Module.new
- m.set_temporary_name "m"
- m.name.should == "m"
- outer::M = m
- m.name.should == "m"
- m.inspect.should == "m"
- end
+ it "keeps temporary name when assigned in an anonymous module" do
+ outer = Module.new
+ m = Module.new
+ m.set_temporary_name "m"
+ m.name.should == "m"
+ outer::M = m
+ m.name.should == "m"
+ m.inspect.should == "m"
+ end
- it "keeps temporary name when assigned in an anonymous module and nested before" do
- outer = Module.new
- m = Module.new
- outer::A = m
- m.set_temporary_name "m"
- m.name.should == "m"
- outer::M = m
- m.name.should == "m"
- m.inspect.should == "m"
- end
+ it "keeps temporary name when assigned in an anonymous module and nested before" do
+ outer = Module.new
+ m = Module.new
+ outer::A = m
+ m.set_temporary_name "m"
+ m.name.should == "m"
+ outer::M = m
+ m.name.should == "m"
+ m.inspect.should == "m"
end
end
diff --git a/spec/ruby/core/module/shared/class_eval.rb b/spec/ruby/core/module/shared/class_eval.rb
index b1d5cb3814edea..526d0a20363dc8 100644
--- a/spec/ruby/core/module/shared/class_eval.rb
+++ b/spec/ruby/core/module/shared/class_eval.rb
@@ -52,10 +52,8 @@ def foo
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
+ it "uses the caller location as default filename" do
+ ModuleSpecs.send(@method, "[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
end
it "converts a non-string filename to a string using to_str" do
diff --git a/spec/ruby/core/nil/singleton_method_spec.rb b/spec/ruby/core/nil/singleton_method_spec.rb
index 8d898b1cc94d70..fb47af0c3e8c5d 100644
--- a/spec/ruby/core/nil/singleton_method_spec.rb
+++ b/spec/ruby/core/nil/singleton_method_spec.rb
@@ -1,15 +1,13 @@
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
+ 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)
- begin
- def (nil).foo; end
- -> { nil.singleton_method(:foo) }.should raise_error(NameError)
- ensure
- NilClass.send(:remove_method, :foo)
- end
+ ensure
+ NilClass.send(:remove_method, :foo)
end
end
end
diff --git a/spec/ruby/core/numeric/remainder_spec.rb b/spec/ruby/core/numeric/remainder_spec.rb
index 674fa22d8ef997..29654310d231e2 100644
--- a/spec/ruby/core/numeric/remainder_spec.rb
+++ b/spec/ruby/core/numeric/remainder_spec.rb
@@ -6,9 +6,7 @@
@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
+ @other.should_receive(:coerce).with(@obj).and_return([@obj, @other])
end
it "returns the result of calling self#% with other if self is 0" do
diff --git a/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb b/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb
index 8050e2c30729d6..b1804ec9b003b7 100644
--- a/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb
@@ -1,27 +1,25 @@
require_relative '../../../spec_helper'
-ruby_version_is '3.3' do
- describe "ObjectSpace::WeakKeyMap#clear" do
- it "removes all the entries" do
- m = ObjectSpace::WeakKeyMap.new
+describe "ObjectSpace::WeakKeyMap#clear" do
+ it "removes all the entries" do
+ m = ObjectSpace::WeakKeyMap.new
- key = Object.new
- value = Object.new
- m[key] = value
+ key = Object.new
+ value = Object.new
+ m[key] = value
- key2 = Object.new
- value2 = Object.new
- m[key2] = value2
+ key2 = Object.new
+ value2 = Object.new
+ m[key2] = value2
- m.clear
+ m.clear
- m.key?(key).should == false
- m.key?(key2).should == false
- end
+ m.key?(key).should == false
+ m.key?(key2).should == false
+ end
- it "returns self" do
- m = ObjectSpace::WeakKeyMap.new
- m.clear.should.equal?(m)
- end
+ it "returns self" do
+ m = ObjectSpace::WeakKeyMap.new
+ m.clear.should.equal?(m)
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
index 3cd61355d64f9f..ad32c2c75efda4 100644
--- a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
@@ -1,51 +1,49 @@
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
+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
+ 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
+ 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
+ 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::WeakKeyMap.new
- m.delete(Object.new).should == nil
- end
+ it "returns nil if the key is not found when no block is given" do
+ m = ObjectSpace::WeakKeyMap.new
+ m.delete(Object.new).should == nil
+ end
- it "returns nil when a key cannot be garbage collected" do
- map = ObjectSpace::WeakKeyMap.new
+ it "returns nil when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
- map.delete(1).should == nil
- map.delete(1.0).should == nil
- map.delete(:a).should == nil
- map.delete(true).should == nil
- map.delete(false).should == nil
- map.delete(nil).should == nil
- end
+ map.delete(1).should == nil
+ map.delete(1.0).should == nil
+ map.delete(:a).should == nil
+ map.delete(true).should == nil
+ map.delete(false).should == nil
+ map.delete(nil).should == nil
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
index 51368e8d3ba3af..53eff79c40fb1c 100644
--- a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
@@ -1,107 +1,105 @@
require_relative '../../../spec_helper'
require_relative 'fixtures/classes'
-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 "compares keys with #eql? semantics" do
- map = ObjectSpace::WeakKeyMap.new
- key = [1.0]
- map[key] = "x"
- map[[1]].should == nil
- map[[1.0]].should == "x"
- key.should == [1.0] # keep the key alive until here to keep the map entry
-
- map = ObjectSpace::WeakKeyMap.new
- key = [1]
- map[key] = "x"
- map[[1.0]].should == nil
- map[[1]].should == "x"
- key.should == [1] # keep the key alive until here to keep the map entry
-
- map = ObjectSpace::WeakKeyMap.new
- key1, key2 = %w[a a].map(&:upcase)
- ref = "x"
- map[key1] = ref
- map[key2].should == ref
- end
-
- it "compares key via #hash first" do
- x = mock('0')
- x.should_receive(:hash).and_return(0)
-
- map = ObjectSpace::WeakKeyMap.new
- key = 'foo'
- map[key] = :bar
- map[x].should == nil
- end
-
- it "does not compare keys with different #hash values via #eql?" do
- x = mock('x')
- x.should_not_receive(:eql?)
- x.stub!(:hash).and_return(0)
-
- y = mock('y')
- y.should_not_receive(:eql?)
- y.stub!(:hash).and_return(1)
-
- map = ObjectSpace::WeakKeyMap.new
- map[y] = 1
- map[x].should == nil
- end
-
- it "compares keys with the same #hash value via #eql?" do
- x = mock('x')
- x.should_receive(:eql?).and_return(true)
- x.stub!(:hash).and_return(42)
-
- y = mock('y')
- y.should_not_receive(:eql?)
- y.stub!(:hash).and_return(42)
-
- map = ObjectSpace::WeakKeyMap.new
- map[y] = 1
- map[x].should == 1
- end
-
- it "finds a value via an identical key even when its #eql? isn't reflexive" do
- x = mock('x')
- x.should_receive(:hash).at_least(1).and_return(42)
- x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
-
- map = ObjectSpace::WeakKeyMap.new
- map[x] = :x
- map[x].should == :x
- end
-
- it "supports keys with private #hash method" do
- key = WeakKeyMapSpecs::KeyWithPrivateHash.new
- map = ObjectSpace::WeakKeyMap.new
- map[key] = 42
- map[key].should == 42
- end
-
- it "returns nil and does not raise error when a key cannot be garbage collected" do
- map = ObjectSpace::WeakKeyMap.new
-
- map[1].should == nil
- map[1.0].should == nil
- map[:a].should == nil
- map[true].should == nil
- map[false].should == nil
- map[nil].should == nil
- end
+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 "compares keys with #eql? semantics" do
+ map = ObjectSpace::WeakKeyMap.new
+ key = [1.0]
+ map[key] = "x"
+ map[[1]].should == nil
+ map[[1.0]].should == "x"
+ key.should == [1.0] # keep the key alive until here to keep the map entry
+
+ map = ObjectSpace::WeakKeyMap.new
+ key = [1]
+ map[key] = "x"
+ map[[1.0]].should == nil
+ map[[1]].should == "x"
+ key.should == [1] # keep the key alive until here to keep the map entry
+
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2 = %w[a a].map(&:upcase)
+ ref = "x"
+ map[key1] = ref
+ map[key2].should == ref
+ end
+
+ it "compares key via #hash first" do
+ x = mock('0')
+ x.should_receive(:hash).and_return(0)
+
+ map = ObjectSpace::WeakKeyMap.new
+ key = 'foo'
+ map[key] = :bar
+ map[x].should == nil
+ end
+
+ it "does not compare keys with different #hash values via #eql?" do
+ x = mock('x')
+ x.should_not_receive(:eql?)
+ x.stub!(:hash).and_return(0)
+
+ y = mock('y')
+ y.should_not_receive(:eql?)
+ y.stub!(:hash).and_return(1)
+
+ map = ObjectSpace::WeakKeyMap.new
+ map[y] = 1
+ map[x].should == nil
+ end
+
+ it "compares keys with the same #hash value via #eql?" do
+ x = mock('x')
+ x.should_receive(:eql?).and_return(true)
+ x.stub!(:hash).and_return(42)
+
+ y = mock('y')
+ y.should_not_receive(:eql?)
+ y.stub!(:hash).and_return(42)
+
+ map = ObjectSpace::WeakKeyMap.new
+ map[y] = 1
+ map[x].should == 1
+ end
+
+ it "finds a value via an identical key even when its #eql? isn't reflexive" do
+ x = mock('x')
+ x.should_receive(:hash).at_least(1).and_return(42)
+ x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
+
+ map = ObjectSpace::WeakKeyMap.new
+ map[x] = :x
+ map[x].should == :x
+ end
+
+ it "supports keys with private #hash method" do
+ key = WeakKeyMapSpecs::KeyWithPrivateHash.new
+ map = ObjectSpace::WeakKeyMap.new
+ map[key] = 42
+ map[key].should == 42
+ end
+
+ it "returns nil and does not raise error when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
+
+ map[1].should == nil
+ map[1.0].should == nil
+ map[:a].should == nil
+ map[true].should == nil
+ map[false].should == nil
+ map[nil].should == nil
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
index 8db8d780c71a86..c480aa661ae2fd 100644
--- a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
@@ -1,82 +1,80 @@
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
+describe "ObjectSpace::WeakKeyMap#[]=" do
+ def should_accept(map, key, value)
+ (map[key] = value).should == value
+ map.should.key?(key)
+ map[key].should == value
+ 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 "is correct" do
+ 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 "does not duplicate and freeze String keys (like Hash#[]= does)" do
+ map = ObjectSpace::WeakKeyMap.new
+ key = +"a"
+ map[key] = 1
+
+ map.getkey("a").should.equal? key
+ map.getkey("a").should_not.frozen?
+
+ key.should == "a" # keep the key alive until here to keep the map entry
+ end
+
+ context "a key cannot be garbage collected" do
+ it "raises ArgumentError when Integer is used as a key" 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
+ -> { map[1] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
- it "requires the keys to implement #hash" do
+ it "raises ArgumentError when Float is used as a key" do
map = ObjectSpace::WeakKeyMap.new
- -> { map[BasicObject.new] = 1 }.should raise_error(NoMethodError, /undefined method [`']hash' for an instance of BasicObject/)
+ -> { map[1.0] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
- it "accepts frozen keys or values" do
+ it "raises ArgumentError when Symbol is used as a key" 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)
+ -> { map[:a] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
- it "does not duplicate and freeze String keys (like Hash#[]= does)" do
+ it "raises ArgumentError when true is used as a key" do
map = ObjectSpace::WeakKeyMap.new
- key = +"a"
- map[key] = 1
-
- map.getkey("a").should.equal? key
- map.getkey("a").should_not.frozen?
-
- key.should == "a" # keep the key alive until here to keep the map entry
+ -> { map[true] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
- context "a key cannot be garbage collected" do
- it "raises ArgumentError when Integer is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[1] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
-
- it "raises ArgumentError when Float is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[1.0] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
-
- it "raises ArgumentError when Symbol is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[:a] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
-
- it "raises ArgumentError when true is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[true] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
-
- it "raises ArgumentError when false is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[false] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
+ it "raises ArgumentError when false is used as a key" do
+ map = ObjectSpace::WeakKeyMap.new
+ -> { map[false] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
+ end
- it "raises ArgumentError when nil is used as a key" do
- map = ObjectSpace::WeakKeyMap.new
- -> { map[nil] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
- end
+ it "raises ArgumentError when nil is used as a key" do
+ map = ObjectSpace::WeakKeyMap.new
+ -> { map[nil] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
end
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
index 8a2dbf809d8c23..0c8dec8aea5248 100644
--- a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
@@ -1,28 +1,26 @@
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)
+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
+ map[key1] = true
+ map.getkey(key2).should equal(key1)
+ map.getkey("X").should == nil
- key1.should == "A" # keep the key alive until here to keep the map entry
- key2.should == "A" # keep the key alive until here to keep the map entry
- end
+ key1.should == "A" # keep the key alive until here to keep the map entry
+ key2.should == "A" # keep the key alive until here to keep the map entry
+ end
- it "returns nil when a key cannot be garbage collected" do
- map = ObjectSpace::WeakKeyMap.new
+ it "returns nil when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
- map.getkey(1).should == nil
- map.getkey(1.0).should == nil
- map.getkey(:a).should == nil
- map.getkey(true).should == nil
- map.getkey(false).should == nil
- map.getkey(nil).should == nil
- end
+ map.getkey(1).should == nil
+ map.getkey(1.0).should == nil
+ map.getkey(:a).should == nil
+ map.getkey(true).should == nil
+ map.getkey(false).should == nil
+ map.getkey(nil).should == nil
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
index 319f050970e31a..b6bb4691584293 100644
--- a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
@@ -1,21 +1,19 @@
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\#\z/
- map[key1] = 1
- map.inspect.should =~ /\A\#\z/
- map[key2] = 2
- map.inspect.should =~ /\A\#\z/
- map[key3] = 3
- map.inspect.should =~ /\A\#\z/
+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\#\z/
+ map[key1] = 1
+ map.inspect.should =~ /\A\#\z/
+ map[key2] = 2
+ map.inspect.should =~ /\A\#\z/
+ map[key3] = 3
+ map.inspect.should =~ /\A\#\z/
- key1.should == "foo" # keep the key alive until here to keep the map entry
- key2.should == "bar" # keep the key alive until here to keep the map entry
- key3.should == "bar" # keep the key alive until here to keep the map entry
- end
+ key1.should == "foo" # keep the key alive until here to keep the map entry
+ key2.should == "bar" # keep the key alive until here to keep the map entry
+ key3.should == "bar" # keep the key alive until here to keep the map entry
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
index a9a2e12432c845..e0b686667197cc 100644
--- a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
@@ -1,44 +1,42 @@
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]
+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
+ 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 "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
+ 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
- it "returns false when a key cannot be garbage collected" do
- map = ObjectSpace::WeakKeyMap.new
+ it "returns false when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
- map.key?(1).should == false
- map.key?(1.0).should == false
- map.key?(:a).should == false
- map.key?(true).should == false
- map.key?(false).should == false
- map.key?(nil).should == false
- end
+ map.key?(1).should == false
+ map.key?(1.0).should == false
+ map.key?(:a).should == false
+ map.key?(true).should == false
+ map.key?(false).should == false
+ map.key?(nil).should == false
end
end
diff --git a/spec/ruby/core/objectspace/weakmap/delete_spec.rb b/spec/ruby/core/objectspace/weakmap/delete_spec.rb
index 302de264fb2998..03beebbb83419d 100644
--- a/spec/ruby/core/objectspace/weakmap/delete_spec.rb
+++ b/spec/ruby/core/objectspace/weakmap/delete_spec.rb
@@ -1,30 +1,28 @@
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
+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
+ 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
+ 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
+ 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
diff --git a/spec/ruby/core/proc/clone_spec.rb b/spec/ruby/core/proc/clone_spec.rb
index 730dc421a87086..7d47f2cde5b4a5 100644
--- a/spec/ruby/core/proc/clone_spec.rb
+++ b/spec/ruby/core/proc/clone_spec.rb
@@ -5,7 +5,7 @@
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
+ ruby_bug "cloning a frozen proc is broken on Ruby 3.3", ""..."3.4" do
it "preserves frozen status" do
proc = Proc.new { }
proc.freeze
@@ -14,17 +14,15 @@
end
end
- ruby_version_is "3.3" do
- it "calls #initialize_clone on subclass" do
- obj = ProcSpecs::MyProc2.new(:a, 2) { }
- dup = obj.clone
+ it "calls #initialize_clone on subclass" do
+ obj = ProcSpecs::MyProc2.new(:a, 2) { }
+ dup = obj.clone
- dup.should_not equal(obj)
- dup.class.should == ProcSpecs::MyProc2
+ dup.should_not equal(obj)
+ dup.class.should == ProcSpecs::MyProc2
- dup.first.should == :a
- dup.second.should == 2
- dup.initializer.should == :clone
- end
+ dup.first.should == :a
+ dup.second.should == 2
+ dup.initializer.should == :clone
end
end
diff --git a/spec/ruby/core/proc/dup_spec.rb b/spec/ruby/core/proc/dup_spec.rb
index 716357d1f0e327..bdb7d8ab5a4e82 100644
--- a/spec/ruby/core/proc/dup_spec.rb
+++ b/spec/ruby/core/proc/dup_spec.rb
@@ -12,17 +12,15 @@
proc.dup.frozen?.should == false
end
- ruby_version_is "3.3" do
- it "calls #initialize_dup on subclass" do
- obj = ProcSpecs::MyProc2.new(:a, 2) { }
- dup = obj.dup
+ it "calls #initialize_dup on subclass" do
+ obj = ProcSpecs::MyProc2.new(:a, 2) { }
+ dup = obj.dup
- dup.should_not equal(obj)
- dup.class.should == ProcSpecs::MyProc2
+ dup.should_not equal(obj)
+ dup.class.should == ProcSpecs::MyProc2
- dup.first.should == :a
- dup.second.should == 2
- dup.initializer.should == :dup
- end
+ dup.first.should == :a
+ dup.second.should == 2
+ dup.initializer.should == :dup
end
end
diff --git a/spec/ruby/core/proc/lambda_spec.rb b/spec/ruby/core/proc/lambda_spec.rb
index 5c3c38fc2a64c1..67ee4645cd1f0a 100644
--- a/spec/ruby/core/proc/lambda_spec.rb
+++ b/spec/ruby/core/proc/lambda_spec.rb
@@ -14,13 +14,6 @@
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
- end
-
it "is preserved when passing a Proc with & to the proc keyword" do
proc(&->{}).lambda?.should be_true
proc(&proc{}).lambda?.should be_false
diff --git a/spec/ruby/core/process/argv0_spec.rb b/spec/ruby/core/process/argv0_spec.rb
index f5aba719e96a73..9cba382c009da4 100644
--- a/spec/ruby/core/process/argv0_spec.rb
+++ b/spec/ruby/core/process/argv0_spec.rb
@@ -13,10 +13,8 @@
end
end
- ruby_bug "#19597", ""..."3.3" do
- it "returns a frozen object" do
- Process.argv0.should.frozen?
- end
+ it "returns a frozen object" do
+ Process.argv0.should.frozen?
end
it "returns every time the same object" do
diff --git a/spec/ruby/core/process/status/bit_and_spec.rb b/spec/ruby/core/process/status/bit_and_spec.rb
index a80536462947f2..9fd1425a97600e 100644
--- a/spec/ruby/core/process/status/bit_and_spec.rb
+++ b/spec/ruby/core/process/status/bit_and_spec.rb
@@ -17,7 +17,7 @@
end
end
- ruby_version_is "3.3"..."4.0" do
+ ruby_version_is ""..."4.0" do
it "raises an ArgumentError if mask is negative" do
suppress_warning do
ruby_exe("exit(0)")
diff --git a/spec/ruby/core/process/status/right_shift_spec.rb b/spec/ruby/core/process/status/right_shift_spec.rb
index 355aaf4c9532cb..3eaedf50550e1d 100644
--- a/spec/ruby/core/process/status/right_shift_spec.rb
+++ b/spec/ruby/core/process/status/right_shift_spec.rb
@@ -16,7 +16,7 @@
end
end
- ruby_version_is "3.3"..."4.0" do
+ ruby_version_is ""..."4.0" do
it "raises an ArgumentError if shift value is negative" do
suppress_warning do
ruby_exe("exit(0)")
diff --git a/spec/ruby/core/process/warmup_spec.rb b/spec/ruby/core/process/warmup_spec.rb
index b562d52d226715..4530ae222c2606 100644
--- a/spec/ruby/core/process/warmup_spec.rb
+++ b/spec/ruby/core/process/warmup_spec.rb
@@ -1,11 +1,9 @@
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
+ # 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
diff --git a/spec/ruby/core/range/case_compare_spec.rb b/spec/ruby/core/range/case_compare_spec.rb
index c9b253f0a585d9..7a76487d68c575 100644
--- a/spec/ruby/core/range/case_compare_spec.rb
+++ b/spec/ruby/core/range/case_compare_spec.rb
@@ -11,9 +11,7 @@
it_behaves_like :range_cover_and_include, :===
it_behaves_like :range_cover, :===
- ruby_bug "#19533", ""..."3.3" do
- it "returns true on any value if begin and end are both nil" do
- (nil..nil).should === 1
- end
+ it "returns true on any value if begin and end are both nil" do
+ (nil..nil).should === 1
end
end
diff --git a/spec/ruby/core/range/overlap_spec.rb b/spec/ruby/core/range/overlap_spec.rb
index 9b6fc134934208..3e7d2bdda8acf9 100644
--- a/spec/ruby/core/range/overlap_spec.rb
+++ b/spec/ruby/core/range/overlap_spec.rb
@@ -1,89 +1,87 @@
require_relative '../../spec_helper'
-ruby_version_is '3.3' do
- describe "Range#overlap?" do
- it "returns true if other Range overlaps self" do
- (0..2).overlap?(1..3).should == true
- (1..3).overlap?(0..2).should == true
- (0..2).overlap?(0..2).should == true
- (0..3).overlap?(1..2).should == true
- (1..2).overlap?(0..3).should == true
-
- ('a'..'c').overlap?('b'..'d').should == true
- end
-
- it "returns false if other Range does not overlap self" do
- (0..2).overlap?(3..4).should == false
- (0..2).overlap?(-4..-1).should == false
-
- ('a'..'c').overlap?('d'..'f').should == false
- end
-
- it "raises TypeError when called with non-Range argument" do
- -> {
- (0..2).overlap?(1)
- }.should raise_error(TypeError, "wrong argument type Integer (expected Range)")
- end
-
- it "returns true when beginningless and endless Ranges overlap" do
- (0..2).overlap?(..3).should == true
- (0..2).overlap?(..1).should == true
- (0..2).overlap?(..0).should == true
-
- (..3).overlap?(0..2).should == true
- (..1).overlap?(0..2).should == true
- (..0).overlap?(0..2).should == true
-
- (0..2).overlap?(-1..).should == true
- (0..2).overlap?(1..).should == true
- (0..2).overlap?(2..).should == true
-
- (-1..).overlap?(0..2).should == true
- (1..).overlap?(0..2).should == true
- (2..).overlap?(0..2).should == true
-
- (0..).overlap?(2..).should == true
- (..0).overlap?(..2).should == true
- end
-
- it "returns false when beginningless and endless Ranges do not overlap" do
- (0..2).overlap?(..-1).should == false
- (0..2).overlap?(3..).should == false
-
- (..-1).overlap?(0..2).should == false
- (3..).overlap?(0..2).should == false
- end
-
- it "returns false when Ranges are not compatible" do
- (0..2).overlap?('a'..'d').should == false
- end
-
- it "return false when self is empty" do
- (2..0).overlap?(1..3).should == false
- (2...2).overlap?(1..3).should == false
- (1...1).overlap?(1...1).should == false
- (2..0).overlap?(2..0).should == false
-
- ('c'..'a').overlap?('b'..'d').should == false
- ('a'...'a').overlap?('b'..'d').should == false
- ('b'...'b').overlap?('b'...'b').should == false
- ('c'...'a').overlap?('c'...'a').should == false
- end
-
- it "return false when other Range is empty" do
- (1..3).overlap?(2..0).should == false
- (1..3).overlap?(2...2).should == false
-
- ('b'..'d').overlap?('c'..'a').should == false
- ('b'..'d').overlap?('c'...'c').should == false
- end
-
- it "takes into account exclusive end" do
- (0...2).overlap?(2..4).should == false
- (2..4).overlap?(0...2).should == false
-
- ('a'...'c').overlap?('c'..'e').should == false
- ('c'..'e').overlap?('a'...'c').should == false
- end
+describe "Range#overlap?" do
+ it "returns true if other Range overlaps self" do
+ (0..2).overlap?(1..3).should == true
+ (1..3).overlap?(0..2).should == true
+ (0..2).overlap?(0..2).should == true
+ (0..3).overlap?(1..2).should == true
+ (1..2).overlap?(0..3).should == true
+
+ ('a'..'c').overlap?('b'..'d').should == true
+ end
+
+ it "returns false if other Range does not overlap self" do
+ (0..2).overlap?(3..4).should == false
+ (0..2).overlap?(-4..-1).should == false
+
+ ('a'..'c').overlap?('d'..'f').should == false
+ end
+
+ it "raises TypeError when called with non-Range argument" do
+ -> {
+ (0..2).overlap?(1)
+ }.should raise_error(TypeError, "wrong argument type Integer (expected Range)")
+ end
+
+ it "returns true when beginningless and endless Ranges overlap" do
+ (0..2).overlap?(..3).should == true
+ (0..2).overlap?(..1).should == true
+ (0..2).overlap?(..0).should == true
+
+ (..3).overlap?(0..2).should == true
+ (..1).overlap?(0..2).should == true
+ (..0).overlap?(0..2).should == true
+
+ (0..2).overlap?(-1..).should == true
+ (0..2).overlap?(1..).should == true
+ (0..2).overlap?(2..).should == true
+
+ (-1..).overlap?(0..2).should == true
+ (1..).overlap?(0..2).should == true
+ (2..).overlap?(0..2).should == true
+
+ (0..).overlap?(2..).should == true
+ (..0).overlap?(..2).should == true
+ end
+
+ it "returns false when beginningless and endless Ranges do not overlap" do
+ (0..2).overlap?(..-1).should == false
+ (0..2).overlap?(3..).should == false
+
+ (..-1).overlap?(0..2).should == false
+ (3..).overlap?(0..2).should == false
+ end
+
+ it "returns false when Ranges are not compatible" do
+ (0..2).overlap?('a'..'d').should == false
+ end
+
+ it "return false when self is empty" do
+ (2..0).overlap?(1..3).should == false
+ (2...2).overlap?(1..3).should == false
+ (1...1).overlap?(1...1).should == false
+ (2..0).overlap?(2..0).should == false
+
+ ('c'..'a').overlap?('b'..'d').should == false
+ ('a'...'a').overlap?('b'..'d').should == false
+ ('b'...'b').overlap?('b'...'b').should == false
+ ('c'...'a').overlap?('c'...'a').should == false
+ end
+
+ it "return false when other Range is empty" do
+ (1..3).overlap?(2..0).should == false
+ (1..3).overlap?(2...2).should == false
+
+ ('b'..'d').overlap?('c'..'a').should == false
+ ('b'..'d').overlap?('c'...'c').should == false
+ end
+
+ it "takes into account exclusive end" do
+ (0...2).overlap?(2..4).should == false
+ (2..4).overlap?(0...2).should == false
+
+ ('a'...'c').overlap?('c'..'e').should == false
+ ('c'..'e').overlap?('a'...'c').should == false
end
end
diff --git a/spec/ruby/core/range/reverse_each_spec.rb b/spec/ruby/core/range/reverse_each_spec.rb
index 56390cc0da4822..16aaace6afaa60 100644
--- a/spec/ruby/core/range/reverse_each_spec.rb
+++ b/spec/ruby/core/range/reverse_each_spec.rb
@@ -1,102 +1,124 @@
require_relative '../../spec_helper'
-ruby_version_is "3.3" do
- describe "Range#reverse_each" do
- it "traverses the Range in reverse order and passes each element to block" do
- a = []
- (1..3).reverse_each { |i| a << i }
- a.should == [3, 2, 1]
+describe "Range#reverse_each" do
+ it "traverses the Range in reverse order and passes each element to block" do
+ a = []
+ (1..3).reverse_each { |i| a << i }
+ a.should == [3, 2, 1]
+
+ a = []
+ (1...3).reverse_each { |i| a << i }
+ a.should == [2, 1]
+ end
- a = []
- (1...3).reverse_each { |i| a << i }
- a.should == [2, 1]
- end
+ it "returns self" do
+ r = (1..3)
+ r.reverse_each { |x| }.should equal(r)
+ end
- it "returns self" do
- r = (1..3)
- r.reverse_each { |x| }.should equal(r)
- end
+ it "returns an Enumerator if no block given" do
+ enum = (1..3).reverse_each
+ enum.should be_an_instance_of(Enumerator)
+ enum.to_a.should == [3, 2, 1]
+ end
- it "returns an Enumerator if no block given" do
- enum = (1..3).reverse_each
- enum.should be_an_instance_of(Enumerator)
- enum.to_a.should == [3, 2, 1]
- end
+ it "raises a TypeError for endless Ranges of Integers" do
+ -> {
+ (1..).reverse_each.take(3)
+ }.should raise_error(TypeError, "can't iterate from NilClass")
+ end
- it "raises a TypeError for endless Ranges of Integers" do
- -> {
- (1..).reverse_each.take(3)
- }.should raise_error(TypeError, "can't iterate from NilClass")
- end
+ it "raises a TypeError for endless Ranges of non-Integers" do
+ -> {
+ ("a"..).reverse_each.take(3)
+ }.should raise_error(TypeError, "can't iterate from NilClass")
+ end
- it "raises a TypeError for endless Ranges of non-Integers" do
- -> {
- ("a"..).reverse_each.take(3)
- }.should raise_error(TypeError, "can't iterate from NilClass")
+ context "Integer boundaries" do
+ it "supports beginningless Ranges" do
+ (..5).reverse_each.take(3).should == [5, 4, 3]
end
+ end
- context "Integer boundaries" do
- it "supports beginningless Ranges" do
- (..5).reverse_each.take(3).should == [5, 4, 3]
- end
+ context "non-Integer boundaries" do
+ it "uses #succ to iterate a Range of non-Integer elements" do
+ y = mock('y')
+ x = mock('x')
+
+ x.should_receive(:succ).any_number_of_times.and_return(y)
+ x.should_receive(:<=>).with(y).any_number_of_times.and_return(-1)
+ x.should_receive(:<=>).with(x).any_number_of_times.and_return(0)
+ y.should_receive(:<=>).with(x).any_number_of_times.and_return(1)
+ y.should_receive(:<=>).with(y).any_number_of_times.and_return(0)
+
+ a = []
+ (x..y).each { |i| a << i }
+ a.should == [x, y]
end
- context "non-Integer boundaries" do
- it "uses #succ to iterate a Range of non-Integer elements" do
- y = mock('y')
- x = mock('x')
+ it "uses #succ to iterate a Range of Strings" do
+ a = []
+ ('A'..'D').reverse_each { |i| a << i }
+ a.should == ['D','C','B','A']
+ end
- x.should_receive(:succ).any_number_of_times.and_return(y)
- x.should_receive(:<=>).with(y).any_number_of_times.and_return(-1)
- x.should_receive(:<=>).with(x).any_number_of_times.and_return(0)
- y.should_receive(:<=>).with(x).any_number_of_times.and_return(1)
- y.should_receive(:<=>).with(y).any_number_of_times.and_return(0)
+ it "uses #succ to iterate a Range of Symbols" do
+ a = []
+ (:A..:D).reverse_each { |i| a << i }
+ a.should == [:D, :C, :B, :A]
+ end
- a = []
- (x..y).each { |i| a << i }
- a.should == [x, y]
- end
+ it "raises a TypeError when `begin` value does not respond to #succ" do
+ -> { (Time.now..Time.now).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Time/)
+ -> { (//..//).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Regexp/)
+ -> { ([]..[]).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Array/)
+ end
- it "uses #succ to iterate a Range of Strings" do
- a = []
- ('A'..'D').reverse_each { |i| a << i }
- a.should == ['D','C','B','A']
- end
+ it "does not support beginningless Ranges" do
+ -> {
+ (..'a').reverse_each { |x| x }
+ }.should raise_error(TypeError, /can't iterate from NilClass/)
+ end
+ end
- it "uses #succ to iterate a Range of Symbols" do
- a = []
- (:A..:D).reverse_each { |i| a << i }
- a.should == [:D, :C, :B, :A]
- end
+ context "when no block is given" do
+ describe "returned Enumerator size" do
+ it "returns the Range size when Range size is finite" do
+ (1..3).reverse_each.size.should == 3
+ (1...3).reverse_each.size.should == 2
- it "raises a TypeError when `begin` value does not respond to #succ" do
- -> { (Time.now..Time.now).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Time/)
- -> { (//..//).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Regexp/)
- -> { ([]..[]).reverse_each { |x| x } }.should raise_error(TypeError, /can't iterate from Array/)
+ (1..3.3).reverse_each.size.should == 3
+ (1...3.3).reverse_each.size.should == 3
end
- it "does not support beginningless Ranges" do
- -> {
- (..'a').reverse_each { |x| x }
- }.should raise_error(TypeError, /can't iterate from NilClass/)
+ ruby_version_is ""..."3.4" do
+ it "returns a size when it is not iterable" do
+ (1.1..3).reverse_each.size.should == 2
+ (1.1..3.3).reverse_each.size.should == 3
+ (1.1..nil).reverse_each.size.should == Float::INFINITY
+ (nil..3.3).reverse_each.size.should == Float::INFINITY
+ (nil..nil).reverse_each.size.should == nil
+ end
end
- end
- context "when no block is given" do
- describe "returned Enumerator size" do
- it "returns the Range size when Range size is finite" do
- (1..3).reverse_each.size.should == 3
+ ruby_version_is "3.4" do
+ it "raises TypeError when the range is not iterable" do
+ -> { (1.1..3).reverse_each.size }.should raise_error(TypeError, /can't iterate from Integer/)
+ -> { (1.1..3.3).reverse_each.size }.should raise_error(TypeError, /can't iterate from Float/)
+ -> { (1.1..nil).reverse_each.size }.should raise_error(TypeError, /can't iterate from NilClass/)
+ -> { (nil..3.3).reverse_each.size }.should raise_error(TypeError, /can't iterate from Float/)
+ -> { (nil..nil).reverse_each.size }.should raise_error(TypeError, /can't iterate from NilClass/)
end
+ end
- ruby_bug "#20936", "3.4"..."4.0" do
- it "returns Infinity when Range size is infinite" do
- (..3).reverse_each.size.should == Float::INFINITY
- end
+ ruby_bug "#20936", "3.4"..."4.0" do
+ it "returns Infinity when Range size is infinite" do
+ (..3).reverse_each.size.should == Float::INFINITY
end
+ end
- it "returns nil when Range size is unknown" do
- ('a'..'z').reverse_each.size.should == nil
- end
+ it "returns nil when Range size is unknown" do
+ ('a'..'z').reverse_each.size.should == nil
end
end
end
diff --git a/spec/ruby/core/range/to_set_spec.rb b/spec/ruby/core/range/to_set_spec.rb
index 589c0e9aedec26..14e0ce1e31eac1 100644
--- a/spec/ruby/core/range/to_set_spec.rb
+++ b/spec/ruby/core/range/to_set_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
require_relative '../enumerable/fixtures/classes'
-describe "Enumerable#to_set" do
+describe "Range#to_set" do
it "returns a new Set created from self" do
(1..4).to_set.should == Set[1, 2, 3, 4]
(1...4).to_set.should == Set[1, 2, 3]
@@ -11,45 +11,44 @@
(1..3).to_set { |x| x * x }.should == Set[1, 4, 9]
end
+ it "raises a TypeError for a beginningless range" do
+ -> {
+ (..0).to_set
+ }.should raise_error(TypeError, "can't iterate from NilClass")
+ end
+
ruby_version_is "4.0" do
- it "raises a RangeError if the range is infinite" do
+ it "raises a RangeError if the range is endless" do
-> { (1..).to_set }.should raise_error(RangeError, "cannot convert endless range to a set")
-> { (1...).to_set }.should raise_error(RangeError, "cannot convert endless range to a set")
end
end
- ruby_version_is ""..."4.0" do
- it "instantiates an object of provided as the first argument set class" do
- set = (1..3).to_set(EnumerableSpecs::SetSubclass)
- set.should be_kind_of(EnumerableSpecs::SetSubclass)
- set.to_a.sort.should == [1, 2, 3]
- end
- end
-
- ruby_version_is "4.0"..."4.1" do
- it "instantiates an object of provided as the first argument set class and warns" do
- set = nil
- proc {
+ context "given positional arguments" do
+ ruby_version_is ""..."4.0" do
+ it "instantiates an object of provided as the first argument set class" do
set = (1..3).to_set(EnumerableSpecs::SetSubclass)
- }.should complain(/Enumerable#to_set/)
- set.should be_kind_of(EnumerableSpecs::SetSubclass)
- set.to_a.sort.should == [1, 2, 3]
+ set.should be_kind_of(EnumerableSpecs::SetSubclass)
+ set.to_a.sort.should == [1, 2, 3]
+ end
end
- end
- ruby_version_is "4.1" do
- it "does not accept any positional argument" do
- -> {
- (1..3).to_set(EnumerableSpecs::SetSubclass)
- }.should raise_error(ArgumentError, 'wrong number of arguments (given 1, expected 0)')
+ ruby_version_is "4.0"..."4.1" do
+ it "instantiates an object of provided as the first argument set class and warns" do
+ -> {
+ set = (1..3).to_set(EnumerableSpecs::SetSubclass)
+ set.should be_kind_of(EnumerableSpecs::SetSubclass)
+ set.to_a.sort.should == [1, 2, 3]
+ }.should complain(/warning: passing arguments to Enumerable#to_set is deprecated/)
+ end
end
- end
- it "does not need explicit `require 'set'`" do
- output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1')
- puts (1..3).to_set.to_a.inspect
- RUBY
-
- output.chomp.should == "[1, 2, 3]"
+ ruby_version_is "4.1" do
+ it "does not accept any positional argument" do
+ -> {
+ (1..3).to_set(EnumerableSpecs::SetSubclass)
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 1, expected 0)")
+ end
+ end
end
end
diff --git a/spec/ruby/core/rational/ceil_spec.rb b/spec/ruby/core/rational/ceil_spec.rb
index d5bdadf3b6b000..0c0327448f35c6 100644
--- a/spec/ruby/core/rational/ceil_spec.rb
+++ b/spec/ruby/core/rational/ceil_spec.rb
@@ -1,45 +1,48 @@
require_relative "../../spec_helper"
+require_relative "../integer/shared/integer_ceil_precision"
describe "Rational#ceil" do
+ context "with values equal to integers" do
+ it_behaves_like :integer_ceil_precision, :Rational
+ end
+
before do
@rational = Rational(2200, 7)
end
describe "with no arguments (precision = 0)" do
- it "returns an Integer" do
- @rational.ceil.should be_kind_of(Integer)
- end
+ it "returns the Integer value rounded toward positive infinity" do
+ @rational.ceil.should eql 315
- it "returns the truncated value toward positive infinity" do
- @rational.ceil.should == 315
- Rational(1, 2).ceil.should == 1
- Rational(-1, 2).ceil.should == 0
+ Rational(1, 2).ceil.should eql 1
+ Rational(-1, 2).ceil.should eql 0
+ Rational(1, 1).ceil.should eql 1
end
end
describe "with a precision < 0" do
- it "returns an Integer" do
- @rational.ceil(-2).should be_kind_of(Integer)
- @rational.ceil(-1).should be_kind_of(Integer)
- end
+ it "moves the rounding point n decimal places left, returning an Integer" do
+ @rational.ceil(-3).should eql 1000
+ @rational.ceil(-2).should eql 400
+ @rational.ceil(-1).should eql 320
- it "moves the truncation point n decimal places left" do
- @rational.ceil(-3).should == 1000
- @rational.ceil(-2).should == 400
- @rational.ceil(-1).should == 320
+ Rational(100, 2).ceil(-1).should eql 50
+ Rational(100, 2).ceil(-2).should eql 100
+ Rational(-100, 2).ceil(-1).should eql(-50)
+ Rational(-100, 2).ceil(-2).should eql(0)
end
end
describe "with precision > 0" do
- it "returns a Rational" do
- @rational.ceil(1).should be_kind_of(Rational)
- @rational.ceil(2).should be_kind_of(Rational)
- end
+ it "moves the rounding point n decimal places right, returning a Rational" do
+ @rational.ceil(1).should eql Rational(3143, 10)
+ @rational.ceil(2).should eql Rational(31429, 100)
+ @rational.ceil(3).should eql Rational(157143, 500)
- it "moves the truncation point n decimal places right" do
- @rational.ceil(1).should == Rational(3143, 10)
- @rational.ceil(2).should == Rational(31429, 100)
- @rational.ceil(3).should == Rational(157143, 500)
+ Rational(100, 2).ceil(1).should eql Rational(50, 1)
+ Rational(100, 2).ceil(2).should eql Rational(50, 1)
+ Rational(-100, 2).ceil(1).should eql Rational(-50, 1)
+ Rational(-100, 2).ceil(2).should eql Rational(-50, 1)
end
end
end
diff --git a/spec/ruby/core/rational/exponent_spec.rb b/spec/ruby/core/rational/exponent_spec.rb
index 65fbf2ed1ca895..1f8a03740cc087 100644
--- a/spec/ruby/core/rational/exponent_spec.rb
+++ b/spec/ruby/core/rational/exponent_spec.rb
@@ -108,37 +108,37 @@
it "raises an ArgumentError when self is > 1" do
-> {
(Rational(2) ** bignum_value)
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, "exponent is too large")
-> {
(Rational(fixnum_max) ** bignum_value)
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, "exponent is too large")
end
it "raises an ArgumentError when self is > 1 and the exponent is negative" do
-> {
(Rational(2) ** -bignum_value)
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, "exponent is too large")
-> {
(Rational(fixnum_max) ** -bignum_value)
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, "exponent is too large")
end
it "raises an ArgumentError when self is < -1" do
-> {
(Rational(-2) ** bignum_value)
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, "exponent is too large")
-> {
(Rational(fixnum_min) ** bignum_value)
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, "exponent is too large")
end
it "raises an ArgumentError when self is < -1 and the exponent is negative" do
-> {
(Rational(-2) ** -bignum_value)
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, "exponent is too large")
-> {
(Rational(fixnum_min) ** -bignum_value)
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, "exponent is too large")
end
end
diff --git a/spec/ruby/core/rational/floor_spec.rb b/spec/ruby/core/rational/floor_spec.rb
index 8068aaf119e70f..5108e363f7a67c 100644
--- a/spec/ruby/core/rational/floor_spec.rb
+++ b/spec/ruby/core/rational/floor_spec.rb
@@ -1,45 +1,49 @@
require_relative "../../spec_helper"
+require_relative "../integer/shared/integer_floor_precision"
describe "Rational#floor" do
+ context "with values equal to integers" do
+ it_behaves_like :integer_floor_precision, :Rational
+ end
+
before do
@rational = Rational(2200, 7)
end
describe "with no arguments (precision = 0)" do
- it "returns an integer" do
- @rational.floor.should be_kind_of(Integer)
- end
- it "returns the truncated value toward negative infinity" do
- @rational.floor.should == 314
- Rational(1, 2).floor.should == 0
- Rational(-1, 2).floor.should == -1
+ it "returns the Integer value rounded toward negative infinity" do
+ @rational.floor.should eql 314
+
+ Rational(1, 2).floor.should eql 0
+ Rational(-1, 2).floor.should eql(-1)
+ Rational(1, 1).floor.should eql 1
end
end
describe "with a precision < 0" do
- it "returns an integer" do
- @rational.floor(-2).should be_kind_of(Integer)
- @rational.floor(-1).should be_kind_of(Integer)
- end
+ it "moves the rounding point n decimal places left, returning an Integer" do
+ @rational.floor(-3).should eql 0
+ @rational.floor(-2).should eql 300
+ @rational.floor(-1).should eql 310
- it "moves the truncation point n decimal places left" do
- @rational.floor(-3).should == 0
- @rational.floor(-2).should == 300
- @rational.floor(-1).should == 310
+ Rational(100, 2).floor(-1).should eql 50
+ Rational(100, 2).floor(-2).should eql 0
+ Rational(-100, 2).floor(-1).should eql(-50)
+ Rational(-100, 2).floor(-2).should eql(-100)
end
end
describe "with a precision > 0" do
- it "returns a Rational" do
- @rational.floor(1).should be_kind_of(Rational)
- @rational.floor(2).should be_kind_of(Rational)
- end
+ it "moves the rounding point n decimal places right, returning a Rational" do
+ @rational.floor(1).should eql Rational(1571, 5)
+ @rational.floor(2).should eql Rational(7857, 25)
+ @rational.floor(3).should eql Rational(62857, 200)
- it "moves the truncation point n decimal places right" do
- @rational.floor(1).should == Rational(1571, 5)
- @rational.floor(2).should == Rational(7857, 25)
- @rational.floor(3).should == Rational(62857, 200)
+ Rational(100, 2).floor(1).should eql Rational(50, 1)
+ Rational(100, 2).floor(2).should eql Rational(50, 1)
+ Rational(-100, 2).floor(1).should eql Rational(-50, 1)
+ Rational(-100, 2).floor(2).should eql Rational(-50, 1)
end
end
end
diff --git a/spec/ruby/core/refinement/refined_class_spec.rb b/spec/ruby/core/refinement/refined_class_spec.rb
index 60a58380ccf00b..b532d9a7738cca 100644
--- a/spec/ruby/core/refinement/refined_class_spec.rb
+++ b/spec/ruby/core/refinement/refined_class_spec.rb
@@ -2,11 +2,7 @@
require_relative 'shared/target'
describe "Refinement#refined_class" do
- ruby_version_is ""..."3.3" do
- it_behaves_like :refinement_target, :refined_class
- end
-
- ruby_version_is "3.3"..."3.4" do
+ ruby_version_is ""..."3.4" do
it "has been deprecated in favour of Refinement#target" do
refinement_int = nil
diff --git a/spec/ruby/core/refinement/target_spec.rb b/spec/ruby/core/refinement/target_spec.rb
index fee9588a96ed65..8bd816aea622dd 100644
--- a/spec/ruby/core/refinement/target_spec.rb
+++ b/spec/ruby/core/refinement/target_spec.rb
@@ -2,7 +2,5 @@
require_relative 'shared/target'
describe "Refinement#target" do
- ruby_version_is "3.3" do
- it_behaves_like :refinement_target, :target
- end
+ it_behaves_like :refinement_target, :target
end
diff --git a/spec/ruby/core/regexp/linear_time_spec.rb b/spec/ruby/core/regexp/linear_time_spec.rb
index cf9e73c37c2b64..2f3f81ed207236 100644
--- a/spec/ruby/core/regexp/linear_time_spec.rb
+++ b/spec/ruby/core/regexp/linear_time_spec.rb
@@ -25,9 +25,7 @@
}.should complain(/warning: flags ignored/)
end
- ruby_version_is "3.3" do
- it "returns true for positive lookarounds" do
- Regexp.linear_time?(/(?:(?=a*)a)*/).should == true
- end
+ it "returns true for positive lookarounds" do
+ Regexp.linear_time?(/(?:(?=a*)a)*/).should == true
end
end
diff --git a/spec/ruby/core/set/flatten_spec.rb b/spec/ruby/core/set/flatten_spec.rb
index f2cb3dfa524a35..b26bc8481af58f 100644
--- a/spec/ruby/core/set/flatten_spec.rb
+++ b/spec/ruby/core/set/flatten_spec.rb
@@ -46,14 +46,4 @@
(set = Set[]) << set
-> { set.flatten! }.should raise_error(ArgumentError)
end
-
- version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
- ruby_version_is ""..."4.0" 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
- end
- end
- end
end
diff --git a/spec/ruby/core/set/merge_spec.rb b/spec/ruby/core/set/merge_spec.rb
index 0c6ed276700e7d..bf945cdcc02238 100644
--- a/spec/ruby/core/set/merge_spec.rb
+++ b/spec/ruby/core/set/merge_spec.rb
@@ -23,15 +23,7 @@
end
end
- ruby_version_is ""..."3.3" do
- it "accepts only a single argument" do
- -> { Set[].merge([], []) }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 1)")
- end
- end
-
- ruby_version_is "3.3" do
- it "accepts multiple arguments" do
- Set[:a, :b].merge(Set[:b, :c], [:d]).should == Set[:a, :b, :c, :d]
- end
+ it "accepts multiple arguments" do
+ Set[:a, :b].merge(Set[:b, :c], [:d]).should == Set[:a, :b, :c, :d]
end
end
diff --git a/spec/ruby/core/set/proper_subset_spec.rb b/spec/ruby/core/set/proper_subset_spec.rb
index fb7848c0015200..6f99447019b852 100644
--- a/spec/ruby/core/set/proper_subset_spec.rb
+++ b/spec/ruby/core/set/proper_subset_spec.rb
@@ -32,14 +32,4 @@
-> { Set[].proper_subset?("test") }.should raise_error(ArgumentError)
-> { Set[].proper_subset?(Object.new) }.should raise_error(ArgumentError)
end
-
- version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
- ruby_version_is ""..."4.0" 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
- end
- end
- end
end
diff --git a/spec/ruby/core/set/subset_spec.rb b/spec/ruby/core/set/subset_spec.rb
index 112bd9b38adc12..da80d174da4fa1 100644
--- a/spec/ruby/core/set/subset_spec.rb
+++ b/spec/ruby/core/set/subset_spec.rb
@@ -32,14 +32,4 @@
-> { Set[].subset?("test") }.should raise_error(ArgumentError)
-> { Set[].subset?(Object.new) }.should raise_error(ArgumentError)
end
-
- version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
- ruby_version_is ""..."4.0" 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
- end
- end
- end
end
diff --git a/spec/ruby/core/string/append_as_bytes_spec.rb b/spec/ruby/core/string/append_as_bytes_spec.rb
index b1703e5f89baf9..def663d5ce2239 100644
--- a/spec/ruby/core/string/append_as_bytes_spec.rb
+++ b/spec/ruby/core/string/append_as_bytes_spec.rb
@@ -7,14 +7,16 @@
-> { str.append_as_bytes("\xE2\x82") }.should raise_error(FrozenError)
end
- it "allows creating broken strings" do
+ it "allows creating broken strings in UTF8" do
str = +"hello"
str.append_as_bytes("\xE2\x82")
str.valid_encoding?.should == false
str.append_as_bytes("\xAC")
str.valid_encoding?.should == true
+ end
+ it "allows creating broken strings in UTF_32" do
str = "abc".encode(Encoding::UTF_32LE)
str.append_as_bytes("def")
str.encoding.should == Encoding::UTF_32LE
diff --git a/spec/ruby/core/string/bytesplice_spec.rb b/spec/ruby/core/string/bytesplice_spec.rb
index 2c770e340aad27..cfd9e3ea9a7f39 100644
--- a/spec/ruby/core/string/bytesplice_spec.rb
+++ b/spec/ruby/core/string/bytesplice_spec.rb
@@ -57,77 +57,75 @@
-> { s.bytesplice(2, 1, "xxx") }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
end
- ruby_version_is "3.3" do
- it "raises IndexError when str_index is less than -bytesize" do
- -> { "hello".bytesplice(2, 1, "HELLO", -6, 0) }.should raise_error(IndexError, "index -6 out of string")
- end
-
- it "raises IndexError when str_index is greater than bytesize" do
- -> { "hello".bytesplice(2, 1, "HELLO", 6, 0) }.should raise_error(IndexError, "index 6 out of string")
- end
-
- it "raises IndexError for negative str length" do
- -> { "abc".bytesplice(0, 1, "", 0, -2) }.should raise_error(IndexError, "negative length -2")
- end
-
- it "replaces with integer str indices" do
- "hello".bytesplice(1, 2, "HELLO", -5, 0).should == "hlo"
- "hello".bytesplice(1, 2, "HELLO", 0, 0).should == "hlo"
- "hello".bytesplice(1, 2, "HELLO", 0, 1).should == "hHlo"
- "hello".bytesplice(1, 2, "HELLO", 0, 5).should == "hHELLOlo"
- "hello".bytesplice(1, 2, "HELLO", 0, 6).should == "hHELLOlo"
- end
-
- it "raises RangeError when str range left boundary is less than -bytesize" do
- -> { "hello".bytesplice(0..1, "HELLO", -6...-6) }.should raise_error(RangeError, "-6...-6 out of range")
- end
-
- it "replaces with str ranges" do
- "hello".bytesplice(1..2, "HELLO", -5...-5).should == "hlo"
- "hello".bytesplice(1..2, "HELLO", 0...0).should == "hlo"
- "hello".bytesplice(1..2, "HELLO", 0..0).should == "hHlo"
- "hello".bytesplice(1..2, "HELLO", 0...1).should == "hHlo"
- "hello".bytesplice(1..2, "HELLO", 0..1).should == "hHElo"
- "hello".bytesplice(1..2, "HELLO", 0..-1).should == "hHELLOlo"
- "hello".bytesplice(1..2, "HELLO", 0...5).should == "hHELLOlo"
- "hello".bytesplice(1..2, "HELLO", 0...6).should == "hHELLOlo"
- end
-
- it "raises ArgumentError when integer str index is provided without str length argument" do
- -> { "hello".bytesplice(0, 1, "xxx", 0) }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 2, 3, or 5)")
- end
-
- it "replaces on an empty string with str index/length" do
- "".bytesplice(0, 0, "", 0, 0).should == ""
- "".bytesplice(0, 0, "xxx", 0, 1).should == "x"
- end
-
- it "mutates self with substring and str index/length" do
- s = "hello"
- s.bytesplice(2, 1, "xxx", 1, 2).should.equal?(s)
- s.should.eql?("hexxlo")
- end
-
- it "raises when string is frozen and str index/length" do
- s = "hello".freeze
- -> { s.bytesplice(2, 1, "xxx", 0, 1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
- end
-
- it "replaces on an empty string with str range" do
- "".bytesplice(0..0, "", 0..0).should == ""
- "".bytesplice(0..0, "xyz", 0..1).should == "xy"
- end
-
- it "mutates self with substring and str range" do
- s = "hello"
- s.bytesplice(2..2, "xyz", 1..2).should.equal?(s)
- s.should.eql?("heyzlo")
- end
-
- it "raises when string is frozen and str range" do
- s = "hello".freeze
- -> { s.bytesplice(2..2, "yzx", 0..1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
- end
+ it "raises IndexError when str_index is less than -bytesize" do
+ -> { "hello".bytesplice(2, 1, "HELLO", -6, 0) }.should raise_error(IndexError, "index -6 out of string")
+ end
+
+ it "raises IndexError when str_index is greater than bytesize" do
+ -> { "hello".bytesplice(2, 1, "HELLO", 6, 0) }.should raise_error(IndexError, "index 6 out of string")
+ end
+
+ it "raises IndexError for negative str length" do
+ -> { "abc".bytesplice(0, 1, "", 0, -2) }.should raise_error(IndexError, "negative length -2")
+ end
+
+ it "replaces with integer str indices" do
+ "hello".bytesplice(1, 2, "HELLO", -5, 0).should == "hlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 0).should == "hlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 1).should == "hHlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 5).should == "hHELLOlo"
+ "hello".bytesplice(1, 2, "HELLO", 0, 6).should == "hHELLOlo"
+ end
+
+ it "raises RangeError when str range left boundary is less than -bytesize" do
+ -> { "hello".bytesplice(0..1, "HELLO", -6...-6) }.should raise_error(RangeError, "-6...-6 out of range")
+ end
+
+ it "replaces with str ranges" do
+ "hello".bytesplice(1..2, "HELLO", -5...-5).should == "hlo"
+ "hello".bytesplice(1..2, "HELLO", 0...0).should == "hlo"
+ "hello".bytesplice(1..2, "HELLO", 0..0).should == "hHlo"
+ "hello".bytesplice(1..2, "HELLO", 0...1).should == "hHlo"
+ "hello".bytesplice(1..2, "HELLO", 0..1).should == "hHElo"
+ "hello".bytesplice(1..2, "HELLO", 0..-1).should == "hHELLOlo"
+ "hello".bytesplice(1..2, "HELLO", 0...5).should == "hHELLOlo"
+ "hello".bytesplice(1..2, "HELLO", 0...6).should == "hHELLOlo"
+ end
+
+ it "raises ArgumentError when integer str index is provided without str length argument" do
+ -> { "hello".bytesplice(0, 1, "xxx", 0) }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 2, 3, or 5)")
+ end
+
+ it "replaces on an empty string with str index/length" do
+ "".bytesplice(0, 0, "", 0, 0).should == ""
+ "".bytesplice(0, 0, "xxx", 0, 1).should == "x"
+ end
+
+ it "mutates self with substring and str index/length" do
+ s = "hello"
+ s.bytesplice(2, 1, "xxx", 1, 2).should.equal?(s)
+ s.should.eql?("hexxlo")
+ end
+
+ it "raises when string is frozen and str index/length" do
+ s = "hello".freeze
+ -> { s.bytesplice(2, 1, "xxx", 0, 1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
+ end
+
+ it "replaces on an empty string with str range" do
+ "".bytesplice(0..0, "", 0..0).should == ""
+ "".bytesplice(0..0, "xyz", 0..1).should == "xy"
+ end
+
+ it "mutates self with substring and str range" do
+ s = "hello"
+ s.bytesplice(2..2, "xyz", 1..2).should.equal?(s)
+ s.should.eql?("heyzlo")
+ end
+
+ it "raises when string is frozen and str range" do
+ s = "hello".freeze
+ -> { s.bytesplice(2..2, "yzx", 0..1) }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
end
end
@@ -201,94 +199,92 @@
result.encoding.should == Encoding::UTF_8
end
- ruby_version_is "3.3" do
- it "raises IndexError when str_index is out of byte size boundary" do
- -> { "こんにちは".bytesplice(3, 3, "こんにちは", -16, 0) }.should raise_error(IndexError, "index -16 out of string")
- end
-
- it "raises IndexError when str_index is not on a codepoint boundary" do
- -> { "こんにちは".bytesplice(3, 3, "こんにちは", 1, 0) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- end
-
- it "raises IndexError when str_length is not matching the codepoint boundary" do
- -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 1) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 2) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- end
-
- it "replaces with integer str indices" do
- "こんにちは".bytesplice(3, 3, "こんにちは", -15, 0).should == "こにちは"
- "こんにちは".bytesplice(3, 3, "こんにちは", 0, 0).should == "こにちは"
- "こんにちは".bytesplice(3, 3, "こんにちは", 0, 3).should == "ここにちは"
- "こんにちは".bytesplice(3, 3, "はは", 3, 3).should == "こはにちは"
- "こんにちは".bytesplice(3, 3, "こんにちは", 15, 0).should == "こにちは"
- end
-
- it "replaces with str range" do
- "こんにちは".bytesplice(0..2, "こんにちは", -15...-16).should == "んにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 0...0).should == "んにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 3..5).should == "んんにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 3...6).should == "んんにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 3..8).should == "んにんにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 0..-1).should == "こんにちはんにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 0...15).should == "こんにちはんにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 0...18).should == "こんにちはんにちは"
- end
-
- it "treats negative length for str range as 0" do
- "こんにちは".bytesplice(0..2, "こんにちは", 0...-100).should == "んにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", 3...-100).should == "んにちは"
- "こんにちは".bytesplice(0..2, "こんにちは", -15...-100).should == "んにちは"
- end
-
- it "raises when ranges not match codepoint boundaries in str" do
- -> { "こんにちは".bytesplice(3...3, "こ", 0..0) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- -> { "こんにちは".bytesplice(3...3, "こ", 0..1) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- # Begin is incorrect
- -> { "こんにちは".bytesplice(3...3, "こんにちは", -4..-1) }.should raise_error(IndexError, "offset 11 does not land on character boundary")
- -> { "こんにちは".bytesplice(3...3, "こんにちは", -5..-1) }.should raise_error(IndexError, "offset 10 does not land on character boundary")
- # End is incorrect
- -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-2) }.should raise_error(IndexError, "offset 14 does not land on character boundary")
- -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-3) }.should raise_error(IndexError, "offset 13 does not land on character boundary")
- end
-
- it "deals with a different encoded argument with str index/length" do
- s = "こんにちは"
- s.encoding.should == Encoding::UTF_8
- sub = "goodbye"
- sub.force_encoding(Encoding::US_ASCII)
-
- result = s.bytesplice(3, 3, sub, 0, 3)
- result.should == "こgooにちは"
- result.encoding.should == Encoding::UTF_8
-
- s = "hello"
- s.force_encoding(Encoding::US_ASCII)
- sub = "こんにちは"
- sub.encoding.should == Encoding::UTF_8
-
- result = s.bytesplice(1, 2, sub, 3, 3)
- result.should == "hんlo"
- result.encoding.should == Encoding::UTF_8
- end
-
- it "deals with a different encoded argument with str range" do
- s = "こんにちは"
- s.encoding.should == Encoding::UTF_8
- sub = "goodbye"
- sub.force_encoding(Encoding::US_ASCII)
-
- result = s.bytesplice(3..5, sub, 0..2)
- result.should == "こgooにちは"
- result.encoding.should == Encoding::UTF_8
-
- s = "hello"
- s.force_encoding(Encoding::US_ASCII)
- sub = "こんにちは"
- sub.encoding.should == Encoding::UTF_8
-
- result = s.bytesplice(1..2, sub, 3..5)
- result.should == "hんlo"
- result.encoding.should == Encoding::UTF_8
- end
+ it "raises IndexError when str_index is out of byte size boundary" do
+ -> { "こんにちは".bytesplice(3, 3, "こんにちは", -16, 0) }.should raise_error(IndexError, "index -16 out of string")
+ end
+
+ it "raises IndexError when str_index is not on a codepoint boundary" do
+ -> { "こんにちは".bytesplice(3, 3, "こんにちは", 1, 0) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ end
+
+ it "raises IndexError when str_length is not matching the codepoint boundary" do
+ -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 1) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "こんにちは".bytesplice(3, 3, "こんにちは", 0, 2) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ end
+
+ it "replaces with integer str indices" do
+ "こんにちは".bytesplice(3, 3, "こんにちは", -15, 0).should == "こにちは"
+ "こんにちは".bytesplice(3, 3, "こんにちは", 0, 0).should == "こにちは"
+ "こんにちは".bytesplice(3, 3, "こんにちは", 0, 3).should == "ここにちは"
+ "こんにちは".bytesplice(3, 3, "はは", 3, 3).should == "こはにちは"
+ "こんにちは".bytesplice(3, 3, "こんにちは", 15, 0).should == "こにちは"
+ end
+
+ it "replaces with str range" do
+ "こんにちは".bytesplice(0..2, "こんにちは", -15...-16).should == "んにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 0...0).should == "んにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 3..5).should == "んんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 3...6).should == "んんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 3..8).should == "んにんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 0..-1).should == "こんにちはんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 0...15).should == "こんにちはんにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 0...18).should == "こんにちはんにちは"
+ end
+
+ it "treats negative length for str range as 0" do
+ "こんにちは".bytesplice(0..2, "こんにちは", 0...-100).should == "んにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", 3...-100).should == "んにちは"
+ "こんにちは".bytesplice(0..2, "こんにちは", -15...-100).should == "んにちは"
+ end
+
+ it "raises when ranges not match codepoint boundaries in str" do
+ -> { "こんにちは".bytesplice(3...3, "こ", 0..0) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "こんにちは".bytesplice(3...3, "こ", 0..1) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ # Begin is incorrect
+ -> { "こんにちは".bytesplice(3...3, "こんにちは", -4..-1) }.should raise_error(IndexError, "offset 11 does not land on character boundary")
+ -> { "こんにちは".bytesplice(3...3, "こんにちは", -5..-1) }.should raise_error(IndexError, "offset 10 does not land on character boundary")
+ # End is incorrect
+ -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-2) }.should raise_error(IndexError, "offset 14 does not land on character boundary")
+ -> { "こんにちは".bytesplice(3...3, "こんにちは", -3..-3) }.should raise_error(IndexError, "offset 13 does not land on character boundary")
+ end
+
+ it "deals with a different encoded argument with str index/length" do
+ s = "こんにちは"
+ s.encoding.should == Encoding::UTF_8
+ sub = "goodbye"
+ sub.force_encoding(Encoding::US_ASCII)
+
+ result = s.bytesplice(3, 3, sub, 0, 3)
+ result.should == "こgooにちは"
+ result.encoding.should == Encoding::UTF_8
+
+ s = "hello"
+ s.force_encoding(Encoding::US_ASCII)
+ sub = "こんにちは"
+ sub.encoding.should == Encoding::UTF_8
+
+ result = s.bytesplice(1, 2, sub, 3, 3)
+ result.should == "hんlo"
+ result.encoding.should == Encoding::UTF_8
+ end
+
+ it "deals with a different encoded argument with str range" do
+ s = "こんにちは"
+ s.encoding.should == Encoding::UTF_8
+ sub = "goodbye"
+ sub.force_encoding(Encoding::US_ASCII)
+
+ result = s.bytesplice(3..5, sub, 0..2)
+ result.should == "こgooにちは"
+ result.encoding.should == Encoding::UTF_8
+
+ s = "hello"
+ s.force_encoding(Encoding::US_ASCII)
+ sub = "こんにちは"
+ sub.encoding.should == Encoding::UTF_8
+
+ result = s.bytesplice(1..2, sub, 3..5)
+ result.should == "hんlo"
+ result.encoding.should == Encoding::UTF_8
end
end
diff --git a/spec/ruby/core/string/index_spec.rb b/spec/ruby/core/string/index_spec.rb
index 835263a2cd58c2..01e6a6a4009720 100644
--- a/spec/ruby/core/string/index_spec.rb
+++ b/spec/ruby/core/string/index_spec.rb
@@ -231,15 +231,13 @@
$~.should == nil
end
- ruby_bug "#20421", ""..."3.3" do
- it "always clear $~" do
- "a".index(/a/)
- $~.should_not == nil
-
- string = "blablabla"
- string.index(/bla/, string.length + 1)
- $~.should == nil
- end
+ it "always clear $~" do
+ "a".index(/a/)
+ $~.should_not == nil
+
+ string = "blablabla"
+ string.index(/bla/, string.length + 1)
+ $~.should == nil
end
it "starts the search at the given offset" do
@@ -330,21 +328,10 @@
"われわわれ".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
"あれ".index re
- end.should raise_error(Encoding::CompatibilityError)
+ end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
end
end
diff --git a/spec/ruby/core/string/shared/chars.rb b/spec/ruby/core/string/shared/chars.rb
index c730643cf49874..74a32fb513f024 100644
--- a/spec/ruby/core/string/shared/chars.rb
+++ b/spec/ruby/core/string/shared/chars.rb
@@ -14,7 +14,6 @@
s.send(@method){}.should equal(s)
end
-
it "is unicode aware" do
"\303\207\342\210\202\303\251\306\222g".send(@method).to_a.should ==
["\303\207", "\342\210\202", "\303\251", "\306\222", "g"]
@@ -63,4 +62,25 @@
[0xA2].pack('C').force_encoding('SJIS')
]
end
+
+ it "returns individual chars for dummy encodings" do
+ "ab".dup.force_encoding(Encoding::UTF_7).send(@method).to_a.should == [
+ "\x61".dup.force_encoding(Encoding::UTF_7),
+ "\x62".dup.force_encoding(Encoding::UTF_7)
+ ]
+
+ "abcd".dup.force_encoding(Encoding::UTF_16).send(@method).to_a.should == [
+ "\x61".dup.force_encoding(Encoding::UTF_16),
+ "\x62".dup.force_encoding(Encoding::UTF_16),
+ "\x63".dup.force_encoding(Encoding::UTF_16),
+ "\x64".dup.force_encoding(Encoding::UTF_16)
+ ]
+
+ "abcd".dup.force_encoding(Encoding::UTF_32).send(@method).to_a.should == [
+ "\x61".dup.force_encoding(Encoding::UTF_32),
+ "\x62".dup.force_encoding(Encoding::UTF_32),
+ "\x63".dup.force_encoding(Encoding::UTF_32),
+ "\x64".dup.force_encoding(Encoding::UTF_32)
+ ]
+ end
end
diff --git a/spec/ruby/core/string/shared/codepoints.rb b/spec/ruby/core/string/shared/codepoints.rb
index 1c28ba3d5e22ff..ecdf7d719db553 100644
--- a/spec/ruby/core/string/shared/codepoints.rb
+++ b/spec/ruby/core/string/shared/codepoints.rb
@@ -59,4 +59,9 @@
s.ascii_only?.should be_true
s.send(@method).to_a.should == s.bytes.to_a
end
+
+ it "returns individual bytes for dummy encodings UTF-16 and UTF-32" do
+ "abcd".dup.force_encoding(Encoding::UTF_16).send(@method).to_a.should == [97, 98, 99, 100]
+ "abcd".dup.force_encoding(Encoding::UTF_32).send(@method).to_a.should == [97, 98, 99, 100]
+ end
end
diff --git a/spec/ruby/core/string/shared/each_line.rb b/spec/ruby/core/string/shared/each_line.rb
index 231a6d9d4ff3a2..c2f3abfa80e0a6 100644
--- a/spec/ruby/core/string/shared/each_line.rb
+++ b/spec/ruby/core/string/shared/each_line.rb
@@ -159,4 +159,18 @@
a.should == ["hello\r\n", "world\r\n"]
end
end
+
+ it "does not split lines for dummy UTF-16" do
+ "a\nb".encode(Encoding::UTF_16).lines.should == [
+ "\xFE\xFF\x00\x61\x00\n\x00\x62".dup.force_encoding(Encoding::UTF_16)
+ ]
+
+ str = "\x00\n\n\x00".dup.force_encoding(Encoding::UTF_16)
+ str.lines.should == [str]
+ end
+
+ it "raises Encoding::ConverterNotFoundError for dummy UTF-7" do
+ str = "a\nb".dup.force_encoding(Encoding::UTF_7)
+ -> { str.lines }.should raise_error(Encoding::ConverterNotFoundError)
+ end
end
diff --git a/spec/ruby/core/string/shared/grapheme_clusters.rb b/spec/ruby/core/string/shared/grapheme_clusters.rb
index 8b666868b1df68..985b558f08a03e 100644
--- a/spec/ruby/core/string/shared/grapheme_clusters.rb
+++ b/spec/ruby/core/string/shared/grapheme_clusters.rb
@@ -9,6 +9,15 @@
a.should == ['a', 'b', "\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}", "\u{1F43E}"]
end
+ it "returns grapheme clusters for various UTF encodings" do
+ [Encoding::UTF_16LE, Encoding::UTF_16BE, Encoding::UTF_32LE, Encoding::UTF_32BE].each do |enc|
+ a = []
+ # test string: abc[rainbow flag emoji][paw prints]
+ "ab\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}\u{1F43E}".encode(enc).send(@method) { |c| a << c }
+ a.should == ['a', 'b', "\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}", "\u{1F43E}"].map { |s| s.encode(enc) }
+ end
+ end
+
it "returns self" do
s = StringSpecs::MyString.new "ab\u{1f3f3}\u{fe0f}\u{200d}\u{1f308}\u{1F43E}"
s.send(@method) {}.should equal(s)
diff --git a/spec/ruby/core/string/start_with_spec.rb b/spec/ruby/core/string/start_with_spec.rb
index 35e33b46a668ee..8b0ba6b5a7ec3b 100644
--- a/spec/ruby/core/string/start_with_spec.rb
+++ b/spec/ruby/core/string/start_with_spec.rb
@@ -11,17 +11,8 @@
"\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
+ 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
diff --git a/spec/ruby/core/string/tr_s_spec.rb b/spec/ruby/core/string/tr_s_spec.rb
index dd72da440c93d5..693ff8ace21bb5 100644
--- a/spec/ruby/core/string/tr_s_spec.rb
+++ b/spec/ruby/core/string/tr_s_spec.rb
@@ -18,13 +18,11 @@
"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
+ 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
it "pads to_str with its last char if it is shorter than from_string" do
diff --git a/spec/ruby/core/string/tr_spec.rb b/spec/ruby/core/string/tr_spec.rb
index 75841a974fcc53..8478ccc9d2879c 100644
--- a/spec/ruby/core/string/tr_spec.rb
+++ b/spec/ruby/core/string/tr_spec.rb
@@ -17,13 +17,11 @@
"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
+ 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
it "pads to_str with its last char if it is shorter than from_string" do
diff --git a/spec/ruby/core/string/unpack/b_spec.rb b/spec/ruby/core/string/unpack/b_spec.rb
index b088f901fc026c..70ea1cb6ad98e3 100644
--- a/spec/ruby/core/string/unpack/b_spec.rb
+++ b/spec/ruby/core/string/unpack/b_spec.rb
@@ -86,20 +86,10 @@
].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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x80\x00".unpack("B\x00B")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -194,20 +184,10 @@
].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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x00".unpack("b\x00b")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/c_spec.rb b/spec/ruby/core/string/unpack/c_spec.rb
index 1e9548fb82411a..e42b027c7b8d6c 100644
--- a/spec/ruby/core/string/unpack/c_spec.rb
+++ b/spec/ruby/core/string/unpack/c_spec.rb
@@ -35,20 +35,10 @@
].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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abc".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
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 535836087d0f56..130b36401a7d05 100644
--- a/spec/ruby/core/string/unpack/h_spec.rb
+++ b/spec/ruby/core/string/unpack/h_spec.rb
@@ -56,20 +56,10 @@
].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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x10".unpack("H\x00H")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -133,20 +123,10 @@
].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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x10".unpack("h\x00h")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/shared/basic.rb b/spec/ruby/core/string/unpack/shared/basic.rb
index 734630bda0a620..132c4ef08acf21 100644
--- a/spec/ruby/core/string/unpack/shared/basic.rb
+++ b/spec/ruby/core/string/unpack/shared/basic.rb
@@ -9,20 +9,10 @@
"abc".unpack(d).should be_an_instance_of(Array)
end
- ruby_version_is ""..."3.3" do
- it "warns about using an unknown directive" do
- -> { "abcdefgh".unpack("a R" + unpack_format) }.should complain(/unknown unpack directive 'R' in 'a R#{unpack_format}'/)
- -> { "abcdefgh".unpack("a 0" + unpack_format) }.should complain(/unknown unpack directive '0' in 'a 0#{unpack_format}'/)
- -> { "abcdefgh".unpack("a :" + unpack_format) }.should complain(/unknown unpack directive ':' in 'a :#{unpack_format}'/)
- end
- end
-
- ruby_version_is "3.3" do
- it "raises ArgumentError when a directive is unknown" do
- -> { "abcdefgh".unpack("a K" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive 'K' in 'a K#{unpack_format}'")
- -> { "abcdefgh".unpack("a 0" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive '0' in 'a 0#{unpack_format}'")
- -> { "abcdefgh".unpack("a :" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive ':' in 'a :#{unpack_format}'")
- end
+ it "raises ArgumentError when a directive is unknown" do
+ -> { "abcdefgh".unpack("a K" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive 'K' in 'a K#{unpack_format}'")
+ -> { "abcdefgh".unpack("a 0" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive '0' in 'a 0#{unpack_format}'")
+ -> { "abcdefgh".unpack("a :" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive ':' in 'a :#{unpack_format}'")
end
end
diff --git a/spec/ruby/core/string/unpack/shared/float.rb b/spec/ruby/core/string/unpack/shared/float.rb
index b31c2c8bdc406a..0133be2ecb498e 100644
--- a/spec/ruby/core/string/unpack/shared/float.rb
+++ b/spec/ruby/core/string/unpack/shared/float.rb
@@ -56,21 +56,10 @@
[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 "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 spaces between directives" do
@@ -135,21 +124,10 @@
[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 "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 spaces between directives" do
@@ -217,20 +195,10 @@
[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 "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 spaces between directives" do
@@ -297,20 +265,10 @@
[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 "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 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 d3934753ba3ef8..eb994562251732 100644
--- a/spec/ruby/core/string/unpack/shared/integer.rb
+++ b/spec/ruby/core/string/unpack/shared/integer.rb
@@ -32,20 +32,10 @@
].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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abcd".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -97,20 +87,10 @@
].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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "badc".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -163,20 +143,10 @@
].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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abcdefgh".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -229,20 +199,10 @@
].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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "dcbahgfe".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -291,21 +251,10 @@
"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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "badc".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
@@ -365,21 +314,10 @@
"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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/shared/unicode.rb b/spec/ruby/core/string/unpack/shared/unicode.rb
index 9fe07f53aec1b3..b056aaed0be627 100644
--- a/spec/ruby/core/string/unpack/shared/unicode.rb
+++ b/spec/ruby/core/string/unpack/shared/unicode.rb
@@ -50,20 +50,10 @@
"\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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x02".unpack("U\x00U")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
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 7d3533ccae109e..d2ad657b09c8b8 100644
--- a/spec/ruby/core/string/unpack/w_spec.rb
+++ b/spec/ruby/core/string/unpack/w_spec.rb
@@ -15,20 +15,10 @@
].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 "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x02\x03".unpack("w\x00w")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/struct/new_spec.rb b/spec/ruby/core/struct/new_spec.rb
index 1d35de7b871230..741d6889af08a1 100644
--- a/spec/ruby/core/struct/new_spec.rb
+++ b/spec/ruby/core/struct/new_spec.rb
@@ -77,18 +77,10 @@ def obj.to_str() "Foo" end
-> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(TypeError)
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 "works when not provided any arguments" do
+ c = Struct.new
+ c.should be_kind_of(Class)
+ c.superclass.should == Struct
end
it "raises ArgumentError when there is a duplicate member" do
diff --git a/spec/ruby/core/symbol/inspect_spec.rb b/spec/ruby/core/symbol/inspect_spec.rb
index df4566c48e6449..f2269996af0f92 100644
--- a/spec/ruby/core/symbol/inspect_spec.rb
+++ b/spec/ruby/core/symbol/inspect_spec.rb
@@ -109,4 +109,23 @@
input.inspect.should == expected
end
end
+
+ it "quotes BINARY symbols" do
+ sym = "foo\xA4".b.to_sym
+ sym.inspect.should == ':"foo\xA4"'
+ end
+
+ it "quotes symbols in non-ASCII-compatible encodings" do
+ Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |encoding|
+ sym = "foo".encode(encoding).to_sym
+ sym.inspect.should == ':"foo"'
+ end
+ end
+
+ it "quotes and escapes symbols in dummy encodings" do
+ Encoding.list.select(&:dummy?).each do |encoding|
+ sym = "abcd".dup.force_encoding(encoding).to_sym
+ sym.inspect.should == ':"\x61\x62\x63\x64"'
+ end
+ end
end
diff --git a/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb b/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb
index e903c3e450fe97..103c36b3a0ab04 100644
--- a/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb
+++ b/spec/ruby/core/thread/backtrace/location/fixtures/classes.rb
@@ -1,10 +1,26 @@
+# These are top-level def on purpose to test those cases
+
+def label_top_method = ThreadBacktraceLocationSpecs::LABEL.call
+
+def self.label_sdef_method_of_main = ThreadBacktraceLocationSpecs::LABEL.call
+
+class << self
+ def label_sclass_method_of_main = ThreadBacktraceLocationSpecs::LABEL.call
+end
+
module ThreadBacktraceLocationSpecs
MODULE_LOCATION = caller_locations(0) rescue nil
+ INSTANCE = Object.new.extend(self)
+ LABEL = -> { caller_locations(1, 1)[0].label }
def self.locations
caller_locations
end
+ def instance_method_location
+ caller_locations(0)
+ end
+
def self.method_location
caller_locations(0)
end
@@ -15,6 +31,12 @@ def self.block_location
end
end
+ def instance_block_location
+ 1.times do
+ return caller_locations(0)
+ end
+ end
+
def self.locations_inside_nested_blocks
first_level_location = nil
second_level_location = nil
@@ -32,4 +54,86 @@ def self.locations_inside_nested_blocks
[first_level_location, second_level_location, third_level_location]
end
+
+ def instance_locations_inside_nested_block
+ loc = nil
+ 1.times do
+ 1.times do
+ loc = caller_locations(0)
+ end
+ end
+ loc
+ end
+
+ def original_method = LABEL.call
+ alias_method :aliased_method, :original_method
+
+ module M
+ class C
+ def regular_instance_method = LABEL.call
+
+ def self.sdef_class_method = LABEL.call
+
+ class << self
+ def sclass_method = LABEL.call
+
+ def block_in_sclass_method
+ -> {
+ -> { LABEL.call }.call
+ }.call
+ end
+ end
+ block_in_sclass_method
+ end
+ end
+
+ class M::D
+ def scoped_method = LABEL.call
+
+ def self.sdef_scoped_method = LABEL.call
+
+ class << self
+ def sclass_scoped_method = LABEL.call
+ end
+
+ module ::ThreadBacktraceLocationSpecs
+ def top = LABEL.call
+ end
+
+ class ::ThreadBacktraceLocationSpecs::Nested
+ def top_nested = LABEL.call
+
+ class C
+ def top_nested_c = LABEL.call
+ end
+ end
+ end
+
+ SOME_OBJECT = Object.new
+ SOME_OBJECT.instance_exec do
+ def unknown_def_singleton_method = LABEL.call
+
+ def self.unknown_sdef_singleton_method = LABEL.call
+ end
+
+ M.module_eval do
+ def module_eval_method = LABEL.call
+
+ def self.sdef_module_eval_method = LABEL.call
+ end
+
+ def ThreadBacktraceLocationSpecs.string_class_method = LABEL.call
+
+ module M
+ def ThreadBacktraceLocationSpecs.nested_class_method = LABEL.call
+ end
+
+ module M
+ module_function def mod_function = LABEL.call
+ end
+
+ expr = self
+ def expr.sdef_expression = LABEL.call
+
+ def expr.block_in_sdef_expression = -> { LABEL.call }.call
end
diff --git a/spec/ruby/core/thread/backtrace/location/label_spec.rb b/spec/ruby/core/thread/backtrace/location/label_spec.rb
index 85ddccc8e3f831..7d358b45ea8fe3 100644
--- a/spec/ruby/core/thread/backtrace/location/label_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/label_spec.rb
@@ -15,7 +15,7 @@
end
it 'returns the module name for a module location' do
- ThreadBacktraceLocationSpecs::MODULE_LOCATION[0].label.should include "ThreadBacktraceLocationSpecs"
+ ThreadBacktraceLocationSpecs::MODULE_LOCATION[0].label.should == ""
end
it 'includes the nesting level of a block as part of the location label' do
@@ -34,4 +34,194 @@
main_label.should == "block in \n"
required_label.should == "block in \n"
end
+
+ it "return the same name as the caller for eval" do
+ this = caller_locations(0)[0].label
+ eval("caller_locations(0)[0]").label.should == this
+
+ b = binding
+ b.eval("caller_locations(0)[0]").label.should == this
+
+ b.local_variable_set(:binding_var1, 1)
+ b.eval("caller_locations(0)[0]").label.should == this
+
+ b.local_variable_set(:binding_var2, 2)
+ b.eval("caller_locations(0)[0]").label.should == this
+
+ b.local_variable_set(:binding_var2, 2)
+ eval("caller_locations(0)[0]", b).label.should == this
+ end
+
+ ruby_version_is "3.4" do
+ describe "is Module#method for" do
+ it "a core method defined natively" do
+ BasicObject.instance_method(:instance_exec).should_not.source_location
+ loc = nil
+ loc = instance_exec { caller_locations(1, 1)[0] }
+ loc.label.should == "BasicObject#instance_exec"
+ end
+
+ it "a core method defined in Ruby" do
+ Kernel.instance_method(:tap).should.source_location
+ loc = nil
+ tap { loc = caller_locations(1, 1)[0] }
+ loc.label.should == "Kernel#tap"
+ end
+
+ it "an instance method defined in Ruby" do
+ ThreadBacktraceLocationSpecs::INSTANCE.instance_method_location[0].label.should == "ThreadBacktraceLocationSpecs#instance_method_location"
+ end
+
+ it "a block in an instance method defined in Ruby" do
+ ThreadBacktraceLocationSpecs::INSTANCE.instance_block_location[0].label.should == "block in ThreadBacktraceLocationSpecs#instance_block_location"
+ end
+
+ it "a nested block in an instance method defined in Ruby" do
+ ThreadBacktraceLocationSpecs::INSTANCE.instance_locations_inside_nested_block[0].label.should == "block (2 levels) in ThreadBacktraceLocationSpecs#instance_locations_inside_nested_block"
+ end
+
+ it "a method defined via module_exec" do
+ ThreadBacktraceLocationSpecs.module_exec do
+ def in_module_exec
+ caller_locations(0)
+ end
+ end
+ ThreadBacktraceLocationSpecs::INSTANCE.in_module_exec[0].label.should == "ThreadBacktraceLocationSpecs#in_module_exec"
+ end
+
+ it "a method defined via module_eval" do
+ ThreadBacktraceLocationSpecs.module_eval <<~RUBY
+ def in_module_eval
+ caller_locations(0)
+ end
+ RUBY
+ ThreadBacktraceLocationSpecs::INSTANCE.in_module_eval[0].label.should == "ThreadBacktraceLocationSpecs#in_module_eval"
+ end
+ end
+
+ describe "is Module.method for" do
+ it "a singleton method defined in Ruby" do
+ ThreadBacktraceLocationSpecs.method_location[0].label.should == "ThreadBacktraceLocationSpecs.method_location"
+ end
+
+ it "a block in a singleton method defined in Ruby" do
+ ThreadBacktraceLocationSpecs.block_location[0].label.should == "block in ThreadBacktraceLocationSpecs.block_location"
+ end
+
+ it "a nested block in a singleton method defined in Ruby" do
+ ThreadBacktraceLocationSpecs.locations_inside_nested_blocks[2].label.should == "block (3 levels) in ThreadBacktraceLocationSpecs.locations_inside_nested_blocks"
+ end
+
+ it "a singleton method defined via def Const.method" do
+ def ThreadBacktraceLocationSpecs.def_singleton
+ caller_locations(0)
+ end
+ ThreadBacktraceLocationSpecs.def_singleton[0].label.should == "ThreadBacktraceLocationSpecs.def_singleton"
+ end
+ end
+
+ it "shows the original method name for an aliased method" do
+ ThreadBacktraceLocationSpecs::INSTANCE.aliased_method.should == "ThreadBacktraceLocationSpecs#original_method"
+ end
+
+ # A wide variety of cases.
+ # These show interesting cases when trying to determine the name statically/at parse time
+ describe "is correct for" do
+ base = ThreadBacktraceLocationSpecs
+
+ it "M::C#regular_instance_method" do
+ base::M::C.new.regular_instance_method.should == "#{base}::M::C#regular_instance_method"
+ end
+
+ it "M::C.sdef_class_method" do
+ base::M::C.sdef_class_method.should == "#{base}::M::C.sdef_class_method"
+ end
+
+ it "M::C.sclass_method" do
+ base::M::C.sclass_method.should == "#{base}::M::C.sclass_method"
+ end
+
+ it "M::C.block_in_sclass_method" do
+ base::M::C.block_in_sclass_method.should == "block (2 levels) in #{base}::M::C.block_in_sclass_method"
+ end
+
+ it "M::D#scoped_method" do
+ base::M::D.new.scoped_method.should == "#{base}::M::D#scoped_method"
+ end
+
+ it "M::D.sdef_scoped_method" do
+ base::M::D.sdef_scoped_method.should == "#{base}::M::D.sdef_scoped_method"
+ end
+
+ it "M::D.sclass_scoped_method" do
+ base::M::D.sclass_scoped_method.should == "#{base}::M::D.sclass_scoped_method"
+ end
+
+ it "ThreadBacktraceLocationSpecs#top" do
+ ThreadBacktraceLocationSpecs::INSTANCE.top.should == "ThreadBacktraceLocationSpecs#top"
+ end
+
+ it "ThreadBacktraceLocationSpecs::Nested#top_nested" do
+ ThreadBacktraceLocationSpecs::Nested.new.top_nested.should == "ThreadBacktraceLocationSpecs::Nested#top_nested"
+ end
+
+ it "ThreadBacktraceLocationSpecs::Nested::C#top_nested_c" do
+ ThreadBacktraceLocationSpecs::Nested::C.new.top_nested_c.should == "ThreadBacktraceLocationSpecs::Nested::C#top_nested_c"
+ end
+
+ it "Object#label_top_method" do
+ label_top_method.should == "Object#label_top_method"
+ end
+
+ it "main.label_sdef_method_of_main" do
+ main = TOPLEVEL_BINDING.receiver
+ main.label_sdef_method_of_main.should == "label_sdef_method_of_main"
+ end
+
+ it "main.label_sclass_method_of_main" do
+ main = TOPLEVEL_BINDING.receiver
+ main.label_sclass_method_of_main.should == "label_sclass_method_of_main"
+ end
+
+ it "unknown_def_singleton_method" do
+ base::SOME_OBJECT.unknown_def_singleton_method.should == "unknown_def_singleton_method"
+ end
+
+ it "unknown_sdef_singleton_method" do
+ base::SOME_OBJECT.unknown_sdef_singleton_method.should == "unknown_sdef_singleton_method"
+ end
+
+ it "M#module_eval_method" do
+ Object.new.extend(base::M).module_eval_method.should == "#{base}::M#module_eval_method"
+ end
+
+ it "M.sdef_module_eval_method" do
+ base::M.sdef_module_eval_method.should == "#{base}::M.sdef_module_eval_method"
+ end
+
+ it "ThreadBacktraceLocationSpecs.string_class_method" do
+ ThreadBacktraceLocationSpecs.string_class_method.should == "ThreadBacktraceLocationSpecs.string_class_method"
+ end
+
+ it "ThreadBacktraceLocationSpecs.nested_class_method" do
+ ThreadBacktraceLocationSpecs.nested_class_method.should == "ThreadBacktraceLocationSpecs.nested_class_method"
+ end
+
+ it "M#mod_function" do
+ Object.new.extend(base::M).send(:mod_function).should == "#{base}::M#mod_function"
+ end
+
+ it "M.mod_function" do
+ base::M.mod_function.should == "#{base}::M.mod_function"
+ end
+
+ it "sdef_expression" do
+ base.sdef_expression.should == "#{base}.sdef_expression"
+ end
+
+ it "block_in_sdef_expression" do
+ base.block_in_sdef_expression.should == "block in #{base}.block_in_sdef_expression"
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/thread/native_thread_id_spec.rb b/spec/ruby/core/thread/native_thread_id_spec.rb
index 374cc592797a20..65d1b5b318dbac 100644
--- a/spec/ruby/core/thread/native_thread_id_spec.rb
+++ b/spec/ruby/core/thread/native_thread_id_spec.rb
@@ -18,12 +18,8 @@
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
+ # native_thread_id can be nil on a M:N scheduler
+ t_thread_id.should be_kind_of(Integer) if t_thread_id != nil
main_thread_id.should_not == t_thread_id
diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb
index dc3ccbdc0052df..f3b5d0142044b4 100644
--- a/spec/ruby/core/time/new_spec.rb
+++ b/spec/ruby/core/time/new_spec.rb
@@ -554,20 +554,10 @@ def obj.to_int; 3; end
Time.new("2020-12-25T00:56:17.123456789876 +09:00").subsec.should == 0.123456789
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
+ 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
it "raises ArgumentError if part of time string is missing" do
diff --git a/spec/ruby/core/tracepoint/path_spec.rb b/spec/ruby/core/tracepoint/path_spec.rb
index dc2ca840b80ca5..aa6868ead2ffd8 100644
--- a/spec/ruby/core/tracepoint/path_spec.rb
+++ b/spec/ruby/core/tracepoint/path_spec.rb
@@ -13,29 +13,14 @@
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 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})"
end
end
diff --git a/spec/ruby/core/tracepoint/raised_exception_spec.rb b/spec/ruby/core/tracepoint/raised_exception_spec.rb
index 5ac85318404964..e74afa9abc96c1 100644
--- a/spec/ruby/core/tracepoint/raised_exception_spec.rb
+++ b/spec/ruby/core/tracepoint/raised_exception_spec.rb
@@ -18,21 +18,19 @@
end
end
- ruby_version_is "3.3" do
- it 'returns value from exception rescued on the :rescue event' do
- raised_exception, error_result = nil
- trace = TracePoint.new(:rescue) { |tp|
- next unless TracePointSpec.target_thread?
- raised_exception = tp.raised_exception
- }
- trace.enable do
- begin
- raise StandardError
- rescue => e
- error_result = e
- end
- raised_exception.should equal(error_result)
+ it 'returns value from exception rescued on the :rescue event' do
+ raised_exception, error_result = nil
+ trace = TracePoint.new(:rescue) { |tp|
+ next unless TracePointSpec.target_thread?
+ raised_exception = tp.raised_exception
+ }
+ trace.enable do
+ begin
+ raise StandardError
+ rescue => e
+ error_result = e
end
+ raised_exception.should equal(error_result)
end
end
end
diff --git a/spec/ruby/core/true/singleton_method_spec.rb b/spec/ruby/core/true/singleton_method_spec.rb
index c06793850fa87a..575c504b728da3 100644
--- a/spec/ruby/core/true/singleton_method_spec.rb
+++ b/spec/ruby/core/true/singleton_method_spec.rb
@@ -1,15 +1,13 @@
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
+ 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)
- begin
- def (true).foo; end
- -> { true.singleton_method(:foo) }.should raise_error(NameError)
- ensure
- TrueClass.send(:remove_method, :foo)
- end
+ ensure
+ TrueClass.send(:remove_method, :foo)
end
end
end
diff --git a/spec/ruby/core/unboundmethod/equal_value_spec.rb b/spec/ruby/core/unboundmethod/equal_value_spec.rb
index b2d78c50afb359..c9f7ad45dacc82 100644
--- a/spec/ruby/core/unboundmethod/equal_value_spec.rb
+++ b/spec/ruby/core/unboundmethod/equal_value_spec.rb
@@ -110,9 +110,6 @@ class << self
c.method(:n).should == Class.instance_method(:new).bind(c)
end
- # On CRuby < 3.2, the 2 specs below pass due to method/instance_method skipping zsuper methods.
- # We are interested in the general pattern working, i.e. the combination of method/instance_method
- # and #== exposes the wanted behavior.
it "considers methods through visibility change equal" do
c = Class.new do
class << self
diff --git a/spec/ruby/core/warning/element_reference_spec.rb b/spec/ruby/core/warning/element_reference_spec.rb
index c0ed37ef139d05..6179c578646255 100644
--- a/spec/ruby/core/warning/element_reference_spec.rb
+++ b/spec/ruby/core/warning/element_reference_spec.rb
@@ -10,11 +10,9 @@
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"
- end
+ 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"
end
it "raises for unknown category" do
diff --git a/spec/ruby/core/warning/element_set_spec.rb b/spec/ruby/core/warning/element_set_spec.rb
index d59a7d4c9e13c8..1dbc66ce26cae9 100644
--- a/spec/ruby/core/warning/element_set_spec.rb
+++ b/spec/ruby/core/warning/element_set_spec.rb
@@ -17,15 +17,13 @@
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
- end
+ it "enables or disables performance warnings" do
+ original = Warning[:performance]
+ begin
+ Warning[:performance] = !original
+ Warning[:performance].should == !original
+ ensure
+ Warning[:performance] = original
end
end
diff --git a/spec/ruby/language/assignments_spec.rb b/spec/ruby/language/assignments_spec.rb
index c4adf73c1cbf67..58a244b7c27d87 100644
--- a/spec/ruby/language/assignments_spec.rb
+++ b/spec/ruby/language/assignments_spec.rb
@@ -219,15 +219,7 @@ def []=(*args, **kw)
end
end
- ruby_version_is ""..."3.3" do
- it "supports keyword arguments in index assignments" do
- a = @klass.new
- eval "a[1, 2, 3, b: 4] += 5"
- a.x.should == [[1, 2, 3, {b: 4}, 105], {}]
- end
- end
-
- ruby_version_is "3.3"..."3.4" do
+ ruby_version_is ""..."3.4" do
it "supports keyword arguments in index assignments" do
a = @klass.new
eval "a[1, 2, 3, b: 4] += 5"
diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb
index cc003b8946270e..67aad76c57e922 100644
--- a/spec/ruby/language/block_spec.rb
+++ b/spec/ruby/language/block_spec.rb
@@ -192,6 +192,22 @@ def m(a) yield a end
m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil]
end
+ it "calls #respond_to? on a BasicObject to check if object has method #to_ary" do
+ ScratchPad.record []
+ obj = BasicObject.new
+ def obj.respond_to?(name, *)
+ ScratchPad << [:respond_to?, name]
+ name == :to_ary ? true : super
+ end
+ def obj.to_ary
+ ScratchPad << :to_ary
+ [1, 2]
+ end
+
+ m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil]
+ ScratchPad.recorded.should == [[:respond_to?, :to_ary], :to_ary]
+ end
+
it "receives the object if it does not respond to #respond_to?" do
obj = BasicObject.new
@@ -1041,8 +1057,8 @@ def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, **
end
end
-describe "`it` calls without arguments in a block with no ordinary parameters" do
- ruby_version_is "3.3"..."3.4" do
+describe "`it` calls without arguments in a block" do
+ ruby_version_is ""..."3.4" do
it "emits a deprecation warning" do
-> {
eval "proc { it }"
@@ -1094,38 +1110,11 @@ def o.it
end
end
end
-
- ruby_version_is "3.4" do
- it "does not emit a deprecation warning" do
- -> {
- eval "proc { it }"
- }.should_not complain
- end
-
- it "acts as the first argument if no local variables exist" do
- eval("proc { it * 2 }").call(5).should == 10
- end
-
- it "can be reassigned to act as a local variable" do
- eval("proc { tmp = it; it = tmp * 2; it }").call(21).should == 42
- end
-
- it "can be used in nested calls" do
- eval("proc { it.map { it * 2 } }").call([1, 2, 3]).should == [2, 4, 6]
- end
-
- it "cannot be mixed with numbered parameters" do
- -> {
- eval "proc { it + _1 }"
- }.should raise_error(SyntaxError, /numbered parameters are not allowed when 'it' is already used|'it' is already used in/)
-
- -> {
- eval "proc { _1 + it }"
- }.should raise_error(SyntaxError, /numbered parameter is already used in|'it' is not allowed when a numbered parameter is already used/)
- end
- end
end
+# Duplicates specs in language/it_parameter_spec.rb
+# Need them here to run on Ruby versions prior 3.4
+# TODO: remove when the minimal supported Ruby version is 3.4
describe "if `it` is defined as a variable" do
it "treats `it` as a captured variable if defined outside of a block" do
it = 5
diff --git a/spec/ruby/language/delegation_spec.rb b/spec/ruby/language/delegation_spec.rb
index c711a536c22d71..cd44956f5d1c65 100644
--- a/spec/ruby/language/delegation_spec.rb
+++ b/spec/ruby/language/delegation_spec.rb
@@ -37,6 +37,16 @@ def delegate(...)
a.new.delegate(1, b: 2, &block).should == [[1], {b: 2}, block]
end
+ it "delegates with additional arguments" do
+ a = Class.new(DelegationSpecs::Target)
+ a.class_eval(<<-RUBY)
+ def delegate(...)
+ target(:first, :second, ...)
+ end
+ RUBY
+ a.new.delegate(1, b: 2).should == [[:first, :second, 1], {b: 2}, nil]
+ end
+
it "parses as open endless Range when brackets are omitted" do
a = Class.new(DelegationSpecs::Target)
suppress_warning do
@@ -99,13 +109,11 @@ def delegate(*)
a.new.delegate(0, 1).should == [[0, 1], {}, nil]
end
- ruby_version_is "3.3" do
- context "within a block that accepts anonymous rest within a method that accepts anonymous rest" do
- it "does not allow delegating rest" do
- -> {
- eval "def m(*); proc { |*| n(*) } end"
- }.should raise_error(SyntaxError, /anonymous rest parameter is also used within block/)
- end
+ context "within a block that accepts anonymous rest within a method that accepts anonymous rest" do
+ it "does not allow delegating rest" do
+ -> {
+ eval "def m(*); proc { |*| n(*) } end"
+ }.should raise_error(SyntaxError, /anonymous rest parameter is also used within block/)
end
end
end
@@ -122,13 +130,11 @@ def delegate(**)
a.new.delegate(a: 1) { |x| x }.should == [[], {a: 1}, nil]
end
- ruby_version_is "3.3" do
- context "within a block that accepts anonymous kwargs within a method that accepts anonymous kwargs" do
- it "does not allow delegating kwargs" do
- -> {
- eval "def m(**); proc { |**| n(**) } end"
- }.should raise_error(SyntaxError, /anonymous keyword rest parameter is also used within block/)
- end
+ context "within a block that accepts anonymous kwargs within a method that accepts anonymous kwargs" do
+ it "does not allow delegating kwargs" do
+ -> {
+ eval "def m(**); proc { |**| n(**) } end"
+ }.should raise_error(SyntaxError, /anonymous keyword rest parameter is also used within block/)
end
end
end
@@ -146,13 +152,11 @@ def delegate(&)
a.new.delegate(&block).should == [[], {}, block]
end
- ruby_version_is "3.3" do
- context "within a block that accepts anonymous block within a method that accepts anonymous block" do
- it "does not allow delegating a block" do
- -> {
- eval "def m(&); proc { |&| n(&) } end"
- }.should raise_error(SyntaxError, /anonymous block parameter is also used within block/)
- end
+ context "within a block that accepts anonymous block within a method that accepts anonymous block" do
+ it "does not allow delegating a block" do
+ -> {
+ eval "def m(&); proc { |&| n(&) } end"
+ }.should raise_error(SyntaxError, /anonymous block parameter is also used within block/)
end
end
end
diff --git a/spec/ruby/language/file_spec.rb b/spec/ruby/language/file_spec.rb
index 59563d9642e00e..36fd329bf6a7ca 100644
--- a/spec/ruby/language/file_spec.rb
+++ b/spec/ruby/language/file_spec.rb
@@ -7,16 +7,8 @@
-> { 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
- 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
+ it "equals (eval at __FILE__:__LINE__) inside an eval" do
+ eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})"
end
end
diff --git a/spec/ruby/language/for_spec.rb b/spec/ruby/language/for_spec.rb
index b8ddfe5f0ddfb0..7fc6751d070eb1 100644
--- a/spec/ruby/language/for_spec.rb
+++ b/spec/ruby/language/for_spec.rb
@@ -129,37 +129,34 @@ class OFor
n.should == 3
end
- # Segfault in MRI 3.3 and lower: https://bugs.ruby-lang.org/issues/20468
- ruby_bug "#20468", ""..."3.4" do
- it "allows an attribute with safe navigation as an iterator name" do
- class OFor
- attr_accessor :target
- end
-
- ofor = OFor.new
- m = [1,2,3]
- n = 0
- eval <<~RUBY
- for ofor&.target in m
- n += 1
- end
- RUBY
- ofor.target.should == 3
- n.should == 3
+ it "allows an attribute with safe navigation as an iterator name" do
+ class OFor
+ attr_accessor :target
end
- it "allows an attribute with safe navigation on a nil base as an iterator name" do
- ofor = nil
- m = [1,2,3]
- n = 0
- eval <<~RUBY
- for ofor&.target in m
- n += 1
- end
- RUBY
- ofor.should be_nil
- n.should == 3
- end
+ ofor = OFor.new
+ m = [1,2,3]
+ n = 0
+ eval <<~RUBY
+ for ofor&.target in m
+ n += 1
+ end
+ RUBY
+ ofor.target.should == 3
+ n.should == 3
+ end
+
+ it "allows an attribute with safe navigation on a nil base as an iterator name" do
+ ofor = nil
+ m = [1,2,3]
+ n = 0
+ eval <<~RUBY
+ for ofor&.target in m
+ n += 1
+ end
+ RUBY
+ ofor.should be_nil
+ n.should == 3
end
it "allows an array index writer as an iterator name" do
diff --git a/spec/ruby/language/hash_spec.rb b/spec/ruby/language/hash_spec.rb
index 668716e2e325da..c7e1bf2d88bffd 100644
--- a/spec/ruby/language/hash_spec.rb
+++ b/spec/ruby/language/hash_spec.rb
@@ -167,6 +167,17 @@ def h.to_hash; {:b => 2, :c => 3}; end
{**nil}.should == {}
{a: 1, **nil}.should == {a: 1}
end
+
+ it "expands nil using ** into {} and provides a copy to the callable" do
+ ScratchPad.record []
+ insert = -> key, **kw do
+ kw[key] = 1
+ ScratchPad << kw
+ end
+ insert.call(:foo, **nil)
+ insert.call(:bar, **nil)
+ ScratchPad.recorded.should == [{ foo: 1 }, { bar: 1 }]
+ end
end
it "expands an '**{}' or '**obj' element with the last key/value pair taking precedence" do
@@ -264,17 +275,15 @@ def m(**h)
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
- def m(h)
- h.delete(:one); h
- end
-
- h = { one: 1, two: 2 }
- m(**h).should == { two: 2 }
- m(**h).should_not.equal?(h)
- h.should == { one: 1, two: 2 }
+ it "makes a 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_not.equal?(h)
+ h.should == { one: 1, two: 2 }
end
describe "hash with omitted value" do
diff --git a/spec/ruby/language/it_parameter_spec.rb b/spec/ruby/language/it_parameter_spec.rb
index 72023180d91d54..58ec3a6faf0f1a 100644
--- a/spec/ruby/language/it_parameter_spec.rb
+++ b/spec/ruby/language/it_parameter_spec.rb
@@ -1,6 +1,7 @@
require_relative '../spec_helper'
ruby_version_is "3.4" do
+ eval <<-RUBY # use eval to avoid warnings on Ruby 3.3
describe "The `it` parameter" do
it "provides it in a block" do
-> { it }.call("a").should == "a"
@@ -17,9 +18,28 @@
-> { it + -> { it * it }.call(2) }.call(3).should == 7
end
+ it "can be reassigned to act as a local variable" do
+ proc { tmp = it; it = tmp * 2; it }.call(21).should == 42
+ end
+
it "is a regular local variable if there is already a 'it' local variable" do
- it = 0
- proc { it }.call("a").should == 0
+ it = 0
+ proc { it }.call("a").should == 0
+ end
+
+ it "is a regular local variable if there is a method `it` defined" do
+ o = Object.new
+ def o.it
+ 21
+ end
+
+ o.instance_eval("proc { it * 2 }").call(1).should == 2
+ end
+
+ it "is not shadowed by an reassignment in a block" do
+ a = nil
+ proc { a = it; it = 42 }.call(0)
+ a.should == 0 # if `it` were shadowed its value would be nil
end
it "raises SyntaxError when block parameters are specified explicitly" do
@@ -36,6 +56,16 @@
-> { eval("['a'].map { |x| it }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
end
+ it "cannot be mixed with numbered parameters" do
+ -> {
+ eval("proc { it + _1 }")
+ }.should raise_error(SyntaxError, /numbered parameters are not allowed when 'it' is already used|'it' is already used in/)
+
+ -> {
+ eval("proc { _1 + it }")
+ }.should raise_error(SyntaxError, /numbered parameter is already used in|'it' is not allowed when a numbered parameter is already used/)
+ end
+
it "affects block arity" do
-> {}.arity.should == 0
-> { it }.arity.should == 1
@@ -62,5 +92,17 @@ def obj.foo; it; end
-> { obj.foo("a") }.should raise_error(ArgumentError, /wrong number of arguments/)
end
+
+ context "given multiple arguments" do
+ it "provides it in a block and assigns the first argument for a block" do
+ proc { it }.call("a", "b").should == "a"
+ end
+
+ it "raises ArgumentError for a proc" do
+ -> { -> { it }.call("a", "b") }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 1)")
+ -> { lambda { it }.call("a", "b") }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 1)")
+ end
+ end
end
+ RUBY
end
diff --git a/spec/ruby/language/keyword_arguments_spec.rb b/spec/ruby/language/keyword_arguments_spec.rb
index 4f6370d419e03b..c51c3bc656d4e9 100644
--- a/spec/ruby/language/keyword_arguments_spec.rb
+++ b/spec/ruby/language/keyword_arguments_spec.rb
@@ -87,16 +87,14 @@ def m(*a)
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}
+ 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
it "copies the given Hash for a method taking (**kwargs)" do
diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb
index 8f72bd45ed8cbe..8f9f094fd89a45 100644
--- a/spec/ruby/language/method_spec.rb
+++ b/spec/ruby/language/method_spec.rb
@@ -1234,10 +1234,8 @@ def n(value, &block)
args.should == [true]
end
- ruby_version_is "3.3" do
- it "supports multiple statements" do
- eval("m (1; 2)").should == [2]
- end
+ it "supports multiple statements" do
+ eval("m (1; 2)").should == [2]
end
end
diff --git a/spec/ruby/library/English/English_spec.rb b/spec/ruby/library/English/English_spec.rb
index 4d615d1e2506ef..166785f066640b 100644
--- a/spec/ruby/library/English/English_spec.rb
+++ b/spec/ruby/library/English/English_spec.rb
@@ -130,18 +130,6 @@
$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
- end
- end
-
it "aliases $ARGV to $*" do
$ARGV.should_not be_nil
$ARGV.should == $*
diff --git a/spec/ruby/library/bigdecimal/remainder_spec.rb b/spec/ruby/library/bigdecimal/remainder_spec.rb
index 0eb06f7ef1d402..b31967e76bd53c 100644
--- a/spec/ruby/library/bigdecimal/remainder_spec.rb
+++ b/spec/ruby/library/bigdecimal/remainder_spec.rb
@@ -56,25 +56,6 @@
@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?
-
- @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
- end
-
it "coerces arguments to BigDecimal if possible" do
@three.remainder(2).should == @one
end
diff --git a/spec/ruby/library/bigdecimal/to_s_spec.rb b/spec/ruby/library/bigdecimal/to_s_spec.rb
index ba9f960eb32450..025057b4d7e873 100644
--- a/spec/ruby/library/bigdecimal/to_s_spec.rb
+++ b/spec/ruby/library/bigdecimal/to_s_spec.rb
@@ -52,10 +52,8 @@
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
+ 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
it "can return a leading space for values > 0" do
diff --git a/spec/ruby/library/random/formatter/alphanumeric_spec.rb b/spec/ruby/library/random/formatter/alphanumeric_spec.rb
index 9bd325e1d0a6ab..ce45b96dc2b7a7 100644
--- a/spec/ruby/library/random/formatter/alphanumeric_spec.rb
+++ b/spec/ruby/library/random/formatter/alphanumeric_spec.rb
@@ -41,16 +41,14 @@
}.should raise_error(ArgumentError)
end
- ruby_version_is "3.3" do
- it "accepts a 'chars' argument with the output alphabet" do
- @object.alphanumeric(chars: ['a', 'b']).should =~ /\A[ab]+\z/
- end
+ it "accepts a 'chars' argument with the output alphabet" do
+ @object.alphanumeric(chars: ['a', 'b']).should =~ /\A[ab]+\z/
+ end
- it "converts the elements of chars using #to_s" do
- to_s = mock("to_s")
- to_s.should_receive(:to_s).and_return("[mock to_s]")
- # Using 1 value in chars results in an infinite loop
- @object.alphanumeric(1, chars: [to_s, to_s]).should == "[mock to_s]"
- end
+ it "converts the elements of chars using #to_s" do
+ to_s = mock("to_s")
+ to_s.should_receive(:to_s).and_return("[mock to_s]")
+ # Using 1 value in chars results in an infinite loop
+ @object.alphanumeric(1, chars: [to_s, to_s]).should == "[mock to_s]"
end
end
diff --git a/spec/ruby/library/ripper/lex_spec.rb b/spec/ruby/library/ripper/lex_spec.rb
index 97cfb06904fad6..0255480579ee4f 100644
--- a/spec/ruby/library/ripper/lex_spec.rb
+++ b/spec/ruby/library/ripper/lex_spec.rb
@@ -10,14 +10,14 @@
[[1, 5], :on_lparen, "(", 'BEG|LABEL'],
[[1, 6], :on_ident, "a", 'ARG'],
[[1, 7], :on_rparen, ")", 'ENDFN'],
- [[1, 8], :on_sp, " ", 'BEG'],
+ [[1, 8], :on_semicolon, ";", 'BEG'],
[[1, 9], :on_kw, "nil", 'END'],
[[1, 12], :on_sp, " ", 'END'],
[[1, 13], :on_kw, "end", 'END']
]
- lexed = Ripper.lex("def m(a) nil end")
+ lexed = Ripper.lex("def m(a);nil end")
lexed.map { |e|
- e[0...-1] + [e[-1].to_s.split('|').map { |s| s.sub(/^EXPR_/, '') }.join('|')]
+ e[0...-1] + [e[-1].to_s]
}.should == expected
end
end
diff --git a/spec/ruby/library/socket/addrinfo/initialize_spec.rb b/spec/ruby/library/socket/addrinfo/initialize_spec.rb
index 1f16531aaa4dea..c556bd758b925a 100644
--- a/spec/ruby/library/socket/addrinfo/initialize_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/initialize_spec.rb
@@ -53,11 +53,11 @@
@addrinfo.ip_port.should == 25
end
- it "returns the INET6 pfamily" do
+ it "returns the specified family" do
@addrinfo.pfamily.should == Socket::PF_INET6
end
- it "returns the INET6 afamily" do
+ it "returns the specified family" do
@addrinfo.afamily.should == Socket::AF_INET6
end
@@ -83,11 +83,11 @@
@addrinfo.ip_port.should == 25
end
- it "returns the INET6 pfamily" do
+ it "returns the specified family" do
@addrinfo.pfamily.should == Socket::PF_INET6
end
- it "returns the INET6 afamily" do
+ it "returns the specified family" do
@addrinfo.afamily.should == Socket::AF_INET6
end
@@ -113,11 +113,11 @@
@addrinfo.ip_port.should == 25
end
- it "returns the INET6 pfamily" do
+ it "returns the specified family" do
@addrinfo.pfamily.should == Socket::PF_INET6
end
- it "returns the INET6 afamily" do
+ it "returns the specified family" do
@addrinfo.afamily.should == Socket::AF_INET6
end
@@ -147,11 +147,11 @@
@addrinfo.ip_port.should == 46102
end
- it "returns the INET pfamily" do
+ it "returns the specified family" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the INET afamily" do
+ it "returns the specified family" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -217,11 +217,11 @@
@addrinfo.ip_port.should == 46102
end
- it "returns the INET pfamily" do
+ it "returns the specified family" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the INET afamily" do
+ it "returns the specified family" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -247,11 +247,11 @@
@addrinfo.ip_port.should == 46102
end
- it "returns the INET pfamily" do
+ it "returns the specified family" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the INET afamily" do
+ it "returns the specified family" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -311,11 +311,11 @@
@addrinfo.ip_port.should == 46102
end
- it "returns the INET pfamily" do
+ it "returns the specified family" do
@addrinfo.pfamily.should == Socket::PF_INET
end
- it "returns the INET afamily" do
+ it "returns the specified family" do
@addrinfo.afamily.should == Socket::AF_INET
end
@@ -514,13 +514,13 @@
@sockaddr = Socket.sockaddr_in(80, '127.0.0.1')
end
- it 'returns an Addrinfo with :PF_INET family' do
+ it 'returns an Addrinfo with the specified family' do
addr = Addrinfo.new(@sockaddr, :PF_INET)
addr.pfamily.should == Socket::PF_INET
end
- it 'returns an Addrinfo with :INET family' do
+ it 'returns an Addrinfo with the specified family' do
addr = Addrinfo.new(@sockaddr, :INET)
addr.pfamily.should == Socket::PF_INET
@@ -544,13 +544,13 @@
@sockaddr = Socket.sockaddr_in(80, '127.0.0.1')
end
- it 'returns an Addrinfo with "PF_INET" family' do
+ it 'returns an Addrinfo with the specified family' do
addr = Addrinfo.new(@sockaddr, 'PF_INET')
addr.pfamily.should == Socket::PF_INET
end
- it 'returns an Addrinfo with "INET" family' do
+ it 'returns an Addrinfo with the specified family' do
addr = Addrinfo.new(@sockaddr, 'INET')
addr.pfamily.should == Socket::PF_INET
diff --git a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
index f2a6682f12b8ea..f2383513f286b2 100644
--- a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
@@ -112,60 +112,30 @@
@server.close unless @server.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String on a closed stream socket" do
- ready = false
-
- t = Thread.new do
- client = @server.accept
-
- Thread.pass while !ready
- begin
- client.recv_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ it "returns nil on a closed stream socket" do
+ ready = false
- socket = TCPSocket.new('127.0.0.1', @port)
- socket.close
- ready = true
+ t = Thread.new do
+ client = @server.accept
- t.value.should == ""
- end
- end
-
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- ready = false
-
- t = Thread.new do
- client = @server.accept
-
- Thread.pass while !ready
- begin
- client.recv_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
+ Thread.pass while !ready
+ begin
+ client.recv_nonblock(10)
+ rescue IO::EAGAINWaitReadable
+ retry
end
+ ensure
+ client.close if client
+ end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ 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
- ready = true
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.close
+ ready = true
- t.value.should be_nil
- end
+ t.value.should be_nil
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/recv_spec.rb b/spec/ruby/library/socket/basicsocket/recv_spec.rb
index a51920f52a092a..7581f1bc1533fa 100644
--- a/spec/ruby/library/socket/basicsocket/recv_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recv_spec.rb
@@ -184,42 +184,21 @@
@server.close unless @server.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- client.recv(10)
- ensure
- client.close if client
- 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 == ""
+ it "returns nil on a closed stream socket" do
+ t = Thread.new do
+ client = @server.accept
+ client.recv(10)
+ ensure
+ client.close if client
end
- end
-
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- client.recv(10)
- ensure
- client.close if client
- end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ 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
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.close
- t.value.should be_nil
- end
+ t.value.should be_nil
end
end
diff --git a/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb
index b5fdd7c93bee8d..d1cde4411bd8bc 100644
--- a/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb
@@ -235,64 +235,31 @@
@server.close unless @server.closed?
end
- ruby_version_is ""..."3.3" do
- platform_is_not :windows do # #recvmsg_nonblock() raises 'Errno::EINVAL: Invalid argument - recvmsg(2)'
- it "returns an empty String as received data on a closed stream socket" do
- ready = false
+ platform_is_not :windows do
+ it "returns nil on a closed stream socket" do
+ ready = false
- t = Thread.new do
- client = @server.accept
+ t = Thread.new do
+ client = @server.accept
- Thread.pass while !ready
- begin
- client.recvmsg_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
+ Thread.pass while !ready
+ begin
+ client.recvmsg_nonblock(10)
+ rescue IO::EAGAINWaitReadable
+ retry
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
- ready = true
-
- t.value.should.is_a? Array
- t.value[0].should == ""
+ ensure
+ client.close if client
end
- end
- end
- ruby_version_is "3.3" do
- platform_is_not :windows do
- it "returns nil on a closed stream socket" do
- ready = false
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not be_nil
- t = Thread.new do
- client = @server.accept
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.close
+ ready = true
- Thread.pass while !ready
- begin
- client.recvmsg_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
- 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
- ready = true
-
- t.value.should be_nil
- end
+ t.value.should be_nil
end
end
end
diff --git a/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb b/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb
index 04ba1d74c768c1..cfa0f4c61d476f 100644
--- a/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recvmsg_spec.rb
@@ -208,46 +208,22 @@
@server.close unless @server.closed?
end
- ruby_version_is ""..."3.3" do
- platform_is_not :windows do
- it "returns an empty String as received data on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- client.recvmsg(10)
- ensure
- client.close if client
- 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.is_a? Array
- t.value[0].should == ""
+ platform_is_not :windows do
+ it "returns nil on a closed stream socket" do
+ t = Thread.new do
+ client = @server.accept
+ client.recvmsg(10)
+ ensure
+ client.close if client
end
- end
- end
-
- ruby_version_is "3.3" do
- platform_is_not :windows do
- it "returns nil on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- client.recvmsg(10)
- ensure
- client.close if client
- end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ 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
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.close
- t.value.should be_nil
- end
+ t.value.should be_nil
end
end
end
diff --git a/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb b/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb
index b58903df237b9d..5e6a145c9bdaeb 100644
--- a/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb
+++ b/spec/ruby/library/socket/ipsocket/recvfrom_spec.rb
@@ -83,43 +83,21 @@
@client.close unless @client.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String as received data on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- message = client.recvfrom(10)
- message
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- @client.close
-
- t.value.should.is_a? Array
- t.value[0].should == ""
+ it "returns nil on a closed stream socket" do
+ t = Thread.new do
+ client = @server.accept
+ message = client.recvfrom(10)
+ message
+ ensure
+ client.close if client
end
- end
-
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- t = Thread.new do
- client = @server.accept
- message = client.recvfrom(10)
- message
- ensure
- client.close if client
- end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not be_nil
- @client.close
+ @client.close
- t.value.should be_nil
- end
+ t.value.should be_nil
end
end
diff --git a/spec/ruby/library/socket/socket/getaddrinfo_spec.rb b/spec/ruby/library/socket/socket/getaddrinfo_spec.rb
index 6576af52eeadc7..17ffeaccaf498b 100644
--- a/spec/ruby/library/socket/socket/getaddrinfo_spec.rb
+++ b/spec/ruby/library/socket/socket/getaddrinfo_spec.rb
@@ -107,22 +107,12 @@
res.each { |a| expected.should include(a) }
end
- ruby_version_is ""..."3.3" do
- it "raises SocketError when fails to resolve address" do
- -> {
- Socket.getaddrinfo("www.kame.net", 80, "AF_UNIX")
- }.should raise_error(SocketError)
- end
- end
-
- ruby_version_is "3.3" do
- it "raises ResolutionError when fails to resolve address" do
- -> {
- Socket.getaddrinfo("www.kame.net", 80, "AF_UNIX")
- }.should raise_error(Socket::ResolutionError) { |e|
- [Socket::EAI_FAMILY, Socket::EAI_FAIL].should.include?(e.error_code)
- }
- end
+ it "raises ResolutionError when fails to resolve address" do
+ -> {
+ Socket.getaddrinfo("www.kame.net", 80, "AF_UNIX")
+ }.should raise_error(Socket::ResolutionError) { |e|
+ [Socket::EAI_FAMILY, Socket::EAI_FAIL].should.include?(e.error_code)
+ }
end
end
end
diff --git a/spec/ruby/library/socket/socket/getnameinfo_spec.rb b/spec/ruby/library/socket/socket/getnameinfo_spec.rb
index af4a10c9c2baa5..48cc94bcd182ab 100644
--- a/spec/ruby/library/socket/socket/getnameinfo_spec.rb
+++ b/spec/ruby/library/socket/socket/getnameinfo_spec.rb
@@ -61,22 +61,12 @@ def should_be_valid_dns_name(name)
name_info[1].should == 'discard'
end
- ruby_version_is ""..."3.3" do
- it "raises SocketError when fails to resolve address" do
- -> {
- Socket.getnameinfo(["AF_UNIX", 80, "0.0.0.0"])
- }.should raise_error(SocketError)
- end
- end
-
- ruby_version_is "3.3" do
- it "raises ResolutionError when fails to resolve address" do
- -> {
- Socket.getnameinfo(["AF_UNIX", 80, "0.0.0.0"])
- }.should raise_error(Socket::ResolutionError) { |e|
- [Socket::EAI_FAMILY, Socket::EAI_FAIL].should.include?(e.error_code)
- }
- end
+ it "raises ResolutionError when fails to resolve address" do
+ -> {
+ Socket.getnameinfo(["AF_UNIX", 80, "0.0.0.0"])
+ }.should raise_error(Socket::ResolutionError) { |e|
+ [Socket::EAI_FAMILY, Socket::EAI_FAIL].should.include?(e.error_code)
+ }
end
end
diff --git a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
index 01b42bcc52b4fa..38a9f5ff5bc3fe 100644
--- a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
+++ b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
@@ -158,61 +158,30 @@
@client.close unless @client.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String as received data on a closed stream socket" do
- ready = false
-
- t = Thread.new do
- client, _ = @server.accept
-
- Thread.pass while !ready
- begin
- client.recvfrom_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ it "returns nil on a closed stream socket" do
+ ready = false
- @client.connect(@server_addr)
- @client.close
- ready = true
-
- t.value.should.is_a? Array
- t.value[0].should == ""
- end
- end
+ t = Thread.new do
+ client, _ = @server.accept
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- ready = false
-
- t = Thread.new do
- client, _ = @server.accept
-
- Thread.pass while !ready
- begin
- client.recvfrom_nonblock(10)
- rescue IO::EAGAINWaitReadable
- retry
- end
- ensure
- client.close if client
+ Thread.pass while !ready
+ begin
+ client.recvfrom_nonblock(10)
+ rescue IO::EAGAINWaitReadable
+ retry
end
+ ensure
+ client.close if client
+ end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not be_nil
- @client.connect(@server_addr)
- @client.close
- ready = true
+ @client.connect(@server_addr)
+ @client.close
+ ready = true
- t.value.should be_nil
- end
+ t.value.should be_nil
end
end
end
diff --git a/spec/ruby/library/socket/socket/recvfrom_spec.rb b/spec/ruby/library/socket/socket/recvfrom_spec.rb
index 6ba39ffcaf534c..cbbc162f6b0d28 100644
--- a/spec/ruby/library/socket/socket/recvfrom_spec.rb
+++ b/spec/ruby/library/socket/socket/recvfrom_spec.rb
@@ -111,43 +111,21 @@
@client.close unless @client.closed?
end
- ruby_version_is ""..."3.3" do
- it "returns an empty String as received data on a closed stream socket" do
- t = Thread.new do
- client, _ = @server.accept
- client.recvfrom(10)
- ensure
- client.close if client
- end
-
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
-
- @client.connect(@server_addr)
- @client.close
-
- t.value.should.is_a? Array
- t.value[0].should == ""
+ it "returns nil on a closed stream socket" do
+ t = Thread.new do
+ client, _ = @server.accept
+ client.recvfrom(10)
+ ensure
+ client.close if client
end
- end
-
- ruby_version_is "3.3" do
- it "returns nil on a closed stream socket" do
- t = Thread.new do
- client, _ = @server.accept
- client.recvfrom(10)
- ensure
- client.close if client
- end
- Thread.pass while t.status and t.status != "sleep"
- t.status.should_not be_nil
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not be_nil
- @client.connect(@server_addr)
- @client.close
+ @client.connect(@server_addr)
+ @client.close
- t.value.should be_nil
- end
+ t.value.should be_nil
end
end
diff --git a/spec/ruby/library/stringscanner/named_captures_spec.rb b/spec/ruby/library/stringscanner/named_captures_spec.rb
index a68d66c216a82e..927784a6c4a8a9 100644
--- a/spec/ruby/library/stringscanner/named_captures_spec.rb
+++ b/spec/ruby/library/stringscanner/named_captures_spec.rb
@@ -16,11 +16,9 @@
@s.named_captures.should == {}
end
- # https://github.com/ruby/strscan/issues/132
- ruby_bug "", ""..."3.3" do # fixed in strscan v3.0.7
- it "returns {} if there is no any matching done" do
- @s.named_captures.should == {}
- end
+ # https://github.com/ruby/strscan/issues/132 fixed in strscan v3.0.7
+ it "returns {} if there is no any matching done" do
+ @s.named_captures.should == {}
end
it "returns nil for an optional named capturing group if it doesn't match" do
diff --git a/spec/ruby/optional/capi/encoding_spec.rb b/spec/ruby/optional/capi/encoding_spec.rb
index c14983c7ead703..734b5f125381db 100644
--- a/spec/ruby/optional/capi/encoding_spec.rb
+++ b/spec/ruby/optional/capi/encoding_spec.rb
@@ -745,4 +745,34 @@
ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
end
end
+
+ describe "ONIGENC_IS_UNICODE" do
+ it "is true only for select UTF-related encodings" do
+ unicode = [
+ Encoding::UTF_8,
+ Encoding::UTF8_DOCOMO,
+ Encoding::UTF8_KDDI,
+ Encoding::UTF8_MAC,
+ Encoding::UTF8_SOFTBANK,
+ Encoding::CESU_8,
+ Encoding::UTF_16LE,
+ Encoding::UTF_16BE,
+ Encoding::UTF_32LE,
+ Encoding::UTF_32BE
+ ]
+ unicode.each do |enc|
+ @s.should.ONIGENC_IS_UNICODE(enc)
+ end
+
+ (Encoding.list - unicode).each { |enc|
+ @s.should_not.ONIGENC_IS_UNICODE(enc)
+ }
+ end
+
+ # Redundant with the above but more explicit
+ it "is false for the dummy UTF-16 and UTF-32 encodings" do
+ @s.should_not.ONIGENC_IS_UNICODE(Encoding::UTF_16)
+ @s.should_not.ONIGENC_IS_UNICODE(Encoding::UTF_32)
+ end
+ end
end
diff --git a/spec/ruby/optional/capi/ext/encoding_spec.c b/spec/ruby/optional/capi/ext/encoding_spec.c
index aa8662cfbd6426..98d4e2e3b772c8 100644
--- a/spec/ruby/optional/capi/ext/encoding_spec.c
+++ b/spec/ruby/optional/capi/ext/encoding_spec.c
@@ -324,6 +324,10 @@ static VALUE encoding_spec_rb_define_dummy_encoding(VALUE self, VALUE name) {
return INT2NUM(rb_define_dummy_encoding(RSTRING_PTR(name)));
}
+static VALUE encoding_spec_ONIGENC_IS_UNICODE(VALUE self, VALUE encoding) {
+ return ONIGENC_IS_UNICODE(rb_to_encoding(encoding)) ? Qtrue : Qfalse;
+}
+
void Init_encoding_spec(void) {
VALUE cls;
native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*));
@@ -384,6 +388,7 @@ void Init_encoding_spec(void) {
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);
rb_define_method(cls, "rb_define_dummy_encoding", encoding_spec_rb_define_dummy_encoding, 1);
+ rb_define_method(cls, "ONIGENC_IS_UNICODE", encoding_spec_ONIGENC_IS_UNICODE, 1);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c
index a8fed21b5900b6..eee324052d0936 100644
--- a/spec/ruby/optional/capi/ext/kernel_spec.c
+++ b/spec/ruby/optional/capi/ext/kernel_spec.c
@@ -1,4 +1,5 @@
#include "ruby.h"
+#include "ruby/vm.h"
#include "rubyspec.h"
#include
@@ -337,6 +338,15 @@ static VALUE kernel_spec_rb_set_end_proc(VALUE self, VALUE io) {
return Qnil;
}
+static void at_exit_hook(ruby_vm_t *vm) {
+ puts("ruby_vm_at_exit hook ran");
+}
+
+static VALUE kernel_spec_ruby_vm_at_exit(VALUE self) {
+ ruby_vm_at_exit(at_exit_hook);
+ return self;
+}
+
static VALUE kernel_spec_rb_f_sprintf(VALUE self, VALUE ary) {
return rb_f_sprintf((int)RARRAY_LEN(ary), RARRAY_PTR(ary));
}
@@ -434,6 +444,7 @@ void Init_kernel_spec(void) {
rb_define_method(cls, "rb_yield_splat", kernel_spec_rb_yield_splat, 1);
rb_define_method(cls, "rb_exec_recursive", kernel_spec_rb_exec_recursive, 1);
rb_define_method(cls, "rb_set_end_proc", kernel_spec_rb_set_end_proc, 1);
+ rb_define_method(cls, "ruby_vm_at_exit", kernel_spec_ruby_vm_at_exit, 0);
rb_define_method(cls, "rb_f_sprintf", kernel_spec_rb_f_sprintf, 1);
rb_define_method(cls, "rb_str_format", kernel_spec_rb_str_format, 3);
rb_define_method(cls, "rb_make_backtrace", kernel_spec_rb_make_backtrace, 0);
diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c
index 094013e049cbf6..74aa9e56e816fe 100644
--- a/spec/ruby/optional/capi/ext/string_spec.c
+++ b/spec/ruby/optional/capi/ext/string_spec.c
@@ -581,6 +581,14 @@ static VALUE string_spec_rb_str_to_interned_str(VALUE self, VALUE str) {
return rb_str_to_interned_str(str);
}
+static VALUE string_spec_rb_interned_str(VALUE self, VALUE str, VALUE len) {
+ return rb_interned_str(RSTRING_PTR(str), FIX2LONG(len));
+}
+
+static VALUE string_spec_rb_interned_str_cstr(VALUE self, VALUE str) {
+ return rb_interned_str_cstr(RSTRING_PTR(str));
+}
+
void Init_string_spec(void) {
VALUE cls = rb_define_class("CApiStringSpecs", rb_cObject);
rb_define_method(cls, "rb_cstr2inum", string_spec_rb_cstr2inum, 2);
@@ -681,6 +689,8 @@ void Init_string_spec(void) {
rb_define_method(cls, "rb_enc_interned_str_cstr", string_spec_rb_enc_interned_str_cstr, 2);
rb_define_method(cls, "rb_enc_interned_str", string_spec_rb_enc_interned_str, 3);
rb_define_method(cls, "rb_str_to_interned_str", string_spec_rb_str_to_interned_str, 1);
+ rb_define_method(cls, "rb_interned_str", string_spec_rb_interned_str, 2);
+ rb_define_method(cls, "rb_interned_str_cstr", string_spec_rb_interned_str_cstr, 1);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/io_spec.rb b/spec/ruby/optional/capi/io_spec.rb
index ab7a7fc8f6f661..dc4ac3e3744ce8 100644
--- a/spec/ruby/optional/capi/io_spec.rb
+++ b/spec/ruby/optional/capi/io_spec.rb
@@ -494,166 +494,164 @@
end
end
- ruby_version_is "3.3" do
- describe "rb_io_mode" do
- it "returns the mode" do
- (@o.rb_io_mode(@r_io) & 0b11).should == 0b01
- (@o.rb_io_mode(@w_io) & 0b11).should == 0b10
- (@o.rb_io_mode(@rw_io) & 0b11).should == 0b11
- end
+ describe "rb_io_mode" do
+ it "returns the mode" do
+ (@o.rb_io_mode(@r_io) & 0b11).should == 0b01
+ (@o.rb_io_mode(@w_io) & 0b11).should == 0b10
+ (@o.rb_io_mode(@rw_io) & 0b11).should == 0b11
end
+ end
- describe "rb_io_path" do
- it "returns the IO#path" do
- @o.rb_io_path(@r_io).should == @r_io.path
- @o.rb_io_path(@rw_io).should == @rw_io.path
- @o.rb_io_path(@rw_io).should == @name
- end
+ describe "rb_io_path" do
+ it "returns the IO#path" do
+ @o.rb_io_path(@r_io).should == @r_io.path
+ @o.rb_io_path(@rw_io).should == @rw_io.path
+ @o.rb_io_path(@rw_io).should == @name
end
+ end
- describe "rb_io_closed_p" do
- it "returns false when io is not closed" do
- @o.rb_io_closed_p(@r_io).should == false
- @r_io.closed?.should == false
- end
+ describe "rb_io_closed_p" do
+ it "returns false when io is not closed" do
+ @o.rb_io_closed_p(@r_io).should == false
+ @r_io.closed?.should == false
+ end
- it "returns true when io is closed" do
- @r_io.close
+ it "returns true when io is closed" do
+ @r_io.close
- @o.rb_io_closed_p(@r_io).should == true
- @r_io.closed?.should == true
- end
+ @o.rb_io_closed_p(@r_io).should == true
+ @r_io.closed?.should == true
end
+ end
- quarantine! do # "Errno::EBADF: Bad file descriptor" at closing @r_io, @rw_io etc in the after :each hook
- describe "rb_io_open_descriptor" do
- it "creates a new IO instance" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.should.is_a?(IO)
- end
-
- it "return an instance of the specified class" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.class.should == File
+ quarantine! do # "Errno::EBADF: Bad file descriptor" at closing @r_io, @rw_io etc in the after :each hook
+ describe "rb_io_open_descriptor" do
+ it "creates a new IO instance" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.should.is_a?(IO)
+ end
- io = @o.rb_io_open_descriptor(IO, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.class.should == IO
- end
+ it "return an instance of the specified class" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.class.should == File
- it "sets the specified file descriptor" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.fileno.should == @r_io.fileno
- end
+ io = @o.rb_io_open_descriptor(IO, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.class.should == IO
+ end
- it "sets the specified path" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.path.should == "a.txt"
- end
+ it "sets the specified file descriptor" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.fileno.should == @r_io.fileno
+ end
- it "sets the specified mode" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, CApiIOSpecs::FMODE_BINMODE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.should.binmode?
+ it "sets the specified path" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.path.should == "a.txt"
+ end
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, CApiIOSpecs::FMODE_TEXTMODE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.should_not.binmode?
- end
+ it "sets the specified mode" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, CApiIOSpecs::FMODE_BINMODE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.should.binmode?
- it "sets the specified timeout" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.timeout.should == 60
- end
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, CApiIOSpecs::FMODE_TEXTMODE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.should_not.binmode?
+ end
- it "sets the specified internal encoding" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.internal_encoding.should == Encoding::US_ASCII
- end
+ it "sets the specified timeout" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.timeout.should == 60
+ end
- it "sets the specified external encoding" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.external_encoding.should == Encoding::UTF_8
- end
+ it "sets the specified internal encoding" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.internal_encoding.should == Encoding::US_ASCII
+ end
- it "does not apply the specified encoding flags" do
- name = tmp("rb_io_open_descriptor_specs")
- File.write(name, "123\r\n456\n89")
- file = File.open(name, "r")
+ it "sets the specified external encoding" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.external_encoding.should == Encoding::UTF_8
+ end
- io = @o.rb_io_open_descriptor(File, file.fileno, CApiIOSpecs::FMODE_READABLE, "a.txt", 60, "US-ASCII", "UTF-8", CApiIOSpecs::ECONV_UNIVERSAL_NEWLINE_DECORATOR, {})
- io.read_nonblock(20).should == "123\r\n456\n89"
- ensure
- file.close
- rm_r name
- end
+ it "does not apply the specified encoding flags" do
+ name = tmp("rb_io_open_descriptor_specs")
+ File.write(name, "123\r\n456\n89")
+ file = File.open(name, "r")
- it "ignores the IO open options" do
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {external_encoding: "windows-1251"})
- io.external_encoding.should == Encoding::UTF_8
+ io = @o.rb_io_open_descriptor(File, file.fileno, CApiIOSpecs::FMODE_READABLE, "a.txt", 60, "US-ASCII", "UTF-8", CApiIOSpecs::ECONV_UNIVERSAL_NEWLINE_DECORATOR, {})
+ io.read_nonblock(20).should == "123\r\n456\n89"
+ ensure
+ file.close
+ rm_r name
+ end
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {internal_encoding: "windows-1251"})
- io.internal_encoding.should == Encoding::US_ASCII
+ it "ignores the IO open options" do
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {external_encoding: "windows-1251"})
+ io.external_encoding.should == Encoding::UTF_8
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {encoding: "windows-1251:binary"})
- io.external_encoding.should == Encoding::UTF_8
- io.internal_encoding.should == Encoding::US_ASCII
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {internal_encoding: "windows-1251"})
+ io.internal_encoding.should == Encoding::US_ASCII
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {textmode: false})
- io.should_not.binmode?
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {encoding: "windows-1251:binary"})
+ io.external_encoding.should == Encoding::UTF_8
+ io.internal_encoding.should == Encoding::US_ASCII
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {binmode: true})
- io.should_not.binmode?
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {textmode: false})
+ io.should_not.binmode?
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {autoclose: false})
- io.should.autoclose?
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {binmode: true})
+ io.should_not.binmode?
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {path: "a.txt"})
- io.path.should == "a.txt"
- end
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {autoclose: false})
+ io.should.autoclose?
- it "ignores the IO encoding options" do
- io = @o.rb_io_open_descriptor(File, @w_io.fileno, CApiIOSpecs::FMODE_WRITABLE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {crlf_newline: true})
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, "a.txt", 60, "US-ASCII", "UTF-8", 0, {path: "a.txt"})
+ io.path.should == "a.txt"
+ end
- io.write("123\r\n456\n89")
- io.flush
+ it "ignores the IO encoding options" do
+ io = @o.rb_io_open_descriptor(File, @w_io.fileno, CApiIOSpecs::FMODE_WRITABLE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {crlf_newline: true})
- @r_io.read_nonblock(20).should == "123\r\n456\n89"
- end
+ io.write("123\r\n456\n89")
+ io.flush
- it "allows wrong mode" do
- io = @o.rb_io_open_descriptor(File, @w_io.fileno, CApiIOSpecs::FMODE_READABLE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
- io.should.is_a?(File)
+ @r_io.read_nonblock(20).should == "123\r\n456\n89"
+ end
- platform_is_not :windows do
- -> { io.read_nonblock(1) }.should raise_error(Errno::EBADF)
- end
+ it "allows wrong mode" do
+ io = @o.rb_io_open_descriptor(File, @w_io.fileno, CApiIOSpecs::FMODE_READABLE, "a.txt", 60, "US-ASCII", "UTF-8", 0, {})
+ io.should.is_a?(File)
- platform_is :windows do
- -> { io.read_nonblock(1) }.should raise_error(IO::EWOULDBLOCKWaitReadable)
- end
+ platform_is_not :windows do
+ -> { io.read_nonblock(1) }.should raise_error(Errno::EBADF)
end
- it "tolerates NULL as rb_io_encoding *encoding parameter" do
- io = @o.rb_io_open_descriptor_without_encoding(File, @r_io.fileno, 0, "a.txt", 60)
- io.should.is_a?(File)
+ platform_is :windows do
+ -> { io.read_nonblock(1) }.should raise_error(IO::EWOULDBLOCKWaitReadable)
end
+ end
- it "deduplicates path String" do
- path = "a.txt".dup
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {})
- io.path.should_not equal(path)
+ it "tolerates NULL as rb_io_encoding *encoding parameter" do
+ io = @o.rb_io_open_descriptor_without_encoding(File, @r_io.fileno, 0, "a.txt", 60)
+ io.should.is_a?(File)
+ end
- path = "a.txt".freeze
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {})
- io.path.should_not equal(path)
- end
+ it "deduplicates path String" do
+ path = "a.txt".dup
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {})
+ io.path.should_not equal(path)
+
+ path = "a.txt".freeze
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {})
+ io.path.should_not equal(path)
+ end
- it "calls #to_str to convert a path to a String" do
- path = Object.new
- def path.to_str; "a.txt"; end
+ it "calls #to_str to convert a path to a String" do
+ path = Object.new
+ def path.to_str; "a.txt"; end
- io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {})
+ io = @o.rb_io_open_descriptor(File, @r_io.fileno, 0, path, 60, "US-ASCII", "UTF-8", 0, {})
- io.path.should == "a.txt"
- end
+ io.path.should == "a.txt"
end
end
end
diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb
index 6633ee50c1f8ac..0a2362fb304ab8 100644
--- a/spec/ruby/optional/capi/kernel_spec.rb
+++ b/spec/ruby/optional/capi/kernel_spec.rb
@@ -703,6 +703,12 @@ def proc_caller
end
end
+ describe "ruby_vm_at_exit" do
+ it "runs a C function after the VM is terminated" do
+ ruby_exe("require #{kernel_path.inspect}; CApiKernelSpecs.new.ruby_vm_at_exit").should == "ruby_vm_at_exit hook ran\n"
+ end
+ end
+
describe "rb_f_sprintf" do
it "returns a string according to format and arguments" do
@s.rb_f_sprintf(["%d %f %s", 10, 2.5, "test"]).should == "10 2.500000 test"
diff --git a/spec/ruby/optional/capi/object_spec.rb b/spec/ruby/optional/capi/object_spec.rb
index 8b4d8a9bba0e58..6716fd9e33766c 100644
--- a/spec/ruby/optional/capi/object_spec.rb
+++ b/spec/ruby/optional/capi/object_spec.rb
@@ -1004,7 +1004,6 @@ def reach
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
@@ -1012,7 +1011,6 @@ def reach
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
diff --git a/spec/ruby/optional/capi/spec_helper.rb b/spec/ruby/optional/capi/spec_helper.rb
index e7abf46e6ccf65..d937c967d062fc 100644
--- a/spec/ruby/optional/capi/spec_helper.rb
+++ b/spec/ruby/optional/capi/spec_helper.rb
@@ -59,7 +59,11 @@ def compile_extension(name)
tmpdir = tmp("cext_#{name}")
Dir.mkdir(tmpdir)
begin
- ["#{core_ext_dir}/rubyspec.h", "#{spec_ext_dir}/#{ext}.c"].each do |file|
+ files = ["#{core_ext_dir}/rubyspec.h", "#{spec_ext_dir}/#{ext}.c"]
+ if spec_ext_dir != core_ext_dir
+ files += Dir.glob("#{spec_ext_dir}/*.h")
+ end
+ files.each do |file|
if cxx and file.end_with?('.c')
cp file, "#{tmpdir}/#{File.basename(file, '.c')}.cpp"
else
diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb
index 72f20ee6a52455..889f0a6cfe5d51 100644
--- a/spec/ruby/optional/capi/string_spec.rb
+++ b/spec/ruby/optional/capi/string_spec.rb
@@ -1369,8 +1369,133 @@ def inspect
result1.should_not.equal?(result2)
end
+ it "preserves the encoding of the original string" do
+ result1 = @s.rb_str_to_interned_str("hello".dup.force_encoding(Encoding::US_ASCII))
+ result2 = @s.rb_str_to_interned_str("hello".dup.force_encoding(Encoding::UTF_8))
+ result1.encoding.should == Encoding::US_ASCII
+ result2.encoding.should == Encoding::UTF_8
+ end
+
it "returns the same string as String#-@" do
@s.rb_str_to_interned_str("hello").should.equal?(-"hello")
end
end
+
+ describe "rb_interned_str" do
+ it "returns a frozen string" do
+ str = "hello"
+ result = @s.rb_interned_str(str, str.bytesize)
+ result.should.is_a?(String)
+ result.should.frozen?
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns the same frozen string" do
+ str = "hello"
+ result1 = @s.rb_interned_str(str, str.bytesize)
+ result2 = @s.rb_interned_str(str, str.bytesize)
+ result1.should.equal?(result2)
+ end
+
+ it "supports strings with embedded null bytes" do
+ str = "foo\x00bar\x00baz".b
+ result = @s.rb_interned_str(str, str.bytesize)
+ result.should == str
+ end
+
+ it "return US_ASCII encoding for an empty string" do
+ result = @s.rb_interned_str("", 0)
+ result.should == ""
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns US_ASCII encoding for strings of only 7 bit ASCII" do
+ 0x00.upto(0x7f).each do |char|
+ result = @s.rb_interned_str(char.chr, 1)
+ result.encoding.should == Encoding::US_ASCII
+ end
+ end
+
+ ruby_bug "21842", ""..."4.1" do
+ it "returns BINARY encoding for strings that use the 8th bit" do
+ 0x80.upto(0xff) do |char|
+ result = @s.rb_interned_str(char.chr, 1)
+ result.encoding.should == Encoding::BINARY
+ end
+ end
+ end
+
+ it 'returns the same string when using non-ascii characters' do
+ str = 'こんにちは'
+ result1 = @s.rb_interned_str(str, str.bytesize)
+ result2 = @s.rb_interned_str(str, str.bytesize)
+ result1.should.equal?(result2)
+ end
+
+ ruby_bug "21842", ""..."4.1" do
+ it "returns the same string as String#-@" do
+ str = "hello".dup.force_encoding(Encoding::US_ASCII)
+ @s.rb_interned_str(str, str.bytesize).should.equal?(-str)
+ end
+ end
+ end
+
+ describe "rb_interned_str_cstr" do
+ it "returns a frozen string" do
+ str = "hello"
+ result = @s.rb_interned_str_cstr(str)
+ result.should.is_a?(String)
+ result.should.frozen?
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns the same frozen string" do
+ str = "hello"
+ result1 = @s.rb_interned_str_cstr(str)
+ result2 = @s.rb_interned_str_cstr(str)
+ result1.should.equal?(result2)
+ end
+
+ it "does not support strings with embedded null bytes" do
+ str = "foo\x00bar\x00baz".b
+ result = @s.rb_interned_str_cstr(str)
+ result.should == "foo"
+ end
+
+ it "return US_ASCII encoding for an empty string" do
+ result = @s.rb_interned_str_cstr("")
+ result.should == ""
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "returns US_ASCII encoding for strings of only 7 bit ASCII" do
+ 0x01.upto(0x7f).each do |char|
+ result = @s.rb_interned_str_cstr(char.chr)
+ result.encoding.should == Encoding::US_ASCII
+ end
+ end
+
+ ruby_bug "21842", ""..."4.1" do
+ it "returns BINARY encoding for strings that use the 8th bit" do
+ 0x80.upto(0xff) do |char|
+ result = @s.rb_interned_str_cstr(char.chr)
+ result.encoding.should == Encoding::BINARY
+ end
+ end
+ end
+
+ it 'returns the same string when using non-ascii characters' do
+ str = 'こんにちは'
+ result1 = @s.rb_interned_str_cstr(str)
+ result2 = @s.rb_interned_str_cstr(str)
+ result1.should.equal?(result2)
+ end
+
+ ruby_bug "21842", ""..."4.1" do
+ it "returns the same string as String#-@" do
+ str = "hello".dup.force_encoding(Encoding::US_ASCII)
+ @s.rb_interned_str_cstr(str).should.equal?(-str)
+ end
+ end
+ end
end
diff --git a/spec/ruby/optional/capi/struct_spec.rb b/spec/ruby/optional/capi/struct_spec.rb
index cc8d7f932e53b1..3f9eff52bc0b10 100644
--- a/spec/ruby/optional/capi/struct_spec.rb
+++ b/spec/ruby/optional/capi/struct_spec.rb
@@ -239,78 +239,76 @@
end
end
-ruby_version_is "3.3" do
- describe "C-API Data function" do
- before :all do
- @s = CApiStructSpecs.new
- @klass = @s.rb_data_define(nil, "a", "b", "c")
- end
-
- describe "rb_data_define" do
- it "returns a subclass of Data class when passed nil as the first argument" do
- @klass.should.is_a? Class
- @klass.superclass.should == Data
- end
-
- it "returns a subclass of a class when passed as the first argument" do
- superclass = Class.new(Data)
- klass = @s.rb_data_define(superclass, "a", "b", "c")
-
- klass.should.is_a? Class
- klass.superclass.should == superclass
- end
-
- it "creates readers for the members" do
- obj = @klass.new(1, 2, 3)
-
- obj.a.should == 1
- obj.b.should == 2
- obj.c.should == 3
- end
-
- it "returns the member names as Symbols" do
- obj = @klass.new(0, 0, 0)
-
- obj.members.should == [:a, :b, :c]
- end
-
- it "raises an ArgumentError if arguments contain duplicate member name" do
- -> { @s.rb_data_define(nil, "a", "b", "a") }.should raise_error(ArgumentError)
- end
-
- it "raises when first argument is not a class" do
- -> { @s.rb_data_define([], "a", "b", "c") }.should raise_error(TypeError, "wrong argument type Array (expected Class)")
- end
- end
-
- describe "rb_struct_initialize" do
- it "sets all members for a Data instance" do
- data = @klass.allocate
- @s.rb_struct_initialize(data, [1, 2, 3]).should == nil
- data.a.should == 1
- data.b.should == 2
- data.c.should == 3
- end
-
- it "freezes the Data instance" do
- data = @klass.allocate
- @s.rb_struct_initialize(data, [1, 2, 3]).should == nil
- data.should.frozen?
- -> { @s.rb_struct_initialize(data, [1, 2, 3]) }.should raise_error(FrozenError)
- end
-
- it "raises ArgumentError if too many values" do
- data = @klass.allocate
- -> { @s.rb_struct_initialize(data, [1, 2, 3, 4]) }.should raise_error(ArgumentError, "struct size differs")
- end
-
- it "treats missing values as nil" do
- data = @klass.allocate
- @s.rb_struct_initialize(data, [1, 2]).should == nil
- data.a.should == 1
- data.b.should == 2
- data.c.should == nil
- end
+describe "C-API Data function" do
+ before :all do
+ @s = CApiStructSpecs.new
+ @klass = @s.rb_data_define(nil, "a", "b", "c")
+ end
+
+ describe "rb_data_define" do
+ it "returns a subclass of Data class when passed nil as the first argument" do
+ @klass.should.is_a? Class
+ @klass.superclass.should == Data
+ end
+
+ it "returns a subclass of a class when passed as the first argument" do
+ superclass = Class.new(Data)
+ klass = @s.rb_data_define(superclass, "a", "b", "c")
+
+ klass.should.is_a? Class
+ klass.superclass.should == superclass
+ end
+
+ it "creates readers for the members" do
+ obj = @klass.new(1, 2, 3)
+
+ obj.a.should == 1
+ obj.b.should == 2
+ obj.c.should == 3
+ end
+
+ it "returns the member names as Symbols" do
+ obj = @klass.new(0, 0, 0)
+
+ obj.members.should == [:a, :b, :c]
+ end
+
+ it "raises an ArgumentError if arguments contain duplicate member name" do
+ -> { @s.rb_data_define(nil, "a", "b", "a") }.should raise_error(ArgumentError)
+ end
+
+ it "raises when first argument is not a class" do
+ -> { @s.rb_data_define([], "a", "b", "c") }.should raise_error(TypeError, "wrong argument type Array (expected Class)")
+ end
+ end
+
+ describe "rb_struct_initialize" do
+ it "sets all members for a Data instance" do
+ data = @klass.allocate
+ @s.rb_struct_initialize(data, [1, 2, 3]).should == nil
+ data.a.should == 1
+ data.b.should == 2
+ data.c.should == 3
+ end
+
+ it "freezes the Data instance" do
+ data = @klass.allocate
+ @s.rb_struct_initialize(data, [1, 2, 3]).should == nil
+ data.should.frozen?
+ -> { @s.rb_struct_initialize(data, [1, 2, 3]) }.should raise_error(FrozenError)
+ end
+
+ it "raises ArgumentError if too many values" do
+ data = @klass.allocate
+ -> { @s.rb_struct_initialize(data, [1, 2, 3, 4]) }.should raise_error(ArgumentError, "struct size differs")
+ end
+
+ it "treats missing values as nil" do
+ data = @klass.allocate
+ @s.rb_struct_initialize(data, [1, 2]).should == nil
+ data.a.should == 1
+ data.b.should == 2
+ data.c.should == nil
end
end
end
diff --git a/spec/ruby/security/cve_2020_10663_spec.rb b/spec/ruby/security/cve_2020_10663_spec.rb
index c44a13a0dd4b5d..7f42c407420b46 100644
--- a/spec/ruby/security/cve_2020_10663_spec.rb
+++ b/spec/ruby/security/cve_2020_10663_spec.rb
@@ -21,7 +21,7 @@ def to_json(*args)
guard -> {
JSON.const_defined?(:Pure) or
- version_is(JSON::VERSION, '2.3.0')
+ version_is(JSON::VERSION, '2.3.0'...'2.11.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
diff --git a/spec/ruby/shared/kernel/at_exit.rb b/spec/ruby/shared/kernel/at_exit.rb
index 29db79bb391428..d57ab73920f3fa 100644
--- a/spec/ruby/shared/kernel/at_exit.rb
+++ b/spec/ruby/shared/kernel/at_exit.rb
@@ -60,10 +60,7 @@
result = ruby_exe('{', options: "-r#{script}", args: "2>&1", exit_status: 1)
$?.should_not.success?
result.should.include?("handler ran\n")
-
- # it's tempting not to rely on error message and rely only on exception class name,
- # but CRuby before 3.2 doesn't print class name for syntax error
- result.should include_any_of("syntax error", "SyntaxError")
+ result.should include("SyntaxError")
end
it "calls the nested handler right after the outer one if a handler is nested into another handler" do
diff --git a/spec/ruby/shared/queue/freeze.rb b/spec/ruby/shared/queue/freeze.rb
index 4c506a42355f62..5dedd005df4975 100644
--- a/spec/ruby/shared/queue/freeze.rb
+++ b/spec/ruby/shared/queue/freeze.rb
@@ -1,18 +1,8 @@
describe :queue_freeze, shared: true do
- ruby_version_is ""..."3.3" do
- it "can be frozen" do
- queue = @object.call
+ it "raises an exception when freezing" do
+ queue = @object.call
+ -> {
queue.freeze
- queue.should.frozen?
- end
- end
-
- ruby_version_is "3.3" do
- it "raises an exception when freezing" do
- queue = @object.call
- -> {
- queue.freeze
- }.should raise_error(TypeError, "cannot freeze #{queue}")
- end
+ }.should raise_error(TypeError, "cannot freeze #{queue}")
end
end
diff --git a/spec/ruby/shared/string/start_with.rb b/spec/ruby/shared/string/start_with.rb
index 4b947a3bbf0ea8..9592eda4d43d31 100644
--- a/spec/ruby/shared/string/start_with.rb
+++ b/spec/ruby/shared/string/start_with.rb
@@ -70,15 +70,7 @@
$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
+ it "checks that we are not matching part of a character" do
+ "\xC3\xA9".send(@method).should_not.start_with?("\xC3")
end
end
diff --git a/test/monitor/test_monitor.rb b/test/monitor/test_monitor.rb
index 4c55afca6c869e..7a26831bafe2ba 100644
--- a/test/monitor/test_monitor.rb
+++ b/test/monitor/test_monitor.rb
@@ -274,7 +274,7 @@ def test_timedwait
@monitor.synchronize do
queue2.enq(nil)
assert_equal("foo", b)
- result2 = cond.wait(0.1)
+ result2 = cond.wait(10)
assert_equal(true, result2)
assert_equal("bar", b)
end
diff --git a/zjit/src/codegen.rs b/zjit/src/codegen.rs
index a77bd7debd0dfc..5d6060dd49d3a3 100644
--- a/zjit/src/codegen.rs
+++ b/zjit/src/codegen.rs
@@ -478,8 +478,8 @@ fn gen_insn(cb: &mut CodeBlock, jit: &mut JITState, asm: &mut Assembler, functio
Insn::Snapshot { .. } => return Ok(()), // we don't need to do anything for this instruction at the moment
&Insn::Send { cd, blockiseq, state, reason, .. } => gen_send(jit, asm, cd, blockiseq, &function.frame_state(state), reason),
&Insn::SendForward { cd, blockiseq, state, reason, .. } => gen_send_forward(jit, asm, cd, blockiseq, &function.frame_state(state), reason),
+ Insn::SendDirect { cme, iseq, recv, args, kw_bits, blockiseq, state, .. } => gen_send_iseq_direct(cb, jit, asm, *cme, *iseq, opnd!(recv), opnds!(args), *kw_bits, &function.frame_state(*state), *blockiseq),
&Insn::SendWithoutBlock { cd, state, reason, .. } => gen_send_without_block(jit, asm, cd, &function.frame_state(state), reason),
- Insn::SendWithoutBlockDirect { cme, iseq, recv, args, kw_bits, state, .. } => gen_send_iseq_direct(cb, jit, asm, *cme, *iseq, opnd!(recv), opnds!(args), *kw_bits, &function.frame_state(*state), None),
&Insn::InvokeSuper { cd, blockiseq, state, reason, .. } => gen_invokesuper(jit, asm, cd, blockiseq, &function.frame_state(state), reason),
&Insn::InvokeSuperForward { cd, blockiseq, state, reason, .. } => gen_invokesuperforward(jit, asm, cd, blockiseq, &function.frame_state(state), reason),
&Insn::InvokeBlock { cd, state, reason, .. } => gen_invokeblock(jit, asm, cd, &function.frame_state(state), reason),
@@ -1024,6 +1024,15 @@ fn gen_ccall(asm: &mut Assembler, cfunc: *const u8, name: ID, recv: Opnd, args:
asm.ccall(cfunc, cfunc_args)
}
+// Change cfp->block_code in the current frame. See vm_caller_setup_arg_block().
+// VM_CFP_TO_CAPTURED_BLOCK then turns &cfp->self into a block handler.
+// rb_captured_block->code.iseq aliases with cfp->block_code.
+fn gen_block_handler_specval(asm: &mut Assembler, blockiseq: IseqPtr) -> lir::Opnd {
+ asm.store(Opnd::mem(VALUE_BITS, CFP, RUBY_OFFSET_CFP_BLOCK_CODE), VALUE::from(blockiseq).into());
+ let cfp_self_addr = asm.lea(Opnd::mem(VALUE_BITS, CFP, RUBY_OFFSET_CFP_SELF));
+ asm.or(cfp_self_addr, Opnd::Imm(1))
+}
+
/// Generate code for a variadic C function call
/// func(int argc, VALUE *argv, VALUE recv)
fn gen_ccall_variadic(
@@ -1053,13 +1062,8 @@ fn gen_ccall_variadic(
gen_spill_stack(jit, asm, state);
gen_spill_locals(jit, asm, state);
- let block_handler_specval = if let Some(block_iseq) = blockiseq {
- // Change cfp->block_code in the current frame. See vm_caller_setup_arg_block().
- // VM_CFP_TO_CAPTURED_BLOCK then turns &cfp->self into a block handler.
- // rb_captured_block->code.iseq aliases with cfp->block_code.
- asm.store(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_BLOCK_CODE), VALUE::from(block_iseq).into());
- let cfp_self_addr = asm.lea(Opnd::mem(64, CFP, RUBY_OFFSET_CFP_SELF));
- asm.or(cfp_self_addr, Opnd::Imm(1))
+ let block_handler_specval = if let Some(blockiseq) = blockiseq {
+ gen_block_handler_specval(asm, blockiseq)
} else {
VM_BLOCK_HANDLER_NONE.into()
};
@@ -1446,7 +1450,7 @@ fn gen_send_iseq_direct(
args: Vec,
kw_bits: u32,
state: &FrameState,
- block_handler: Option,
+ blockiseq: Option,
) -> lir::Opnd {
gen_incr_counter(asm, Counter::iseq_optimized_send_count);
@@ -1462,6 +1466,12 @@ fn gen_send_iseq_direct(
gen_spill_locals(jit, asm, state);
gen_spill_stack(jit, asm, state);
+ // This mirrors vm_caller_setup_arg_block() in for the `blockiseq != NULL` case.
+ // The HIR specialization guards ensure we will only reach here for literal blocks,
+ // not &block forwarding, &:foo, etc. Thise are rejected in `type_specialize` by
+ // `unspecializable_call_type`.
+ let block_handler = blockiseq.map(|b| gen_block_handler_specval(asm, b));
+
let (frame_type, specval) = if VM_METHOD_TYPE_BMETHOD == unsafe { get_cme_def_type(cme) } {
// Extract EP from the Proc instance
let procv = unsafe { rb_get_def_bmethod_proc((*cme).def) };
@@ -1513,11 +1523,25 @@ fn gen_send_iseq_direct(
asm.mov(CFP, new_cfp);
asm.store(Opnd::mem(64, EC, RUBY_OFFSET_EC_CFP as i32), CFP);
+ let params = unsafe { iseq.params() };
+
+ // For &block, the JIT entrypoint expects the block_handler as an argument
+ // This HIR param is not actually used, things read from specval from the VM frame today.
+ // TODO: Remove unused param from HIR, or pass specval through c_args.
+ // See https://github.com/ruby/ruby/pull/15911#discussion_r2710544982
+ let needs_block = params.flags.has_block() != 0;
+
// Set up arguments
- let mut c_args = vec![recv];
+ let mut c_args = Vec::with_capacity({
+ // This is a heuristic to avoid re-allocation, not necessary for correctness
+ 1 /* recv */ + args.len() + if needs_block { 1 } else { 0 }
+ });
+ c_args.push(recv);
c_args.extend(&args);
+ if needs_block {
+ c_args.push(specval);
+ }
- let params = unsafe { iseq.params() };
let num_optionals_passed = if params.flags.has_opt() != 0 {
// See vm_call_iseq_setup_normal_opt_start in vm_inshelper.c
let lead_num = params.lead_num as u32;
@@ -2714,7 +2738,7 @@ fn function_stub_hit_body(cb: &mut CodeBlock, iseq_call: &IseqCallRef) -> Result
Ok(jit_entry_ptr)
}
-/// Compile a stub for an ISEQ called by SendWithoutBlockDirect
+/// Compile a stub for an ISEQ called by SendDirect
fn gen_function_stub(cb: &mut CodeBlock, iseq_call: IseqCallRef) -> Result {
let (mut asm, scratch_reg) = Assembler::new_with_scratch_reg();
asm.new_block_without_id();
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index 51ab45937cb5d2..b523d8430f3e5e 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -625,10 +625,10 @@ pub enum SendFallbackReason {
SendWithoutBlockNotOptimizedNeedPermission,
SendWithoutBlockBopRedefined,
SendWithoutBlockOperandsNotFixnum,
- SendWithoutBlockDirectKeywordMismatch,
- SendWithoutBlockDirectKeywordCountMismatch,
- SendWithoutBlockDirectMissingKeyword,
- SendWithoutBlockDirectTooManyKeywords,
+ SendDirectKeywordMismatch,
+ SendDirectKeywordCountMismatch,
+ SendDirectMissingKeyword,
+ SendDirectTooManyKeywords,
SendPolymorphic,
SendMegamorphic,
SendNoProfiles,
@@ -686,10 +686,10 @@ impl Display for SendFallbackReason {
SendNotOptimizedNeedPermission => write!(f, "Send: method private or protected and no FCALL"),
SendWithoutBlockBopRedefined => write!(f, "SendWithoutBlock: basic operation was redefined"),
SendWithoutBlockOperandsNotFixnum => write!(f, "SendWithoutBlock: operands are not fixnums"),
- SendWithoutBlockDirectKeywordMismatch => write!(f, "SendWithoutBlockDirect: keyword mismatch"),
- SendWithoutBlockDirectKeywordCountMismatch => write!(f, "SendWithoutBlockDirect: keyword count mismatch"),
- SendWithoutBlockDirectMissingKeyword => write!(f, "SendWithoutBlockDirect: missing keyword"),
- SendWithoutBlockDirectTooManyKeywords => write!(f, "SendWithoutBlockDirect: too many keywords for fixnum bitmask"),
+ SendDirectKeywordMismatch => write!(f, "SendDirect: keyword mismatch"),
+ SendDirectKeywordCountMismatch => write!(f, "SendDirect: keyword count mismatch"),
+ SendDirectMissingKeyword => write!(f, "SendDirect: missing keyword"),
+ SendDirectTooManyKeywords => write!(f, "SendDirect: too many keywords for fixnum bitmask"),
SendPolymorphic => write!(f, "Send: polymorphic call site"),
SendMegamorphic => write!(f, "Send: megamorphic call site"),
SendNoProfiles => write!(f, "Send: no profile data available"),
@@ -959,13 +959,14 @@ pub enum Insn {
},
/// Optimized ISEQ call
- SendWithoutBlockDirect {
+ SendDirect {
recv: InsnId,
cd: *const rb_call_data,
cme: *const rb_callable_method_entry_t,
iseq: IseqPtr,
args: Vec,
kw_bits: u32,
+ blockiseq: Option,
state: InsnId,
},
@@ -1193,7 +1194,7 @@ impl Insn {
Insn::InvokeSuper { .. } => effects::Any,
Insn::InvokeSuperForward { .. } => effects::Any,
Insn::InvokeBlock { .. } => effects::Any,
- Insn::SendWithoutBlockDirect { .. } => effects::Any,
+ Insn::SendDirect { .. } => effects::Any,
Insn::InvokeBuiltin { .. } => effects::Any,
Insn::EntryPoint { .. } => effects::Any,
Insn::Return { .. } => effects::Any,
@@ -1446,8 +1447,8 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
write!(f, " # SendFallbackReason: {reason}")?;
Ok(())
}
- Insn::SendWithoutBlockDirect { recv, cd, iseq, args, .. } => {
- write!(f, "SendWithoutBlockDirect {recv}, :{} ({:?})", ruby_call_method_name(*cd), self.ptr_map.map_ptr(iseq))?;
+ Insn::SendDirect { recv, cd, iseq, args, blockiseq, .. } => {
+ write!(f, "SendDirect {recv}, {:p}, :{} ({:?})", self.ptr_map.map_ptr(blockiseq), ruby_call_method_name(*cd), self.ptr_map.map_ptr(iseq))?;
for arg in args {
write!(f, ", {arg}")?;
}
@@ -1838,7 +1839,8 @@ pub enum ValidationError {
MiscValidationError(InsnId, String),
}
-fn can_direct_send(function: &mut Function, block: BlockId, iseq: *const rb_iseq_t, ci: *const rb_callinfo, send_insn: InsnId, args: &[InsnId]) -> bool {
+/// Check if we can do a direct send to the given iseq with the given args.
+fn can_direct_send(function: &mut Function, block: BlockId, iseq: *const rb_iseq_t, ci: *const rb_callinfo, send_insn: InsnId, args: &[InsnId], blockiseq: Option) -> bool {
let mut can_send = true;
let mut count_failure = |counter| {
can_send = false;
@@ -1846,10 +1848,14 @@ fn can_direct_send(function: &mut Function, block: BlockId, iseq: *const rb_iseq
};
let params = unsafe { iseq.params() };
+ let caller_has_literal_block: bool = blockiseq.is_some();
+ let callee_has_block_param = 0 != params.flags.has_block();
+
use Counter::*;
if 0 != params.flags.has_rest() { count_failure(complex_arg_pass_param_rest) }
if 0 != params.flags.has_post() { count_failure(complex_arg_pass_param_post) }
- if 0 != params.flags.has_block() { count_failure(complex_arg_pass_param_block) }
+ if callee_has_block_param && !caller_has_literal_block
+ { count_failure(complex_arg_pass_param_block) }
if 0 != params.flags.forwardable() { count_failure(complex_arg_pass_param_forwardable) }
if 0 != params.flags.has_kwrest() { count_failure(complex_arg_pass_param_kwrest) }
@@ -1884,7 +1890,11 @@ fn can_direct_send(function: &mut Function, block: BlockId, iseq: *const rb_iseq
let kwarg = unsafe { rb_vm_ci_kwarg(ci) };
let caller_kw_count = if kwarg.is_null() { 0 } else { (unsafe { get_cikw_keyword_len(kwarg) }) as usize };
let caller_positional = args.len() - caller_kw_count;
- let final_argc = caller_positional + kw_total_num as usize;
+ // Right now, the JIT entrypoint accepts the block as an param
+ // We may remove it, remove the block_arg addition to match
+ // See: https://github.com/ruby/ruby/pull/15911#discussion_r2710544982
+ let block_arg = if 0 != params.flags.has_block() { 1 } else { 0 };
+ let final_argc = caller_positional + kw_total_num as usize + block_arg;
if final_argc + 1 > C_ARG_OPNDS.len() { // +1 for self
function.set_dynamic_send_reason(send_insn, TooManyArgsForLir);
return false;
@@ -2261,13 +2271,14 @@ impl Function {
state,
reason,
},
- &SendWithoutBlockDirect { recv, cd, cme, iseq, ref args, kw_bits, state } => SendWithoutBlockDirect {
+ &SendDirect { recv, cd, cme, iseq, ref args, kw_bits, blockiseq, state } => SendDirect {
recv: find!(recv),
cd,
cme,
iseq,
args: find_vec!(args),
kw_bits,
+ blockiseq,
state,
},
&Send { recv, cd, blockiseq, ref args, state, reason } => Send {
@@ -2499,7 +2510,7 @@ impl Function {
Insn::FixnumRShift { .. } => types::Fixnum,
Insn::PutSpecialObject { .. } => types::BasicObject,
Insn::SendWithoutBlock { .. } => types::BasicObject,
- Insn::SendWithoutBlockDirect { .. } => types::BasicObject,
+ Insn::SendDirect { .. } => types::BasicObject,
Insn::Send { .. } => types::BasicObject,
Insn::SendForward { .. } => types::BasicObject,
Insn::InvokeSuper { .. } => types::BasicObject,
@@ -2666,7 +2677,7 @@ impl Function {
}
/// Prepare arguments for a direct send, handling keyword argument reordering and default synthesis.
- /// Returns the (state, processed_args, kw_bits) to use for the SendWithoutBlockDirect instruction,
+ /// Returns the (state, processed_args, kw_bits) to use for the SendDirect instruction,
/// or Err with the fallback reason if direct send isn't possible.
fn prepare_direct_send_args(
&mut self,
@@ -2711,7 +2722,7 @@ impl Function {
if callee_keyword.is_null() {
if !kwarg.is_null() {
// Caller is passing kwargs but callee doesn't expect them.
- return Err(SendWithoutBlockDirectKeywordMismatch);
+ return Err(SendDirectKeywordMismatch);
}
// Neither caller nor callee have keywords - nothing to do
return Ok((args.to_vec(), args.len(), 0));
@@ -2724,7 +2735,7 @@ impl Function {
// When there are 31+ keywords, CRuby uses a hash instead of a fixnum bitmask
// for kw_bits. Fall back to VM dispatch for this rare case.
if callee_kw_count >= VM_KW_SPECIFIED_BITS_MAX as usize {
- return Err(SendWithoutBlockDirectTooManyKeywords);
+ return Err(SendDirectTooManyKeywords);
}
let callee_kw_required = unsafe { (*callee_keyword).required_num } as usize;
@@ -2733,7 +2744,7 @@ impl Function {
// Caller can't provide more keywords than callee expects (no **kwrest support yet).
if caller_kw_count > callee_kw_count {
- return Err(SendWithoutBlockDirectKeywordCountMismatch);
+ return Err(SendDirectKeywordCountMismatch);
}
// The keyword arguments are the last arguments in the args vector.
@@ -2763,7 +2774,7 @@ impl Function {
if !found {
// Caller is passing an unknown keyword - this will raise ArgumentError.
// Fall back to VM dispatch to handle the error.
- return Err(SendWithoutBlockDirectKeywordMismatch);
+ return Err(SendDirectKeywordMismatch);
}
}
@@ -2787,7 +2798,7 @@ impl Function {
if !found {
// Required keyword not provided by caller which will raise an ArgumentError.
if i < callee_kw_required {
- return Err(SendWithoutBlockDirectMissingKeyword);
+ return Err(SendDirectMissingKeyword);
}
// Optional keyword not provided - use default value
@@ -2965,9 +2976,11 @@ impl Function {
}
}
- /// Rewrite SendWithoutBlock opcodes into SendWithoutBlockDirect opcodes if we know the target
- /// ISEQ statically. This removes run-time method lookups and opens the door for inlining.
+ /// Rewrite eligible Send/SendWithoutBlock opcodes into SendDirect
+ /// opcodes if we know the target ISEQ statically. This removes run-time method lookups and
+ /// opens the door for inlining.
/// Also try and inline constant caches, specialize object allocations, and more.
+ /// Calls to C functions are handled separately in optimize_c_calls.
fn type_specialize(&mut self) {
for block in self.rpo() {
let old_insns = std::mem::take(&mut self.blocks[block.0].insns);
@@ -3037,7 +3050,7 @@ impl Function {
def_type = unsafe { get_cme_def_type(cme) };
}
- // If the call site info indicates that the `Function` has overly complex arguments, then do not optimize into a `SendWithoutBlockDirect`.
+ // If the call site info indicates that the `Function` has overly complex arguments, then do not optimize into a `SendDirect`.
// Optimized methods(`VM_METHOD_TYPE_OPTIMIZED`) handle their own argument constraints (e.g., kw_splat for Proc call).
if def_type != VM_METHOD_TYPE_OPTIMIZED && unspecializable_call_type(flags) {
self.count_complex_call_features(block, flags);
@@ -3050,15 +3063,20 @@ impl Function {
// Only specialize positional-positional calls
// TODO(max): Handle other kinds of parameter passing
let iseq = unsafe { get_def_iseq_ptr((*cme).def) };
- if !can_direct_send(self, block, iseq, ci, insn_id, args.as_slice()) {
+ if !can_direct_send(self, block, iseq, ci, insn_id, args.as_slice(), None) {
self.push_insn_id(block, insn_id); continue;
}
+
// Check singleton class assumption first, before emitting other patchpoints
if !self.assume_no_singleton_classes(block, klass, state) {
self.set_dynamic_send_reason(insn_id, SingletonClassSeen);
self.push_insn_id(block, insn_id); continue;
}
+
+ // Add PatchPoint for method redefinition
self.push_insn(block, Insn::PatchPoint { invariant: Invariant::MethodRedefined { klass, method: mid, cme }, state });
+
+ // Add GuardType for profiled receiver
if let Some(profiled_type) = profiled_type {
recv = self.push_insn(block, Insn::GuardType { val: recv, guard_type: Type::from_profiled_type(profiled_type), state });
}
@@ -3068,7 +3086,7 @@ impl Function {
self.push_insn_id(block, insn_id); continue;
};
- let send_direct = self.push_insn(block, Insn::SendWithoutBlockDirect { recv, cd, cme, iseq, args: processed_args, kw_bits, state: send_state });
+ let send_direct = self.push_insn(block, Insn::SendDirect { recv, cd, cme, iseq, args: processed_args, kw_bits, state: send_state, blockiseq: None });
self.make_equal_to(insn_id, send_direct);
} else if def_type == VM_METHOD_TYPE_BMETHOD {
let procv = unsafe { rb_get_def_bmethod_proc((*cme).def) };
@@ -3083,11 +3101,9 @@ impl Function {
let capture = unsafe { proc_block.as_.captured.as_ref() };
let iseq = unsafe { *capture.code.iseq.as_ref() };
- if !can_direct_send(self, block, iseq, ci, insn_id, args.as_slice()) {
+ if !can_direct_send(self, block, iseq, ci, insn_id, args.as_slice(), None) {
self.push_insn_id(block, insn_id); continue;
}
- // Can't pass a block to a block for now
- assert!((unsafe { rb_vm_ci_flag(ci) } & VM_CALL_ARGS_BLOCKARG) == 0, "SendWithoutBlock but has a block arg");
// Patch points:
// Check for "defined with an un-shareable Proc in a different Ractor"
@@ -3111,7 +3127,7 @@ impl Function {
self.push_insn_id(block, insn_id); continue;
};
- let send_direct = self.push_insn(block, Insn::SendWithoutBlockDirect { recv, cd, cme, iseq, args: processed_args, kw_bits, state: send_state });
+ let send_direct = self.push_insn(block, Insn::SendDirect { recv, cd, cme, iseq, args: processed_args, kw_bits, state: send_state, blockiseq: None });
self.make_equal_to(insn_id, send_direct);
} else if def_type == VM_METHOD_TYPE_IVAR && args.is_empty() {
// Check if we're accessing ivars of a Class or Module object as they require single-ractor mode.
@@ -3240,14 +3256,12 @@ impl Function {
self.push_insn_id(block, insn_id); continue;
}
}
- // This doesn't actually optimize Send yet, just replaces the fallback reason to be more precise.
- // The actual optimization is done in reduce_send_to_ccall.
- Insn::Send { recv, cd, state, .. } => {
+ Insn::Send { mut recv, cd, state, blockiseq, args, .. } => {
let frame_state = self.frame_state(state);
- let klass = match self.resolve_receiver_type(recv, self.type_of(recv), frame_state.insn_idx) {
- ReceiverTypeResolution::StaticallyKnown { class } => class,
+ let (klass, profiled_type) = match self.resolve_receiver_type(recv, self.type_of(recv), frame_state.insn_idx) {
+ ReceiverTypeResolution::StaticallyKnown { class } => (class, None),
ReceiverTypeResolution::Monomorphic { profiled_type }
- | ReceiverTypeResolution::SkewedPolymorphic { profiled_type } => profiled_type.class(),
+ | ReceiverTypeResolution::SkewedPolymorphic { profiled_type } => (profiled_type.class(), Some(profiled_type)),
ReceiverTypeResolution::SkewedMegamorphic { .. }
| ReceiverTypeResolution::Megamorphic => {
if get_option!(stats) {
@@ -3272,6 +3286,9 @@ impl Function {
}
};
let ci = unsafe { get_call_data_ci(cd) }; // info about the call site
+
+ let flags = unsafe { rb_vm_ci_flag(ci) };
+
let mid = unsafe { vm_ci_mid(ci) };
// Do method lookup
let mut cme = unsafe { rb_callable_method_entry(klass, mid) };
@@ -3282,13 +3299,70 @@ impl Function {
// Load an overloaded cme if applicable. See vm_search_cc().
// It allows you to use a faster ISEQ if possible.
cme = unsafe { rb_check_overloaded_cme(cme, ci) };
+ let visibility = unsafe { METHOD_ENTRY_VISI(cme) };
+ match (visibility, flags & VM_CALL_FCALL != 0) {
+ (METHOD_VISI_PUBLIC, _) => {}
+ (METHOD_VISI_PRIVATE, true) => {}
+ (METHOD_VISI_PROTECTED, true) => {}
+ _ => {
+ self.set_dynamic_send_reason(insn_id, SendNotOptimizedNeedPermission);
+ self.push_insn_id(block, insn_id); continue;
+ }
+ }
let mut def_type = unsafe { get_cme_def_type(cme) };
while def_type == VM_METHOD_TYPE_ALIAS {
cme = unsafe { rb_aliased_callable_method_entry(cme) };
def_type = unsafe { get_cme_def_type(cme) };
}
- self.set_dynamic_send_reason(insn_id, SendNotOptimizedMethodType(MethodType::from(def_type)));
- self.push_insn_id(block, insn_id); continue;
+
+ // If the call site info indicates that the `Function` has overly complex arguments, then do not optimize into a `SendDirect`.
+ // Optimized methods(`VM_METHOD_TYPE_OPTIMIZED`) handle their own argument constraints (e.g., kw_splat for Proc call).
+ if def_type != VM_METHOD_TYPE_OPTIMIZED && unspecializable_call_type(flags) {
+ self.count_complex_call_features(block, flags);
+ self.set_dynamic_send_reason(insn_id, ComplexArgPass);
+ self.push_insn_id(block, insn_id); continue;
+ }
+
+ if def_type == VM_METHOD_TYPE_ISEQ {
+ let iseq = unsafe { get_def_iseq_ptr((*cme).def) };
+ if !can_direct_send(self, block, iseq, ci, insn_id, args.as_slice(), Some(blockiseq)) {
+ self.push_insn_id(block, insn_id); continue;
+ }
+
+ // Check singleton class assumption first, before emitting other patchpoints
+ if !self.assume_no_singleton_classes(block, klass, state) {
+ self.set_dynamic_send_reason(insn_id, SingletonClassSeen);
+ self.push_insn_id(block, insn_id); continue;
+ }
+
+ // Add PatchPoint for method redefinition
+ self.push_insn(block, Insn::PatchPoint { invariant: Invariant::MethodRedefined { klass, method: mid, cme }, state });
+
+ // Add GuardType for profiled receiver
+ if let Some(profiled_type) = profiled_type {
+ recv = self.push_insn(block, Insn::GuardType { val: recv, guard_type: Type::from_profiled_type(profiled_type), state });
+ }
+
+ let Ok((send_state, processed_args, kw_bits)) = self.prepare_direct_send_args(block, &args, ci, iseq, state)
+ .inspect_err(|&reason| self.set_dynamic_send_reason(insn_id, reason)) else {
+ self.push_insn_id(block, insn_id); continue;
+ };
+
+ let send_direct = self.push_insn(block, Insn::SendDirect {
+ recv,
+ cd,
+ cme,
+ iseq,
+ args: processed_args,
+ kw_bits,
+ blockiseq: Some(blockiseq),
+ state: send_state,
+ });
+ self.make_equal_to(insn_id, send_direct);
+ } else {
+ self.set_dynamic_send_reason(insn_id, SendNotOptimizedMethodType(MethodType::from(def_type)));
+ self.push_insn_id(block, insn_id); continue;
+ }
}
Insn::GetConstantPath { ic, state, .. } => {
let idlist: *const ID = unsafe { (*ic).segments };
@@ -3464,7 +3538,8 @@ impl Function {
// Check if the super method's parameters support direct send.
// If not, we can't do direct dispatch.
let super_iseq = unsafe { get_def_iseq_ptr((*super_cme).def) };
- if !can_direct_send(self, block, super_iseq, ci, insn_id, args.as_slice()) {
+ // TODO: pass Option to can_direct_send when we start specializing super { ... }
+ if !can_direct_send(self, block, super_iseq, ci, insn_id, args.as_slice(), None) {
self.push_insn_id(block, insn_id);
self.set_dynamic_send_reason(insn_id, SuperTargetComplexArgsPass);
continue;
@@ -3502,15 +3577,16 @@ impl Function {
self.push_insn_id(block, insn_id); continue;
};
- // Use SendWithoutBlockDirect with the super method's CME and ISEQ.
- let send_direct = self.push_insn(block, Insn::SendWithoutBlockDirect {
+ // Use SendDirect with the super method's CME and ISEQ.
+ let send_direct = self.push_insn(block, Insn::SendDirect {
recv,
cd,
cme: super_cme,
iseq: super_iseq,
args: processed_args,
kw_bits,
- state: send_state
+ state: send_state,
+ blockiseq: None,
});
self.make_equal_to(insn_id, send_direct);
}
@@ -3528,7 +3604,7 @@ impl Function {
for insn_id in old_insns {
match self.find(insn_id) {
// Reject block ISEQs to avoid autosplat and other block parameter complications.
- Insn::SendWithoutBlockDirect { recv, iseq, cd, args, state, .. } => {
+ Insn::SendDirect { recv, iseq, cd, args, state, blockiseq: None, .. } => {
let call_info = unsafe { (*cd).ci };
let ci_flags = unsafe { vm_ci_flag(call_info) };
// .send call is not currently supported for builtins
@@ -3776,7 +3852,7 @@ impl Function {
self.push_insn(block, Insn::PatchPoint { invariant: Invariant::MethodRedefined { klass: recv_class, method: method_id, cme }, state });
}
- /// Optimize SendWithoutBlock that land in a C method to a direct CCall without
+ /// Optimize Send/SendWithoutBlock that land in a C method to a direct CCall without
/// runtime lookup.
fn optimize_c_calls(&mut self) {
if unsafe { rb_zjit_method_tracing_currently_enabled() } {
@@ -3841,7 +3917,10 @@ impl Function {
// When seeing &block argument, fall back to dynamic dispatch for now
// TODO: Support block forwarding
if unspecializable_c_call_type(ci_flags) {
- fun.count_complex_call_features(block, ci_flags);
+ // Only count features NOT already counted in type_specialize.
+ if !unspecializable_call_type(ci_flags) {
+ fun.count_complex_call_features(block, ci_flags);
+ }
fun.set_dynamic_send_reason(send_insn_id, ComplexArgPass);
return Err(());
}
@@ -4011,7 +4090,10 @@ impl Function {
// Filter for simple call sites (i.e. no splats etc.)
if ci_flags & VM_CALL_ARGS_SIMPLE == 0 {
- fun.count_complex_call_features(block, ci_flags);
+ // Only count features NOT already counted in type_specialize.
+ if !unspecializable_call_type(ci_flags) {
+ fun.count_complex_call_features(block, ci_flags);
+ }
fun.set_dynamic_send_reason(send_insn_id, ComplexArgPass);
return Err(());
}
@@ -4091,8 +4173,10 @@ impl Function {
// func(int argc, VALUE *argv, VALUE recv)
let ci_flags = unsafe { vm_ci_flag(call_info) };
if ci_flags & VM_CALL_ARGS_SIMPLE == 0 {
- // TODO(alan): Add fun.count_complex_call_features() here without double
- // counting splat
+ // Only count features NOT already counted in type_specialize.
+ if !unspecializable_call_type(ci_flags) {
+ fun.count_complex_call_features(block, ci_flags);
+ }
fun.set_dynamic_send_reason(send_insn_id, ComplexArgPass);
return Err(());
} else {
@@ -4616,7 +4700,7 @@ impl Function {
| &Insn::SendWithoutBlock { recv, ref args, state, .. }
| &Insn::CCallVariadic { recv, ref args, state, .. }
| &Insn::CCallWithFrame { recv, ref args, state, .. }
- | &Insn::SendWithoutBlockDirect { recv, ref args, state, .. }
+ | &Insn::SendDirect { recv, ref args, state, .. }
| &Insn::InvokeBuiltin { recv, ref args, state, .. }
| &Insn::InvokeSuper { recv, ref args, state, .. }
| &Insn::InvokeSuperForward { recv, ref args, state, .. }
@@ -5276,7 +5360,7 @@ impl Function {
}
// Instructions with recv and a Vec of Ruby objects
Insn::SendWithoutBlock { recv, ref args, .. }
- | Insn::SendWithoutBlockDirect { recv, ref args, .. }
+ | Insn::SendDirect { recv, ref args, .. }
| Insn::Send { recv, ref args, .. }
| Insn::SendForward { recv, ref args, .. }
| Insn::InvokeSuper { recv, ref args, .. }
diff --git a/zjit/src/hir/opt_tests.rs b/zjit/src/hir/opt_tests.rs
index 0110af3f2c4c5d..70afd54022e40e 100644
--- a/zjit/src/hir/opt_tests.rs
+++ b/zjit/src/hir/opt_tests.rs
@@ -701,7 +701,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v18:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v19:BasicObject = SendWithoutBlockDirect v18, :foo (0x1038)
+ v19:BasicObject = SendDirect v18, 0x1038, :foo (0x1048)
CheckInterrupts
Return v19
");
@@ -795,7 +795,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v20:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v21:BasicObject = SendWithoutBlockDirect v20, :foo (0x1038), v11
+ v21:BasicObject = SendDirect v20, 0x1038, :foo (0x1048), v11
CheckInterrupts
Return v21
");
@@ -913,7 +913,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v18:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v19:BasicObject = SendWithoutBlockDirect v18, :foo (0x1038)
+ v19:BasicObject = SendDirect v18, 0x1038, :foo (0x1048)
CheckInterrupts
Return v19
");
@@ -941,7 +941,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, Integer@0x1008, cme:0x1010)
v20:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v21:BasicObject = SendWithoutBlockDirect v20, :Integer (0x1038), v11
+ v21:BasicObject = SendDirect v20, 0x1038, :Integer (0x1048), v11
CheckInterrupts
Return v21
");
@@ -971,7 +971,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v22:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v23:BasicObject = SendWithoutBlockDirect v22, :foo (0x1038), v11, v13
+ v23:BasicObject = SendDirect v22, 0x1038, :foo (0x1048), v11, v13
CheckInterrupts
Return v23
");
@@ -1001,11 +1001,11 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v23:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v24:BasicObject = SendWithoutBlockDirect v23, :foo (0x1038)
+ v24:BasicObject = SendDirect v23, 0x1038, :foo (0x1048)
PatchPoint NoSingletonClass(Object@0x1000)
- PatchPoint MethodRedefined(Object@0x1000, bar@0x1040, cme:0x1048)
+ PatchPoint MethodRedefined(Object@0x1000, bar@0x1050, cme:0x1058)
v27:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v28:BasicObject = SendWithoutBlockDirect v27, :bar (0x1038)
+ v28:BasicObject = SendDirect v27, 0x1038, :bar (0x1048)
CheckInterrupts
Return v28
");
@@ -1031,7 +1031,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v18:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v19:BasicObject = SendWithoutBlockDirect v18, :foo (0x1038)
+ v19:BasicObject = SendDirect v18, 0x1038, :foo (0x1048)
CheckInterrupts
Return v19
");
@@ -1058,7 +1058,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v20:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v21:BasicObject = SendWithoutBlockDirect v20, :foo (0x1038), v11
+ v21:BasicObject = SendDirect v20, 0x1038, :foo (0x1048), v11
CheckInterrupts
Return v21
");
@@ -1086,7 +1086,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v22:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v23:BasicObject = SendWithoutBlockDirect v22, :foo (0x1038), v11, v13
+ v23:BasicObject = SendDirect v22, 0x1038, :foo (0x1048), v11, v13
CheckInterrupts
Return v23
");
@@ -1113,14 +1113,14 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, target@0x1008, cme:0x1010)
v44:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v45:BasicObject = SendWithoutBlockDirect v44, :target (0x1038)
+ v45:BasicObject = SendDirect v44, 0x1038, :target (0x1048)
v14:Fixnum[10] = Const Value(10)
v16:Fixnum[20] = Const Value(20)
v18:Fixnum[30] = Const Value(30)
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, target@0x1008, cme:0x1010)
v48:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v49:BasicObject = SendWithoutBlockDirect v48, :target (0x1038), v14, v16, v18
+ v49:BasicObject = SendDirect v48, 0x1038, :target (0x1048), v14, v16, v18
v24:Fixnum[10] = Const Value(10)
v26:Fixnum[20] = Const Value(20)
v28:Fixnum[30] = Const Value(30)
@@ -2865,20 +2865,21 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(C@0x1000)
PatchPoint MethodRedefined(C@0x1000, foo@0x1008, cme:0x1010)
v21:HeapObject[class_exact:C] = GuardType v9, HeapObject[class_exact:C]
- v22:BasicObject = SendWithoutBlockDirect v21, :foo (0x1038)
+ v22:BasicObject = SendDirect v21, 0x1038, :foo (0x1048)
CheckInterrupts
Return v22
");
}
#[test]
- fn dont_specialize_call_to_iseq_with_block() {
- eval("
- def foo(&block) = 1
- def test = foo {|| }
+ fn test_send_direct_iseq_with_block() {
+ let result = eval("
+ def foo(a, b, &block) = block.call(a, b)
+ def test = foo(1, 2) { |a, b| a + b }
test
test
");
+ assert_eq!(VALUE::fixnum_from_usize(3), result);
assert_snapshot!(hir_string("test"), @r"
fn test@:3:
bb0():
@@ -2889,9 +2890,14 @@ mod hir_opt_tests {
EntryPoint JIT(0)
Jump bb2(v4)
bb2(v6:BasicObject):
- v11:BasicObject = Send v6, 0x1000, :foo # SendFallbackReason: Send: unsupported method type Iseq
+ v11:Fixnum[1] = Const Value(1)
+ v13:Fixnum[2] = Const Value(2)
+ PatchPoint NoSingletonClass(Object@0x1000)
+ PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
+ v22:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v23:BasicObject = SendDirect v22, 0x1038, :foo (0x1048), v11, v13
CheckInterrupts
- Return v11
+ Return v23
");
}
@@ -2921,7 +2927,10 @@ mod hir_opt_tests {
bb2(v8:BasicObject, v9:NilClass):
v13:Fixnum[1] = Const Value(1)
SetLocal :a, l0, EP@3, v13
- v19:BasicObject = Send v8, 0x1000, :foo # SendFallbackReason: Send: unsupported method type Iseq
+ PatchPoint NoSingletonClass(Object@0x1000)
+ PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
+ v31:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v8, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v32:BasicObject = SendDirect v31, 0x1038, :foo (0x1048)
v20:BasicObject = GetLocal :a, l0, EP@3
v24:BasicObject = GetLocal :a, l0, EP@3
CheckInterrupts
@@ -3003,7 +3012,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v22:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v23:BasicObject = SendWithoutBlockDirect v22, :foo (0x1038), v11, v13
+ v23:BasicObject = SendDirect v22, 0x1038, :foo (0x1048), v11, v13
CheckInterrupts
Return v23
");
@@ -3033,7 +3042,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v24:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v26:BasicObject = SendWithoutBlockDirect v24, :foo (0x1038), v13, v15, v11
+ v26:BasicObject = SendDirect v24, 0x1038, :foo (0x1048), v13, v15, v11
CheckInterrupts
Return v26
");
@@ -3063,7 +3072,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v24:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v26:BasicObject = SendWithoutBlockDirect v24, :foo (0x1038), v11, v15, v13
+ v26:BasicObject = SendDirect v24, 0x1038, :foo (0x1048), v11, v15, v13
CheckInterrupts
Return v26
");
@@ -3092,7 +3101,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v22:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v23:BasicObject = SendWithoutBlockDirect v22, :foo (0x1038), v11, v13
+ v23:BasicObject = SendDirect v22, 0x1038, :foo (0x1048), v11, v13
CheckInterrupts
Return v23
");
@@ -3122,7 +3131,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v37:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v38:BasicObject = SendWithoutBlockDirect v37, :foo (0x1038), v11, v13, v15
+ v38:BasicObject = SendDirect v37, 0x1038, :foo (0x1048), v11, v13, v15
v20:Fixnum[1] = Const Value(1)
v22:Fixnum[2] = Const Value(2)
v24:Fixnum[4] = Const Value(4)
@@ -3130,7 +3139,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v41:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v43:BasicObject = SendWithoutBlockDirect v41, :foo (0x1038), v20, v22, v26, v24
+ v43:BasicObject = SendDirect v41, 0x1038, :foo (0x1048), v20, v22, v26, v24
v30:ArrayExact = NewArray v38, v43
CheckInterrupts
Return v30
@@ -3161,7 +3170,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v35:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
v36:Fixnum[4] = Const Value(4)
- v38:BasicObject = SendWithoutBlockDirect v35, :foo (0x1038), v11, v13, v36
+ v38:BasicObject = SendDirect v35, 0x1038, :foo (0x1048), v11, v13, v36
v18:Fixnum[1] = Const Value(1)
v20:Fixnum[2] = Const Value(2)
v22:Fixnum[40] = Const Value(40)
@@ -3169,7 +3178,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v41:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v43:BasicObject = SendWithoutBlockDirect v41, :foo (0x1038), v18, v20, v24, v22
+ v43:BasicObject = SendDirect v41, 0x1038, :foo (0x1048), v18, v20, v24, v22
v28:ArrayExact = NewArray v38, v43
CheckInterrupts
Return v28
@@ -3198,7 +3207,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, target@0x1008, cme:0x1010)
v48:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v49:BasicObject = SendWithoutBlockDirect v48, :target (0x1038), v11
+ v49:BasicObject = SendDirect v48, 0x1038, :target (0x1048), v11
v16:Fixnum[10] = Const Value(10)
v18:Fixnum[20] = Const Value(20)
v20:Fixnum[30] = Const Value(30)
@@ -3206,7 +3215,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, target@0x1008, cme:0x1010)
v52:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v53:BasicObject = SendWithoutBlockDirect v52, :target (0x1038), v16, v18, v20, v22
+ v53:BasicObject = SendDirect v52, 0x1038, :target (0x1048), v16, v18, v20, v22
v27:Fixnum[10] = Const Value(10)
v29:Fixnum[20] = Const Value(20)
v31:Fixnum[30] = Const Value(30)
@@ -3242,7 +3251,7 @@ mod hir_opt_tests {
PatchPoint NoSingletonClass(Object@0x1000)
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v20:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
- v21:BasicObject = SendWithoutBlockDirect v20, :foo (0x1038), v11
+ v21:BasicObject = SendDirect v20, 0x1038, :foo (0x1048), v11
CheckInterrupts
Return v21
");
@@ -3296,7 +3305,7 @@ mod hir_opt_tests {
PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
v18:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
v19:Fixnum[1] = Const Value(1)
- v21:BasicObject = SendWithoutBlockDirect v18, :foo (0x1038), v19
+ v21:BasicObject = SendDirect v18, 0x1038, :foo (0x1048), v19
CheckInterrupts
Return v21
");
@@ -3374,6 +3383,7 @@ mod hir_opt_tests {
v11:StringExact[VALUE(0x1000)] = Const Value(VALUE(0x1000))
v12:StringExact = StringCopy v11
v14:Fixnum[1] = Const Value(1)
+ IncrCounter complex_arg_pass_caller_kwarg
v16:BasicObject = SendWithoutBlock v6, :sprintf, v12, v14 # SendFallbackReason: Complex argument passing
CheckInterrupts
Return v16
@@ -3578,7 +3588,7 @@ mod hir_opt_tests {
v49:HeapObject[class_exact:C] = ObjectAllocClass C:VALUE(0x1008)
PatchPoint NoSingletonClass(C@0x1008)
PatchPoint MethodRedefined(C@0x1008, initialize@0x1038, cme:0x1040)
- v52:BasicObject = SendWithoutBlockDirect v49, :initialize (0x1068), v16
+ v52:BasicObject = SendDirect v49, 0x1068, :initialize (0x1078), v16
CheckInterrupts
CheckInterrupts
Return v49
@@ -5312,7 +5322,7 @@ mod hir_opt_tests {
v13:Fixnum[10] = Const Value(10)
PatchPoint NoSingletonClass(Array@0x1008)
PatchPoint MethodRedefined(Array@0x1008, []@0x1010, cme:0x1018)
- v23:BasicObject = SendWithoutBlockDirect v11, :[] (0x1040), v13
+ v23:BasicObject = SendDirect v11, 0x1040, :[] (0x1050), v13
CheckInterrupts
Return v23
");
@@ -5370,7 +5380,7 @@ mod hir_opt_tests {
v11:ArrayExact = ArrayDup v10
PatchPoint NoSingletonClass(Array@0x1008)
PatchPoint MethodRedefined(Array@0x1008, max@0x1010, cme:0x1018)
- v20:BasicObject = SendWithoutBlockDirect v11, :max (0x1040)
+ v20:BasicObject = SendDirect v11, 0x1040, :max (0x1050)
CheckInterrupts
Return v20
");
@@ -6534,15 +6544,16 @@ mod hir_opt_tests {
}
#[test]
- fn test_do_not_optimize_send_to_iseq_method_with_block() {
- eval(r#"
+ fn test_send_direct_iseq_with_block_no_callee_block_param() {
+ let result = eval(r#"
def foo
yield 1
end
- def test = foo {}
+ def test = foo { |x| x * 2 }
test; test
"#);
+ assert_eq!(VALUE::fixnum_from_usize(2), result);
assert_snapshot!(hir_string("test"), @r"
fn test@:6:
bb0():
@@ -6553,9 +6564,12 @@ mod hir_opt_tests {
EntryPoint JIT(0)
Jump bb2(v4)
bb2(v6:BasicObject):
- v11:BasicObject = Send v6, 0x1000, :foo # SendFallbackReason: Send: unsupported method type Iseq
+ PatchPoint NoSingletonClass(Object@0x1000)
+ PatchPoint MethodRedefined(Object@0x1000, foo@0x1008, cme:0x1010)
+ v18:HeapObject[class_exact*:Object@VALUE(0x1000)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1000)]
+ v19:BasicObject = SendDirect v18, 0x1038, :foo (0x1048)
CheckInterrupts
- Return v11
+ Return v19
");
}
@@ -11029,8 +11043,8 @@ mod hir_opt_tests {
// A Ruby method as the target of `super` should optimize provided no block is given.
let hir = hir_string_proc("B.new.method(:foo)");
- assert!(!hir.contains("InvokeSuper "), "InvokeSuper should optimize to SendWithoutBlockDirect but got:\n{hir}");
- assert!(hir.contains("SendWithoutBlockDirect"), "Should optimize to SendWithoutBlockDirect for call without args or block:\n{hir}");
+ assert!(!hir.contains("InvokeSuper "), "InvokeSuper should optimize to SendDirect but got:\n{hir}");
+ assert!(hir.contains("SendDirect"), "Should optimize to SendDirect for call without args or block:\n{hir}");
assert_snapshot!(hir, @r"
fn foo@:10:
@@ -11047,7 +11061,7 @@ mod hir_opt_tests {
GuardSuperMethodEntry v17, 0x1038
v19:RubyValue = GetBlockHandler v17
v20:FalseClass = GuardBitEquals v19, Value(false)
- v21:BasicObject = SendWithoutBlockDirect v6, :foo (0x1040)
+ v21:BasicObject = SendDirect v6, 0x1040, :foo (0x1050)
CheckInterrupts
Return v21
");
@@ -11072,8 +11086,8 @@ mod hir_opt_tests {
");
let hir = hir_string_proc("B.new.method(:foo)");
- assert!(!hir.contains("InvokeSuper "), "InvokeSuper should optimize to SendWithoutBlockDirect but got:\n{hir}");
- assert!(hir.contains("SendWithoutBlockDirect"), "Should optimize to SendWithoutBlockDirect for call without args or block:\n{hir}");
+ assert!(!hir.contains("InvokeSuper "), "InvokeSuper should optimize to SendDirect but got:\n{hir}");
+ assert!(hir.contains("SendDirect"), "Should optimize to SendDirect for call without args or block:\n{hir}");
assert_snapshot!(hir, @r"
fn foo@:10:
@@ -11091,9 +11105,9 @@ mod hir_opt_tests {
GuardSuperMethodEntry v26, 0x1038
v28:RubyValue = GetBlockHandler v26
v29:FalseClass = GuardBitEquals v28, Value(false)
- v30:BasicObject = SendWithoutBlockDirect v8, :foo (0x1040), v9
+ v30:BasicObject = SendDirect v8, 0x1040, :foo (0x1050), v9
v17:Fixnum[1] = Const Value(1)
- PatchPoint MethodRedefined(Integer@0x1048, +@0x1050, cme:0x1058)
+ PatchPoint MethodRedefined(Integer@0x1058, +@0x1060, cme:0x1068)
v33:Fixnum = GuardType v30, Fixnum
v34:Fixnum = FixnumAdd v33, v17
IncrCounter inline_cfunc_optimized_send_count
@@ -11122,7 +11136,7 @@ mod hir_opt_tests {
let hir = hir_string_proc("B.new.method(:foo)");
assert!(hir.contains("InvokeSuper "), "Expected unoptimized InvokeSuper but got:\n{hir}");
- assert!(!hir.contains("SendWithoutBlockDirect"), "Should not optimize to SendWithoutBlockDirect for explicit blockarg:\n{hir}");
+ assert!(!hir.contains("SendDirect"), "Should not optimize to SendDirect for explicit blockarg:\n{hir}");
assert_snapshot!(hir, @r"
fn foo@:10:
@@ -11162,9 +11176,9 @@ mod hir_opt_tests {
let hir = hir_string_proc("B.new.method(:foo)");
assert!(hir.contains("InvokeSuper "), "Expected unoptimized InvokeSuper but got:\n{hir}");
- assert!(!hir.contains("SendWithoutBlockDirect"), "Should not optimize to SendWithoutBlockDirect for block literal:\n{hir}");
+ assert!(!hir.contains("SendDirect"), "Should not optimize to SendDirect for block literal:\n{hir}");
- // With a block, we don't optimize to SendWithoutBlockDirect
+ // With a block, we don't optimize to SendDirect
assert_snapshot!(hir, @r"
fn foo@:10:
bb0():
@@ -11195,7 +11209,7 @@ mod hir_opt_tests {
let hir = hir_string_proc("MyArray.new.method(:length)");
assert!(hir.contains("InvokeSuper "), "Expected unoptimized InvokeSuper but got:\n{hir}");
- assert!(!hir.contains("SendWithoutBlockDirect"), "Should not optimize to SendWithoutBlockDirect for CFUNC:\n{hir}");
+ assert!(!hir.contains("SendDirect"), "Should not optimize to SendDirect for CFUNC:\n{hir}");
assert_snapshot!(hir, @r"
fn length@:4:
@@ -11234,7 +11248,7 @@ mod hir_opt_tests {
let hir = hir_string_proc("B.new.method(:foo)");
assert!(hir.contains("InvokeSuper "), "Expected unoptimized InvokeSuper but got:\n{hir}");
- assert!(!hir.contains("SendWithoutBlockDirect"), "Should not optimize to SendWithoutBlockDirect for explicit blockarg:\n{hir}");
+ assert!(!hir.contains("SendDirect"), "Should not optimize to SendDirect for explicit blockarg:\n{hir}");
assert_snapshot!(hir, @r"
fn foo@:10:
@@ -11282,7 +11296,7 @@ mod hir_opt_tests {
let hir = hir_string_proc("B.new.method(:foo)");
assert!(hir.contains("InvokeSuper "), "Expected unoptimized InvokeSuper but got:\n{hir}");
- assert!(!hir.contains("SendWithoutBlockDirect"), "Should not optimize to SendWithoutBlockDirect for symbol-to-proc:\n{hir}");
+ assert!(!hir.contains("SendDirect"), "Should not optimize to SendDirect for symbol-to-proc:\n{hir}");
assert_snapshot!(hir, @r"
fn foo@:10:
diff --git a/zjit/src/hir/tests.rs b/zjit/src/hir/tests.rs
index c21402449f52fb..e0b0129ea1ce5a 100644
--- a/zjit/src/hir/tests.rs
+++ b/zjit/src/hir/tests.rs
@@ -80,8 +80,8 @@ mod snapshot_tests {
PatchPoint MethodRedefined(Object@0x1010, foo@0x1018, cme:0x1020)
v24:HeapObject[class_exact*:Object@VALUE(0x1010)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1010)]
v25:Any = Snapshot FrameState { pc: 0x1008, stack: [v6, v13, v15, v11], locals: [] }
- v26:BasicObject = SendWithoutBlockDirect v24, :foo (0x1048), v13, v15, v11
- v18:Any = Snapshot FrameState { pc: 0x1050, stack: [v26], locals: [] }
+ v26:BasicObject = SendDirect v24, 0x1048, :foo (0x1058), v13, v15, v11
+ v18:Any = Snapshot FrameState { pc: 0x1060, stack: [v26], locals: [] }
PatchPoint NoTracePoint
CheckInterrupts
Return v26
@@ -114,8 +114,8 @@ mod snapshot_tests {
PatchPoint NoSingletonClass(Object@0x1010)
PatchPoint MethodRedefined(Object@0x1010, foo@0x1018, cme:0x1020)
v22:HeapObject[class_exact*:Object@VALUE(0x1010)] = GuardType v6, HeapObject[class_exact*:Object@VALUE(0x1010)]
- v23:BasicObject = SendWithoutBlockDirect v22, :foo (0x1048), v11, v13
- v16:Any = Snapshot FrameState { pc: 0x1050, stack: [v23], locals: [] }
+ v23:BasicObject = SendDirect v22, 0x1048, :foo (0x1058), v11, v13
+ v16:Any = Snapshot FrameState { pc: 0x1060, stack: [v23], locals: [] }
PatchPoint NoTracePoint
CheckInterrupts
Return v23
diff --git a/zjit/src/stats.rs b/zjit/src/stats.rs
index 96d75b7aec84b7..bb11b96dd9a403 100644
--- a/zjit/src/stats.rs
+++ b/zjit/src/stats.rs
@@ -599,10 +599,10 @@ pub fn send_fallback_counter(reason: crate::hir::SendFallbackReason) -> Counter
TooManyArgsForLir => send_fallback_too_many_args_for_lir,
SendWithoutBlockBopRedefined => send_fallback_send_without_block_bop_redefined,
SendWithoutBlockOperandsNotFixnum => send_fallback_send_without_block_operands_not_fixnum,
- SendWithoutBlockDirectKeywordMismatch => send_fallback_send_without_block_direct_keyword_mismatch,
- SendWithoutBlockDirectKeywordCountMismatch=> send_fallback_send_without_block_direct_keyword_count_mismatch,
- SendWithoutBlockDirectMissingKeyword => send_fallback_send_without_block_direct_missing_keyword,
- SendWithoutBlockDirectTooManyKeywords => send_fallback_send_without_block_direct_too_many_keywords,
+ SendDirectKeywordMismatch => send_fallback_send_without_block_direct_keyword_mismatch,
+ SendDirectKeywordCountMismatch => send_fallback_send_without_block_direct_keyword_count_mismatch,
+ SendDirectMissingKeyword => send_fallback_send_without_block_direct_missing_keyword,
+ SendDirectTooManyKeywords => send_fallback_send_without_block_direct_too_many_keywords,
SendPolymorphic => send_fallback_send_polymorphic,
SendMegamorphic => send_fallback_send_megamorphic,
SendNoProfiles => send_fallback_send_no_profiles,