summaryrefslogtreecommitdiff
path: root/spec/ruby
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby')
-rw-r--r--spec/ruby/.rubocop.yml2
-rw-r--r--spec/ruby/command_line/frozen_strings_spec.rb12
-rw-r--r--spec/ruby/core/array/fixtures/classes.rb744
-rw-r--r--spec/ruby/core/array/pack/buffer_spec.rb10
-rw-r--r--spec/ruby/core/binding/dup_spec.rb17
-rw-r--r--spec/ruby/core/binding/irb_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/next_values_spec.rb8
-rw-r--r--spec/ruby/core/enumerator/peek_values_spec.rb8
-rw-r--r--spec/ruby/core/io/pread_spec.rb9
-rw-r--r--spec/ruby/core/io/read_spec.rb15
-rw-r--r--spec/ruby/core/io/readpartial_spec.rb3
-rw-r--r--spec/ruby/core/io/sysread_spec.rb9
-rw-r--r--spec/ruby/core/module/include_spec.rb28
-rw-r--r--spec/ruby/core/module/prepend_spec.rb48
-rw-r--r--spec/ruby/core/string/chilled_string_spec.rb12
-rw-r--r--spec/ruby/core/string/index_spec.rb11
-rw-r--r--spec/ruby/core/string/modulo_spec.rb65
-rw-r--r--spec/ruby/core/tracepoint/inspect_spec.rb12
-rw-r--r--spec/ruby/core/warning/element_reference_spec.rb4
-rw-r--r--spec/ruby/core/warning/performance_warning_spec.rb28
-rw-r--r--spec/ruby/core/warning/warn_spec.rb24
-rw-r--r--spec/ruby/fixtures/io.rb (renamed from spec/ruby/library/io-wait/fixtures/classes.rb)10
-rw-r--r--spec/ruby/language/block_spec.rb31
-rw-r--r--spec/ruby/language/break_spec.rb19
-rw-r--r--spec/ruby/language/case_spec.rb39
-rw-r--r--spec/ruby/language/def_spec.rb26
-rw-r--r--spec/ruby/language/execution_spec.rb4
-rw-r--r--spec/ruby/language/hash_spec.rb32
-rw-r--r--spec/ruby/language/keyword_arguments_spec.rb28
-rw-r--r--spec/ruby/language/lambda_spec.rb23
-rw-r--r--spec/ruby/language/pattern_matching/3.1.rb75
-rw-r--r--spec/ruby/language/pattern_matching_spec.rb1468
-rw-r--r--spec/ruby/language/regexp/back-references_spec.rb9
-rw-r--r--spec/ruby/language/retry_spec.rb5
-rw-r--r--spec/ruby/language/yield_spec.rb12
-rw-r--r--spec/ruby/library/date/time/to_date_spec.rb (renamed from spec/ruby/library/time/to_date_spec.rb)2
-rw-r--r--spec/ruby/library/datetime/time/to_datetime_spec.rb (renamed from spec/ruby/library/time/to_datetime_spec.rb)2
-rw-r--r--spec/ruby/library/find/fixtures/common.rb14
-rw-r--r--spec/ruby/library/io-wait/wait_readable_spec.rb19
-rw-r--r--spec/ruby/library/io-wait/wait_spec.rb39
-rw-r--r--spec/ruby/library/io-wait/wait_writable_spec.rb21
-rw-r--r--spec/ruby/library/rbconfig/rbconfig_spec.rb55
-rw-r--r--spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb16
-rw-r--r--spec/ruby/library/socket/basicsocket/recv_spec.rb22
-rw-r--r--spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb21
-rw-r--r--spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb9
-rw-r--r--spec/ruby/library/socket/unixsocket/recvfrom_spec.rb23
-rw-r--r--spec/ruby/library/stringio/shared/read.rb20
-rw-r--r--spec/ruby/optional/capi/class_spec.rb12
-rw-r--r--spec/ruby/optional/capi/data_spec.rb73
-rw-r--r--spec/ruby/optional/capi/ext/class_spec.c5
-rw-r--r--spec/ruby/optional/capi/ext/data_spec.c4
-rw-r--r--spec/ruby/optional/capi/ext/gc_spec.c10
-rw-r--r--spec/ruby/optional/capi/ext/io_spec.c14
-rw-r--r--spec/ruby/optional/capi/ext/object_spec.c16
-rw-r--r--spec/ruby/optional/capi/ext/rubyspec.h4
-rw-r--r--spec/ruby/optional/capi/ext/typed_data_spec.c2
-rw-r--r--spec/ruby/optional/capi/gc_spec.rb4
-rw-r--r--spec/ruby/optional/capi/io_spec.rb63
-rw-r--r--spec/ruby/optional/capi/rbasic_spec.rb56
-rw-r--r--spec/ruby/shared/kernel/at_exit.rb6
61 files changed, 1941 insertions, 1443 deletions
diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml
index be32ce8900..5a902e0f01 100644
--- a/spec/ruby/.rubocop.yml
+++ b/spec/ruby/.rubocop.yml
@@ -1,7 +1,7 @@
inherit_from: .rubocop_todo.yml
AllCops:
- TargetRubyVersion: 3.0
+ TargetRubyVersion: 3.1
DisplayCopNames: true
Exclude:
- command_line/fixtures/bad_syntax.rb
diff --git a/spec/ruby/command_line/frozen_strings_spec.rb b/spec/ruby/command_line/frozen_strings_spec.rb
index 334b98273b..06889755d2 100644
--- a/spec/ruby/command_line/frozen_strings_spec.rb
+++ b/spec/ruby/command_line/frozen_strings_spec.rb
@@ -42,16 +42,8 @@ describe "With neither --enable-frozen-string-literal nor --disable-frozen-strin
ruby_exe(fixture(__FILE__, "freeze_flag_one_literal.rb")).chomp.should == "false"
end
- ruby_version_is "3.4" do
- it "if file has no frozen_string_literal comment produce different frozen strings each time" do
- ruby_exe(fixture(__FILE__, "string_literal_raw.rb")).chomp.should == "frozen:true interned:false"
- end
- end
-
- ruby_version_is ""..."3.4" do
- it "if file has no frozen_string_literal comment produce different mutable strings each time" do
- ruby_exe(fixture(__FILE__, "string_literal_raw.rb")).chomp.should == "frozen:false interned:false"
- end
+ it "if file has no frozen_string_literal comment produce different mutable strings each time" do
+ ruby_exe(fixture(__FILE__, "string_literal_raw.rb")).chomp.should == "frozen:false interned:false"
end
it "if file has frozen_string_literal:true comment produce same frozen strings each time" do
diff --git a/spec/ruby/core/array/fixtures/classes.rb b/spec/ruby/core/array/fixtures/classes.rb
index 8596245fb8..05283c0f74 100644
--- a/spec/ruby/core/array/fixtures/classes.rb
+++ b/spec/ruby/core/array/fixtures/classes.rb
@@ -56,23 +56,20 @@ module ArraySpecs
101.621, 102.816, 104.010, 105.202, 106.393, 107.583, 108.771, 109.958, 111.144, 112.329,
113.512, 114.695, 115.876, 117.057, 118.236, 119.414, 120.591, 121.767, 122.942, 124.116,
125.289, 126.462, 127.633, 128.803, 129.973, 131.141, 132.309, 133.476, 134.642, 135.807,
- ]
+ ]
def self.measure_sample_fairness(size, samples, iters)
ary = Array.new(size) { |x| x }
+ expected = iters.fdiv size
(samples).times do |i|
chi_results = []
3.times do
- counts = Array.new(size) { 0 }
- expected = iters / size
+ counts = Array.new(size, 0)
iters.times do
x = ary.sample(samples)[i]
counts[x] += 1
end
- chi_squared = 0.0
- counts.each do |count|
- chi_squared += (((count - expected) ** 2) * 1.0 / expected)
- end
+ chi_squared = counts.sum {|count| (count - expected) ** 2} / expected
chi_results << chi_squared
break if chi_squared <= CHI_SQUARED_CRITICAL_VALUES[size]
end
@@ -83,17 +80,14 @@ module ArraySpecs
def self.measure_sample_fairness_large_sample_size(size, samples, iters)
ary = Array.new(size) { |x| x }
- counts = Array.new(size) { 0 }
- expected = iters * samples / size
+ counts = Array.new(size, 0)
+ expected = (iters * samples).fdiv size
iters.times do
ary.sample(samples).each do |sample|
counts[sample] += 1
end
end
- chi_squared = 0.0
- counts.each do |count|
- chi_squared += (((count - expected) ** 2) * 1.0 / expected)
- end
+ chi_squared = counts.sum {|count| (count - expected) ** 2} / expected
# Chi squared critical values for tests with 4 degrees of freedom
# Values obtained from NIST Engineering Statistic Handbook at
@@ -223,366 +217,370 @@ module ArraySpecs
obj
end
- LargeArray = ["test_create_table_with_force_true_does_not_drop_nonexisting_table",
- "test_add_table",
- "assert_difference",
- "assert_operator",
- "instance_variables",
- "class",
- "instance_variable_get",
- "__class__",
- "expects",
- "assert_no_difference",
- "name",
- "assert_blank",
- "assert_not_same",
- "is_a?",
- "test_add_table_with_decimals",
- "test_create_table_with_timestamps_should_create_datetime_columns",
- "assert_present",
- "assert_no_match",
- "__instance_of__",
- "assert_deprecated",
- "assert",
- "assert_throws",
- "kind_of?",
- "try",
- "__instance_variable_get__",
- "object_id",
- "timeout",
- "instance_variable_set",
- "assert_nothing_thrown",
- "__instance_variable_set__",
- "copy_object",
- "test_create_table_with_timestamps_should_create_datetime_columns_with_options",
- "assert_not_deprecated",
- "assert_in_delta",
- "id",
- "copy_metaclass",
- "test_create_table_without_a_block",
- "dup",
- "assert_not_nil",
- "send",
- "__instance_variables__",
- "to_sql",
- "mock",
- "assert_send",
- "instance_variable_defined?",
- "clone",
- "require",
- "test_migrator",
- "__instance_variable_defined_eh__",
- "frozen?",
- "test_add_column_not_null_with_default",
- "freeze",
- "test_migrator_one_up",
- "test_migrator_one_down",
- "singleton_methods",
- "method_exists?",
- "create_fixtures",
- "test_migrator_one_up_one_down",
- "test_native_decimal_insert_manual_vs_automatic",
- "instance_exec",
- "__is_a__",
- "test_migrator_double_up",
- "stub",
- "private_methods",
- "stubs",
- "test_migrator_double_down",
- "fixture_path",
- "private_singleton_methods",
- "stub_everything",
- "test_migrator_one_up_with_exception_and_rollback",
- "sequence",
- "protected_methods",
- "enum_for",
- "test_finds_migrations",
- "run_before_mocha",
- "states",
- "protected_singleton_methods",
- "to_json",
- "instance_values",
- "==",
- "mocha_setup",
- "public_methods",
- "test_finds_pending_migrations",
- "mocha_verify",
- "assert_kind_of",
- "===",
- "=~",
- "test_relative_migrations",
- "mocha_teardown",
- "gem",
- "mocha",
- "test_only_loads_pending_migrations",
- "test_add_column_with_precision_and_scale",
- "require_or_load",
- "eql?",
- "require_dependency",
- "test_native_types",
- "test_target_version_zero_should_run_only_once",
- "extend",
- "to_matcher",
- "unloadable",
- "require_association",
- "hash",
- "__id__",
- "load_dependency",
- "equals",
- "test_migrator_db_has_no_schema_migrations_table",
- "test_migrator_verbosity",
- "kind_of",
- "to_yaml",
- "to_bool",
- "test_migrator_verbosity_off",
- "taint",
- "test_migrator_going_down_due_to_version_target",
- "tainted?",
- "mocha_inspect",
- "test_migrator_rollback",
- "vim",
- "untaint",
- "taguri=",
- "test_migrator_forward",
- "test_schema_migrations_table_name",
- "test_proper_table_name",
- "all_of",
- "test_add_drop_table_with_prefix_and_suffix",
- "_setup_callbacks",
- "setup",
- "Not",
- "test_create_table_with_binary_column",
- "assert_not_equal",
- "enable_warnings",
- "acts_like?",
- "Rational",
- "_removed_setup_callbacks",
- "Table",
- "bind",
- "any_of",
- "__method__",
- "test_migrator_with_duplicates",
- "_teardown_callbacks",
- "method",
- "test_migrator_with_duplicate_names",
- "_removed_teardown_callbacks",
- "any_parameters",
- "test_migrator_with_missing_version_numbers",
- "test_add_remove_single_field_using_string_arguments",
- "test_create_table_with_custom_sequence_name",
- "test_add_remove_single_field_using_symbol_arguments",
- "_one_time_conditions_valid_14?",
- "_one_time_conditions_valid_16?",
- "run_callbacks",
- "anything",
- "silence_warnings",
- "instance_variable_names",
- "_fixture_path",
- "copy_instance_variables_from",
- "fixture_path?",
- "has_entry",
- "__marshal__",
- "_fixture_table_names",
- "__kind_of__",
- "fixture_table_names?",
- "test_add_rename",
- "assert_equal",
- "_fixture_class_names",
- "fixture_class_names?",
- "has_entries",
- "_use_transactional_fixtures",
- "people",
- "test_rename_column_using_symbol_arguments",
- "use_transactional_fixtures?",
- "instance_eval",
- "blank?",
- "with_warnings",
- "__nil__",
- "load",
- "metaclass",
- "_use_instantiated_fixtures",
- "has_key",
- "class_eval",
- "present?",
- "test_rename_column",
- "teardown",
- "use_instantiated_fixtures?",
- "method_name",
- "silence_stderr",
- "presence",
- "test_rename_column_preserves_default_value_not_null",
- "silence_stream",
- "_pre_loaded_fixtures",
- "__metaclass__",
- "__fixnum__",
- "pre_loaded_fixtures?",
- "has_value",
- "suppress",
- "to_yaml_properties",
- "test_rename_nonexistent_column",
- "test_add_index",
- "includes",
- "find_correlate_in",
- "equality_predicate_sql",
- "assert_nothing_raised",
- "let",
- "not_predicate_sql",
- "test_rename_column_with_sql_reserved_word",
- "singleton_class",
- "test_rename_column_with_an_index",
- "display",
- "taguri",
- "to_yaml_style",
- "test_remove_column_with_index",
- "size",
- "current_adapter?",
- "test_remove_column_with_multi_column_index",
- "respond_to?",
- "test_change_type_of_not_null_column",
- "is_a",
- "to_a",
- "test_rename_table_for_sqlite_should_work_with_reserved_words",
- "require_library_or_gem",
- "setup_fixtures",
- "equal?",
- "teardown_fixtures",
- "nil?",
- "fixture_table_names",
- "fixture_class_names",
- "test_create_table_without_id",
- "use_transactional_fixtures",
- "test_add_column_with_primary_key_attribute",
- "repair_validations",
- "use_instantiated_fixtures",
- "instance_of?",
- "test_create_table_adds_id",
- "test_rename_table",
- "pre_loaded_fixtures",
- "to_enum",
- "test_create_table_with_not_null_column",
- "instance_of",
- "test_change_column_nullability",
- "optionally",
- "test_rename_table_with_an_index",
- "run",
- "test_change_column",
- "default_test",
- "assert_raise",
- "test_create_table_with_defaults",
- "assert_nil",
- "flunk",
- "regexp_matches",
- "duplicable?",
- "reset_mocha",
- "stubba_method",
- "filter_backtrace",
- "test_create_table_with_limits",
- "responds_with",
- "stubba_object",
- "test_change_column_with_nil_default",
- "assert_block",
- "__show__",
- "assert_date_from_db",
- "__respond_to_eh__",
- "run_in_transaction?",
- "inspect",
- "assert_sql",
- "test_change_column_with_new_default",
- "yaml_equivalent",
- "build_message",
- "to_s",
- "test_change_column_default",
- "assert_queries",
- "pending",
- "as_json",
- "assert_no_queries",
- "test_change_column_quotes_column_names",
- "assert_match",
- "test_keeping_default_and_notnull_constraint_on_change",
- "methods",
- "connection_allow_concurrency_setup",
- "connection_allow_concurrency_teardown",
- "test_create_table_with_primary_key_prefix_as_table_name_with_underscore",
- "__send__",
- "make_connection",
- "assert_raises",
- "tap",
- "with_kcode",
- "assert_instance_of",
- "test_create_table_with_primary_key_prefix_as_table_name",
- "assert_respond_to",
- "test_change_column_default_to_null",
- "assert_same",
- "__extend__"]
-
- LargeTestArraySorted = ["test_add_column_not_null_with_default",
- "test_add_column_with_precision_and_scale",
- "test_add_column_with_primary_key_attribute",
- "test_add_drop_table_with_prefix_and_suffix",
- "test_add_index",
- "test_add_remove_single_field_using_string_arguments",
- "test_add_remove_single_field_using_symbol_arguments",
- "test_add_rename",
- "test_add_table",
- "test_add_table_with_decimals",
- "test_change_column",
- "test_change_column_default",
- "test_change_column_default_to_null",
- "test_change_column_nullability",
- "test_change_column_quotes_column_names",
- "test_change_column_with_new_default",
- "test_change_column_with_nil_default",
- "test_change_type_of_not_null_column",
- "test_create_table_adds_id",
- "test_create_table_with_binary_column",
- "test_create_table_with_custom_sequence_name",
- "test_create_table_with_defaults",
- "test_create_table_with_force_true_does_not_drop_nonexisting_table",
- "test_create_table_with_limits",
- "test_create_table_with_not_null_column",
- "test_create_table_with_primary_key_prefix_as_table_name",
- "test_create_table_with_primary_key_prefix_as_table_name_with_underscore",
- "test_create_table_with_timestamps_should_create_datetime_columns",
- "test_create_table_with_timestamps_should_create_datetime_columns_with_options",
- "test_create_table_without_a_block",
- "test_create_table_without_id",
- "test_finds_migrations",
- "test_finds_pending_migrations",
- "test_keeping_default_and_notnull_constraint_on_change",
- "test_migrator",
- "test_migrator_db_has_no_schema_migrations_table",
- "test_migrator_double_down",
- "test_migrator_double_up",
- "test_migrator_forward",
- "test_migrator_going_down_due_to_version_target",
- "test_migrator_one_down",
- "test_migrator_one_up",
- "test_migrator_one_up_one_down",
- "test_migrator_one_up_with_exception_and_rollback",
- "test_migrator_rollback",
- "test_migrator_verbosity",
- "test_migrator_verbosity_off",
- "test_migrator_with_duplicate_names",
- "test_migrator_with_duplicates",
- "test_migrator_with_missing_version_numbers",
- "test_native_decimal_insert_manual_vs_automatic",
- "test_native_types",
- "test_only_loads_pending_migrations",
- "test_proper_table_name",
- "test_relative_migrations",
- "test_remove_column_with_index",
- "test_remove_column_with_multi_column_index",
- "test_rename_column",
- "test_rename_column_preserves_default_value_not_null",
- "test_rename_column_using_symbol_arguments",
- "test_rename_column_with_an_index",
- "test_rename_column_with_sql_reserved_word",
- "test_rename_nonexistent_column",
- "test_rename_table",
- "test_rename_table_for_sqlite_should_work_with_reserved_words",
- "test_rename_table_with_an_index",
- "test_schema_migrations_table_name",
- "test_target_version_zero_should_run_only_once"]
+ LargeArray = [
+ "test_create_table_with_force_true_does_not_drop_nonexisting_table",
+ "test_add_table",
+ "assert_difference",
+ "assert_operator",
+ "instance_variables",
+ "class",
+ "instance_variable_get",
+ "__class__",
+ "expects",
+ "assert_no_difference",
+ "name",
+ "assert_blank",
+ "assert_not_same",
+ "is_a?",
+ "test_add_table_with_decimals",
+ "test_create_table_with_timestamps_should_create_datetime_columns",
+ "assert_present",
+ "assert_no_match",
+ "__instance_of__",
+ "assert_deprecated",
+ "assert",
+ "assert_throws",
+ "kind_of?",
+ "try",
+ "__instance_variable_get__",
+ "object_id",
+ "timeout",
+ "instance_variable_set",
+ "assert_nothing_thrown",
+ "__instance_variable_set__",
+ "copy_object",
+ "test_create_table_with_timestamps_should_create_datetime_columns_with_options",
+ "assert_not_deprecated",
+ "assert_in_delta",
+ "id",
+ "copy_metaclass",
+ "test_create_table_without_a_block",
+ "dup",
+ "assert_not_nil",
+ "send",
+ "__instance_variables__",
+ "to_sql",
+ "mock",
+ "assert_send",
+ "instance_variable_defined?",
+ "clone",
+ "require",
+ "test_migrator",
+ "__instance_variable_defined_eh__",
+ "frozen?",
+ "test_add_column_not_null_with_default",
+ "freeze",
+ "test_migrator_one_up",
+ "test_migrator_one_down",
+ "singleton_methods",
+ "method_exists?",
+ "create_fixtures",
+ "test_migrator_one_up_one_down",
+ "test_native_decimal_insert_manual_vs_automatic",
+ "instance_exec",
+ "__is_a__",
+ "test_migrator_double_up",
+ "stub",
+ "private_methods",
+ "stubs",
+ "test_migrator_double_down",
+ "fixture_path",
+ "private_singleton_methods",
+ "stub_everything",
+ "test_migrator_one_up_with_exception_and_rollback",
+ "sequence",
+ "protected_methods",
+ "enum_for",
+ "test_finds_migrations",
+ "run_before_mocha",
+ "states",
+ "protected_singleton_methods",
+ "to_json",
+ "instance_values",
+ "==",
+ "mocha_setup",
+ "public_methods",
+ "test_finds_pending_migrations",
+ "mocha_verify",
+ "assert_kind_of",
+ "===",
+ "=~",
+ "test_relative_migrations",
+ "mocha_teardown",
+ "gem",
+ "mocha",
+ "test_only_loads_pending_migrations",
+ "test_add_column_with_precision_and_scale",
+ "require_or_load",
+ "eql?",
+ "require_dependency",
+ "test_native_types",
+ "test_target_version_zero_should_run_only_once",
+ "extend",
+ "to_matcher",
+ "unloadable",
+ "require_association",
+ "hash",
+ "__id__",
+ "load_dependency",
+ "equals",
+ "test_migrator_db_has_no_schema_migrations_table",
+ "test_migrator_verbosity",
+ "kind_of",
+ "to_yaml",
+ "to_bool",
+ "test_migrator_verbosity_off",
+ "taint",
+ "test_migrator_going_down_due_to_version_target",
+ "tainted?",
+ "mocha_inspect",
+ "test_migrator_rollback",
+ "vim",
+ "untaint",
+ "taguri=",
+ "test_migrator_forward",
+ "test_schema_migrations_table_name",
+ "test_proper_table_name",
+ "all_of",
+ "test_add_drop_table_with_prefix_and_suffix",
+ "_setup_callbacks",
+ "setup",
+ "Not",
+ "test_create_table_with_binary_column",
+ "assert_not_equal",
+ "enable_warnings",
+ "acts_like?",
+ "Rational",
+ "_removed_setup_callbacks",
+ "Table",
+ "bind",
+ "any_of",
+ "__method__",
+ "test_migrator_with_duplicates",
+ "_teardown_callbacks",
+ "method",
+ "test_migrator_with_duplicate_names",
+ "_removed_teardown_callbacks",
+ "any_parameters",
+ "test_migrator_with_missing_version_numbers",
+ "test_add_remove_single_field_using_string_arguments",
+ "test_create_table_with_custom_sequence_name",
+ "test_add_remove_single_field_using_symbol_arguments",
+ "_one_time_conditions_valid_14?",
+ "_one_time_conditions_valid_16?",
+ "run_callbacks",
+ "anything",
+ "silence_warnings",
+ "instance_variable_names",
+ "_fixture_path",
+ "copy_instance_variables_from",
+ "fixture_path?",
+ "has_entry",
+ "__marshal__",
+ "_fixture_table_names",
+ "__kind_of__",
+ "fixture_table_names?",
+ "test_add_rename",
+ "assert_equal",
+ "_fixture_class_names",
+ "fixture_class_names?",
+ "has_entries",
+ "_use_transactional_fixtures",
+ "people",
+ "test_rename_column_using_symbol_arguments",
+ "use_transactional_fixtures?",
+ "instance_eval",
+ "blank?",
+ "with_warnings",
+ "__nil__",
+ "load",
+ "metaclass",
+ "_use_instantiated_fixtures",
+ "has_key",
+ "class_eval",
+ "present?",
+ "test_rename_column",
+ "teardown",
+ "use_instantiated_fixtures?",
+ "method_name",
+ "silence_stderr",
+ "presence",
+ "test_rename_column_preserves_default_value_not_null",
+ "silence_stream",
+ "_pre_loaded_fixtures",
+ "__metaclass__",
+ "__fixnum__",
+ "pre_loaded_fixtures?",
+ "has_value",
+ "suppress",
+ "to_yaml_properties",
+ "test_rename_nonexistent_column",
+ "test_add_index",
+ "includes",
+ "find_correlate_in",
+ "equality_predicate_sql",
+ "assert_nothing_raised",
+ "let",
+ "not_predicate_sql",
+ "test_rename_column_with_sql_reserved_word",
+ "singleton_class",
+ "test_rename_column_with_an_index",
+ "display",
+ "taguri",
+ "to_yaml_style",
+ "test_remove_column_with_index",
+ "size",
+ "current_adapter?",
+ "test_remove_column_with_multi_column_index",
+ "respond_to?",
+ "test_change_type_of_not_null_column",
+ "is_a",
+ "to_a",
+ "test_rename_table_for_sqlite_should_work_with_reserved_words",
+ "require_library_or_gem",
+ "setup_fixtures",
+ "equal?",
+ "teardown_fixtures",
+ "nil?",
+ "fixture_table_names",
+ "fixture_class_names",
+ "test_create_table_without_id",
+ "use_transactional_fixtures",
+ "test_add_column_with_primary_key_attribute",
+ "repair_validations",
+ "use_instantiated_fixtures",
+ "instance_of?",
+ "test_create_table_adds_id",
+ "test_rename_table",
+ "pre_loaded_fixtures",
+ "to_enum",
+ "test_create_table_with_not_null_column",
+ "instance_of",
+ "test_change_column_nullability",
+ "optionally",
+ "test_rename_table_with_an_index",
+ "run",
+ "test_change_column",
+ "default_test",
+ "assert_raise",
+ "test_create_table_with_defaults",
+ "assert_nil",
+ "flunk",
+ "regexp_matches",
+ "duplicable?",
+ "reset_mocha",
+ "stubba_method",
+ "filter_backtrace",
+ "test_create_table_with_limits",
+ "responds_with",
+ "stubba_object",
+ "test_change_column_with_nil_default",
+ "assert_block",
+ "__show__",
+ "assert_date_from_db",
+ "__respond_to_eh__",
+ "run_in_transaction?",
+ "inspect",
+ "assert_sql",
+ "test_change_column_with_new_default",
+ "yaml_equivalent",
+ "build_message",
+ "to_s",
+ "test_change_column_default",
+ "assert_queries",
+ "pending",
+ "as_json",
+ "assert_no_queries",
+ "test_change_column_quotes_column_names",
+ "assert_match",
+ "test_keeping_default_and_notnull_constraint_on_change",
+ "methods",
+ "connection_allow_concurrency_setup",
+ "connection_allow_concurrency_teardown",
+ "test_create_table_with_primary_key_prefix_as_table_name_with_underscore",
+ "__send__",
+ "make_connection",
+ "assert_raises",
+ "tap",
+ "with_kcode",
+ "assert_instance_of",
+ "test_create_table_with_primary_key_prefix_as_table_name",
+ "assert_respond_to",
+ "test_change_column_default_to_null",
+ "assert_same",
+ "__extend__",
+ ]
+
+ LargeTestArraySorted = [
+ "test_add_column_not_null_with_default",
+ "test_add_column_with_precision_and_scale",
+ "test_add_column_with_primary_key_attribute",
+ "test_add_drop_table_with_prefix_and_suffix",
+ "test_add_index",
+ "test_add_remove_single_field_using_string_arguments",
+ "test_add_remove_single_field_using_symbol_arguments",
+ "test_add_rename",
+ "test_add_table",
+ "test_add_table_with_decimals",
+ "test_change_column",
+ "test_change_column_default",
+ "test_change_column_default_to_null",
+ "test_change_column_nullability",
+ "test_change_column_quotes_column_names",
+ "test_change_column_with_new_default",
+ "test_change_column_with_nil_default",
+ "test_change_type_of_not_null_column",
+ "test_create_table_adds_id",
+ "test_create_table_with_binary_column",
+ "test_create_table_with_custom_sequence_name",
+ "test_create_table_with_defaults",
+ "test_create_table_with_force_true_does_not_drop_nonexisting_table",
+ "test_create_table_with_limits",
+ "test_create_table_with_not_null_column",
+ "test_create_table_with_primary_key_prefix_as_table_name",
+ "test_create_table_with_primary_key_prefix_as_table_name_with_underscore",
+ "test_create_table_with_timestamps_should_create_datetime_columns",
+ "test_create_table_with_timestamps_should_create_datetime_columns_with_options",
+ "test_create_table_without_a_block",
+ "test_create_table_without_id",
+ "test_finds_migrations",
+ "test_finds_pending_migrations",
+ "test_keeping_default_and_notnull_constraint_on_change",
+ "test_migrator",
+ "test_migrator_db_has_no_schema_migrations_table",
+ "test_migrator_double_down",
+ "test_migrator_double_up",
+ "test_migrator_forward",
+ "test_migrator_going_down_due_to_version_target",
+ "test_migrator_one_down",
+ "test_migrator_one_up",
+ "test_migrator_one_up_one_down",
+ "test_migrator_one_up_with_exception_and_rollback",
+ "test_migrator_rollback",
+ "test_migrator_verbosity",
+ "test_migrator_verbosity_off",
+ "test_migrator_with_duplicate_names",
+ "test_migrator_with_duplicates",
+ "test_migrator_with_missing_version_numbers",
+ "test_native_decimal_insert_manual_vs_automatic",
+ "test_native_types",
+ "test_only_loads_pending_migrations",
+ "test_proper_table_name",
+ "test_relative_migrations",
+ "test_remove_column_with_index",
+ "test_remove_column_with_multi_column_index",
+ "test_rename_column",
+ "test_rename_column_preserves_default_value_not_null",
+ "test_rename_column_using_symbol_arguments",
+ "test_rename_column_with_an_index",
+ "test_rename_column_with_sql_reserved_word",
+ "test_rename_nonexistent_column",
+ "test_rename_table",
+ "test_rename_table_for_sqlite_should_work_with_reserved_words",
+ "test_rename_table_with_an_index",
+ "test_schema_migrations_table_name",
+ "test_target_version_zero_should_run_only_once",
+ ]
class PrivateToAry
private
diff --git a/spec/ruby/core/array/pack/buffer_spec.rb b/spec/ruby/core/array/pack/buffer_spec.rb
index f1206efb3e..b77b2d1efa 100644
--- a/spec/ruby/core/array/pack/buffer_spec.rb
+++ b/spec/ruby/core/array/pack/buffer_spec.rb
@@ -28,6 +28,16 @@ describe "Array#pack with :buffer option" do
TypeError, "buffer must be String, not Array")
end
+ it "raise FrozenError if buffer is frozen" do
+ -> { [65].pack("c", buffer: "frozen-string".freeze) }.should raise_error(FrozenError)
+ end
+
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ [65, 66, 67].pack("ccc", buffer: buffer)
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
+
context "offset (@) is specified" do
it 'keeps buffer content if it is longer than offset' do
n = [ 65, 66, 67 ]
diff --git a/spec/ruby/core/binding/dup_spec.rb b/spec/ruby/core/binding/dup_spec.rb
index 55fac6e333..4eff66bd9a 100644
--- a/spec/ruby/core/binding/dup_spec.rb
+++ b/spec/ruby/core/binding/dup_spec.rb
@@ -10,4 +10,21 @@ describe "Binding#dup" do
bind.frozen?.should == true
bind.dup.frozen?.should == false
end
+
+ it "retains original binding variables but the list is distinct" do
+ bind1 = binding
+ eval "a = 1", bind1
+
+ bind2 = bind1.dup
+ eval("a = 2", bind2)
+ eval("a", bind1).should == 2
+ eval("a", bind2).should == 2
+
+ eval("b = 2", bind2)
+ -> { eval("b", bind1) }.should raise_error(NameError)
+ eval("b", bind2).should == 2
+
+ bind1.local_variables.sort.should == [:a, :bind1, :bind2]
+ bind2.local_variables.sort.should == [:a, :b, :bind1, :bind2]
+ end
end
diff --git a/spec/ruby/core/binding/irb_spec.rb b/spec/ruby/core/binding/irb_spec.rb
index 25521f0dd7..2607c7ef33 100644
--- a/spec/ruby/core/binding/irb_spec.rb
+++ b/spec/ruby/core/binding/irb_spec.rb
@@ -10,7 +10,7 @@ describe "Binding#irb" do
IO.popen([envs, *ruby_exe, irb_fixture, chdir: dir], "r+") do |pipe|
pipe.puts "a ** 2"
pipe.puts "exit"
- pipe.readlines.map(&:chomp)
+ pipe.readlines.map(&:chomp).reject(&:empty?)
end
end
diff --git a/spec/ruby/core/enumerator/next_values_spec.rb b/spec/ruby/core/enumerator/next_values_spec.rb
index 201b5d323f..2202700c58 100644
--- a/spec/ruby/core/enumerator/next_values_spec.rb
+++ b/spec/ruby/core/enumerator/next_values_spec.rb
@@ -11,6 +11,7 @@ describe "Enumerator#next_values" do
yield :e1, :e2, :e3
yield nil
yield
+ yield [:f1, :f2]
end
@e = o.to_enum
@@ -48,8 +49,13 @@ describe "Enumerator#next_values" do
@e.next_values.should == []
end
- it "raises StopIteration if called on a finished enumerator" do
+ it "returns an array of array if yield is called with an array" do
7.times { @e.next }
+ @e.next_values.should == [[:f1, :f2]]
+ end
+
+ it "raises StopIteration if called on a finished enumerator" do
+ 8.times { @e.next }
-> { @e.next_values }.should raise_error(StopIteration)
end
end
diff --git a/spec/ruby/core/enumerator/peek_values_spec.rb b/spec/ruby/core/enumerator/peek_values_spec.rb
index 7865546515..8b84fc8afc 100644
--- a/spec/ruby/core/enumerator/peek_values_spec.rb
+++ b/spec/ruby/core/enumerator/peek_values_spec.rb
@@ -11,6 +11,7 @@ describe "Enumerator#peek_values" do
yield :e1, :e2, :e3
yield nil
yield
+ yield [:f1, :f2]
end
@e = o.to_enum
@@ -50,8 +51,13 @@ describe "Enumerator#peek_values" do
@e.peek_values.should == []
end
- it "raises StopIteration if called on a finished enumerator" do
+ it "returns an array of array if yield is called with an array" do
7.times { @e.next }
+ @e.peek_values.should == [[:f1, :f2]]
+ end
+
+ it "raises StopIteration if called on a finished enumerator" do
+ 8.times { @e.next }
-> { @e.peek_values }.should raise_error(StopIteration)
end
end
diff --git a/spec/ruby/core/io/pread_spec.rb b/spec/ruby/core/io/pread_spec.rb
index 28afc80e5c..6d93b432c2 100644
--- a/spec/ruby/core/io/pread_spec.rb
+++ b/spec/ruby/core/io/pread_spec.rb
@@ -22,7 +22,7 @@ guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
it "accepts a length, an offset, and an output buffer" do
buffer = +"foo"
- @file.pread(3, 4, buffer)
+ @file.pread(3, 4, buffer).should.equal?(buffer)
buffer.should == "567"
end
@@ -38,6 +38,13 @@ guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
buffer.should == "12345"
end
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @file.pread(10, 0, buffer)
+
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
+
it "does not advance the file pointer" do
@file.pread(4, 0).should == "1234"
@file.read.should == "1234567890"
diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb
index eb3652e692..8741d9f017 100644
--- a/spec/ruby/core/io/read_spec.rb
+++ b/spec/ruby/core/io/read_spec.rb
@@ -376,6 +376,21 @@ describe "IO#read" do
buf.should == @contents[0..4]
end
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @io.read(10, buffer)
+
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
+
+ # https://bugs.ruby-lang.org/issues/20416
+ it "does not preserve the encoding of the given buffer when max length is not provided" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @io.read(nil, buffer)
+
+ buffer.encoding.should_not == Encoding::ISO_8859_1
+ end
+
it "returns the given buffer" do
buf = +""
diff --git a/spec/ruby/core/io/readpartial_spec.rb b/spec/ruby/core/io/readpartial_spec.rb
index 0060beb545..0852f20b2d 100644
--- a/spec/ruby/core/io/readpartial_spec.rb
+++ b/spec/ruby/core/io/readpartial_spec.rb
@@ -62,7 +62,7 @@ describe "IO#readpartial" do
buffer = +"existing content"
@wr.write("hello world")
@wr.close
- @rd.readpartial(11, buffer)
+ @rd.readpartial(11, buffer).should.equal?(buffer)
buffer.should == "hello world"
end
@@ -106,6 +106,7 @@ describe "IO#readpartial" do
@wr.write("abc")
@wr.close
@rd.readpartial(10, buffer)
+
buffer.encoding.should == Encoding::ISO_8859_1
end
end
diff --git a/spec/ruby/core/io/sysread_spec.rb b/spec/ruby/core/io/sysread_spec.rb
index 003bb9eb94..8851214283 100644
--- a/spec/ruby/core/io/sysread_spec.rb
+++ b/spec/ruby/core/io/sysread_spec.rb
@@ -97,7 +97,7 @@ describe "IO#sysread on a file" do
it "discards the existing buffer content upon successful read" do
buffer = +"existing content"
- @file.sysread(11, buffer)
+ @file.sysread(11, buffer).should.equal?(buffer)
buffer.should == "01234567890"
end
@@ -107,6 +107,13 @@ describe "IO#sysread on a file" do
-> { @file.sysread(1, buffer) }.should raise_error(EOFError)
buffer.should be_empty
end
+
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ string = @file.sysread(10, buffer)
+
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
end
describe "IO#sysread" do
diff --git a/spec/ruby/core/module/include_spec.rb b/spec/ruby/core/module/include_spec.rb
index c073bc31ca..78f6b41031 100644
--- a/spec/ruby/core/module/include_spec.rb
+++ b/spec/ruby/core/module/include_spec.rb
@@ -47,6 +47,34 @@ describe "Module#include" do
-> { ModuleSpecs::SubclassSpec.include(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
end
+ ruby_version_is ""..."3.2" do
+ it "raises ArgumentError when the argument is a refinement" do
+ refinement = nil
+
+ Module.new do
+ refine String do
+ refinement = self
+ end
+ end
+
+ -> { ModuleSpecs::Basic.include(refinement) }.should raise_error(ArgumentError, "refinement module is not allowed")
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "raises a TypeError when the argument is a refinement" do
+ refinement = nil
+
+ Module.new do
+ refine String do
+ refinement = self
+ end
+ end
+
+ -> { ModuleSpecs::Basic.include(refinement) }.should raise_error(TypeError, "Cannot include refinement")
+ end
+ end
+
it "imports constants to modules and classes" do
ModuleSpecs::A.constants.should include(:CONSTANT_A)
ModuleSpecs::B.constants.should include(:CONSTANT_A, :CONSTANT_B)
diff --git a/spec/ruby/core/module/prepend_spec.rb b/spec/ruby/core/module/prepend_spec.rb
index c90fa9700e..b40d12f0de 100644
--- a/spec/ruby/core/module/prepend_spec.rb
+++ b/spec/ruby/core/module/prepend_spec.rb
@@ -75,6 +75,26 @@ describe "Module#prepend" do
foo.call.should == 'm'
end
+ it "updates the optimized method when a prepended module is updated" do
+ out = ruby_exe(<<~RUBY)
+ module M; end
+ class Integer
+ prepend M
+ end
+ l = -> { 1 + 2 }
+ p l.call
+ M.module_eval do
+ def +(o)
+ $called = true
+ super(o)
+ end
+ end
+ p l.call
+ p $called
+ RUBY
+ out.should == "3\n3\ntrue\n"
+ end
+
it "updates the method when there is a base included method and the prepended module overrides it" do
base_module = Module.new do
def foo
@@ -415,6 +435,34 @@ describe "Module#prepend" do
-> { ModuleSpecs::SubclassSpec.prepend(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
end
+ ruby_version_is ""..."3.2" do
+ it "raises ArgumentError when the argument is a refinement" do
+ refinement = nil
+
+ Module.new do
+ refine String do
+ refinement = self
+ end
+ end
+
+ -> { ModuleSpecs::Basic.prepend(refinement) }.should raise_error(ArgumentError, "refinement module is not allowed")
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "raises a TypeError when the argument is a refinement" do
+ refinement = nil
+
+ Module.new do
+ refine String do
+ refinement = self
+ end
+ end
+
+ -> { ModuleSpecs::Basic.prepend(refinement) }.should raise_error(TypeError, "Cannot prepend refinement")
+ end
+ end
+
it "imports constants" do
m1 = Module.new
m1::MY_CONSTANT = 1
diff --git a/spec/ruby/core/string/chilled_string_spec.rb b/spec/ruby/core/string/chilled_string_spec.rb
index 8de4fc421b..9f81b1af6d 100644
--- a/spec/ruby/core/string/chilled_string_spec.rb
+++ b/spec/ruby/core/string/chilled_string_spec.rb
@@ -3,8 +3,8 @@ require_relative '../../spec_helper'
describe "chilled String" do
guard -> { ruby_version_is "3.4" and !"test".equal?("test") } do
describe "#frozen?" do
- it "returns true" do
- "chilled".frozen?.should == true
+ it "returns false" do
+ "chilled".frozen?.should == false
end
end
@@ -45,7 +45,7 @@ describe "chilled String" do
input.should == "chilled-mutated"
end
- it "emits a warning on singleton_class creaation" do
+ it "emits a warning on singleton_class creation" do
-> {
"chilled".singleton_class
}.should complain(/literal string will be frozen in the future/)
@@ -57,12 +57,14 @@ describe "chilled String" do
}.should complain(/literal string will be frozen in the future/)
end
- it "raises FrozenError after the string was explictly frozen" do
+ it "raises FrozenError after the string was explicitly frozen" do
input = "chilled"
input.freeze
-> {
+ -> {
input << "mutated"
- }.should raise_error(FrozenError)
+ }.should raise_error(FrozenError)
+ }.should_not complain(/literal string will be frozen in the future/)
end
end
end
diff --git a/spec/ruby/core/string/index_spec.rb b/spec/ruby/core/string/index_spec.rb
index be79708045..835263a2cd 100644
--- a/spec/ruby/core/string/index_spec.rb
+++ b/spec/ruby/core/string/index_spec.rb
@@ -231,6 +231,17 @@ describe "String#index with Regexp" do
$~.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
+ end
+
it "starts the search at the given offset" do
"blablabla".index(/.{0}/, 5).should == 5
"blablabla".index(/.{1}/, 5).should == 5
diff --git a/spec/ruby/core/string/modulo_spec.rb b/spec/ruby/core/string/modulo_spec.rb
index bf96a82874..9045afa263 100644
--- a/spec/ruby/core/string/modulo_spec.rb
+++ b/spec/ruby/core/string/modulo_spec.rb
@@ -55,33 +55,48 @@ describe "String#%" do
-> { ("foo%" % [])}.should raise_error(ArgumentError)
end
- it "formats single % character before a newline as literal %" do
- ("%\n" % []).should == "%\n"
- ("foo%\n" % []).should == "foo%\n"
- ("%\n.3f" % 1.2).should == "%\n.3f"
- end
+ ruby_version_is ""..."3.4" do
+ it "formats single % character before a newline as literal %" do
+ ("%\n" % []).should == "%\n"
+ ("foo%\n" % []).should == "foo%\n"
+ ("%\n.3f" % 1.2).should == "%\n.3f"
+ end
- it "formats single % character before a NUL as literal %" do
- ("%\0" % []).should == "%\0"
- ("foo%\0" % []).should == "foo%\0"
- ("%\0.3f" % 1.2).should == "%\0.3f"
- end
+ it "formats single % character before a NUL as literal %" do
+ ("%\0" % []).should == "%\0"
+ ("foo%\0" % []).should == "foo%\0"
+ ("%\0.3f" % 1.2).should == "%\0.3f"
+ end
- it "raises an error if single % appears anywhere else" do
- -> { (" % " % []) }.should raise_error(ArgumentError)
- -> { ("foo%quux" % []) }.should raise_error(ArgumentError)
- end
+ it "raises an error if single % appears anywhere else" do
+ -> { (" % " % []) }.should raise_error(ArgumentError)
+ -> { ("foo%quux" % []) }.should raise_error(ArgumentError)
+ end
- it "raises an error if NULL or \\n appear anywhere else in the format string" do
- begin
- old_debug, $DEBUG = $DEBUG, false
+ it "raises an error if NULL or \\n appear anywhere else in the format string" do
+ begin
+ old_debug, $DEBUG = $DEBUG, false
+ -> { "%.\n3f" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.3\nf" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.\03f" % 1.2 }.should raise_error(ArgumentError)
+ -> { "%.3\0f" % 1.2 }.should raise_error(ArgumentError)
+ ensure
+ $DEBUG = old_debug
+ end
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "raises an ArgumentError if % is not followed by a conversion specifier" do
+ -> { "%" % [] }.should raise_error(ArgumentError)
+ -> { "%\n" % [] }.should raise_error(ArgumentError)
+ -> { "%\0" % [] }.should raise_error(ArgumentError)
+ -> { " % " % [] }.should raise_error(ArgumentError)
-> { "%.\n3f" % 1.2 }.should raise_error(ArgumentError)
-> { "%.3\nf" % 1.2 }.should raise_error(ArgumentError)
-> { "%.\03f" % 1.2 }.should raise_error(ArgumentError)
-> { "%.3\0f" % 1.2 }.should raise_error(ArgumentError)
- ensure
- $DEBUG = old_debug
end
end
@@ -125,8 +140,16 @@ describe "String#%" do
end
end
- it "replaces trailing absolute argument specifier without type with percent sign" do
- ("hello %1$" % "foo").should == "hello %"
+ ruby_version_is ""..."3.4" do
+ it "replaces trailing absolute argument specifier without type with percent sign" do
+ ("hello %1$" % "foo").should == "hello %"
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "raises an ArgumentError if absolute argument specifier is followed by a conversion specifier" do
+ -> { "hello %1$" % "foo" }.should raise_error(ArgumentError)
+ end
end
it "raises an ArgumentError when given invalid argument specifiers" do
diff --git a/spec/ruby/core/tracepoint/inspect_spec.rb b/spec/ruby/core/tracepoint/inspect_spec.rb
index cc6bf0f842..0c94a94d5c 100644
--- a/spec/ruby/core/tracepoint/inspect_spec.rb
+++ b/spec/ruby/core/tracepoint/inspect_spec.rb
@@ -24,6 +24,8 @@ describe 'TracePoint#inspect' do
line = nil
TracePoint.new(:line) { |tp|
next unless TracePointSpec.target_thread?
+ next unless tp.path == __FILE__
+
inspect ||= tp.inspect
}.enable do
line = __LINE__
@@ -37,6 +39,8 @@ describe 'TracePoint#inspect' do
line = nil
TracePoint.new(:call) { |tp|
next unless TracePointSpec.target_thread?
+ next unless tp.path == __FILE__
+
inspect ||= tp.inspect
}.enable do
line = __LINE__ + 1
@@ -52,6 +56,8 @@ describe 'TracePoint#inspect' do
line = nil
TracePoint.new(:return) { |tp|
next unless TracePointSpec.target_thread?
+ next unless tp.path == __FILE__
+
inspect ||= tp.inspect
}.enable do
line = __LINE__ + 4
@@ -69,6 +75,8 @@ describe 'TracePoint#inspect' do
inspect = nil
tracepoint = TracePoint.new(:c_call) { |tp|
next unless TracePointSpec.target_thread?
+ next unless tp.path == __FILE__
+
inspect ||= tp.inspect
}
line = __LINE__ + 2
@@ -84,6 +92,8 @@ describe 'TracePoint#inspect' do
line = nil
TracePoint.new(:class) { |tp|
next unless TracePointSpec.target_thread?
+ next unless tp.path == __FILE__
+
inspect ||= tp.inspect
}.enable do
line = __LINE__ + 1
@@ -100,6 +110,7 @@ describe 'TracePoint#inspect' do
thread_inspection = nil
TracePoint.new(:thread_begin) { |tp|
next unless Thread.current == thread
+
inspect ||= tp.inspect
}.enable(target_thread: nil) do
thread = Thread.new {}
@@ -116,6 +127,7 @@ describe 'TracePoint#inspect' do
thread_inspection = nil
TracePoint.new(:thread_end) { |tp|
next unless Thread.current == thread
+
inspect ||= tp.inspect
}.enable(target_thread: nil) do
thread = Thread.new {}
diff --git a/spec/ruby/core/warning/element_reference_spec.rb b/spec/ruby/core/warning/element_reference_spec.rb
index 8cb4018c20..c0ed37ef13 100644
--- a/spec/ruby/core/warning/element_reference_spec.rb
+++ b/spec/ruby/core/warning/element_reference_spec.rb
@@ -2,6 +2,10 @@ require_relative '../../spec_helper'
describe "Warning.[]" do
it "returns default values for categories :deprecated and :experimental" do
+ # If any warning options were set on the Ruby that will be executed, then
+ # it's possible this test will fail. In this case we will skip this test.
+ skip if ruby_exe.any? { |opt| opt.start_with?("-W") }
+
ruby_exe('p [Warning[:deprecated], Warning[:experimental]]').chomp.should == "[false, true]"
ruby_exe('p [Warning[:deprecated], Warning[:experimental]]', options: "-w").chomp.should == "[true, true]"
end
diff --git a/spec/ruby/core/warning/performance_warning_spec.rb b/spec/ruby/core/warning/performance_warning_spec.rb
new file mode 100644
index 0000000000..ab0badcd3d
--- /dev/null
+++ b/spec/ruby/core/warning/performance_warning_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../spec_helper'
+
+
+describe "Performance warnings" do
+ guard -> { ruby_version_is("3.4") || RUBY_ENGINE == "truffleruby" } do
+ # Optimising Integer, Float or Symbol methods is kind of implementation detail
+ # but multiple implementations do so. So it seems reasonable to have a test case
+ # for at least one such common method.
+ # See https://bugs.ruby-lang.org/issues/20429
+ context "when redefined optimised methods" do
+ it "emits performance warning for redefining Integer#+" do
+ code = <<~CODE
+ Warning[:performance] = true
+
+ class Integer
+ ORIG_METHOD = instance_method(:+)
+
+ def +(...)
+ ORIG_METHOD.bind(self).call(...)
+ end
+ end
+ CODE
+
+ ruby_exe(code, args: "2>&1").should.include?("warning: Redefining 'Integer#+' disables interpreter and JIT optimizations")
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/warning/warn_spec.rb b/spec/ruby/core/warning/warn_spec.rb
index 8f96fe9287..1c21fe29e0 100644
--- a/spec/ruby/core/warning/warn_spec.rb
+++ b/spec/ruby/core/warning/warn_spec.rb
@@ -121,6 +121,30 @@ describe "Warning.warn" do
end
end
+ ruby_bug '#19530', ''...'3.4' do
+ it "isn't called by Kernel.warn when category is :deprecated but Warning[:deprecated] is false" do
+ warn_deprecated = Warning[:deprecated]
+ begin
+ Warning[:deprecated] = false
+ Warning.should_not_receive(:warn)
+ Kernel.warn("foo", category: :deprecated)
+ ensure
+ Warning[:deprecated] = warn_deprecated
+ end
+ end
+
+ it "isn't called by Kernel.warn when category is :experimental but Warning[:experimental] is false" do
+ warn_experimental = Warning[:experimental]
+ begin
+ Warning[:experimental] = false
+ Warning.should_not_receive(:warn)
+ Kernel.warn("foo", category: :experimental)
+ ensure
+ Warning[:experimental] = warn_experimental
+ end
+ end
+ end
+
it "prints the message when VERBOSE is false" do
-> { Warning.warn("foo") }.should complain("foo")
end
diff --git a/spec/ruby/library/io-wait/fixtures/classes.rb b/spec/ruby/fixtures/io.rb
index 837c7edd06..87ebbbb2bd 100644
--- a/spec/ruby/library/io-wait/fixtures/classes.rb
+++ b/spec/ruby/fixtures/io.rb
@@ -1,12 +1,12 @@
-module IOWaitSpec
+module IOSpec
def self.exhaust_write_buffer(io)
written = 0
buf = " " * 4096
- begin
+ while true
written += io.write_nonblock(buf)
- rescue Errno::EAGAIN, Errno::EWOULDBLOCK
- return written
- end while true
+ end
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK
+ written
end
end
diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb
index 578d9cb3b0..cf0931b688 100644
--- a/spec/ruby/language/block_spec.rb
+++ b/spec/ruby/language/block_spec.rb
@@ -960,24 +960,27 @@ describe "Post-args" do
end
describe "with a circular argument reference" do
- it "raises a SyntaxError if using an existing local with the same name as the argument" do
- a = 1
- -> {
- @proc = eval "proc { |a=a| a }"
- }.should raise_error(SyntaxError)
+ ruby_version_is ""..."3.4" do
+ it "raises a SyntaxError if using the argument in its default value" do
+ a = 1
+ -> {
+ eval "proc { |a=a| a }"
+ }.should raise_error(SyntaxError)
+ end
end
- it "raises a SyntaxError if there is an existing method with the same name as the argument" do
- def a; 1; end
- -> {
- @proc = eval "proc { |a=a| a }"
- }.should raise_error(SyntaxError)
+ ruby_version_is "3.4" do
+ it "is nil if using the argument in its default value" do
+ -> {
+ eval "proc { |a=a| a }.call"
+ }.call.should == nil
+ end
end
+ end
- it "calls an existing method with the same name as the argument if explicitly using ()" do
- def a; 1; end
- proc { |a=a()| a }.call.should == 1
- end
+ it "calls an existing method with the same name as the argument if explicitly using ()" do
+ def a; 1; end
+ proc { |a=a()| a }.call.should == 1
end
end
diff --git a/spec/ruby/language/break_spec.rb b/spec/ruby/language/break_spec.rb
index e725e77e80..7e5b6fb328 100644
--- a/spec/ruby/language/break_spec.rb
+++ b/spec/ruby/language/break_spec.rb
@@ -252,6 +252,25 @@ describe "Break inside a while loop" do
end
end
+describe "The break statement in a method" do
+ it "is invalid and raises a SyntaxError" do
+ -> {
+ eval("def m; break; end")
+ }.should raise_error(SyntaxError)
+ end
+end
+
+describe "The break statement in a module literal" do
+ it "is invalid and raises a SyntaxError" do
+ code = <<~RUBY
+ module BreakSpecs:ModuleWithBreak
+ break
+ end
+ RUBY
+
+ -> { eval(code) }.should raise_error(SyntaxError)
+ end
+end
# TODO: Rewrite all the specs from here to the end of the file in the style
# above.
diff --git a/spec/ruby/language/case_spec.rb b/spec/ruby/language/case_spec.rb
index 3262f09dd5..464d06e46a 100644
--- a/spec/ruby/language/case_spec.rb
+++ b/spec/ruby/language/case_spec.rb
@@ -416,17 +416,34 @@ describe "The 'case'-construct" do
self.test(true).should == true
end
- it "warns if there are identical when clauses" do
- -> {
- eval <<~RUBY
- case 1
- when 2
- :foo
- when 2
- :bar
- end
- RUBY
- }.should complain(/warning: duplicated .when' clause with line \d+ is ignored/, verbose: true)
+ ruby_version_is ""..."3.4" do
+ it "warns if there are identical when clauses" do
+ -> {
+ eval <<~RUBY
+ case 1
+ when 2
+ :foo
+ when 2
+ :bar
+ end
+ RUBY
+ }.should complain(/warning: (duplicated .when' clause with line \d+ is ignored|'when' clause on line \d+ duplicates 'when' clause on line \d+ and is ignored)/, verbose: true)
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "warns if there are identical when clauses" do
+ -> {
+ eval <<~RUBY
+ case 1
+ when 2
+ :foo
+ when 2
+ :bar
+ end
+ RUBY
+ }.should complain(/warning: 'when' clause on line \d+ duplicates 'when' clause on line \d+ and is ignored/, verbose: true)
+ end
end
end
diff --git a/spec/ruby/language/def_spec.rb b/spec/ruby/language/def_spec.rb
index 42e721c68c..ce8077eb69 100644
--- a/spec/ruby/language/def_spec.rb
+++ b/spec/ruby/language/def_spec.rb
@@ -197,15 +197,25 @@ describe "An instance method with a default argument" do
foo(2,3,3).should == [2,3,[3]]
end
- it "raises a SyntaxError when there is an existing method with the same name as the local variable" do
- def bar
- 1
+ ruby_version_is ""..."3.4" do
+ it "raises a SyntaxError if using the argument in its default value" do
+ -> {
+ eval "def foo(bar = bar)
+ bar
+ end"
+ }.should raise_error(SyntaxError)
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "is nil if using the argument in its default value" do
+ -> {
+ eval "def foo(bar = bar)
+ bar
+ end
+ foo"
+ }.call.should == nil
end
- -> {
- eval "def foo(bar = bar)
- bar
- end"
- }.should raise_error(SyntaxError)
end
it "calls a method with the same name as the local when explicitly using ()" do
diff --git a/spec/ruby/language/execution_spec.rb b/spec/ruby/language/execution_spec.rb
index ef1de38899..51bcde62e8 100644
--- a/spec/ruby/language/execution_spec.rb
+++ b/spec/ruby/language/execution_spec.rb
@@ -38,7 +38,7 @@ describe "``" do
2.times do
runner.instance_exec do
- `test #{:command}`
+ `test #{:command}` # rubocop:disable Lint/LiteralInInterpolation
end
end
@@ -84,7 +84,7 @@ describe "%x" do
2.times do
runner.instance_exec do
- %x{test #{:command}}
+ %x{test #{:command}} # rubocop:disable Lint/LiteralInInterpolation
end
end
diff --git a/spec/ruby/language/hash_spec.rb b/spec/ruby/language/hash_spec.rb
index a7631fb0d6..068ac0f39c 100644
--- a/spec/ruby/language/hash_spec.rb
+++ b/spec/ruby/language/hash_spec.rb
@@ -86,6 +86,30 @@ describe "Hash literal" do
-> { eval("{:a ==> 1}") }.should raise_error(SyntaxError)
end
+ it "recognizes '!' at the end of the key" do
+ eval("{:a! =>1}").should == {:"a!" => 1}
+ eval("{:a! => 1}").should == {:"a!" => 1}
+
+ eval("{a!:1}").should == {:"a!" => 1}
+ eval("{a!: 1}").should == {:"a!" => 1}
+ end
+
+ it "raises a SyntaxError if there is no space between `!` and `=>`" do
+ -> { eval("{:a!=> 1}") }.should raise_error(SyntaxError)
+ end
+
+ it "recognizes '?' at the end of the key" do
+ eval("{:a? =>1}").should == {:"a?" => 1}
+ eval("{:a? => 1}").should == {:"a?" => 1}
+
+ eval("{a?:1}").should == {:"a?" => 1}
+ eval("{a?: 1}").should == {:"a?" => 1}
+ end
+
+ it "raises a SyntaxError if there is no space between `?` and `=>`" do
+ -> { eval("{:a?=> 1}") }.should raise_error(SyntaxError)
+ end
+
it "constructs a new hash with the given elements" do
{foo: 123}.should == {foo: 123}
h = {rbx: :cool, specs: 'fail_sometimes'}
@@ -271,6 +295,14 @@ describe "The ** operator" do
a.new.foo(1).should == {bar: "baz", val: 1}
end
+
+ it "raises a SyntaxError when the hash key ends with `!`" do
+ -> { eval("{a!:}") }.should raise_error(SyntaxError, /identifier a! is not valid to get/)
+ end
+
+ it "raises a SyntaxError when the hash key ends with `?`" do
+ -> { eval("{a?:}") }.should raise_error(SyntaxError, /identifier a\? is not valid to get/)
+ end
end
end
end
diff --git a/spec/ruby/language/keyword_arguments_spec.rb b/spec/ruby/language/keyword_arguments_spec.rb
index ffb5b1fab0..8668799d26 100644
--- a/spec/ruby/language/keyword_arguments_spec.rb
+++ b/spec/ruby/language/keyword_arguments_spec.rb
@@ -395,4 +395,32 @@ describe "Keyword arguments" do
end
end
end
+
+ context "in define_method(name, &proc)" do
+ # This tests that a free-standing proc used in define_method and converted to ruby2_keywords adopts that logic.
+ # See jruby/jruby#8119 for a case where aggressive JIT optimization broke later ruby2_keywords changes.
+ it "works with ruby2_keywords" do
+ m = Class.new do
+ def bar(a, foo: nil)
+ [a, foo]
+ end
+
+ # define_method and ruby2_keywords using send to avoid peephole optimizations
+ def self.setup
+ pr = make_proc
+ send :define_method, :foo, &pr
+ send :ruby2_keywords, :foo
+ end
+
+ # create proc in isolated method to force jit compilation on some implementations
+ def self.make_proc
+ proc { |a, *args| bar(a, *args) }
+ end
+ end
+
+ m.setup
+
+ m.new.foo(1, foo:2).should == [1, 2]
+ end
+ end
end
diff --git a/spec/ruby/language/lambda_spec.rb b/spec/ruby/language/lambda_spec.rb
index 3ab3569ebe..ed5a1c69e8 100644
--- a/spec/ruby/language/lambda_spec.rb
+++ b/spec/ruby/language/lambda_spec.rb
@@ -263,18 +263,21 @@ describe "A lambda literal -> () { }" do
end
describe "with circular optional argument reference" do
- it "raises a SyntaxError if using an existing local with the same name as the argument" do
- a = 1
- -> {
- @proc = eval "-> (a=a) { a }"
- }.should raise_error(SyntaxError)
+ ruby_version_is ""..."3.4" do
+ it "raises a SyntaxError if using the argument in its default value" do
+ a = 1
+ -> {
+ eval "-> (a=a) { a }"
+ }.should raise_error(SyntaxError)
+ end
end
- it "raises a SyntaxError if there is an existing method with the same name as the argument" do
- def a; 1; end
- -> {
- @proc = eval "-> (a=a) { a }"
- }.should raise_error(SyntaxError)
+ ruby_version_is "3.4" do
+ it "is nil if using the argument in its default value" do
+ -> {
+ eval "-> (a=a) { a }.call"
+ }.call.should == nil
+ end
end
it "calls an existing method with the same name as the argument if explicitly using ()" do
diff --git a/spec/ruby/language/pattern_matching/3.1.rb b/spec/ruby/language/pattern_matching/3.1.rb
new file mode 100644
index 0000000000..7a09084e41
--- /dev/null
+++ b/spec/ruby/language/pattern_matching/3.1.rb
@@ -0,0 +1,75 @@
+describe "Pattern matching" do
+ before :each do
+ ScratchPad.record []
+ end
+
+ describe "Ruby 3.1 improvements" do
+ ruby_version_is "3.1" do
+ it "can omit parentheses in one line pattern matching" do
+ [1, 2] => a, b
+ [a, b].should == [1, 2]
+
+ {a: 1} => a:
+ a.should == 1
+ end
+
+ it "supports pinning instance variables" do
+ @a = /a/
+ case 'abc'
+ in ^@a
+ true
+ end.should == true
+ end
+
+ it "supports pinning class variables" do
+ result = nil
+ Module.new do
+ result = module_eval(<<~RUBY)
+ @@a = 0..10
+
+ case 2
+ in ^@@a
+ true
+ end
+ RUBY
+ end
+
+ result.should == true
+ end
+
+ it "supports pinning global variables" do
+ $a = /a/
+ case 'abc'
+ in ^$a
+ true
+ end.should == true
+ end
+
+ it "supports pinning expressions" do
+ case 'abc'
+ in ^(/a/)
+ true
+ end.should == true
+
+ case 0
+ in ^(0 + 0)
+ true
+ end.should == true
+ end
+
+ it "supports pinning expressions in array pattern" do
+ case [3]
+ in [^(1 + 2)]
+ true
+ end.should == true
+ end
+
+ it "supports pinning expressions in hash pattern" do
+ case {name: '2.6', released_at: Time.new(2018, 12, 25)}
+ in {released_at: ^(Time.new(2010)..Time.new(2020))}
+ true
+ end.should == true
+ end
+ end
+ end
+end
diff --git a/spec/ruby/language/pattern_matching_spec.rb b/spec/ruby/language/pattern_matching_spec.rb
index a8ec078cd0..8c5df06a17 100644
--- a/spec/ruby/language/pattern_matching_spec.rb
+++ b/spec/ruby/language/pattern_matching_spec.rb
@@ -1,9 +1,6 @@
require_relative '../spec_helper'
describe "Pattern matching" do
- # TODO: Remove excessive eval calls when Ruby 3 is the minimum version.
- # It is best to keep the eval's longer if other Ruby impls cannot parse pattern matching yet.
-
before :each do
ScratchPad.record []
end
@@ -11,145 +8,119 @@ describe "Pattern matching" do
describe "can be standalone assoc operator that" do
it "deconstructs value" do
suppress_warning do
- eval(<<-RUBY).should == [0, 1]
- [0, 1] => [a, b]
- [a, b]
- RUBY
+ [0, 1] => [a, b]
+ [a, b].should == [0, 1]
end
end
it "deconstructs value and properly scopes variables" do
suppress_warning do
- eval(<<-RUBY).should == [0, nil]
- a = nil
- eval(<<-PATTERN)
- [0, 1] => [a, b]
- PATTERN
- [a, defined?(b)]
- RUBY
+ a = nil
+ 1.times {
+ [0, 1] => [a, b]
+ }
+ [a, defined?(b)].should == [0, nil]
end
end
end
describe "find pattern" do
it "captures preceding elements to the pattern" do
- eval(<<~RUBY).should == [0, 1]
- case [0, 1, 2, 3]
- in [*pre, 2, 3]
- pre
- else
- false
- end
- RUBY
+ case [0, 1, 2, 3]
+ in [*pre, 2, 3]
+ pre
+ else
+ false
+ end.should == [0, 1]
end
it "captures following elements to the pattern" do
- eval(<<~RUBY).should == [2, 3]
- case [0, 1, 2, 3]
- in [0, 1, *post]
- post
- else
- false
- end
- RUBY
+ case [0, 1, 2, 3]
+ in [0, 1, *post]
+ post
+ else
+ false
+ end.should == [2, 3]
end
it "captures both preceding and following elements to the pattern" do
- eval(<<~RUBY).should == [[0, 1], [3, 4]]
- case [0, 1, 2, 3, 4]
- in [*pre, 2, *post]
- [pre, post]
- else
- false
- end
- RUBY
+ case [0, 1, 2, 3, 4]
+ in [*pre, 2, *post]
+ [pre, post]
+ else
+ false
+ end.should == [[0, 1], [3, 4]]
end
it "can capture the entirety of the pattern" do
- eval(<<~RUBY).should == [0, 1, 2, 3, 4]
- case [0, 1, 2, 3, 4]
- in [*everything]
- everything
- else
- false
- end
- RUBY
+ case [0, 1, 2, 3, 4]
+ in [*everything]
+ everything
+ else
+ false
+ end.should == [0, 1, 2, 3, 4]
end
it "will match an empty Array-like structure" do
- eval(<<~RUBY).should == []
- case []
- in [*everything]
- everything
- else
- false
- end
- RUBY
+ case []
+ in [*everything]
+ everything
+ else
+ false
+ end.should == []
end
it "can be nested" do
- eval(<<~RUBY).should == [[0, [2, 4, 6]], [[4, 16, 64]], 27]
- case [0, [2, 4, 6], [3, 9, 27], [4, 16, 64]]
- in [*pre, [*, 9, a], *post]
- [pre, post, a]
- else
- false
- end
- RUBY
+ case [0, [2, 4, 6], [3, 9, 27], [4, 16, 64]]
+ in [*pre, [*, 9, a], *post]
+ [pre, post, a]
+ else
+ false
+ end.should == [[0, [2, 4, 6]], [[4, 16, 64]], 27]
end
it "can be nested with an array pattern" do
- eval(<<~RUBY).should == [[4, 16, 64]]
- case [0, [2, 4, 6], [3, 9, 27], [4, 16, 64]]
- in [_, _, [*, 9, *], *post]
- post
- else
- false
- end
- RUBY
+ case [0, [2, 4, 6], [3, 9, 27], [4, 16, 64]]
+ in [_, _, [*, 9, *], *post]
+ post
+ else
+ false
+ end.should == [[4, 16, 64]]
end
it "can be nested within a hash pattern" do
- eval(<<~RUBY).should == [27]
- case {a: [3, 9, 27]}
- in {a: [*, 9, *post]}
- post
- else
- false
- end
- RUBY
+ case {a: [3, 9, 27]}
+ in {a: [*, 9, *post]}
+ post
+ else
+ false
+ end.should == [27]
end
it "can nest hash and array patterns" do
- eval(<<~RUBY).should == [42, 2]
- case [0, {a: 42, b: [0, 1]}, {a: 42, b: [1, 2]}]
- in [*, {a:, b: [1, c]}, *]
- [a, c]
- else
- false
- end
- RUBY
+ case [0, {a: 42, b: [0, 1]}, {a: 42, b: [1, 2]}]
+ in [*, {a:, b: [1, c]}, *]
+ [a, c]
+ else
+ false
+ end.should == [42, 2]
end
end
it "extends case expression with case/in construction" do
- eval(<<~RUBY).should == :bar
- case [0, 1]
- in [0]
- :foo
- in [0, 1]
- :bar
- end
- RUBY
+ case [0, 1]
+ in [0]
+ :foo
+ in [0, 1]
+ :bar
+ end.should == :bar
end
it "allows using then operator" do
- eval(<<~RUBY).should == :bar
- case [0, 1]
- in [0] then :foo
- in [0, 1] then :bar
- end
- RUBY
+ case [0, 1]
+ in [0] then :foo
+ in [0, 1] then :bar
+ end.should == :bar
end
describe "warning" do
@@ -191,12 +162,10 @@ describe "Pattern matching" do
end
it "binds variables" do
- eval(<<~RUBY).should == 1
- case [0, 1]
- in [0, a]
- a
- end
- RUBY
+ case [0, 1]
+ in [0, a]
+ a
+ end.should == 1
end
it "cannot mix in and when operators" do
@@ -220,47 +189,45 @@ describe "Pattern matching" do
end
it "checks patterns until the first matching" do
- eval(<<~RUBY).should == :bar
- case [0, 1]
- in [0]
- :foo
- in [0, 1]
- :bar
- in [0, 1]
- :baz
- end
- RUBY
+ case [0, 1]
+ in [0]
+ :foo
+ in [0, 1]
+ :bar
+ in [0, 1]
+ :baz
+ end.should == :bar
end
it "executes else clause if no pattern matches" do
- eval(<<~RUBY).should == false
- case [0, 1]
- in [0]
- true
- else
- false
- end
- RUBY
+ case [0, 1]
+ in [0]
+ true
+ else
+ false
+ end.should == false
end
it "raises NoMatchingPatternError if no pattern matches and no else clause" do
-> {
- eval <<~RUBY
- case [0, 1]
- in [0]
- end
- RUBY
+ case [0, 1]
+ in [0]
+ end
}.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
+
+ -> {
+ case {a: 0, b: 1}
+ in a: 1, b: 1
+ end
+ }.should raise_error(NoMatchingPatternError, /\{:a=>0, :b=>1\}/)
end
it "raises NoMatchingPatternError if no pattern matches and evaluates the expression only once" do
evals = 0
-> {
- eval <<~RUBY
- case (evals += 1; [0, 1])
- in [0]
- end
- RUBY
+ case (evals += 1; [0, 1])
+ in [0]
+ end
}.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
evals.should == 1
end
@@ -273,230 +240,185 @@ describe "Pattern matching" do
true
end
RUBY
- }.should raise_error(SyntaxError, /unexpected|expected a delimiter after the predicates of a `when` clause/)
+ }.should raise_error(SyntaxError, /unexpected|expected a delimiter after the patterns of an `in` clause/)
end
it "evaluates the case expression once for multiple patterns, caching the result" do
- eval(<<~RUBY).should == true
- case (ScratchPad << :foo; 1)
- in 0
- false
- in 1
- true
- end
- RUBY
+ case (ScratchPad << :foo; 1)
+ in 0
+ false
+ in 1
+ true
+ end.should == true
ScratchPad.recorded.should == [:foo]
end
describe "guards" do
it "supports if guard" do
- eval(<<~RUBY).should == false
- case 0
- in 0 if false
- true
- else
- false
- end
- RUBY
+ case 0
+ in 0 if false
+ true
+ else
+ false
+ end.should == false
- eval(<<~RUBY).should == true
- case 0
- in 0 if true
- true
- else
- false
- end
- RUBY
+ case 0
+ in 0 if true
+ true
+ else
+ false
+ end.should == true
end
it "supports unless guard" do
- eval(<<~RUBY).should == false
- case 0
- in 0 unless true
- true
- else
- false
- end
- RUBY
+ case 0
+ in 0 unless true
+ true
+ else
+ false
+ end.should == false
- eval(<<~RUBY).should == true
- case 0
- in 0 unless false
- true
- else
- false
- end
- RUBY
+ case 0
+ in 0 unless false
+ true
+ else
+ false
+ end.should == true
end
it "makes bound variables visible in guard" do
- eval(<<~RUBY).should == true
- case [0, 1]
- in [a, 1] if a >= 0
- true
- end
- RUBY
+ case [0, 1]
+ in [a, 1] if a >= 0
+ true
+ end.should == true
end
it "does not evaluate guard if pattern does not match" do
- eval <<~RUBY
- case 0
- in 1 if (ScratchPad << :foo) || true
- else
- end
- RUBY
+ case 0
+ in 1 if (ScratchPad << :foo) || true
+ else
+ end
ScratchPad.recorded.should == []
end
it "takes guards into account when there are several matching patterns" do
- eval(<<~RUBY).should == :bar
- case 0
- in 0 if false
- :foo
- in 0 if true
- :bar
- end
- RUBY
+ case 0
+ in 0 if false
+ :foo
+ in 0 if true
+ :bar
+ end.should == :bar
end
it "executes else clause if no guarded pattern matches" do
- eval(<<~RUBY).should == false
- case 0
- in 0 if false
- true
- else
- false
- end
- RUBY
+ case 0
+ in 0 if false
+ true
+ else
+ false
+ end.should == false
end
it "raises NoMatchingPatternError if no guarded pattern matches and no else clause" do
-> {
- eval <<~RUBY
- case [0, 1]
- in [0, 1] if false
- end
- RUBY
+ case [0, 1]
+ in [0, 1] if false
+ end
}.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
end
end
describe "value pattern" do
it "matches an object such that pattern === object" do
- eval(<<~RUBY).should == true
- case 0
- in 0
- true
- end
- RUBY
+ case 0
+ in 0
+ true
+ end.should == true
- eval(<<~RUBY).should == true
- case 0
- in (-1..1)
- true
- end
- RUBY
+ case 0
+ in (
+ -1..1)
+ true
+ end.should == true
- eval(<<~RUBY).should == true
- case 0
- in Integer
- true
- end
- RUBY
+ case 0
+ in Integer
+ true
+ end.should == true
- eval(<<~RUBY).should == true
- case "0"
- in /0/
- true
- end
- RUBY
+ case "0"
+ in /0/
+ true
+ end.should == true
- eval(<<~RUBY).should == true
- case "0"
- in ->(s) { s == "0" }
- true
- end
- RUBY
+ case "0"
+ in -> s { s == "0" }
+ true
+ end.should == true
end
it "allows string literal with interpolation" do
x = "x"
- eval(<<~RUBY).should == true
- case "x"
- in "#{x + ""}"
- true
- end
- RUBY
+ case "x"
+ in "#{x + ""}"
+ true
+ end.should == true
end
end
describe "variable pattern" do
it "matches a value and binds variable name to this value" do
- eval(<<~RUBY).should == 0
- case 0
- in a
- a
- end
- RUBY
+ case 0
+ in a
+ a
+ end.should == 0
end
it "makes bounded variable visible outside a case statement scope" do
- eval(<<~RUBY).should == 0
- case 0
- in a
- end
+ case 0
+ in a
+ end
- a
- RUBY
+ a.should == 0
end
it "create local variables even if a pattern doesn't match" do
- eval(<<~RUBY).should == [0, nil, nil]
- case 0
- in a
- in b
- in c
- end
+ case 0
+ in a
+ in b
+ in c
+ end
- [a, b, c]
- RUBY
+ [a, b, c].should == [0, nil, nil]
end
it "allow using _ name to drop values" do
- eval(<<~RUBY).should == 0
- case [0, 1]
- in [a, _]
- a
- end
- RUBY
+ case [0, 1]
+ in [a, _]
+ a
+ end.should == 0
end
it "supports using _ in a pattern several times" do
- eval(<<~RUBY).should == true
- case [0, 1, 2]
- in [0, _, _]
- true
- end
- RUBY
+ case [0, 1, 2]
+ in [0, _, _]
+ true
+ end.should == true
end
it "supports using any name with _ at the beginning in a pattern several times" do
- eval(<<~RUBY).should == true
- case [0, 1, 2]
- in [0, _x, _x]
- true
- end
- RUBY
+ case [0, 1, 2]
+ in [0, _x, _x]
+ true
+ end.should == true
- eval(<<~RUBY).should == true
- case {a: 0, b: 1, c: 2}
- in {a: 0, b: _x, c: _x}
- true
- end
- RUBY
+ case {a: 0, b: 1, c: 2}
+ in {a: 0, b: _x, c: _x}
+ true
+ end.should == true
end
it "does not support using variable name (except _) several times" do
@@ -512,30 +434,24 @@ describe "Pattern matching" do
it "supports existing variables in a pattern specified with ^ operator" do
a = 0
- eval(<<~RUBY).should == true
- case 0
- in ^a
- true
- end
- RUBY
+ case 0
+ in ^a
+ true
+ end.should == true
end
it "allows applying ^ operator to bound variables" do
- eval(<<~RUBY).should == 1
- case [1, 1]
- in [n, ^n]
- n
- end
- RUBY
+ case [1, 1]
+ in [n, ^n]
+ n
+ end.should == 1
- eval(<<~RUBY).should == false
- case [1, 2]
- in [n, ^n]
- true
- else
- false
- end
- RUBY
+ case [1, 2]
+ in [n, ^n]
+ true
+ else
+ false
+ end.should == false
end
it "requires bound variable to be specified in a pattern before ^ operator when it relies on a bound variable" do
@@ -554,12 +470,10 @@ describe "Pattern matching" do
describe "alternative pattern" do
it "matches if any of patterns matches" do
- eval(<<~RUBY).should == true
- case 0
- in 0 | 1 | 2
- true
- end
- RUBY
+ case 0
+ in 0 | 1 | 2
+ true
+ end.should == true
end
it "does not support variable binding" do
@@ -573,120 +487,99 @@ describe "Pattern matching" do
end
it "support underscore prefixed variables in alternation" do
- eval(<<~RUBY).should == true
- case [0, 1]
- in [1, _]
- false
- in [0, 0] | [0, _a]
- true
- end
- RUBY
+ case [0, 1]
+ in [1, _]
+ false
+ in [0, 0] | [0, _a]
+ true
+ end.should == true
end
it "can be used as a nested pattern" do
- eval(<<~RUBY).should == true
- case [[1], ["2"]]
- in [[0] | nil, _]
- false
- in [[1], [1]]
- false
- in [[1], [2 | "2"]]
- true
- end
- RUBY
+ case [[1], ["2"]]
+ in [[0] | nil, _]
+ false
+ in [[1], [1]]
+ false
+ in [[1], [2 | "2"]]
+ true
+ end.should == true
- eval(<<~RUBY).should == true
- case [1, 2]
- in [0, _] | {a: 0}
- false
- in {a: 1, b: 2} | [1, 2]
- true
- end
- RUBY
+ case [1, 2]
+ in [0, _] | {a: 0}
+ false
+ in {a: 1, b: 2} | [1, 2]
+ true
+ end.should == true
end
end
describe "AS pattern" do
it "binds a variable to a value if pattern matches" do
- eval(<<~RUBY).should == 0
- case 0
- in Integer => n
- n
- end
- RUBY
+ case 0
+ in Integer => n
+ n
+ end.should == 0
end
it "can be used as a nested pattern" do
- eval(<<~RUBY).should == [2, 3]
- case [1, [2, 3]]
- in [1, Array => ary]
- ary
- end
- RUBY
+ case [1, [2, 3]]
+ in [1, Array => ary]
+ ary
+ end.should == [2, 3]
end
end
describe "Array pattern" do
it "supports form Constant(pat, pat, ...)" do
- eval(<<~RUBY).should == true
- case [0, 1, 2]
- in Array(0, 1, 2)
- true
- end
- RUBY
+ case [0, 1, 2]
+ in Array(0, 1, 2)
+ true
+ end.should == true
end
it "supports form Constant[pat, pat, ...]" do
- eval(<<~RUBY).should == true
- case [0, 1, 2]
- in Array[0, 1, 2]
- true
- end
- RUBY
+ case [0, 1, 2]
+ in Array[0, 1, 2]
+ true
+ end.should == true
end
it "supports form [pat, pat, ...]" do
- eval(<<~RUBY).should == true
- case [0, 1, 2]
- in [0, 1, 2]
- true
- end
- RUBY
+ case [0, 1, 2]
+ in [0, 1, 2]
+ true
+ end.should == true
end
it "supports form pat, pat, ..." do
- eval(<<~RUBY).should == true
- case [0, 1, 2]
- in 0, 1, 2
- true
- end
- RUBY
+ case [0, 1, 2]
+ in 0, 1, 2
+ true
+ end.should == true
- eval(<<~RUBY).should == 1
- case [0, 1, 2]
- in 0, a, 2
- a
- end
- RUBY
+ case [0, 1, 2]
+ in 0, a, 2
+ a
+ end.should == 1
- eval(<<~RUBY).should == [1, 2]
- case [0, 1, 2]
- in 0, *rest
- rest
- end
- RUBY
+ case [0, 1, 2]
+ in 0, *rest
+ rest
+ end.should == [1, 2]
end
it "matches an object with #deconstruct method which returns an array and each element in array matches element in pattern" do
obj = Object.new
- def obj.deconstruct; [0, 1] end
- eval(<<~RUBY).should == true
- case obj
- in [Integer, Integer]
- true
- end
- RUBY
+ def obj.deconstruct
+ [0, 1]
+ end
+
+ case obj
+ in [Integer, Integer]
+ true
+ end.should == true
end
it "calls #deconstruct once for multiple patterns, caching the result" do
@@ -697,314 +590,267 @@ describe "Pattern matching" do
[0, 1]
end
- eval(<<~RUBY).should == true
- case obj
- in [1, 2]
- false
- in [0, 1]
- true
- end
- RUBY
+ case obj
+ in [1, 2]
+ false
+ in [0, 1]
+ true
+ end.should == true
ScratchPad.recorded.should == [:deconstruct]
end
it "calls #deconstruct even on objects that are already an array" do
obj = [1, 2]
+
def obj.deconstruct
ScratchPad << :deconstruct
[3, 4]
end
- eval(<<~RUBY).should == true
- case obj
- in [3, 4]
- true
- else
- false
- end
- RUBY
+ case obj
+ in [3, 4]
+ true
+ else
+ false
+ end.should == true
ScratchPad.recorded.should == [:deconstruct]
end
it "does not match object if Constant === object returns false" do
- eval(<<~RUBY).should == false
- case [0, 1, 2]
- in String[0, 1, 2]
- true
- else
- false
- end
- RUBY
+ case [0, 1, 2]
+ in String[0, 1, 2]
+ true
+ else
+ false
+ end.should == false
end
it "checks Constant === object before calling #deconstruct" do
c1 = Class.new
obj = c1.new
obj.should_not_receive(:deconstruct)
- eval(<<~RUBY).should == false
- case obj
- in String[1]
- true
- else
- false
- end
- RUBY
+
+ case obj
+ in String[1]
+ true
+ else
+ false
+ end.should == false
end
it "does not match object without #deconstruct method" do
obj = Object.new
obj.should_receive(:respond_to?).with(:deconstruct)
- eval(<<~RUBY).should == false
- case obj
- in Object[]
- true
- else
- false
- end
- RUBY
+ case obj
+ in Object[]
+ true
+ else
+ false
+ end.should == false
end
it "raises TypeError if #deconstruct method does not return array" do
obj = Object.new
- def obj.deconstruct; "" end
+
+ def obj.deconstruct
+ ""
+ end
-> {
- eval <<~RUBY
- case obj
- in Object[]
- else
- end
- RUBY
+ case obj
+ in Object[]
+ else
+ end
}.should raise_error(TypeError, /deconstruct must return Array/)
end
it "accepts a subclass of Array from #deconstruct" do
obj = Object.new
+
def obj.deconstruct
Class.new(Array).new([0, 1])
end
- eval(<<~RUBY).should == true
- case obj
- in [1, 2]
- false
- in [0, 1]
- true
- end
- RUBY
+ case obj
+ in [1, 2]
+ false
+ in [0, 1]
+ true
+ end.should == true
end
it "does not match object if elements of array returned by #deconstruct method does not match elements in pattern" do
obj = Object.new
- def obj.deconstruct; [1] end
- eval(<<~RUBY).should == false
- case obj
- in Object[0]
- true
- else
- false
- end
- RUBY
+ def obj.deconstruct
+ [1]
+ end
+
+ case obj
+ in Object[0]
+ true
+ else
+ false
+ end.should == false
end
it "binds variables" do
- eval(<<~RUBY).should == [0, 1, 2]
- case [0, 1, 2]
- in [a, b, c]
- [a, b, c]
- end
- RUBY
+ case [0, 1, 2]
+ in [a, b, c]
+ [a, b, c]
+ end.should == [0, 1, 2]
end
it "supports splat operator *rest" do
- eval(<<~RUBY).should == [1, 2]
- case [0, 1, 2]
- in [0, *rest]
- rest
- end
- RUBY
+ case [0, 1, 2]
+ in [0, *rest]
+ rest
+ end.should == [1, 2]
end
it "does not match partially by default" do
- eval(<<~RUBY).should == false
- case [0, 1, 2, 3]
- in [1, 2]
- true
- else
- false
- end
- RUBY
+ case [0, 1, 2, 3]
+ in [1, 2]
+ true
+ else
+ false
+ end.should == false
end
it "does match partially from the array beginning if list + , syntax used" do
- eval(<<~RUBY).should == true
- case [0, 1, 2, 3]
- in [0, 1,]
- true
- end
- RUBY
+ case [0, 1, 2, 3]
+ in [0, 1, ]
+ true
+ end.should == true
- eval(<<~RUBY).should == true
- case [0, 1, 2, 3]
- in 0, 1,;
- true
- end
- RUBY
+ case [0, 1, 2, 3]
+ in 0, 1,;
+ true
+ end.should == true
end
it "matches [] with []" do
- eval(<<~RUBY).should == true
- case []
- in []
- true
- end
- RUBY
+ case []
+ in []
+ true
+ end.should == true
end
it "matches anything with *" do
- eval(<<~RUBY).should == true
- case [0, 1]
- in *;
- true
- end
- RUBY
+ case [0, 1]
+ in *;
+ true
+ end.should == true
end
it "can be used as a nested pattern" do
- eval(<<~RUBY).should == true
- case [[1], ["2"]]
- in [[0] | nil, _]
- false
- in [[1], [1]]
- false
- in [[1], [2 | "2"]]
- true
- end
- RUBY
+ case [[1], ["2"]]
+ in [[0] | nil, _]
+ false
+ in [[1], [1]]
+ false
+ in [[1], [2 | "2"]]
+ true
+ end.should == true
- eval(<<~RUBY).should == true
- case [1, 2]
- in [0, _] | {a: 0}
- false
- in {a: 1, b: 2} | [1, 2]
- true
- end
- RUBY
+ case [1, 2]
+ in [0, _] | {a: 0}
+ false
+ in {a: 1, b: 2} | [1, 2]
+ true
+ end.should == true
end
end
describe "Hash pattern" do
it "supports form Constant(id: pat, id: pat, ...)" do
- eval(<<~RUBY).should == true
- case {a: 0, b: 1}
- in Hash(a: 0, b: 1)
- true
- end
- RUBY
+ case {a: 0, b: 1}
+ in Hash(a: 0, b: 1)
+ true
+ end.should == true
end
it "supports form Constant[id: pat, id: pat, ...]" do
- eval(<<~RUBY).should == true
- case {a: 0, b: 1}
- in Hash[a: 0, b: 1]
- true
- end
- RUBY
+ case {a: 0, b: 1}
+ in Hash[a: 0, b: 1]
+ true
+ end.should == true
end
it "supports form {id: pat, id: pat, ...}" do
- eval(<<~RUBY).should == true
- case {a: 0, b: 1}
- in {a: 0, b: 1}
- true
- end
- RUBY
+ case {a: 0, b: 1}
+ in {a: 0, b: 1}
+ true
+ end.should == true
end
it "supports form id: pat, id: pat, ..." do
- eval(<<~RUBY).should == true
- case {a: 0, b: 1}
- in a: 0, b: 1
- true
- end
- RUBY
+ case {a: 0, b: 1}
+ in a: 0, b: 1
+ true
+ end.should == true
- eval(<<~RUBY).should == [0, 1]
- case {a: 0, b: 1}
- in a: a, b: b
- [a, b]
- end
- RUBY
+ case {a: 0, b: 1}
+ in a: a, b: b
+ [a, b]
+ end.should == [0, 1]
- eval(<<~RUBY).should == { b: 1, c: 2 }
- case {a: 0, b: 1, c: 2}
- in a: 0, **rest
- rest
- end
- RUBY
+ case {a: 0, b: 1, c: 2}
+ in a: 0, **rest
+ rest
+ end.should == {b: 1, c: 2}
end
it "supports a: which means a: a" do
- eval(<<~RUBY).should == [0, 1]
- case {a: 0, b: 1}
- in Hash(a:, b:)
- [a, b]
- end
- RUBY
+ case {a: 0, b: 1}
+ in Hash(a:, b:)
+ [a, b]
+ end.should == [0, 1]
a = b = nil
- eval(<<~RUBY).should == [0, 1]
- case {a: 0, b: 1}
- in Hash[a:, b:]
- [a, b]
- end
- RUBY
+
+ case {a: 0, b: 1}
+ in Hash[a:, b:]
+ [a, b]
+ end.should == [0, 1]
a = b = nil
- eval(<<~RUBY).should == [0, 1]
- case {a: 0, b: 1}
- in {a:, b:}
- [a, b]
- end
- RUBY
+
+ case {a: 0, b: 1}
+ in {a:, b:}
+ [a, b]
+ end.should == [0, 1]
a = nil
- eval(<<~RUBY).should == [0, {b: 1, c: 2}]
- case {a: 0, b: 1, c: 2}
- in {a:, **rest}
- [a, rest]
- end
- RUBY
+
+ case {a: 0, b: 1, c: 2}
+ in {a:, **rest}
+ [a, rest]
+ end.should == [0, {b: 1, c: 2}]
a = b = nil
- eval(<<~RUBY).should == [0, 1]
- case {a: 0, b: 1}
- in a:, b:
- [a, b]
- end
- RUBY
+
+ case {a: 0, b: 1}
+ in a:, b:
+ [a, b]
+ end.should == [0, 1]
end
it "can mix key (a:) and key-value (a: b) declarations" do
- eval(<<~RUBY).should == [0, 1]
- case {a: 0, b: 1}
- in Hash(a:, b: x)
- [a, x]
- end
- RUBY
+ case {a: 0, b: 1}
+ in Hash(a:, b: x)
+ [a, x]
+ end.should == [0, 1]
end
it "supports 'string': key literal" do
- eval(<<~RUBY).should == true
- case {a: 0}
- in {"a": 0}
- true
- end
- RUBY
+ case {a: 0}
+ in {"a": 0}
+ true
+ end.should == true
end
it "does not support non-symbol keys" do
@@ -1018,8 +864,6 @@ describe "Pattern matching" do
end
it "does not support string interpolation in keys" do
- x = "a"
-
-> {
eval <<~'RUBY'
case {a: 1}
@@ -1041,14 +885,15 @@ describe "Pattern matching" do
it "matches an object with #deconstruct_keys method which returns a Hash with equal keys and each value in Hash matches value in pattern" do
obj = Object.new
- def obj.deconstruct_keys(*); {a: 1} end
- eval(<<~RUBY).should == true
- case obj
- in {a: 1}
- true
- end
- RUBY
+ def obj.deconstruct_keys(*)
+ {a: 1}
+ end
+
+ case obj
+ in {a: 1}
+ true
+ end.should == true
end
it "calls #deconstruct_keys per pattern" do
@@ -1059,96 +904,92 @@ describe "Pattern matching" do
{a: 1}
end
- eval(<<~RUBY).should == true
- case obj
- in {b: 1}
- false
- in {a: 1}
- true
- end
- RUBY
+ case obj
+ in {b: 1}
+ false
+ in {a: 1}
+ true
+ end.should == true
ScratchPad.recorded.should == [:deconstruct_keys, :deconstruct_keys]
end
it "does not match object if Constant === object returns false" do
- eval(<<~RUBY).should == false
- case {a: 1}
- in String[a: 1]
- true
- else
- false
- end
- RUBY
+ case {a: 1}
+ in String[a: 1]
+ true
+ else
+ false
+ end.should == false
end
it "checks Constant === object before calling #deconstruct_keys" do
c1 = Class.new
obj = c1.new
obj.should_not_receive(:deconstruct_keys)
- eval(<<~RUBY).should == false
- case obj
- in String(a: 1)
- true
- else
- false
- end
- RUBY
+
+ case obj
+ in String(a: 1)
+ true
+ else
+ false
+ end.should == false
end
it "does not match object without #deconstruct_keys method" do
obj = Object.new
obj.should_receive(:respond_to?).with(:deconstruct_keys)
- eval(<<~RUBY).should == false
- case obj
- in Object[a: 1]
- true
- else
- false
- end
- RUBY
+ case obj
+ in Object[a: 1]
+ true
+ else
+ false
+ end.should == false
end
it "does not match object if #deconstruct_keys method does not return Hash" do
obj = Object.new
- def obj.deconstruct_keys(*); "" end
+
+ def obj.deconstruct_keys(*)
+ ""
+ end
-> {
- eval <<~RUBY
- case obj
- in Object[a: 1]
- end
- RUBY
+ case obj
+ in Object[a: 1]
+ end
}.should raise_error(TypeError, /deconstruct_keys must return Hash/)
end
it "does not match object if #deconstruct_keys method returns Hash with non-symbol keys" do
obj = Object.new
- def obj.deconstruct_keys(*); {"a" => 1} end
- eval(<<~RUBY).should == false
- case obj
- in Object[a: 1]
- true
- else
- false
- end
- RUBY
+ def obj.deconstruct_keys(*)
+ {"a" => 1}
+ end
+
+ case obj
+ in Object[a: 1]
+ true
+ else
+ false
+ end.should == false
end
it "does not match object if elements of Hash returned by #deconstruct_keys method does not match values in pattern" do
obj = Object.new
- def obj.deconstruct_keys(*); {a: 1} end
- eval(<<~RUBY).should == false
- case obj
- in Object[a: 2]
- true
- else
- false
- end
- RUBY
+ def obj.deconstruct_keys(*)
+ {a: 1}
+ end
+
+ case obj
+ in Object[a: 2]
+ true
+ else
+ false
+ end.should == false
end
it "passes keys specified in pattern as arguments to #deconstruct_keys method" do
@@ -1159,11 +1000,9 @@ describe "Pattern matching" do
{a: 1, b: 2, c: 3}
end
- eval <<~RUBY
- case obj
- in Object[a: 1, b: 2, c: 3]
- end
- RUBY
+ case obj
+ in Object[a: 1, b: 2, c: 3]
+ end
ScratchPad.recorded.sort.should == [[[:a, :b, :c]]]
end
@@ -1176,11 +1015,9 @@ describe "Pattern matching" do
{a: 1, b: 2, c: 3}
end
- eval <<~RUBY
- case obj
- in Object[a: 1, b: 2, **]
- end
- RUBY
+ case obj
+ in Object[a: 1, b: 2, **]
+ end
ScratchPad.recorded.sort.should == [[[:a, :b]]]
end
@@ -1193,131 +1030,105 @@ describe "Pattern matching" do
{a: 1, b: 2}
end
- eval <<~RUBY
- case obj
- in Object[a: 1, **rest]
- end
- RUBY
+ case obj
+ in Object[a: 1, **rest]
+ end
ScratchPad.recorded.should == [[nil]]
end
it "binds variables" do
- eval(<<~RUBY).should == [0, 1, 2]
- case {a: 0, b: 1, c: 2}
- in {a: x, b: y, c: z}
- [x, y, z]
- end
- RUBY
+ case {a: 0, b: 1, c: 2}
+ in {a: x, b: y, c: z}
+ [x, y, z]
+ end.should == [0, 1, 2]
end
it "supports double splat operator **rest" do
- eval(<<~RUBY).should == {b: 1, c: 2}
- case {a: 0, b: 1, c: 2}
- in {a: 0, **rest}
- rest
- end
- RUBY
+ case {a: 0, b: 1, c: 2}
+ in {a: 0, **rest}
+ rest
+ end.should == {b: 1, c: 2}
end
it "treats **nil like there should not be any other keys in a matched Hash" do
- eval(<<~RUBY).should == true
- case {a: 1, b: 2}
- in {a: 1, b: 2, **nil}
- true
- end
- RUBY
+ case {a: 1, b: 2}
+ in {a: 1, b: 2, **nil}
+ true
+ end.should == true
- eval(<<~RUBY).should == false
- case {a: 1, b: 2}
- in {a: 1, **nil}
- true
- else
- false
- end
- RUBY
+ case {a: 1, b: 2}
+ in {a: 1, **nil}
+ true
+ else
+ false
+ end.should == false
end
it "can match partially" do
- eval(<<~RUBY).should == true
- case {a: 1, b: 2}
- in {a: 1}
- true
- end
- RUBY
+ case {a: 1, b: 2}
+ in {a: 1}
+ true
+ end.should == true
end
it "matches {} with {}" do
- eval(<<~RUBY).should == true
- case {}
- in {}
- true
- end
- RUBY
+ case {}
+ in {}
+ true
+ end.should == true
end
it "in {} only matches empty hashes" do
- eval(<<~RUBY).should == false
- case {a: 1}
- in {}
- true
- else
- false
- end
- RUBY
+ case {a: 1}
+ in {}
+ true
+ else
+ false
+ end.should == false
end
it "in {**nil} only matches empty hashes" do
- eval(<<~RUBY).should == true
- case {}
- in {**nil}
- true
- else
- false
- end
- RUBY
+ case {}
+ in {**nil}
+ true
+ else
+ false
+ end.should == true
- eval(<<~RUBY).should == false
- case {a: 1}
- in {**nil}
- true
- else
- false
- end
- RUBY
+ case {a: 1}
+ in {**nil}
+ true
+ else
+ false
+ end.should == false
end
it "matches anything with **" do
- eval(<<~RUBY).should == true
- case {a: 1}
- in **;
- true
- end
- RUBY
+ case {a: 1}
+ in **;
+ true
+ end.should == true
end
it "can be used as a nested pattern" do
- eval(<<~RUBY).should == true
- case {a: {a: 1, b: 1}, b: {a: 1, b: 2}}
- in {a: {a: 0}}
- false
- in {a: {a: 1}, b: {b: 1}}
- false
- in {a: {a: 1}, b: {b: 2}}
- true
- end
- RUBY
+ case {a: {a: 1, b: 1}, b: {a: 1, b: 2}}
+ in {a: {a: 0}}
+ false
+ in {a: {a: 1}, b: {b: 1}}
+ false
+ in {a: {a: 1}, b: {b: 2} }
+ true
+ end.should == true
- eval(<<~RUBY).should == true
- case [{a: 1, b: [1]}, {a: 1, c: ["2"]}]
- in [{a:, c:},]
- false
- in [{a: 1, b:}, {a: 1, c: [Integer]}]
- false
- in [_, {a: 1, c: [String]}]
- true
- end
- RUBY
+ case [{a: 1, b: [1]}, {a: 1, c: ["2"]}]
+ in [{a:, c:}, ]
+ false
+ in [{a: 1, b:}, {a: 1, c: [Integer]}]
+ false
+ in [_, {a: 1, c: [String]}]
+ true
+ end.should == true
end
end
@@ -1335,12 +1146,11 @@ describe "Pattern matching" do
Module.new do
using refinery
- result = eval(<<~RUBY)
+ result =
case []
in [0]
true
end
- RUBY
end
result.should == true
@@ -1359,12 +1169,11 @@ describe "Pattern matching" do
Module.new do
using refinery
- result = eval(<<~RUBY)
+ result =
case {}
in a: 0
true
end
- RUBY
end
result.should == true
@@ -1383,127 +1192,18 @@ describe "Pattern matching" do
Module.new do
using refinery
- result = eval(<<~RUBY)
+ result =
case {}
in Array
true
end
- RUBY
end
result.should == true
end
end
+end
- describe "Ruby 3.1 improvements" do
- ruby_version_is "3.1" do
- it "can omit parentheses in one line pattern matching" do
- eval(<<~RUBY).should == [1, 2]
- [1, 2] => a, b
- [a, b]
- RUBY
-
- eval(<<~RUBY).should == 1
- {a: 1} => a:
- a
- RUBY
- end
-
- it "supports pinning instance variables" do
- eval(<<~RUBY).should == true
- @a = /a/
- case 'abc'
- in ^@a
- true
- end
- RUBY
- end
-
- it "supports pinning class variables" do
- result = nil
- Module.new do
- result = module_eval(<<~RUBY)
- @@a = 0..10
-
- case 2
- in ^@@a
- true
- end
- RUBY
- end
-
- result.should == true
- end
-
- it "supports pinning global variables" do
- eval(<<~RUBY).should == true
- $a = /a/
- case 'abc'
- in ^$a
- true
- end
- RUBY
- end
-
- it "supports pinning expressions" do
- eval(<<~RUBY).should == true
- case 'abc'
- in ^(/a/)
- true
- end
- RUBY
-
- eval(<<~RUBY).should == true
- case 0
- in ^(0+0)
- true
- end
- RUBY
- end
-
- it "supports pinning expressions in array pattern" do
- eval(<<~RUBY).should == true
- case [3]
- in [^(1+2)]
- true
- end
- RUBY
- end
-
- it "supports pinning expressions in hash pattern" do
- eval(<<~RUBY).should == true
- case {name: '2.6', released_at: Time.new(2018, 12, 25)}
- in {released_at: ^(Time.new(2010)..Time.new(2020))}
- true
- end
- RUBY
- end
- end
- end
-
- describe "value in pattern" do
- it "returns true if the pattern matches" do
- eval("1 in 1").should == true
-
- eval("1 in Integer").should == true
-
- e = nil
- eval("[1, 2] in [1, e]").should == true
- e.should == 2
-
- k = nil
- eval("{k: 1} in {k:}").should == true
- k.should == 1
- end
-
- it "returns false if the pattern does not match" do
- eval("1 in 2").should == false
-
- eval("1 in Float").should == false
-
- eval("[1, 2] in [2, e]").should == false
-
- eval("{k: 1} in {k: 2}").should == false
- end
- end
+ruby_version_is "3.1" do
+ require_relative 'pattern_matching/3.1'
end
diff --git a/spec/ruby/language/regexp/back-references_spec.rb b/spec/ruby/language/regexp/back-references_spec.rb
index 26750c20c5..627c8daace 100644
--- a/spec/ruby/language/regexp/back-references_spec.rb
+++ b/spec/ruby/language/regexp/back-references_spec.rb
@@ -22,6 +22,15 @@ describe "Regexps with back-references" do
$10.should == "0"
end
+ it "returns nil for numbered variable with too large index" do
+ -> {
+ eval(<<~CODE).should == nil
+ "a" =~ /(.)/
+ eval('$4294967296')
+ CODE
+ }.should complain(/warning: ('|`)\$4294967296' is too big for a number variable, always nil/)
+ end
+
it "will not clobber capture variables across threads" do
cap1, cap2, cap3 = nil
"foo" =~ /(o+)/
diff --git a/spec/ruby/language/retry_spec.rb b/spec/ruby/language/retry_spec.rb
index ee5377946f..669d5f0ff5 100644
--- a/spec/ruby/language/retry_spec.rb
+++ b/spec/ruby/language/retry_spec.rb
@@ -31,8 +31,11 @@ describe "The retry statement" do
results.should == [1, 2, 3, 1, 2, 4, 5, 6, 4, 5]
end
- it "raises a SyntaxError when used outside of a begin statement" do
+ it "raises a SyntaxError when used outside of a rescue statement" do
-> { eval 'retry' }.should raise_error(SyntaxError)
+ -> { eval 'begin; retry; end' }.should raise_error(SyntaxError)
+ -> { eval 'def m; retry; end' }.should raise_error(SyntaxError)
+ -> { eval 'module RetrySpecs; retry; end' }.should raise_error(SyntaxError)
end
end
diff --git a/spec/ruby/language/yield_spec.rb b/spec/ruby/language/yield_spec.rb
index 5283517636..e125cf8e73 100644
--- a/spec/ruby/language/yield_spec.rb
+++ b/spec/ruby/language/yield_spec.rb
@@ -206,3 +206,15 @@ describe "Using yield in non-lambda block" do
-> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
end
end
+
+describe "Using yield in a module literal" do
+ it 'raises a SyntaxError' do
+ code = <<~RUBY
+ module YieldSpecs::ModuleWithYield
+ yield
+ end
+ RUBY
+
+ -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
+ end
+end
diff --git a/spec/ruby/library/time/to_date_spec.rb b/spec/ruby/library/date/time/to_date_spec.rb
index baeafe0847..f9132da289 100644
--- a/spec/ruby/library/time/to_date_spec.rb
+++ b/spec/ruby/library/date/time/to_date_spec.rb
@@ -1,5 +1,5 @@
-require_relative '../../spec_helper'
+require_relative '../../../spec_helper'
require 'time'
describe "Time#to_date" do
diff --git a/spec/ruby/library/time/to_datetime_spec.rb b/spec/ruby/library/datetime/time/to_datetime_spec.rb
index 9c44f38e5c..1125dbe851 100644
--- a/spec/ruby/library/time/to_datetime_spec.rb
+++ b/spec/ruby/library/datetime/time/to_datetime_spec.rb
@@ -1,4 +1,4 @@
-require_relative '../../spec_helper'
+require_relative '../../../spec_helper'
require 'time'
require 'date'
date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
diff --git a/spec/ruby/library/find/fixtures/common.rb b/spec/ruby/library/find/fixtures/common.rb
index 14a7edb09a..99f3bbb45a 100644
--- a/spec/ruby/library/find/fixtures/common.rb
+++ b/spec/ruby/library/find/fixtures/common.rb
@@ -71,13 +71,17 @@ module FindDirSpecs
end
def self.create_mock_dirs
+ tmp('') # make sure there is an tmpdir
umask = File.umask 0
- mock_dir_files.each do |name|
- file = File.join mock_dir, name
- mkdir_p File.dirname(file)
- touch file
+ begin
+ mock_dir_files.each do |name|
+ file = File.join mock_dir, name
+ mkdir_p File.dirname(file)
+ touch file
+ end
+ ensure
+ File.umask umask
end
- File.umask umask
end
def self.delete_mock_dirs
diff --git a/spec/ruby/library/io-wait/wait_readable_spec.rb b/spec/ruby/library/io-wait/wait_readable_spec.rb
index 06ffbda5c8..df25fdb931 100644
--- a/spec/ruby/library/io-wait/wait_readable_spec.rb
+++ b/spec/ruby/library/io-wait/wait_readable_spec.rb
@@ -24,4 +24,23 @@ describe "IO#wait_readable" do
it "waits for the IO to become readable with the given large timeout" do
@io.wait_readable(365 * 24 * 60 * 60).should == @io
end
+
+ it "can be interrupted" do
+ rd, wr = IO.pipe
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+
+ t = Thread.new do
+ rd.wait_readable(10)
+ end
+
+ Thread.pass until t.stop?
+ t.kill
+ t.join
+
+ finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ (finish - start).should < 9
+ ensure
+ rd.close
+ wr.close
+ end
end
diff --git a/spec/ruby/library/io-wait/wait_spec.rb b/spec/ruby/library/io-wait/wait_spec.rb
index fc07c6a8d9..5952f127f7 100644
--- a/spec/ruby/library/io-wait/wait_spec.rb
+++ b/spec/ruby/library/io-wait/wait_spec.rb
@@ -1,5 +1,5 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
+require_relative '../../fixtures/io'
ruby_version_is ''...'3.2' do
require 'io/wait'
@@ -55,7 +55,7 @@ describe "IO#wait" do
end
it "waits for the WRITABLE event to be ready" do
- written_bytes = IOWaitSpec.exhaust_write_buffer(@w)
+ written_bytes = IOSpec.exhaust_write_buffer(@w)
@w.wait(IO::WRITABLE, 0).should == nil
@r.read(written_bytes)
@@ -67,7 +67,7 @@ describe "IO#wait" do
end
it "returns nil when the WRITABLE event is not ready during the timeout" do
- IOWaitSpec.exhaust_write_buffer(@w)
+ IOSpec.exhaust_write_buffer(@w)
@w.wait(IO::WRITABLE, 0).should == nil
end
@@ -92,7 +92,7 @@ describe "IO#wait" do
end
it "changes thread status to 'sleep' when waits for WRITABLE event" do
- written_bytes = IOWaitSpec.exhaust_write_buffer(@w)
+ IOSpec.exhaust_write_buffer(@w)
t = Thread.new { @w.wait(IO::WRITABLE, 10) }
sleep 1
@@ -100,6 +100,37 @@ describe "IO#wait" do
t.kill
t.join # Thread#kill doesn't wait for the thread to end
end
+
+ it "can be interrupted when waiting for READABLE event" do
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+
+ t = Thread.new do
+ @r.wait(IO::READABLE, 10)
+ end
+
+ Thread.pass until t.stop?
+ t.kill
+ t.join # Thread#kill doesn't wait for the thread to end
+
+ finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ (finish - start).should < 9
+ end
+
+ it "can be interrupted when waiting for WRITABLE event" do
+ IOSpec.exhaust_write_buffer(@w)
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+
+ t = Thread.new do
+ @w.wait(IO::WRITABLE, 10)
+ end
+
+ Thread.pass until t.stop?
+ t.kill
+ t.join # Thread#kill doesn't wait for the thread to end
+
+ finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ (finish - start).should < 9
+ end
end
context "[timeout, mode] passed" do
diff --git a/spec/ruby/library/io-wait/wait_writable_spec.rb b/spec/ruby/library/io-wait/wait_writable_spec.rb
index 8c44780d39..8639dd717b 100644
--- a/spec/ruby/library/io-wait/wait_writable_spec.rb
+++ b/spec/ruby/library/io-wait/wait_writable_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative '../../fixtures/io'
ruby_version_is ''...'3.2' do
require 'io/wait'
@@ -17,4 +18,24 @@ describe "IO#wait_writable" do
# Represents one year and is larger than a 32-bit int
STDOUT.wait_writable(365 * 24 * 60 * 60).should == STDOUT
end
+
+ it "can be interrupted" do
+ rd, wr = IO.pipe
+ IOSpec.exhaust_write_buffer(wr)
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+
+ t = Thread.new do
+ wr.wait_writable(10)
+ end
+
+ Thread.pass until t.stop?
+ t.kill
+ t.join
+
+ finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ (finish - start).should < 9
+ ensure
+ rd.close unless rd.closed?
+ wr.close unless wr.closed?
+ end
end
diff --git a/spec/ruby/library/rbconfig/rbconfig_spec.rb b/spec/ruby/library/rbconfig/rbconfig_spec.rb
index b90cc90970..3e06219621 100644
--- a/spec/ruby/library/rbconfig/rbconfig_spec.rb
+++ b/spec/ruby/library/rbconfig/rbconfig_spec.rb
@@ -88,6 +88,30 @@ describe 'RbConfig::CONFIG' do
end
end
end
+
+ guard -> { %w[aarch64 arm64].include? RbConfig::CONFIG['host_cpu'] } do
+ it "['host_cpu'] returns CPU architecture properly for AArch64" do
+ platform_is :darwin do
+ RbConfig::CONFIG['host_cpu'].should == 'arm64'
+ end
+
+ platform_is_not :darwin do
+ RbConfig::CONFIG['host_cpu'].should == 'aarch64'
+ end
+ end
+ end
+
+ guard -> { platform_is(:linux) || platform_is(:darwin) } do
+ it "['host_os'] returns a proper OS name or platform" do
+ platform_is :darwin do
+ RbConfig::CONFIG['host_os'].should.match?(/darwin/)
+ end
+
+ platform_is :linux do
+ RbConfig::CONFIG['host_os'].should.match?(/linux/)
+ end
+ end
+ end
end
describe "RbConfig::TOPDIR" do
@@ -99,3 +123,34 @@ describe "RbConfig::TOPDIR" do
end
end
end
+
+describe "RUBY_PLATFORM" do
+ it "RUBY_PLATFORM contains a proper CPU architecture" do
+ RUBY_PLATFORM.should.include? RbConfig::CONFIG['host_cpu']
+ end
+
+ guard -> { platform_is(:linux) || platform_is(:darwin) } do
+ it "RUBY_PLATFORM contains OS name" do
+ # don't use RbConfig::CONFIG['host_os'] as far as it could be slightly different, e.g. linux-gnu
+ platform_is(:linux) do
+ RUBY_PLATFORM.should.include? 'linux'
+ end
+
+ platform_is(:darwin) do
+ RUBY_PLATFORM.should.include? 'darwin'
+ end
+ end
+ end
+end
+
+describe "RUBY_DESCRIPTION" do
+ guard_not -> { RUBY_ENGINE == "ruby" && !RbConfig::TOPDIR } do
+ it "contains version" do
+ RUBY_DESCRIPTION.should.include? RUBY_VERSION
+ end
+
+ it "contains RUBY_PLATFORM" do
+ RUBY_DESCRIPTION.should.include? RUBY_PLATFORM
+ end
+ end
+end
diff --git a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
index 17c846054d..df42c116fb 100644
--- a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
@@ -52,9 +52,19 @@ describe "Socket::BasicSocket#recv_nonblock" do
@s2.send("data", 0, @s1.getsockname)
IO.select([@s1], nil, nil, 2)
- buf = +"foo"
- @s1.recv_nonblock(5, 0, buf)
- buf.should == "data"
+ buffer = +"foo"
+ @s1.recv_nonblock(5, 0, buffer).should.equal?(buffer)
+ buffer.should == "data"
+ end
+
+ it "preserves the encoding of the given buffer" do
+ @s1.bind(Socket.pack_sockaddr_in(0, ip_address))
+ @s2.send("data", 0, @s1.getsockname)
+ IO.select([@s1], nil, nil, 2)
+
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @s1.recv_nonblock(5, 0, buffer)
+ buffer.encoding.should == Encoding::ISO_8859_1
end
it "does not block if there's no data available" do
diff --git a/spec/ruby/library/socket/basicsocket/recv_spec.rb b/spec/ruby/library/socket/basicsocket/recv_spec.rb
index 9fe8c52f9a..e82a357d3d 100644
--- a/spec/ruby/library/socket/basicsocket/recv_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recv_spec.rb
@@ -100,13 +100,29 @@ describe "BasicSocket#recv" do
socket.write("data")
client = @server.accept
- buf = +"foo"
+ buffer = +"foo"
begin
- client.recv(4, 0, buf)
+ client.recv(4, 0, buffer).should.equal?(buffer)
ensure
client.close
end
- buf.should == "data"
+ buffer.should == "data"
+
+ socket.close
+ end
+
+ it "preserves the encoding of the given buffer" do
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.write("data")
+
+ client = @server.accept
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ begin
+ client.recv(4, 0, buffer)
+ ensure
+ client.close
+ end
+ buffer.encoding.should == Encoding::ISO_8859_1
socket.close
end
diff --git a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
index 94f58ac49f..5596f91bb8 100644
--- a/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
+++ b/spec/ruby/library/socket/socket/recvfrom_nonblock_spec.rb
@@ -52,6 +52,27 @@ describe 'Socket#recvfrom_nonblock' do
end
end
+ it "allows an output buffer as third argument" do
+ @client.write('hello')
+
+ IO.select([@server])
+ buffer = +''
+ message, = @server.recvfrom_nonblock(5, 0, buffer)
+
+ message.should.equal?(buffer)
+ buffer.should == 'hello'
+ end
+
+ it "preserves the encoding of the given buffer" do
+ @client.write('hello')
+
+ IO.select([@server])
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @server.recvfrom_nonblock(5, 0, buffer)
+
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
+
describe 'the returned data' do
it 'is the same as the sent data' do
5.times do
diff --git a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
index 650a061221..b804099589 100644
--- a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
@@ -58,6 +58,15 @@ describe 'UDPSocket#recvfrom_nonblock' do
buffer.should == 'h'
end
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ IO.select([@server])
+ message, = @server.recvfrom_nonblock(1, 0, buffer)
+
+ message.should.equal?(buffer)
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
+
describe 'the returned Array' do
before do
IO.select([@server])
diff --git a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
index fedf74bb2f..d849fdc302 100644
--- a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
@@ -31,6 +31,29 @@ with_feature :unix_socket do
sock.close
end
+ it "allows an output buffer as third argument" do
+ buffer = +''
+
+ @client.send("foobar", 0)
+ sock = @server.accept
+ message, = sock.recvfrom(6, 0, buffer)
+ sock.close
+
+ message.should.equal?(buffer)
+ buffer.should == "foobar"
+ end
+
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+
+ @client.send("foobar", 0)
+ sock = @server.accept
+ sock.recvfrom(6, 0, buffer)
+ sock.close
+
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
+
it "uses different message options" do
@client.send("foobar", Socket::MSG_PEEK)
sock = @server.accept
diff --git a/spec/ruby/library/stringio/shared/read.rb b/spec/ruby/library/stringio/shared/read.rb
index e3840786d9..8ef6ec2734 100644
--- a/spec/ruby/library/stringio/shared/read.rb
+++ b/spec/ruby/library/stringio/shared/read.rb
@@ -11,10 +11,28 @@ describe :stringio_read, shared: true do
end
it "reads length bytes and writes them to the buffer String" do
- @io.send(@method, 7, buffer = +"")
+ @io.send(@method, 7, buffer = +"").should.equal?(buffer)
buffer.should == "example"
end
+ ruby_version_is ""..."3.4" do
+ it "does not preserve the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @io.send(@method, 7, buffer)
+
+ buffer.encoding.should_not == Encoding::ISO_8859_1
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @io.send(@method, 7, buffer)
+
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
+ end
+
it "tries to convert the passed buffer Object to a String using #to_str" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(buffer = +"")
diff --git a/spec/ruby/optional/capi/class_spec.rb b/spec/ruby/optional/capi/class_spec.rb
index d0a9913570..a231245ebe 100644
--- a/spec/ruby/optional/capi/class_spec.rb
+++ b/spec/ruby/optional/capi/class_spec.rb
@@ -487,4 +487,16 @@ describe "C-API Class function" do
@s.rb_class_real(0).should == 0
end
end
+
+ describe "rb_class_get_superclass" do
+ it "returns parent class for a provided class" do
+ a = Class.new
+ @s.rb_class_get_superclass(Class.new(a)).should == a
+ end
+
+ it "returns false when there is no parent class" do
+ @s.rb_class_get_superclass(BasicObject).should == false
+ @s.rb_class_get_superclass(Module.new).should == false
+ end
+ end
end
diff --git a/spec/ruby/optional/capi/data_spec.rb b/spec/ruby/optional/capi/data_spec.rb
index 18c769332e..d000eba6e3 100644
--- a/spec/ruby/optional/capi/data_spec.rb
+++ b/spec/ruby/optional/capi/data_spec.rb
@@ -1,52 +1,53 @@
require_relative 'spec_helper'
+ruby_version_is ""..."3.4" do
+ load_extension("data")
-load_extension("data")
-
-describe "CApiAllocSpecs (a class with an alloc func defined)" do
- it "calls the alloc func" do
- @s = CApiAllocSpecs.new
- @s.wrapped_data.should == 42 # not defined in initialize
- end
-end
-
-describe "CApiWrappedStruct" do
- before :each do
- @s = CApiWrappedStructSpecs.new
- end
-
- it "wraps with Data_Wrap_Struct and Data_Get_Struct returns data" do
- a = @s.wrap_struct(1024)
- @s.get_struct(a).should == 1024
+ describe "CApiAllocSpecs (a class with an alloc func defined)" do
+ it "calls the alloc func" do
+ @s = CApiAllocSpecs.new
+ @s.wrapped_data.should == 42 # not defined in initialize
+ end
end
- describe "RDATA()" do
- it "returns the struct data" do
- a = @s.wrap_struct(1024)
- @s.get_struct_rdata(a).should == 1024
+ describe "CApiWrappedStruct" do
+ before :each do
+ @s = CApiWrappedStructSpecs.new
end
- it "allows changing the wrapped struct" do
+ it "wraps with Data_Wrap_Struct and Data_Get_Struct returns data" do
a = @s.wrap_struct(1024)
- @s.change_struct(a, 100)
- @s.get_struct(a).should == 100
+ @s.get_struct(a).should == 1024
end
- it "raises a TypeError if the object does not wrap a struct" do
- -> { @s.get_struct(Object.new) }.should raise_error(TypeError)
+ describe "RDATA()" do
+ it "returns the struct data" do
+ a = @s.wrap_struct(1024)
+ @s.get_struct_rdata(a).should == 1024
+ end
+
+ it "allows changing the wrapped struct" do
+ a = @s.wrap_struct(1024)
+ @s.change_struct(a, 100)
+ @s.get_struct(a).should == 100
+ end
+
+ it "raises a TypeError if the object does not wrap a struct" do
+ -> { @s.get_struct(Object.new) }.should raise_error(TypeError)
+ end
end
- end
- describe "rb_check_type" do
- it "does not raise an exception when checking data objects" do
- a = @s.wrap_struct(1024)
- @s.rb_check_type(a, a).should == true
+ describe "rb_check_type" do
+ it "does not raise an exception when checking data objects" do
+ a = @s.wrap_struct(1024)
+ @s.rb_check_type(a, a).should == true
+ end
end
- end
- describe "DATA_PTR" do
- it "returns the struct data" do
- a = @s.wrap_struct(1024)
- @s.get_struct_data_ptr(a).should == 1024
+ describe "DATA_PTR" do
+ it "returns the struct data" do
+ a = @s.wrap_struct(1024)
+ @s.get_struct_data_ptr(a).should == 1024
+ end
end
end
end
diff --git a/spec/ruby/optional/capi/ext/class_spec.c b/spec/ruby/optional/capi/ext/class_spec.c
index f376534924..c13f02ecf2 100644
--- a/spec/ruby/optional/capi/ext/class_spec.c
+++ b/spec/ruby/optional/capi/ext/class_spec.c
@@ -79,6 +79,10 @@ static VALUE class_spec_rb_class_real(VALUE self, VALUE object) {
}
}
+static VALUE class_spec_rb_class_get_superclass(VALUE self, VALUE klass) {
+ return rb_class_get_superclass(klass);
+}
+
static VALUE class_spec_rb_class_superclass(VALUE self, VALUE klass) {
return rb_class_superclass(klass);
}
@@ -160,6 +164,7 @@ void Init_class_spec(void) {
rb_define_method(cls, "rb_class_new_instance_kw", class_spec_rb_class_new_instance_kw, 2);
#endif
rb_define_method(cls, "rb_class_real", class_spec_rb_class_real, 1);
+ rb_define_method(cls, "rb_class_get_superclass", class_spec_rb_class_get_superclass, 1);
rb_define_method(cls, "rb_class_superclass", class_spec_rb_class_superclass, 1);
rb_define_method(cls, "rb_cvar_defined", class_spec_cvar_defined, 2);
rb_define_method(cls, "rb_cvar_get", class_spec_cvar_get, 2);
diff --git a/spec/ruby/optional/capi/ext/data_spec.c b/spec/ruby/optional/capi/ext/data_spec.c
index ef069ef0ba..efefe37c3a 100644
--- a/spec/ruby/optional/capi/ext/data_spec.c
+++ b/spec/ruby/optional/capi/ext/data_spec.c
@@ -3,6 +3,7 @@
#include <string.h>
+#ifndef RUBY_VERSION_IS_3_4
#ifdef __cplusplus
extern "C" {
#endif
@@ -70,8 +71,10 @@ VALUE sws_rb_check_type(VALUE self, VALUE obj, VALUE other) {
rb_check_type(obj, TYPE(other));
return Qtrue;
}
+#endif
void Init_data_spec(void) {
+#ifndef RUBY_VERSION_IS_3_4
VALUE cls = rb_define_class("CApiAllocSpecs", rb_cObject);
rb_define_alloc_func(cls, sdaf_alloc_func);
rb_define_method(cls, "wrapped_data", sdaf_get_struct, 0);
@@ -82,6 +85,7 @@ void Init_data_spec(void) {
rb_define_method(cls, "get_struct_data_ptr", sws_get_struct_data_ptr, 1);
rb_define_method(cls, "change_struct", sws_change_struct, 2);
rb_define_method(cls, "rb_check_type", sws_rb_check_type, 2);
+#endif
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/gc_spec.c b/spec/ruby/optional/capi/ext/gc_spec.c
index 1392bc6ee6..2637ad27ac 100644
--- a/spec/ruby/optional/capi/ext/gc_spec.c
+++ b/spec/ruby/optional/capi/ext/gc_spec.c
@@ -16,6 +16,8 @@ VALUE registered_after_rb_global_variable_bignum;
VALUE registered_after_rb_global_variable_float;
VALUE rb_gc_register_address_outside_init;
+VALUE rb_gc_register_mark_object_not_referenced_float;
+
static VALUE registered_tagged_address(VALUE self) {
return registered_tagged_value;
}
@@ -90,6 +92,10 @@ static VALUE gc_spec_rb_gc_register_mark_object(VALUE self, VALUE obj) {
return Qnil;
}
+static VALUE gc_spec_rb_gc_register_mark_object_not_referenced_float(VALUE self) {
+ return rb_gc_register_mark_object_not_referenced_float;
+}
+
void Init_gc_spec(void) {
VALUE cls = rb_define_class("CApiGCSpecs", rb_cObject);
@@ -115,6 +121,9 @@ void Init_gc_spec(void) {
registered_after_rb_global_variable_float = DBL2NUM(6.28);
rb_global_variable(&registered_after_rb_global_variable_float);
+ rb_gc_register_mark_object_not_referenced_float = DBL2NUM(1.61);
+ rb_gc_register_mark_object(rb_gc_register_mark_object_not_referenced_float);
+
rb_define_method(cls, "registered_tagged_address", registered_tagged_address, 0);
rb_define_method(cls, "registered_reference_address", registered_reference_address, 0);
rb_define_method(cls, "registered_before_rb_gc_register_address", get_registered_before_rb_gc_register_address, 0);
@@ -131,6 +140,7 @@ void Init_gc_spec(void) {
rb_define_method(cls, "rb_gc", gc_spec_rb_gc, 0);
rb_define_method(cls, "rb_gc_adjust_memory_usage", gc_spec_rb_gc_adjust_memory_usage, 1);
rb_define_method(cls, "rb_gc_register_mark_object", gc_spec_rb_gc_register_mark_object, 1);
+ rb_define_method(cls, "rb_gc_register_mark_object_not_referenced_float", gc_spec_rb_gc_register_mark_object_not_referenced_float, 0);
rb_define_method(cls, "rb_gc_latest_gc_info", gc_spec_rb_gc_latest_gc_info, 1);
}
diff --git a/spec/ruby/optional/capi/ext/io_spec.c b/spec/ruby/optional/capi/ext/io_spec.c
index bcd3940e34..1b4d4fccce 100644
--- a/spec/ruby/optional/capi/ext/io_spec.c
+++ b/spec/ruby/optional/capi/ext/io_spec.c
@@ -157,7 +157,7 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) {
return ret ? Qtrue : Qfalse;
#else
- UNREACHABLE;
+ UNREACHABLE_RETURN(Qnil);
#endif
}
@@ -174,6 +174,10 @@ VALUE io_spec_rb_io_maybe_wait_writable(VALUE self, VALUE error, VALUE io, VALUE
#endif
#ifdef RUBY_VERSION_IS_3_1
+#ifdef SET_NON_BLOCKING_FAILS_ALWAYS
+NORETURN(VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE timeout, VALUE read_p));
+#endif
+
VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE timeout, VALUE read_p) {
int fd = io_spec_get_fd(io);
#ifndef SET_NON_BLOCKING_FAILS_ALWAYS
@@ -209,7 +213,7 @@ VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE
return INT2NUM(ret);
#else
- UNREACHABLE;
+ UNREACHABLE_RETURN(Qnil);
#endif
}
#endif
@@ -326,13 +330,15 @@ static VALUE io_spec_errno_set(VALUE self, VALUE val) {
}
VALUE io_spec_mode_sync_flag(VALUE self, VALUE io) {
+ int mode;
#ifdef RUBY_VERSION_IS_3_3
- if (rb_io_mode(io) & FMODE_SYNC) {
+ mode = rb_io_mode(io);
#else
rb_io_t *fp;
GetOpenFile(io, fp);
- if (fp->mode & FMODE_SYNC) {
+ mode = fp->mode;
#endif
+ if (mode & FMODE_SYNC) {
return Qtrue;
} else {
return Qfalse;
diff --git a/spec/ruby/optional/capi/ext/object_spec.c b/spec/ruby/optional/capi/ext/object_spec.c
index 8aa98cc5ce..aa60662e1e 100644
--- a/spec/ruby/optional/capi/ext/object_spec.c
+++ b/spec/ruby/optional/capi/ext/object_spec.c
@@ -390,22 +390,22 @@ static VALUE speced_allocator(VALUE klass) {
return instance;
}
-static VALUE define_alloc_func(VALUE self, VALUE klass) {
+static VALUE object_spec_rb_define_alloc_func(VALUE self, VALUE klass) {
rb_define_alloc_func(klass, speced_allocator);
return Qnil;
}
-static VALUE undef_alloc_func(VALUE self, VALUE klass) {
+static VALUE object_spec_rb_undef_alloc_func(VALUE self, VALUE klass) {
rb_undef_alloc_func(klass);
return Qnil;
}
-static VALUE speced_allocator_p(VALUE self, VALUE klass) {
+static VALUE object_spec_speced_allocator_p(VALUE self, VALUE klass) {
rb_alloc_func_t allocator = rb_get_alloc_func(klass);
return (allocator == speced_allocator) ? Qtrue : Qfalse;
}
-static VALUE custom_alloc_func_p(VALUE self, VALUE klass) {
+static VALUE object_spec_custom_alloc_func_p(VALUE self, VALUE klass) {
rb_alloc_func_t allocator = rb_get_alloc_func(klass);
return allocator ? Qtrue : Qfalse;
}
@@ -485,10 +485,10 @@ void Init_object_spec(void) {
rb_define_method(cls, "rb_ivar_defined", object_spec_rb_ivar_defined, 2);
rb_define_method(cls, "rb_copy_generic_ivar", object_spec_rb_copy_generic_ivar, 2);
rb_define_method(cls, "rb_free_generic_ivar", object_spec_rb_free_generic_ivar, 1);
- rb_define_method(cls, "rb_define_alloc_func", define_alloc_func, 1);
- rb_define_method(cls, "rb_undef_alloc_func", undef_alloc_func, 1);
- rb_define_method(cls, "speced_allocator?", speced_allocator_p, 1);
- rb_define_method(cls, "custom_alloc_func?", custom_alloc_func_p, 1);
+ rb_define_method(cls, "rb_define_alloc_func", object_spec_rb_define_alloc_func, 1);
+ rb_define_method(cls, "rb_undef_alloc_func", object_spec_rb_undef_alloc_func, 1);
+ rb_define_method(cls, "speced_allocator?", object_spec_speced_allocator_p, 1);
+ rb_define_method(cls, "custom_alloc_func?", object_spec_custom_alloc_func_p, 1);
rb_define_method(cls, "not_implemented_method", rb_f_notimplement, -1);
rb_define_method(cls, "rb_ivar_foreach", object_spec_rb_ivar_foreach, 1);
}
diff --git a/spec/ruby/optional/capi/ext/rubyspec.h b/spec/ruby/optional/capi/ext/rubyspec.h
index 09135774af..1df274ead1 100644
--- a/spec/ruby/optional/capi/ext/rubyspec.h
+++ b/spec/ruby/optional/capi/ext/rubyspec.h
@@ -46,6 +46,10 @@
(RUBY_VERSION_MAJOR == (major) && RUBY_VERSION_MINOR == (minor) && RUBY_VERSION_TEENY < (teeny)))
#define RUBY_VERSION_SINCE(major,minor,teeny) (!RUBY_VERSION_BEFORE(major, minor, teeny))
+#if RUBY_VERSION_SINCE(3, 4, 0)
+#define RUBY_VERSION_IS_3_4
+#endif
+
#if RUBY_VERSION_SINCE(3, 3, 0)
#define RUBY_VERSION_IS_3_3
#endif
diff --git a/spec/ruby/optional/capi/ext/typed_data_spec.c b/spec/ruby/optional/capi/ext/typed_data_spec.c
index 38889ecf5c..221f1c8ac4 100644
--- a/spec/ruby/optional/capi/ext/typed_data_spec.c
+++ b/spec/ruby/optional/capi/ext/typed_data_spec.c
@@ -106,6 +106,8 @@ VALUE sws_typed_wrap_struct(VALUE self, VALUE val) {
return TypedData_Wrap_Struct(rb_cObject, &sample_typed_wrapped_struct_data_type, bar);
}
+#undef RUBY_UNTYPED_DATA_WARNING
+#define RUBY_UNTYPED_DATA_WARNING 0
VALUE sws_untyped_wrap_struct(VALUE self, VALUE val) {
int* data = (int*) malloc(sizeof(int));
*data = FIX2INT(val);
diff --git a/spec/ruby/optional/capi/gc_spec.rb b/spec/ruby/optional/capi/gc_spec.rb
index aaced56483..d9661328ab 100644
--- a/spec/ruby/optional/capi/gc_spec.rb
+++ b/spec/ruby/optional/capi/gc_spec.rb
@@ -108,6 +108,10 @@ describe "CApiGCSpecs" do
it "can be called with an object" do
@f.rb_gc_register_mark_object(Object.new).should be_nil
end
+
+ it "keeps the value alive even if the value is not referenced by any Ruby object" do
+ @f.rb_gc_register_mark_object_not_referenced_float.should == 1.61
+ end
end
describe "rb_gc_latest_gc_info" do
diff --git a/spec/ruby/optional/capi/io_spec.rb b/spec/ruby/optional/capi/io_spec.rb
index 870abef3ea..bdec46f5e1 100644
--- a/spec/ruby/optional/capi/io_spec.rb
+++ b/spec/ruby/optional/capi/io_spec.rb
@@ -1,4 +1,5 @@
require_relative 'spec_helper'
+require_relative '../../fixtures/io'
load_extension('io')
@@ -279,6 +280,22 @@ describe "C-API IO function" do
it "raises an IOError if the IO is not initialized" do
-> { @o.rb_io_maybe_wait_writable(0, IO.allocate, nil) }.should raise_error(IOError, "uninitialized stream")
end
+
+ it "can be interrupted" do
+ IOSpec.exhaust_write_buffer(@w_io)
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+
+ t = Thread.new do
+ @o.rb_io_maybe_wait_writable(0, @w_io, 10)
+ end
+
+ Thread.pass until t.stop?
+ t.kill
+ t.join
+
+ finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ (finish - start).should < 9
+ end
end
end
@@ -355,6 +372,21 @@ describe "C-API IO function" do
thr.join
end
+ it "can be interrupted" do
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+
+ t = Thread.new do
+ @o.rb_io_maybe_wait_readable(0, @r_io, 10, false)
+ end
+
+ Thread.pass until t.stop?
+ t.kill
+ t.join
+
+ finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ (finish - start).should < 9
+ end
+
it "raises an IOError if the IO is closed" do
@r_io.close
-> { @o.rb_io_maybe_wait_readable(0, @r_io, nil, false) }.should raise_error(IOError, "closed stream")
@@ -438,6 +470,37 @@ describe "C-API IO function" do
it "raises an IOError if the IO is not initialized" do
-> { @o.rb_io_maybe_wait(0, IO.allocate, IO::WRITABLE, nil) }.should raise_error(IOError, "uninitialized stream")
end
+
+ it "can be interrupted when waiting for READABLE event" do
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+
+ t = Thread.new do
+ @o.rb_io_maybe_wait(0, @r_io, IO::READABLE, 10)
+ end
+
+ Thread.pass until t.stop?
+ t.kill
+ t.join
+
+ finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ (finish - start).should < 9
+ end
+
+ it "can be interrupted when waiting for WRITABLE event" do
+ IOSpec.exhaust_write_buffer(@w_io)
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+
+ t = Thread.new do
+ @o.rb_io_maybe_wait(0, @w_io, IO::WRITABLE, 10)
+ end
+
+ Thread.pass until t.stop?
+ t.kill
+ t.join
+
+ finish = Process.clock_gettime(Process::CLOCK_MONOTONIC)
+ (finish - start).should < 9
+ end
end
end
diff --git a/spec/ruby/optional/capi/rbasic_spec.rb b/spec/ruby/optional/capi/rbasic_spec.rb
index f3367e05ff..7b5b5b2fed 100644
--- a/spec/ruby/optional/capi/rbasic_spec.rb
+++ b/spec/ruby/optional/capi/rbasic_spec.rb
@@ -1,7 +1,9 @@
require_relative 'spec_helper'
require_relative 'shared/rbasic'
load_extension("rbasic")
-load_extension("data")
+ruby_version_is ""..."3.4" do
+ load_extension("data")
+end
load_extension("array")
describe "RBasic support for regular objects" do
@@ -12,33 +14,35 @@ describe "RBasic support for regular objects" do
it_should_behave_like :rbasic
end
-describe "RBasic support for RData" do
- before :all do
- @specs = CApiRBasicRDataSpecs.new
- @wrapping = CApiWrappedStructSpecs.new
- @data = -> { [@wrapping.wrap_struct(1024), @wrapping.wrap_struct(1025)] }
- end
- it_should_behave_like :rbasic
+ruby_version_is ""..."3.4" do
+ describe "RBasic support for RData" do
+ before :all do
+ @specs = CApiRBasicRDataSpecs.new
+ @wrapping = CApiWrappedStructSpecs.new
+ @data = -> { [@wrapping.wrap_struct(1024), @wrapping.wrap_struct(1025)] }
+ end
+ it_should_behave_like :rbasic
- it "supports user flags" do
- obj, _ = @data.call
- initial = @specs.get_flags(obj)
- @specs.set_flags(obj, 1 << 14 | 1 << 16 | initial).should == 1 << 14 | 1 << 16 | initial
- @specs.get_flags(obj).should == 1 << 14 | 1 << 16 | initial
- @specs.set_flags(obj, initial).should == initial
- end
+ it "supports user flags" do
+ obj, _ = @data.call
+ initial = @specs.get_flags(obj)
+ @specs.set_flags(obj, 1 << 14 | 1 << 16 | initial).should == 1 << 14 | 1 << 16 | initial
+ @specs.get_flags(obj).should == 1 << 14 | 1 << 16 | initial
+ @specs.set_flags(obj, initial).should == initial
+ end
- it "supports copying the flags from one object over to the other" do
- obj1, obj2 = @data.call
- initial = @specs.get_flags(obj1)
- @specs.get_flags(obj2).should == initial
- @specs.set_flags(obj1, 1 << 14 | 1 << 16 | initial)
- @specs.get_flags(obj1).should == 1 << 14 | 1 << 16 | initial
+ it "supports copying the flags from one object over to the other" do
+ obj1, obj2 = @data.call
+ initial = @specs.get_flags(obj1)
+ @specs.get_flags(obj2).should == initial
+ @specs.set_flags(obj1, 1 << 14 | 1 << 16 | initial)
+ @specs.get_flags(obj1).should == 1 << 14 | 1 << 16 | initial
- @specs.copy_flags(obj2, obj1)
- @specs.get_flags(obj2).should == 1 << 14 | 1 << 16 | initial
- @specs.set_flags(obj1, initial)
- @specs.copy_flags(obj2, obj1)
- @specs.get_flags(obj2).should == initial
+ @specs.copy_flags(obj2, obj1)
+ @specs.get_flags(obj2).should == 1 << 14 | 1 << 16 | initial
+ @specs.set_flags(obj1, initial)
+ @specs.copy_flags(obj2, obj1)
+ @specs.get_flags(obj2).should == initial
+ end
end
end
diff --git a/spec/ruby/shared/kernel/at_exit.rb b/spec/ruby/shared/kernel/at_exit.rb
index 16d41cb01c..29db79bb39 100644
--- a/spec/ruby/shared/kernel/at_exit.rb
+++ b/spec/ruby/shared/kernel/at_exit.rb
@@ -30,6 +30,12 @@ describe :kernel_at_exit, shared: true do
result.lines.should.include?("The exception matches: true (message=foo)\n")
end
+ it "gives access to an exception raised in a previous handler" do
+ code = "#{@method} { print '$!.message = ' + $!.message }; #{@method} { raise 'foo' }"
+ result = ruby_exe(code, args: "2>&1", exit_status: 1)
+ result.lines.should.include?("$!.message = foo")
+ end
+
it "both exceptions in a handler and in the main script are printed" do
code = "#{@method} { raise 'at_exit_error' }; raise 'main_script_error'"
result = ruby_exe(code, args: "2>&1", exit_status: 1)