summaryrefslogtreecommitdiff
path: root/spec/ruby/core
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby/core')
-rw-r--r--spec/ruby/core/array/drop_spec.rb2
-rw-r--r--spec/ruby/core/array/fetch_values_spec.rb11
-rw-r--r--spec/ruby/core/array/intersect_spec.rb92
-rw-r--r--spec/ruby/core/array/pack/a_spec.rb6
-rw-r--r--spec/ruby/core/array/pack/at_spec.rb2
-rw-r--r--spec/ruby/core/array/pack/b_spec.rb2
-rw-r--r--spec/ruby/core/array/pack/c_spec.rb2
-rw-r--r--spec/ruby/core/array/pack/comment_spec.rb2
-rw-r--r--spec/ruby/core/array/pack/h_spec.rb2
-rw-r--r--spec/ruby/core/array/pack/m_spec.rb2
-rw-r--r--spec/ruby/core/array/pack/shared/basic.rb21
-rw-r--r--spec/ruby/core/array/pack/shared/float.rb2
-rw-r--r--spec/ruby/core/array/pack/shared/integer.rb2
-rw-r--r--spec/ruby/core/array/pack/shared/string.rb2
-rw-r--r--spec/ruby/core/array/pack/u_spec.rb2
-rw-r--r--spec/ruby/core/array/pack/w_spec.rb2
-rw-r--r--spec/ruby/core/array/pack/x_spec.rb2
-rw-r--r--spec/ruby/core/array/pack/z_spec.rb4
-rw-r--r--spec/ruby/core/array/sample_spec.rb7
-rw-r--r--spec/ruby/core/array/shared/slice.rb184
-rw-r--r--spec/ruby/core/array/shared/unshift.rb2
-rw-r--r--spec/ruby/core/array/shuffle_spec.rb13
-rw-r--r--spec/ruby/core/basicobject/instance_eval_spec.rb19
-rw-r--r--spec/ruby/core/basicobject/singleton_method_added_spec.rb2
-rw-r--r--spec/ruby/core/binding/fixtures/irb.rb3
-rw-r--r--spec/ruby/core/binding/irb_spec.rb19
-rw-r--r--spec/ruby/core/binding/shared/clone.rb2
-rw-r--r--spec/ruby/core/builtin_constants/builtin_constants_spec.rb74
-rw-r--r--spec/ruby/core/class/attached_object_spec.rb40
-rw-r--r--spec/ruby/core/class/dup_spec.rb2
-rw-r--r--spec/ruby/core/class/inherited_spec.rb17
-rw-r--r--spec/ruby/core/class/new_spec.rb2
-rw-r--r--spec/ruby/core/class/subclasses_spec.rb126
-rw-r--r--spec/ruby/core/comparable/clamp_spec.rb149
-rw-r--r--spec/ruby/core/comparable/fixtures/classes.rb1
-rw-r--r--spec/ruby/core/complex/polar_spec.rb24
-rw-r--r--spec/ruby/core/complex/shared/rect.rb12
-rw-r--r--spec/ruby/core/data/constants_spec.rb20
-rw-r--r--spec/ruby/core/data/deconstruct_keys_spec.rb130
-rw-r--r--spec/ruby/core/data/deconstruct_spec.rb8
-rw-r--r--spec/ruby/core/data/define_spec.rb48
-rw-r--r--spec/ruby/core/data/eql_spec.rb63
-rw-r--r--spec/ruby/core/data/equal_value_spec.rb63
-rw-r--r--spec/ruby/core/data/fixtures/classes.rb31
-rw-r--r--spec/ruby/core/data/hash_spec.rb25
-rw-r--r--spec/ruby/core/data/initialize_spec.rb145
-rw-r--r--spec/ruby/core/data/inspect_spec.rb6
-rw-r--r--spec/ruby/core/data/members_spec.rb21
-rw-r--r--spec/ruby/core/data/shared/inspect.rb62
-rw-r--r--spec/ruby/core/data/to_h_spec.rb94
-rw-r--r--spec/ruby/core/data/to_s_spec.rb6
-rw-r--r--spec/ruby/core/data/with_spec.rb66
-rw-r--r--spec/ruby/core/dir/chdir_spec.rb106
-rw-r--r--spec/ruby/core/dir/close_spec.rb42
-rw-r--r--spec/ruby/core/dir/exist_spec.rb8
-rw-r--r--spec/ruby/core/dir/fchdir_spec.rb39
-rw-r--r--spec/ruby/core/dir/fixtures/common.rb10
-rw-r--r--spec/ruby/core/dir/for_fd_spec.rb79
-rw-r--r--spec/ruby/core/dir/glob_spec.rb81
-rw-r--r--spec/ruby/core/dir/home_spec.rb46
-rw-r--r--spec/ruby/core/dir/shared/delete.rb18
-rw-r--r--spec/ruby/core/dir/shared/glob.rb63
-rw-r--r--spec/ruby/core/encoding/compatible_spec.rb4
-rw-r--r--spec/ruby/core/encoding/converter/convert_spec.rb2
-rw-r--r--spec/ruby/core/encoding/converter/finish_spec.rb4
-rw-r--r--spec/ruby/core/encoding/converter/last_error_spec.rb2
-rw-r--r--spec/ruby/core/encoding/converter/new_spec.rb2
-rw-r--r--spec/ruby/core/encoding/converter/primitive_convert_spec.rb2
-rw-r--r--spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb2
-rw-r--r--spec/ruby/core/encoding/converter/putback_spec.rb2
-rw-r--r--spec/ruby/core/encoding/converter/search_convpath_spec.rb6
-rw-r--r--spec/ruby/core/encoding/find_spec.rb2
-rw-r--r--spec/ruby/core/encoding/fixtures/classes.rb2
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb2
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb2
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb2
-rw-r--r--spec/ruby/core/encoding/replicate_spec.rb4
-rw-r--r--spec/ruby/core/enumerable/collect_concat_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/collect_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/compact_spec.rb10
-rw-r--r--spec/ruby/core/enumerable/detect_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/each_cons_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/each_slice_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/entries_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/filter_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/find_all_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/find_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/fixtures/classes.rb7
-rw-r--r--spec/ruby/core/enumerable/flat_map_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/map_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/select_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/shared/inject.rb10
-rw-r--r--spec/ruby/core/enumerable/tally_spec.rb112
-rw-r--r--spec/ruby/core/enumerable/to_a_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/to_set_spec.rb33
-rw-r--r--spec/ruby/core/enumerator/each_with_index_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/each_with_object_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/enum_for_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/fixtures/classes.rb15
-rw-r--r--spec/ruby/core/enumerator/lazy/compact_spec.rb18
-rw-r--r--spec/ruby/core/enumerator/lazy/lazy_spec.rb9
-rw-r--r--spec/ruby/core/enumerator/product/each_spec.rb108
-rw-r--r--spec/ruby/core/enumerator/product/initialize_copy_spec.rb74
-rw-r--r--spec/ruby/core/enumerator/product/initialize_spec.rb44
-rw-r--r--spec/ruby/core/enumerator/product/inspect_spec.rb28
-rw-r--r--spec/ruby/core/enumerator/product/rewind_spec.rb90
-rw-r--r--spec/ruby/core/enumerator/product/size_spec.rb102
-rw-r--r--spec/ruby/core/enumerator/product_spec.rb138
-rw-r--r--spec/ruby/core/enumerator/shared/enum_for.rb57
-rw-r--r--spec/ruby/core/enumerator/shared/with_index.rb33
-rw-r--r--spec/ruby/core/enumerator/shared/with_object.rb42
-rw-r--r--spec/ruby/core/enumerator/to_enum_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/with_index_spec.rb2
-rw-r--r--spec/ruby/core/enumerator/with_object_spec.rb2
-rw-r--r--spec/ruby/core/env/clone_spec.rb10
-rw-r--r--spec/ruby/core/env/dup_spec.rb10
-rw-r--r--spec/ruby/core/env/element_reference_spec.rb2
-rw-r--r--spec/ruby/core/env/fetch_spec.rb2
-rw-r--r--spec/ruby/core/env/inspect_spec.rb2
-rw-r--r--spec/ruby/core/env/length_spec.rb2
-rw-r--r--spec/ruby/core/env/shared/update.rb10
-rw-r--r--spec/ruby/core/env/size_spec.rb2
-rw-r--r--spec/ruby/core/exception/detailed_message_spec.rb70
-rw-r--r--spec/ruby/core/exception/errno_spec.rb2
-rw-r--r--spec/ruby/core/exception/fixtures/common.rb3
-rw-r--r--spec/ruby/core/exception/frozen_error_spec.rb16
-rw-r--r--spec/ruby/core/exception/full_message_spec.rb78
-rw-r--r--spec/ruby/core/exception/no_method_error_spec.rb204
-rw-r--r--spec/ruby/core/exception/set_backtrace_spec.rb71
-rw-r--r--spec/ruby/core/exception/shared/set_backtrace.rb64
-rw-r--r--spec/ruby/core/exception/syntax_error_spec.rb36
-rw-r--r--spec/ruby/core/exception/system_call_error_spec.rb26
-rw-r--r--spec/ruby/core/fiber/alive_spec.rb44
-rw-r--r--spec/ruby/core/fiber/blocking_spec.rb22
-rw-r--r--spec/ruby/core/fiber/current_spec.rb50
-rw-r--r--spec/ruby/core/fiber/fixtures/classes.rb16
-rw-r--r--spec/ruby/core/fiber/fixtures/scheduler.rb35
-rw-r--r--spec/ruby/core/fiber/inspect_spec.rb1
-rw-r--r--spec/ruby/core/fiber/raise_spec.rb2
-rw-r--r--spec/ruby/core/fiber/resume_spec.rb15
-rw-r--r--spec/ruby/core/fiber/scheduler_spec.rb8
-rw-r--r--spec/ruby/core/fiber/set_scheduler_spec.rb8
-rw-r--r--spec/ruby/core/fiber/shared/resume.rb58
-rw-r--r--spec/ruby/core/fiber/shared/scheduler.rb51
-rw-r--r--spec/ruby/core/fiber/storage_spec.rb247
-rw-r--r--spec/ruby/core/fiber/transfer_spec.rb84
-rw-r--r--spec/ruby/core/file/basename_spec.rb26
-rw-r--r--spec/ruby/core/file/birthtime_spec.rb62
-rw-r--r--spec/ruby/core/file/constants/constants_spec.rb2
-rw-r--r--spec/ruby/core/file/dirname_spec.rb80
-rw-r--r--spec/ruby/core/file/empty_spec.rb6
-rw-r--r--spec/ruby/core/file/exist_spec.rb8
-rw-r--r--spec/ruby/core/file/flock_spec.rb32
-rw-r--r--spec/ruby/core/file/lchmod_spec.rb2
-rw-r--r--spec/ruby/core/file/path_spec.rb41
-rw-r--r--spec/ruby/core/file/setuid_spec.rb4
-rw-r--r--spec/ruby/core/file/shared/path.rb12
-rw-r--r--spec/ruby/core/file/socket_spec.rb32
-rw-r--r--spec/ruby/core/file/stat/birthtime_spec.rb34
-rw-r--r--spec/ruby/core/file/stat/rdev_major_spec.rb13
-rw-r--r--spec/ruby/core/file/stat/rdev_minor_spec.rb13
-rw-r--r--spec/ruby/core/file/zero_spec.rb6
-rw-r--r--spec/ruby/core/filetest/exist_spec.rb8
-rw-r--r--spec/ruby/core/filetest/socket_spec.rb4
-rw-r--r--spec/ruby/core/filetest/zero_spec.rb6
-rw-r--r--spec/ruby/core/float/comparison_spec.rb2
-rw-r--r--spec/ruby/core/float/round_spec.rb9
-rw-r--r--spec/ruby/core/gc/config_spec.rb83
-rw-r--r--spec/ruby/core/gc/measure_total_time_spec.rb24
-rw-r--r--spec/ruby/core/gc/total_time_spec.rb18
-rw-r--r--spec/ruby/core/hash/compact_spec.rb2
-rw-r--r--spec/ruby/core/hash/constructor_spec.rb11
-rw-r--r--spec/ruby/core/hash/except_spec.rb28
-rw-r--r--spec/ruby/core/hash/hash_spec.rb10
-rw-r--r--spec/ruby/core/hash/invert_spec.rb21
-rw-r--r--spec/ruby/core/hash/merge_spec.rb23
-rw-r--r--spec/ruby/core/hash/reject_spec.rb21
-rw-r--r--spec/ruby/core/hash/replace_spec.rb53
-rw-r--r--spec/ruby/core/hash/shared/select.rb21
-rw-r--r--spec/ruby/core/hash/shared/store.rb6
-rw-r--r--spec/ruby/core/hash/shared/to_s.rb6
-rw-r--r--spec/ruby/core/hash/shift_spec.rb41
-rw-r--r--spec/ruby/core/hash/slice_spec.rb21
-rw-r--r--spec/ruby/core/hash/to_h_spec.rb28
-rw-r--r--spec/ruby/core/hash/transform_keys_spec.rb45
-rw-r--r--spec/ruby/core/hash/transform_values_spec.rb21
-rw-r--r--spec/ruby/core/integer/ceildiv_spec.rb26
-rw-r--r--spec/ruby/core/integer/constants_spec.rb36
-rw-r--r--spec/ruby/core/integer/divide_spec.rb37
-rw-r--r--spec/ruby/core/integer/left_shift_spec.rb6
-rw-r--r--spec/ruby/core/integer/minus_spec.rb17
-rw-r--r--spec/ruby/core/integer/plus_spec.rb17
-rw-r--r--spec/ruby/core/integer/right_shift_spec.rb6
-rw-r--r--spec/ruby/core/integer/shared/modulo.rb46
-rw-r--r--spec/ruby/core/integer/try_convert_spec.rb76
-rw-r--r--spec/ruby/core/io/binread_spec.rb2
-rw-r--r--spec/ruby/core/io/buffer/empty_spec.rb29
-rw-r--r--spec/ruby/core/io/buffer/external_spec.rb108
-rw-r--r--spec/ruby/core/io/buffer/free_spec.rb104
-rw-r--r--spec/ruby/core/io/buffer/initialize_spec.rb103
-rw-r--r--spec/ruby/core/io/buffer/internal_spec.rb108
-rw-r--r--spec/ruby/core/io/buffer/locked_spec.rb75
-rw-r--r--spec/ruby/core/io/buffer/mapped_spec.rb108
-rw-r--r--spec/ruby/core/io/buffer/null_spec.rb29
-rw-r--r--spec/ruby/core/io/buffer/private_spec.rb111
-rw-r--r--spec/ruby/core/io/buffer/readonly_spec.rb143
-rw-r--r--spec/ruby/core/io/buffer/resize_spec.rb155
-rw-r--r--spec/ruby/core/io/buffer/shared/null_and_empty.rb59
-rw-r--r--spec/ruby/core/io/buffer/shared_spec.rb117
-rw-r--r--spec/ruby/core/io/buffer/transfer_spec.rb118
-rw-r--r--spec/ruby/core/io/buffer/valid_spec.rb110
-rw-r--r--spec/ruby/core/io/external_encoding_spec.rb10
-rw-r--r--spec/ruby/core/io/foreach_spec.rb46
-rw-r--r--spec/ruby/core/io/internal_encoding_spec.rb10
-rw-r--r--spec/ruby/core/io/path_spec.rb14
-rw-r--r--spec/ruby/core/io/popen_spec.rb16
-rw-r--r--spec/ruby/core/io/read_spec.rb110
-rw-r--r--spec/ruby/core/io/readlines_spec.rb62
-rw-r--r--spec/ruby/core/io/readpartial_spec.rb17
-rw-r--r--spec/ruby/core/io/shared/each.rb18
-rw-r--r--spec/ruby/core/io/shared/gets_ascii.rb2
-rw-r--r--spec/ruby/core/io/shared/new.rb23
-rw-r--r--spec/ruby/core/io/sysread_spec.rb6
-rw-r--r--spec/ruby/core/io/write_nonblock_spec.rb2
-rw-r--r--spec/ruby/core/io/write_spec.rb2
-rw-r--r--spec/ruby/core/kernel/Float_spec.rb154
-rw-r--r--spec/ruby/core/kernel/Rational_spec.rb234
-rw-r--r--spec/ruby/core/kernel/autoload_spec.rb5
-rw-r--r--spec/ruby/core/kernel/block_given_spec.rb5
-rw-r--r--spec/ruby/core/kernel/caller_locations_spec.rb14
-rw-r--r--spec/ruby/core/kernel/caller_spec.rb25
-rw-r--r--spec/ruby/core/kernel/eval_spec.rb85
-rw-r--r--spec/ruby/core/kernel/fixtures/classes.rb54
-rw-r--r--spec/ruby/core/kernel/inspect_spec.rb59
-rw-r--r--spec/ruby/core/kernel/is_a_spec.rb2
-rw-r--r--spec/ruby/core/kernel/kind_of_spec.rb2
-rw-r--r--spec/ruby/core/kernel/match_spec.rb27
-rw-r--r--spec/ruby/core/kernel/not_match_spec.rb14
-rw-r--r--spec/ruby/core/kernel/open_spec.rb96
-rw-r--r--spec/ruby/core/kernel/raise_spec.rb221
-rw-r--r--spec/ruby/core/kernel/require_spec.rb16
-rw-r--r--spec/ruby/core/kernel/shared/load.rb48
-rw-r--r--spec/ruby/core/kernel/shared/require.rb34
-rw-r--r--spec/ruby/core/kernel/shared/sprintf.rb36
-rw-r--r--spec/ruby/core/kernel/singleton_method_spec.rb46
-rw-r--r--spec/ruby/core/kernel/sleep_spec.rb35
-rw-r--r--spec/ruby/core/kernel/sprintf_spec.rb36
-rw-r--r--spec/ruby/core/kernel/taint_spec.rb23
-rw-r--r--spec/ruby/core/kernel/tainted_spec.rb25
-rw-r--r--spec/ruby/core/kernel/trust_spec.rb24
-rw-r--r--spec/ruby/core/kernel/untaint_spec.rb24
-rw-r--r--spec/ruby/core/kernel/untrust_spec.rb23
-rw-r--r--spec/ruby/core/kernel/untrusted_spec.rb24
-rw-r--r--spec/ruby/core/kernel/warn_spec.rb6
-rw-r--r--spec/ruby/core/main/private_spec.rb12
-rw-r--r--spec/ruby/core/main/public_spec.rb12
-rw-r--r--spec/ruby/core/main/using_spec.rb10
-rw-r--r--spec/ruby/core/marshal/dump_spec.rb290
-rw-r--r--spec/ruby/core/marshal/fixtures/marshal_data.rb65
-rw-r--r--spec/ruby/core/marshal/shared/load.rb526
-rw-r--r--spec/ruby/core/matchdata/bytebegin_spec.rb132
-rw-r--r--spec/ruby/core/matchdata/byteend_spec.rb104
-rw-r--r--spec/ruby/core/matchdata/byteoffset_spec.rb132
-rw-r--r--spec/ruby/core/matchdata/deconstruct_keys_spec.rb86
-rw-r--r--spec/ruby/core/matchdata/deconstruct_spec.rb4
-rw-r--r--spec/ruby/core/matchdata/match_length_spec.rb46
-rw-r--r--spec/ruby/core/matchdata/match_spec.rb46
-rw-r--r--spec/ruby/core/matchdata/offset_spec.rb106
-rw-r--r--spec/ruby/core/math/atanh_spec.rb4
-rw-r--r--spec/ruby/core/math/expm1_spec.rb37
-rw-r--r--spec/ruby/core/math/fixtures/common.rb3
-rw-r--r--spec/ruby/core/math/lgamma_spec.rb11
-rw-r--r--spec/ruby/core/math/log1p_spec.rb49
-rw-r--r--spec/ruby/core/math/shared/atanh.rb44
-rw-r--r--spec/ruby/core/method/owner_spec.rb6
-rw-r--r--spec/ruby/core/method/parameters_spec.rb53
-rw-r--r--spec/ruby/core/method/private_spec.rb25
-rw-r--r--spec/ruby/core/method/protected_spec.rb25
-rw-r--r--spec/ruby/core/method/public_spec.rb25
-rw-r--r--spec/ruby/core/method/shared/dup.rb2
-rw-r--r--spec/ruby/core/method/source_location_spec.rb16
-rw-r--r--spec/ruby/core/method/unbind_spec.rb12
-rw-r--r--spec/ruby/core/module/ancestors_spec.rb15
-rw-r--r--spec/ruby/core/module/autoload_spec.rb161
-rw-r--r--spec/ruby/core/module/const_added_spec.rb293
-rw-r--r--spec/ruby/core/module/const_defined_spec.rb2
-rw-r--r--spec/ruby/core/module/const_get_spec.rb24
-rw-r--r--spec/ruby/core/module/const_set_spec.rb13
-rw-r--r--spec/ruby/core/module/const_source_location_spec.rb34
-rw-r--r--spec/ruby/core/module/define_method_spec.rb3
-rw-r--r--spec/ruby/core/module/fixtures/classes.rb2
-rw-r--r--spec/ruby/core/module/fixtures/set_temporary_name.rb4
-rw-r--r--spec/ruby/core/module/include_spec.rb46
-rw-r--r--spec/ruby/core/module/instance_method_spec.rb5
-rw-r--r--spec/ruby/core/module/module_function_spec.rb37
-rw-r--r--spec/ruby/core/module/name_spec.rb66
-rw-r--r--spec/ruby/core/module/prepend_spec.rb85
-rw-r--r--spec/ruby/core/module/private_spec.rb26
-rw-r--r--spec/ruby/core/module/protected_spec.rb26
-rw-r--r--spec/ruby/core/module/public_spec.rb26
-rw-r--r--spec/ruby/core/module/refine_spec.rb339
-rw-r--r--spec/ruby/core/module/refinements_spec.rb56
-rw-r--r--spec/ruby/core/module/remove_const_spec.rb2
-rw-r--r--spec/ruby/core/module/ruby2_keywords_spec.rb171
-rw-r--r--spec/ruby/core/module/set_temporary_name_spec.rb85
-rw-r--r--spec/ruby/core/module/to_s_spec.rb2
-rw-r--r--spec/ruby/core/module/undefined_instance_methods_spec.rb32
-rw-r--r--spec/ruby/core/module/used_refinements_spec.rb110
-rw-r--r--spec/ruby/core/numeric/shared/imag.rb6
-rw-r--r--spec/ruby/core/numeric/shared/rect.rb26
-rw-r--r--spec/ruby/core/objectspace/_id2ref_spec.rb87
-rw-r--r--spec/ruby/core/objectspace/define_finalizer_spec.rb30
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/clear_spec.rb27
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/delete_spec.rb13
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb83
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb59
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/fixtures/classes.rb5
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb14
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb4
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/key_spec.rb11
-rw-r--r--spec/ruby/core/proc/clone_spec.rb15
-rw-r--r--spec/ruby/core/proc/dup_spec.rb15
-rw-r--r--spec/ruby/core/proc/element_reference_spec.rb2
-rw-r--r--spec/ruby/core/proc/fixtures/common.rb23
-rw-r--r--spec/ruby/core/proc/parameters_spec.rb78
-rw-r--r--spec/ruby/core/proc/ruby2_keywords_spec.rb14
-rw-r--r--spec/ruby/core/proc/shared/dup.rb10
-rw-r--r--spec/ruby/core/proc/source_location_spec.rb51
-rw-r--r--spec/ruby/core/process/_fork_spec.rb30
-rw-r--r--spec/ruby/core/process/fixtures/clocks.rb2
-rw-r--r--spec/ruby/core/process/gid_spec.rb4
-rw-r--r--spec/ruby/core/process/setrlimit_spec.rb28
-rw-r--r--spec/ruby/core/process/status/bit_and_spec.rb49
-rw-r--r--spec/ruby/core/process/status/right_shift_spec.rb47
-rw-r--r--spec/ruby/core/process/tms/cstime_spec.rb17
-rw-r--r--spec/ruby/core/process/tms/cutime_spec.rb17
-rw-r--r--spec/ruby/core/process/tms/stime_spec.rb17
-rw-r--r--spec/ruby/core/process/tms/utime_spec.rb17
-rw-r--r--spec/ruby/core/queue/deq_spec.rb4
-rw-r--r--spec/ruby/core/queue/initialize_spec.rb64
-rw-r--r--spec/ruby/core/queue/pop_spec.rb4
-rw-r--r--spec/ruby/core/queue/shift_spec.rb4
-rw-r--r--spec/ruby/core/random/bytes_spec.rb2
-rw-r--r--spec/ruby/core/random/default_spec.rb32
-rw-r--r--spec/ruby/core/random/new_spec.rb2
-rw-r--r--spec/ruby/core/range/case_compare_spec.rb2
-rw-r--r--spec/ruby/core/range/cover_spec.rb2
-rw-r--r--spec/ruby/core/range/each_spec.rb35
-rw-r--r--spec/ruby/core/range/include_spec.rb2
-rw-r--r--spec/ruby/core/range/last_spec.rb6
-rw-r--r--spec/ruby/core/range/max_spec.rb20
-rw-r--r--spec/ruby/core/range/member_spec.rb2
-rw-r--r--spec/ruby/core/range/overlap_spec.rb89
-rw-r--r--spec/ruby/core/range/reverse_each_spec.rb2
-rw-r--r--spec/ruby/core/range/shared/cover.rb2
-rw-r--r--spec/ruby/core/range/shared/cover_and_include.rb17
-rw-r--r--spec/ruby/core/range/shared/include.rb2
-rw-r--r--spec/ruby/core/range/size_spec.rb11
-rw-r--r--spec/ruby/core/range/step_spec.rb58
-rw-r--r--spec/ruby/core/range/to_set_spec.rb55
-rw-r--r--spec/ruby/core/rational/abs_spec.rb2
-rw-r--r--spec/ruby/core/rational/ceil_spec.rb43
-rw-r--r--spec/ruby/core/rational/comparison_spec.rb84
-rw-r--r--spec/ruby/core/rational/denominator_spec.rb12
-rw-r--r--spec/ruby/core/rational/div_spec.rb46
-rw-r--r--spec/ruby/core/rational/divide_spec.rb66
-rw-r--r--spec/ruby/core/rational/divmod_spec.rb36
-rw-r--r--spec/ruby/core/rational/equal_value_spec.rb31
-rw-r--r--spec/ruby/core/rational/exponent_spec.rb234
-rw-r--r--spec/ruby/core/rational/fdiv_spec.rb3
-rw-r--r--spec/ruby/core/rational/fixtures/rational.rb14
-rw-r--r--spec/ruby/core/rational/floor_spec.rb43
-rw-r--r--spec/ruby/core/rational/hash_spec.rb7
-rw-r--r--spec/ruby/core/rational/inspect_spec.rb12
-rw-r--r--spec/ruby/core/rational/magnitude_spec.rb2
-rw-r--r--spec/ruby/core/rational/minus_spec.rb2
-rw-r--r--spec/ruby/core/rational/modulo_spec.rb41
-rw-r--r--spec/ruby/core/rational/multiply_spec.rb57
-rw-r--r--spec/ruby/core/rational/numerator_spec.rb8
-rw-r--r--spec/ruby/core/rational/plus_spec.rb43
-rw-r--r--spec/ruby/core/rational/quo_spec.rb23
-rw-r--r--spec/ruby/core/rational/remainder_spec.rb3
-rw-r--r--spec/ruby/core/rational/round_spec.rb104
-rw-r--r--spec/ruby/core/rational/shared/abs.rb11
-rw-r--r--spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb11
-rw-r--r--spec/ruby/core/rational/to_f_spec.rb14
-rw-r--r--spec/ruby/core/rational/to_i_spec.rb10
-rw-r--r--spec/ruby/core/rational/to_r_spec.rb9
-rw-r--r--spec/ruby/core/rational/to_s_spec.rb12
-rw-r--r--spec/ruby/core/rational/truncate_spec.rb69
-rw-r--r--spec/ruby/core/refinement/append_features_spec.rb24
-rw-r--r--spec/ruby/core/refinement/extend_object_spec.rb28
-rw-r--r--spec/ruby/core/refinement/import_methods_spec.rb354
-rw-r--r--spec/ruby/core/refinement/include_spec.rb26
-rw-r--r--spec/ruby/core/refinement/prepend_features_spec.rb24
-rw-r--r--spec/ruby/core/refinement/prepend_spec.rb26
-rw-r--r--spec/ruby/core/refinement/refined_class_spec.rb2
-rw-r--r--spec/ruby/core/regexp/compile_spec.rb2
-rw-r--r--spec/ruby/core/regexp/linear_time_spec.rb42
-rw-r--r--spec/ruby/core/regexp/new_spec.rb2
-rw-r--r--spec/ruby/core/regexp/shared/new.rb410
-rw-r--r--spec/ruby/core/regexp/shared/quote.rb2
-rw-r--r--spec/ruby/core/regexp/timeout_spec.rb48
-rw-r--r--spec/ruby/core/set/add_spec.rb34
-rw-r--r--spec/ruby/core/set/append_spec.rb6
-rw-r--r--spec/ruby/core/set/case_compare_spec.rb11
-rw-r--r--spec/ruby/core/set/case_equality_spec.rb6
-rw-r--r--spec/ruby/core/set/classify_spec.rb26
-rw-r--r--spec/ruby/core/set/clear_spec.rb16
-rw-r--r--spec/ruby/core/set/collect_spec.rb6
-rw-r--r--spec/ruby/core/set/compare_by_identity_spec.rb153
-rw-r--r--spec/ruby/core/set/comparison_spec.rb26
-rw-r--r--spec/ruby/core/set/constructor_spec.rb14
-rw-r--r--spec/ruby/core/set/delete_if_spec.rb37
-rw-r--r--spec/ruby/core/set/delete_spec.rb36
-rw-r--r--spec/ruby/core/set/difference_spec.rb6
-rw-r--r--spec/ruby/core/set/disjoint_spec.rb22
-rw-r--r--spec/ruby/core/set/divide_spec.rb68
-rw-r--r--spec/ruby/core/set/each_spec.rb26
-rw-r--r--spec/ruby/core/set/empty_spec.rb9
-rw-r--r--spec/ruby/core/set/enumerable/to_set_spec.rb12
-rw-r--r--spec/ruby/core/set/eql_spec.rb14
-rw-r--r--spec/ruby/core/set/equal_value_spec.rb34
-rw-r--r--spec/ruby/core/set/exclusion_spec.rb17
-rw-r--r--spec/ruby/core/set/filter_spec.rb6
-rw-r--r--spec/ruby/core/set/fixtures/set_like.rb30
-rw-r--r--spec/ruby/core/set/flatten_merge_spec.rb24
-rw-r--r--spec/ruby/core/set/flatten_spec.rb59
-rw-r--r--spec/ruby/core/set/hash_spec.rb19
-rw-r--r--spec/ruby/core/set/include_spec.rb6
-rw-r--r--spec/ruby/core/set/initialize_clone_spec.rb15
-rw-r--r--spec/ruby/core/set/initialize_spec.rb72
-rw-r--r--spec/ruby/core/set/inspect_spec.rb6
-rw-r--r--spec/ruby/core/set/intersect_spec.rb22
-rw-r--r--spec/ruby/core/set/intersection_spec.rb10
-rw-r--r--spec/ruby/core/set/join_spec.rb30
-rw-r--r--spec/ruby/core/set/keep_if_spec.rb37
-rw-r--r--spec/ruby/core/set/length_spec.rb6
-rw-r--r--spec/ruby/core/set/map_spec.rb6
-rw-r--r--spec/ruby/core/set/member_spec.rb6
-rw-r--r--spec/ruby/core/set/merge_spec.rb37
-rw-r--r--spec/ruby/core/set/minus_spec.rb6
-rw-r--r--spec/ruby/core/set/plus_spec.rb6
-rw-r--r--spec/ruby/core/set/pretty_print_cycle_spec.rb14
-rw-r--r--spec/ruby/core/set/proper_subset_spec.rb45
-rw-r--r--spec/ruby/core/set/proper_superset_spec.rb42
-rw-r--r--spec/ruby/core/set/reject_spec.rb41
-rw-r--r--spec/ruby/core/set/replace_spec.rb24
-rw-r--r--spec/ruby/core/set/select_spec.rb6
-rw-r--r--spec/ruby/core/set/set_spec.rb10
-rw-r--r--spec/ruby/core/set/shared/add.rb14
-rw-r--r--spec/ruby/core/set/shared/collect.rb20
-rw-r--r--spec/ruby/core/set/shared/difference.rb15
-rw-r--r--spec/ruby/core/set/shared/include.rb29
-rw-r--r--spec/ruby/core/set/shared/inspect.rb45
-rw-r--r--spec/ruby/core/set/shared/intersection.rb15
-rw-r--r--spec/ruby/core/set/shared/length.rb6
-rw-r--r--spec/ruby/core/set/shared/select.rb41
-rw-r--r--spec/ruby/core/set/shared/union.rb15
-rw-r--r--spec/ruby/core/set/size_spec.rb6
-rw-r--r--spec/ruby/core/set/sortedset/sortedset_spec.rb13
-rw-r--r--spec/ruby/core/set/subset_spec.rb45
-rw-r--r--spec/ruby/core/set/subtract_spec.rb16
-rw-r--r--spec/ruby/core/set/superset_spec.rb42
-rw-r--r--spec/ruby/core/set/to_a_spec.rb7
-rw-r--r--spec/ruby/core/set/to_s_spec.rb11
-rw-r--r--spec/ruby/core/set/union_spec.rb10
-rw-r--r--spec/ruby/core/sizedqueue/append_spec.rb4
-rw-r--r--spec/ruby/core/sizedqueue/deq_spec.rb4
-rw-r--r--spec/ruby/core/sizedqueue/enq_spec.rb4
-rw-r--r--spec/ruby/core/sizedqueue/pop_spec.rb4
-rw-r--r--spec/ruby/core/sizedqueue/push_spec.rb4
-rw-r--r--spec/ruby/core/sizedqueue/shift_spec.rb4
-rw-r--r--spec/ruby/core/string/append_as_bytes_spec.rb12
-rw-r--r--spec/ruby/core/string/byteindex_spec.rb470
-rw-r--r--spec/ruby/core/string/byterindex_spec.rb568
-rw-r--r--spec/ruby/core/string/byteslice_spec.rb2
-rw-r--r--spec/ruby/core/string/bytesplice_spec.rb204
-rw-r--r--spec/ruby/core/string/chilled_string_spec.rb12
-rw-r--r--spec/ruby/core/string/codepoints_spec.rb2
-rw-r--r--spec/ruby/core/string/count_spec.rb2
-rw-r--r--spec/ruby/core/string/dedup_spec.rb4
-rw-r--r--spec/ruby/core/string/lstrip_spec.rb14
-rw-r--r--spec/ruby/core/string/modulo_spec.rb16
-rw-r--r--spec/ruby/core/string/rindex_spec.rb4
-rw-r--r--spec/ruby/core/string/rstrip_spec.rb28
-rw-r--r--spec/ruby/core/string/scan_spec.rb20
-rw-r--r--spec/ruby/core/string/shared/codepoints.rb2
-rw-r--r--spec/ruby/core/string/shared/dedup.rb5
-rw-r--r--spec/ruby/core/string/shared/each_codepoint_without_block.rb2
-rw-r--r--spec/ruby/core/string/shared/eql.rb2
-rw-r--r--spec/ruby/core/string/shared/slice.rb17
-rw-r--r--spec/ruby/core/string/shared/succ.rb2
-rw-r--r--spec/ruby/core/string/squeeze_spec.rb2
-rw-r--r--spec/ruby/core/string/sub_spec.rb16
-rw-r--r--spec/ruby/core/string/swapcase_spec.rb6
-rw-r--r--spec/ruby/core/string/to_c_spec.rb36
-rw-r--r--spec/ruby/core/string/to_f_spec.rb106
-rw-r--r--spec/ruby/core/string/to_i_spec.rb2
-rw-r--r--spec/ruby/core/string/to_r_spec.rb4
-rw-r--r--spec/ruby/core/string/unpack/a_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/at_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/b_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/c_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/comment_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/h_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/m_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/shared/basic.rb17
-rw-r--r--spec/ruby/core/string/unpack/shared/float.rb2
-rw-r--r--spec/ruby/core/string/unpack/shared/integer.rb2
-rw-r--r--spec/ruby/core/string/unpack/u_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/w_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/x_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/z_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack1_spec.rb47
-rw-r--r--spec/ruby/core/string/unpack_spec.rb32
-rw-r--r--spec/ruby/core/string/uplus_spec.rb44
-rw-r--r--spec/ruby/core/struct/constants_spec.rb16
-rw-r--r--spec/ruby/core/struct/deconstruct_keys_spec.rb54
-rw-r--r--spec/ruby/core/struct/element_set_spec.rb7
-rw-r--r--spec/ruby/core/struct/fixtures/classes.rb2
-rw-r--r--spec/ruby/core/struct/initialize_spec.rb20
-rw-r--r--spec/ruby/core/struct/keyword_init_spec.rb61
-rw-r--r--spec/ruby/core/struct/members_spec.rb12
-rw-r--r--spec/ruby/core/struct/new_spec.rb72
-rw-r--r--spec/ruby/core/struct/struct_spec.rb7
-rw-r--r--spec/ruby/core/symbol/inspect_spec.rb15
-rw-r--r--spec/ruby/core/symbol/shared/id2name.rb14
-rw-r--r--spec/ruby/core/symbol/shared/slice.rb2
-rw-r--r--spec/ruby/core/symbol/to_proc_spec.rb44
-rw-r--r--spec/ruby/core/thread/abort_on_exception_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace/limit_spec.rb18
-rw-r--r--spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb17
-rw-r--r--spec/ruby/core/thread/each_caller_location_spec.rb70
-rw-r--r--spec/ruby/core/thread/fixtures/classes.rb25
-rw-r--r--spec/ruby/core/thread/native_thread_id_spec.rb52
-rw-r--r--spec/ruby/core/thread/raise_spec.rb3
-rw-r--r--spec/ruby/core/time/_dump_spec.rb2
-rw-r--r--spec/ruby/core/time/_load_spec.rb2
-rw-r--r--spec/ruby/core/time/at_spec.rb36
-rw-r--r--spec/ruby/core/time/deconstruct_keys_spec.rb80
-rw-r--r--spec/ruby/core/time/getlocal_spec.rb39
-rw-r--r--spec/ruby/core/time/localtime_spec.rb51
-rw-r--r--spec/ruby/core/time/minus_spec.rb2
-rw-r--r--spec/ruby/core/time/new_spec.rb629
-rw-r--r--spec/ruby/core/time/now_spec.rb184
-rw-r--r--spec/ruby/core/time/shared/time_params.rb4
-rw-r--r--spec/ruby/core/time/strftime_spec.rb62
-rw-r--r--spec/ruby/core/time/utc_spec.rb26
-rw-r--r--spec/ruby/core/time/zone_spec.rb22
-rw-r--r--spec/ruby/core/tracepoint/allow_reentry_spec.rb44
-rw-r--r--spec/ruby/core/tracepoint/enable_spec.rb55
-rw-r--r--spec/ruby/core/unboundmethod/equal_value_spec.rb39
-rw-r--r--spec/ruby/core/unboundmethod/owner_spec.rb6
-rw-r--r--spec/ruby/core/unboundmethod/private_spec.rb25
-rw-r--r--spec/ruby/core/unboundmethod/protected_spec.rb25
-rw-r--r--spec/ruby/core/unboundmethod/public_spec.rb25
-rw-r--r--spec/ruby/core/unboundmethod/shared/dup.rb2
-rw-r--r--spec/ruby/core/unboundmethod/shared/to_s.rb15
-rw-r--r--spec/ruby/core/unboundmethod/source_location_spec.rb18
-rw-r--r--spec/ruby/core/warning/categories_spec.rb12
-rw-r--r--spec/ruby/core/warning/warn_spec.rb28
562 files changed, 13978 insertions, 6813 deletions
diff --git a/spec/ruby/core/array/drop_spec.rb b/spec/ruby/core/array/drop_spec.rb
index 0ea748e47d..5926c291b8 100644
--- a/spec/ruby/core/array/drop_spec.rb
+++ b/spec/ruby/core/array/drop_spec.rb
@@ -7,7 +7,7 @@ describe "Array#drop" do
end
it "raises an ArgumentError if the number of elements specified is negative" do
- -> { [1, 2].drop(-3) }.should raise_error(ArgumentError)
+ -> { [1, 2].drop(-3) }.should raise_error(ArgumentError)
end
it "returns an empty Array if all elements are dropped" do
diff --git a/spec/ruby/core/array/fetch_values_spec.rb b/spec/ruby/core/array/fetch_values_spec.rb
index 559b6c2b2f..cf377b3b71 100644
--- a/spec/ruby/core/array/fetch_values_spec.rb
+++ b/spec/ruby/core/array/fetch_values_spec.rb
@@ -11,6 +11,7 @@ describe "Array#fetch_values" do
it "returns the values for indexes" do
@array.fetch_values(0).should == [:a]
@array.fetch_values(0, 2).should == [:a, :c]
+ @array.fetch_values(-1).should == [:c]
end
it "returns the values for indexes ordered in the order of the requested indexes" do
@@ -20,7 +21,7 @@ describe "Array#fetch_values" do
describe "with unmatched indexes" do
it "raises a index error if no block is provided" do
- -> { @array.fetch_values(0, 1, 44) }.should raise_error(IndexError)
+ -> { @array.fetch_values(0, 1, 44) }.should raise_error(IndexError, "index 44 outside of array bounds: -3...3")
end
it "returns the default value from block" do
@@ -41,8 +42,14 @@ describe "Array#fetch_values" do
@array.fetch_values(obj).should == [:c]
end
+ it "does not support a Range object as argument" do
+ -> {
+ @array.fetch_values(1..2)
+ }.should raise_error(TypeError, "no implicit conversion of Range into Integer")
+ end
+
it "raises a TypeError when the passed argument can't be coerced to Integer" do
- -> { [].fetch_values("cat") }.should raise_error(TypeError)
+ -> { [].fetch_values("cat") }.should raise_error(TypeError, "no implicit conversion of String into Integer")
end
end
end
diff --git a/spec/ruby/core/array/intersect_spec.rb b/spec/ruby/core/array/intersect_spec.rb
index 62ac157278..456aa26c6e 100644
--- a/spec/ruby/core/array/intersect_spec.rb
+++ b/spec/ruby/core/array/intersect_spec.rb
@@ -2,65 +2,63 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe 'Array#intersect?' do
- ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/15198
- describe 'when at least one element in two Arrays is the same' do
- it 'returns true' do
- [1, 2].intersect?([2, 3, 4]).should == true
- [2, 3, 4].intersect?([1, 2]).should == true
- end
+ describe 'when at least one element in two Arrays is the same' do
+ it 'returns true' do
+ [1, 2].intersect?([2, 3, 4]).should == true
+ [2, 3, 4].intersect?([1, 2]).should == true
end
+ end
- describe 'when there are no elements in common between two Arrays' do
- it 'returns false' do
- [0, 1, 2].intersect?([3, 4]).should == false
- [3, 4].intersect?([0, 1, 2]).should == false
- [3, 4].intersect?([]).should == false
- [].intersect?([0, 1, 2]).should == false
- end
+ describe 'when there are no elements in common between two Arrays' do
+ it 'returns false' do
+ [0, 1, 2].intersect?([3, 4]).should == false
+ [3, 4].intersect?([0, 1, 2]).should == false
+ [3, 4].intersect?([]).should == false
+ [].intersect?([0, 1, 2]).should == false
end
+ end
- it "tries to convert the passed argument to an Array using #to_ary" do
- obj = mock('[1,2,3]')
- obj.should_receive(:to_ary).and_return([1, 2, 3])
+ it "tries to convert the passed argument to an Array using #to_ary" do
+ obj = mock('[1,2,3]')
+ obj.should_receive(:to_ary).and_return([1, 2, 3])
- [1, 2].intersect?(obj).should == true
- end
+ [1, 2].intersect?(obj).should == true
+ end
- it "determines equivalence between elements in the sense of eql?" do
- obj1 = mock('1')
- obj2 = mock('2')
- obj1.stub!(:hash).and_return(0)
- obj2.stub!(:hash).and_return(0)
- obj1.stub!(:eql?).and_return(true)
- obj2.stub!(:eql?).and_return(true)
+ it "determines equivalence between elements in the sense of eql?" do
+ obj1 = mock('1')
+ obj2 = mock('2')
+ obj1.stub!(:hash).and_return(0)
+ obj2.stub!(:hash).and_return(0)
+ obj1.stub!(:eql?).and_return(true)
+ obj2.stub!(:eql?).and_return(true)
- [obj1].intersect?([obj2]).should == true
+ [obj1].intersect?([obj2]).should == true
- obj1 = mock('3')
- obj2 = mock('4')
- obj1.stub!(:hash).and_return(0)
- obj2.stub!(:hash).and_return(0)
- obj1.stub!(:eql?).and_return(false)
- obj2.stub!(:eql?).and_return(false)
+ obj1 = mock('3')
+ obj2 = mock('4')
+ obj1.stub!(:hash).and_return(0)
+ obj2.stub!(:hash).and_return(0)
+ obj1.stub!(:eql?).and_return(false)
+ obj2.stub!(:eql?).and_return(false)
- [obj1].intersect?([obj2]).should == false
- end
+ [obj1].intersect?([obj2]).should == false
+ end
- it "does not call to_ary on array subclasses" do
- [5, 6].intersect?(ArraySpecs::ToAryArray[1, 2, 5, 6]).should == true
- end
+ it "does not call to_ary on array subclasses" do
+ [5, 6].intersect?(ArraySpecs::ToAryArray[1, 2, 5, 6]).should == true
+ end
- it "properly handles an identical item even when its #eql? isn't reflexive" do
- x = mock('x')
- x.stub!(:hash).and_return(42)
- x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
+ it "properly handles an identical item even when its #eql? isn't reflexive" do
+ x = mock('x')
+ x.stub!(:hash).and_return(42)
+ x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
- [x].intersect?([x]).should == true
- end
+ [x].intersect?([x]).should == true
+ end
- it "has semantic of !(a & b).empty?" do
- [].intersect?([]).should == false
- [nil].intersect?([nil]).should == true
- end
+ it "has semantic of !(a & b).empty?" do
+ [].intersect?([]).should == false
+ [nil].intersect?([nil]).should == true
end
end
diff --git a/spec/ruby/core/array/pack/a_spec.rb b/spec/ruby/core/array/pack/a_spec.rb
index f4a40502c2..8245cd5470 100644
--- a/spec/ruby/core/array/pack/a_spec.rb
+++ b/spec/ruby/core/array/pack/a_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -27,7 +27,7 @@ describe "Array#pack with format 'A'" do
["abc"].pack("A*").should == "abc"
end
- it "padds the output with spaces when the count exceeds the size of the String" do
+ it "pads the output with spaces when the count exceeds the size of the String" do
["abc"].pack("A6").should == "abc "
end
@@ -55,7 +55,7 @@ describe "Array#pack with format 'a'" do
["abc"].pack("a*").should == "abc"
end
- it "padds the output with NULL bytes when the count exceeds the size of the String" do
+ it "pads the output with NULL bytes when the count exceeds the size of the String" do
["abc"].pack("a6").should == "abc\x00\x00\x00"
end
diff --git a/spec/ruby/core/array/pack/at_spec.rb b/spec/ruby/core/array/pack/at_spec.rb
index 3942677913..bb9801440a 100644
--- a/spec/ruby/core/array/pack/at_spec.rb
+++ b/spec/ruby/core/array/pack/at_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/array/pack/b_spec.rb b/spec/ruby/core/array/pack/b_spec.rb
index ec82b7d1ab..247a9ca023 100644
--- a/spec/ruby/core/array/pack/b_spec.rb
+++ b/spec/ruby/core/array/pack/b_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/array/pack/c_spec.rb b/spec/ruby/core/array/pack/c_spec.rb
index ac133ff9b6..47b71b663d 100644
--- a/spec/ruby/core/array/pack/c_spec.rb
+++ b/spec/ruby/core/array/pack/c_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
diff --git a/spec/ruby/core/array/pack/comment_spec.rb b/spec/ruby/core/array/pack/comment_spec.rb
index 254c827ccc..daf1cff06a 100644
--- a/spec/ruby/core/array/pack/comment_spec.rb
+++ b/spec/ruby/core/array/pack/comment_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
diff --git a/spec/ruby/core/array/pack/h_spec.rb b/spec/ruby/core/array/pack/h_spec.rb
index 2c1dac8d4a..ba188874ba 100644
--- a/spec/ruby/core/array/pack/h_spec.rb
+++ b/spec/ruby/core/array/pack/h_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/array/pack/m_spec.rb b/spec/ruby/core/array/pack/m_spec.rb
index c6364af12d..a80f91275c 100644
--- a/spec/ruby/core/array/pack/m_spec.rb
+++ b/spec/ruby/core/array/pack/m_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/array/pack/shared/basic.rb b/spec/ruby/core/array/pack/shared/basic.rb
index 4b28de7ed0..a63f64d296 100644
--- a/spec/ruby/core/array/pack/shared/basic.rb
+++ b/spec/ruby/core/array/pack/shared/basic.rb
@@ -32,29 +32,16 @@ describe :array_pack_basic_non_float, shared: true do
[@obj, @obj, @obj, @obj].pack("aa #{pack_format} # some comment \n#{pack_format}").should be_an_instance_of(String)
end
- ruby_version_is ""..."3.2" do
- it "warns in verbose mode that a directive is unknown" do
- # additional directive ('a') is required for the X directive
- -> { [@obj, @obj].pack("a R" + pack_format) }.should complain(/unknown pack directive 'R'/, verbose: true)
- -> { [@obj, @obj].pack("a 0" + pack_format) }.should complain(/unknown pack directive '0'/, verbose: true)
- -> { [@obj, @obj].pack("a :" + pack_format) }.should complain(/unknown pack directive ':'/, verbose: true)
- end
- end
-
- ruby_version_is "3.2"..."3.3" do
- # https://bugs.ruby-lang.org/issues/19150
- # NOTE: it's just a plan of the Ruby core team
+ ruby_version_is ""..."3.3" do
it "warns that a directive is unknown" do
# additional directive ('a') is required for the X directive
- -> { [@obj, @obj].pack("a R" + pack_format) }.should complain(/unknown pack directive 'R'/)
- -> { [@obj, @obj].pack("a 0" + pack_format) }.should complain(/unknown pack directive '0'/)
- -> { [@obj, @obj].pack("a :" + pack_format) }.should complain(/unknown pack directive ':'/)
+ -> { [@obj, @obj].pack("a K" + pack_format) }.should complain(/unknown pack directive 'K' in 'a K#{pack_format}'/)
+ -> { [@obj, @obj].pack("a 0" + pack_format) }.should complain(/unknown pack directive '0' in 'a 0#{pack_format}'/)
+ -> { [@obj, @obj].pack("a :" + pack_format) }.should complain(/unknown pack directive ':' in 'a :#{pack_format}'/)
end
end
ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19150
- # NOTE: Added this case just to not forget about the decision in the ticket
it "raise ArgumentError when a directive is unknown" do
# additional directive ('a') is required for the X directive
-> { [@obj, @obj].pack("a R" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive 'R'/)
diff --git a/spec/ruby/core/array/pack/shared/float.rb b/spec/ruby/core/array/pack/shared/float.rb
index 1780d7635e..76c800b74d 100644
--- a/spec/ruby/core/array/pack/shared/float.rb
+++ b/spec/ruby/core/array/pack/shared/float.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :array_pack_float_le, shared: true do
it "encodes a positive Float" do
diff --git a/spec/ruby/core/array/pack/shared/integer.rb b/spec/ruby/core/array/pack/shared/integer.rb
index a89b5b733b..61f7cca184 100644
--- a/spec/ruby/core/array/pack/shared/integer.rb
+++ b/spec/ruby/core/array/pack/shared/integer.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :array_pack_16bit_le, shared: true do
it "encodes the least significant 16 bits of a positive number" do
diff --git a/spec/ruby/core/array/pack/shared/string.rb b/spec/ruby/core/array/pack/shared/string.rb
index 2f70dc3951..805f78b53b 100644
--- a/spec/ruby/core/array/pack/shared/string.rb
+++ b/spec/ruby/core/array/pack/shared/string.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :array_pack_string, shared: true do
it "adds count bytes of a String to the output" do
["abc"].pack(pack_format(2)).should == "ab"
diff --git a/spec/ruby/core/array/pack/u_spec.rb b/spec/ruby/core/array/pack/u_spec.rb
index b20093a647..1f84095ac4 100644
--- a/spec/ruby/core/array/pack/u_spec.rb
+++ b/spec/ruby/core/array/pack/u_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/array/pack/w_spec.rb b/spec/ruby/core/array/pack/w_spec.rb
index 48ed4496a5..e770288d67 100644
--- a/spec/ruby/core/array/pack/w_spec.rb
+++ b/spec/ruby/core/array/pack/w_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/array/pack/x_spec.rb b/spec/ruby/core/array/pack/x_spec.rb
index 86c3ad1aa4..012fe4567f 100644
--- a/spec/ruby/core/array/pack/x_spec.rb
+++ b/spec/ruby/core/array/pack/x_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/array/pack/z_spec.rb b/spec/ruby/core/array/pack/z_spec.rb
index 5ad3afd69e..60f8f7bf10 100644
--- a/spec/ruby/core/array/pack/z_spec.rb
+++ b/spec/ruby/core/array/pack/z_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
@@ -26,7 +26,7 @@ describe "Array#pack with format 'Z'" do
["abc"].pack("Z*").should == "abc\x00"
end
- it "padds the output with NULL bytes when the count exceeds the size of the String" do
+ it "pads the output with NULL bytes when the count exceeds the size of the String" do
["abc"].pack("Z6").should == "abc\x00\x00\x00"
end
diff --git a/spec/ruby/core/array/sample_spec.rb b/spec/ruby/core/array/sample_spec.rb
index 6ef78594f0..d4e945152d 100644
--- a/spec/ruby/core/array/sample_spec.rb
+++ b/spec/ruby/core/array/sample_spec.rb
@@ -114,6 +114,13 @@ describe "Array#sample" do
-> { [1, 2].sample(random: random) }.should raise_error(RangeError)
end
+
+ it "raises a RangeError if the value is greater than the Array size" do
+ random = mock("array_sample_random")
+ random.should_receive(:rand).and_return(3)
+
+ -> { [1, 2].sample(random: random) }.should raise_error(RangeError)
+ end
end
end
diff --git a/spec/ruby/core/array/shared/slice.rb b/spec/ruby/core/array/shared/slice.rb
index d2866970a5..b80261d32f 100644
--- a/spec/ruby/core/array/shared/slice.rb
+++ b/spec/ruby/core/array/shared/slice.rb
@@ -754,99 +754,97 @@ describe :array_slice, shared: true do
a.send(@method, (...-9)).should == []
end
- ruby_version_is "3.2" do
- describe "can be sliced with Enumerator::ArithmeticSequence" do
- it "with infinite/inverted ranges and negative steps" do
- @array = [0, 1, 2, 3, 4, 5]
- @array.send(@method, (2..).step(-1)).should == [2, 1, 0]
- @array.send(@method, (2..).step(-2)).should == [2, 0]
- @array.send(@method, (2..).step(-3)).should == [2]
- @array.send(@method, (2..).step(-4)).should == [2]
-
- @array.send(@method, (-3..).step(-1)).should == [3, 2, 1, 0]
- @array.send(@method, (-3..).step(-2)).should == [3, 1]
- @array.send(@method, (-3..).step(-3)).should == [3, 0]
- @array.send(@method, (-3..).step(-4)).should == [3]
- @array.send(@method, (-3..).step(-5)).should == [3]
-
- @array.send(@method, (..0).step(-1)).should == [5, 4, 3, 2, 1, 0]
- @array.send(@method, (..0).step(-2)).should == [5, 3, 1]
- @array.send(@method, (..0).step(-3)).should == [5, 2]
- @array.send(@method, (..0).step(-4)).should == [5, 1]
- @array.send(@method, (..0).step(-5)).should == [5, 0]
- @array.send(@method, (..0).step(-6)).should == [5]
- @array.send(@method, (..0).step(-7)).should == [5]
-
- @array.send(@method, (...0).step(-1)).should == [5, 4, 3, 2, 1]
- @array.send(@method, (...0).step(-2)).should == [5, 3, 1]
- @array.send(@method, (...0).step(-3)).should == [5, 2]
- @array.send(@method, (...0).step(-4)).should == [5, 1]
- @array.send(@method, (...0).step(-5)).should == [5]
- @array.send(@method, (...0).step(-6)).should == [5]
-
- @array.send(@method, (...1).step(-1)).should == [5, 4, 3, 2]
- @array.send(@method, (...1).step(-2)).should == [5, 3]
- @array.send(@method, (...1).step(-3)).should == [5, 2]
- @array.send(@method, (...1).step(-4)).should == [5]
- @array.send(@method, (...1).step(-5)).should == [5]
-
- @array.send(@method, (..-5).step(-1)).should == [5, 4, 3, 2, 1]
- @array.send(@method, (..-5).step(-2)).should == [5, 3, 1]
- @array.send(@method, (..-5).step(-3)).should == [5, 2]
- @array.send(@method, (..-5).step(-4)).should == [5, 1]
- @array.send(@method, (..-5).step(-5)).should == [5]
- @array.send(@method, (..-5).step(-6)).should == [5]
-
- @array.send(@method, (...-5).step(-1)).should == [5, 4, 3, 2]
- @array.send(@method, (...-5).step(-2)).should == [5, 3]
- @array.send(@method, (...-5).step(-3)).should == [5, 2]
- @array.send(@method, (...-5).step(-4)).should == [5]
- @array.send(@method, (...-5).step(-5)).should == [5]
-
- @array.send(@method, (4..1).step(-1)).should == [4, 3, 2, 1]
- @array.send(@method, (4..1).step(-2)).should == [4, 2]
- @array.send(@method, (4..1).step(-3)).should == [4, 1]
- @array.send(@method, (4..1).step(-4)).should == [4]
- @array.send(@method, (4..1).step(-5)).should == [4]
-
- @array.send(@method, (4...1).step(-1)).should == [4, 3, 2]
- @array.send(@method, (4...1).step(-2)).should == [4, 2]
- @array.send(@method, (4...1).step(-3)).should == [4]
- @array.send(@method, (4...1).step(-4)).should == [4]
-
- @array.send(@method, (-2..1).step(-1)).should == [4, 3, 2, 1]
- @array.send(@method, (-2..1).step(-2)).should == [4, 2]
- @array.send(@method, (-2..1).step(-3)).should == [4, 1]
- @array.send(@method, (-2..1).step(-4)).should == [4]
- @array.send(@method, (-2..1).step(-5)).should == [4]
-
- @array.send(@method, (-2...1).step(-1)).should == [4, 3, 2]
- @array.send(@method, (-2...1).step(-2)).should == [4, 2]
- @array.send(@method, (-2...1).step(-3)).should == [4]
- @array.send(@method, (-2...1).step(-4)).should == [4]
-
- @array.send(@method, (4..-5).step(-1)).should == [4, 3, 2, 1]
- @array.send(@method, (4..-5).step(-2)).should == [4, 2]
- @array.send(@method, (4..-5).step(-3)).should == [4, 1]
- @array.send(@method, (4..-5).step(-4)).should == [4]
- @array.send(@method, (4..-5).step(-5)).should == [4]
-
- @array.send(@method, (4...-5).step(-1)).should == [4, 3, 2]
- @array.send(@method, (4...-5).step(-2)).should == [4, 2]
- @array.send(@method, (4...-5).step(-3)).should == [4]
- @array.send(@method, (4...-5).step(-4)).should == [4]
-
- @array.send(@method, (-2..-5).step(-1)).should == [4, 3, 2, 1]
- @array.send(@method, (-2..-5).step(-2)).should == [4, 2]
- @array.send(@method, (-2..-5).step(-3)).should == [4, 1]
- @array.send(@method, (-2..-5).step(-4)).should == [4]
- @array.send(@method, (-2..-5).step(-5)).should == [4]
-
- @array.send(@method, (-2...-5).step(-1)).should == [4, 3, 2]
- @array.send(@method, (-2...-5).step(-2)).should == [4, 2]
- @array.send(@method, (-2...-5).step(-3)).should == [4]
- @array.send(@method, (-2...-5).step(-4)).should == [4]
- end
+ describe "can be sliced with Enumerator::ArithmeticSequence" do
+ it "with infinite/inverted ranges and negative steps" do
+ @array = [0, 1, 2, 3, 4, 5]
+ @array.send(@method, (2..).step(-1)).should == [2, 1, 0]
+ @array.send(@method, (2..).step(-2)).should == [2, 0]
+ @array.send(@method, (2..).step(-3)).should == [2]
+ @array.send(@method, (2..).step(-4)).should == [2]
+
+ @array.send(@method, (-3..).step(-1)).should == [3, 2, 1, 0]
+ @array.send(@method, (-3..).step(-2)).should == [3, 1]
+ @array.send(@method, (-3..).step(-3)).should == [3, 0]
+ @array.send(@method, (-3..).step(-4)).should == [3]
+ @array.send(@method, (-3..).step(-5)).should == [3]
+
+ @array.send(@method, (..0).step(-1)).should == [5, 4, 3, 2, 1, 0]
+ @array.send(@method, (..0).step(-2)).should == [5, 3, 1]
+ @array.send(@method, (..0).step(-3)).should == [5, 2]
+ @array.send(@method, (..0).step(-4)).should == [5, 1]
+ @array.send(@method, (..0).step(-5)).should == [5, 0]
+ @array.send(@method, (..0).step(-6)).should == [5]
+ @array.send(@method, (..0).step(-7)).should == [5]
+
+ @array.send(@method, (...0).step(-1)).should == [5, 4, 3, 2, 1]
+ @array.send(@method, (...0).step(-2)).should == [5, 3, 1]
+ @array.send(@method, (...0).step(-3)).should == [5, 2]
+ @array.send(@method, (...0).step(-4)).should == [5, 1]
+ @array.send(@method, (...0).step(-5)).should == [5]
+ @array.send(@method, (...0).step(-6)).should == [5]
+
+ @array.send(@method, (...1).step(-1)).should == [5, 4, 3, 2]
+ @array.send(@method, (...1).step(-2)).should == [5, 3]
+ @array.send(@method, (...1).step(-3)).should == [5, 2]
+ @array.send(@method, (...1).step(-4)).should == [5]
+ @array.send(@method, (...1).step(-5)).should == [5]
+
+ @array.send(@method, (..-5).step(-1)).should == [5, 4, 3, 2, 1]
+ @array.send(@method, (..-5).step(-2)).should == [5, 3, 1]
+ @array.send(@method, (..-5).step(-3)).should == [5, 2]
+ @array.send(@method, (..-5).step(-4)).should == [5, 1]
+ @array.send(@method, (..-5).step(-5)).should == [5]
+ @array.send(@method, (..-5).step(-6)).should == [5]
+
+ @array.send(@method, (...-5).step(-1)).should == [5, 4, 3, 2]
+ @array.send(@method, (...-5).step(-2)).should == [5, 3]
+ @array.send(@method, (...-5).step(-3)).should == [5, 2]
+ @array.send(@method, (...-5).step(-4)).should == [5]
+ @array.send(@method, (...-5).step(-5)).should == [5]
+
+ @array.send(@method, (4..1).step(-1)).should == [4, 3, 2, 1]
+ @array.send(@method, (4..1).step(-2)).should == [4, 2]
+ @array.send(@method, (4..1).step(-3)).should == [4, 1]
+ @array.send(@method, (4..1).step(-4)).should == [4]
+ @array.send(@method, (4..1).step(-5)).should == [4]
+
+ @array.send(@method, (4...1).step(-1)).should == [4, 3, 2]
+ @array.send(@method, (4...1).step(-2)).should == [4, 2]
+ @array.send(@method, (4...1).step(-3)).should == [4]
+ @array.send(@method, (4...1).step(-4)).should == [4]
+
+ @array.send(@method, (-2..1).step(-1)).should == [4, 3, 2, 1]
+ @array.send(@method, (-2..1).step(-2)).should == [4, 2]
+ @array.send(@method, (-2..1).step(-3)).should == [4, 1]
+ @array.send(@method, (-2..1).step(-4)).should == [4]
+ @array.send(@method, (-2..1).step(-5)).should == [4]
+
+ @array.send(@method, (-2...1).step(-1)).should == [4, 3, 2]
+ @array.send(@method, (-2...1).step(-2)).should == [4, 2]
+ @array.send(@method, (-2...1).step(-3)).should == [4]
+ @array.send(@method, (-2...1).step(-4)).should == [4]
+
+ @array.send(@method, (4..-5).step(-1)).should == [4, 3, 2, 1]
+ @array.send(@method, (4..-5).step(-2)).should == [4, 2]
+ @array.send(@method, (4..-5).step(-3)).should == [4, 1]
+ @array.send(@method, (4..-5).step(-4)).should == [4]
+ @array.send(@method, (4..-5).step(-5)).should == [4]
+
+ @array.send(@method, (4...-5).step(-1)).should == [4, 3, 2]
+ @array.send(@method, (4...-5).step(-2)).should == [4, 2]
+ @array.send(@method, (4...-5).step(-3)).should == [4]
+ @array.send(@method, (4...-5).step(-4)).should == [4]
+
+ @array.send(@method, (-2..-5).step(-1)).should == [4, 3, 2, 1]
+ @array.send(@method, (-2..-5).step(-2)).should == [4, 2]
+ @array.send(@method, (-2..-5).step(-3)).should == [4, 1]
+ @array.send(@method, (-2..-5).step(-4)).should == [4]
+ @array.send(@method, (-2..-5).step(-5)).should == [4]
+
+ @array.send(@method, (-2...-5).step(-1)).should == [4, 3, 2]
+ @array.send(@method, (-2...-5).step(-2)).should == [4, 2]
+ @array.send(@method, (-2...-5).step(-3)).should == [4]
+ @array.send(@method, (-2...-5).step(-4)).should == [4]
end
end
diff --git a/spec/ruby/core/array/shared/unshift.rb b/spec/ruby/core/array/shared/unshift.rb
index 4941e098f6..9e0fe7556a 100644
--- a/spec/ruby/core/array/shared/unshift.rb
+++ b/spec/ruby/core/array/shared/unshift.rb
@@ -49,7 +49,7 @@ describe :array_unshift, shared: true do
-> { ArraySpecs.frozen_array.send(@method) }.should raise_error(FrozenError)
end
- # https://github.com/oracle/truffleruby/issues/2772
+ # https://github.com/truffleruby/truffleruby/issues/2772
it "doesn't rely on Array#[]= so it can be overridden" do
subclass = Class.new(Array) do
def []=(*)
diff --git a/spec/ruby/core/array/shuffle_spec.rb b/spec/ruby/core/array/shuffle_spec.rb
index 1d528c124f..b84394bcb5 100644
--- a/spec/ruby/core/array/shuffle_spec.rb
+++ b/spec/ruby/core/array/shuffle_spec.rb
@@ -69,9 +69,18 @@ describe "Array#shuffle" do
-> { [1, 2].shuffle(random: random) }.should raise_error(RangeError)
end
- it "raises a RangeError if the value is equal to one" do
+ it "raises a RangeError if the value is equal to the Array size" do
value = mock("array_shuffle_random_value")
- value.should_receive(:to_int).at_least(1).times.and_return(1)
+ value.should_receive(:to_int).at_least(1).times.and_return(2)
+ random = mock("array_shuffle_random")
+ random.should_receive(:rand).at_least(1).times.and_return(value)
+
+ -> { [1, 2].shuffle(random: random) }.should raise_error(RangeError)
+ end
+
+ it "raises a RangeError if the value is greater than the Array size" do
+ value = mock("array_shuffle_random_value")
+ value.should_receive(:to_int).at_least(1).times.and_return(3)
random = mock("array_shuffle_random")
random.should_receive(:rand).at_least(1).times.and_return(value)
diff --git a/spec/ruby/core/basicobject/instance_eval_spec.rb b/spec/ruby/core/basicobject/instance_eval_spec.rb
index 1f3a43f341..633b5c2cb1 100644
--- a/spec/ruby/core/basicobject/instance_eval_spec.rb
+++ b/spec/ruby/core/basicobject/instance_eval_spec.rb
@@ -141,22 +141,11 @@ describe "BasicObject#instance_eval" do
caller.get_constant_with_string(receiver).should == :singleton_class
end
- ruby_version_is ""..."3.1" do
- it "looks in the caller scope next" do
- receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
- caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new
+ it "looks in the receiver class next" do
+ receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
+ caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new
- caller.get_constant_with_string(receiver).should == :Caller
- end
- end
-
- ruby_version_is "3.1" do
- it "looks in the receiver class next" do
- receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
- caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new
-
- caller.get_constant_with_string(receiver).should == :Receiver
- end
+ caller.get_constant_with_string(receiver).should == :Receiver
end
it "looks in the caller class next" do
diff --git a/spec/ruby/core/basicobject/singleton_method_added_spec.rb b/spec/ruby/core/basicobject/singleton_method_added_spec.rb
index fc65a091aa..bd21458ea7 100644
--- a/spec/ruby/core/basicobject/singleton_method_added_spec.rb
+++ b/spec/ruby/core/basicobject/singleton_method_added_spec.rb
@@ -96,6 +96,8 @@ describe "BasicObject#singleton_method_added" do
end
}.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for/)
end
+ ensure
+ BasicObjectSpecs.send(:remove_const, :NoSingletonMethodAdded)
end
it "raises NoMethodError for a singleton instance" do
diff --git a/spec/ruby/core/binding/fixtures/irb.rb b/spec/ruby/core/binding/fixtures/irb.rb
deleted file mode 100644
index 5f305f2d5d..0000000000
--- a/spec/ruby/core/binding/fixtures/irb.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-a = 10
-
-binding.irb
diff --git a/spec/ruby/core/binding/irb_spec.rb b/spec/ruby/core/binding/irb_spec.rb
deleted file mode 100644
index 2607c7ef33..0000000000
--- a/spec/ruby/core/binding/irb_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require_relative '../../spec_helper'
-require 'tmpdir'
-
-describe "Binding#irb" do
- it "creates an IRB session with the binding in scope" do
- irb_fixture = fixture __FILE__, "irb.rb"
- envs = %w[IRBRC HOME XDG_CONFIG_HOME].to_h {|e| [e, nil]}
-
- out = Dir.mktmpdir do |dir|
- IO.popen([envs, *ruby_exe, irb_fixture, chdir: dir], "r+") do |pipe|
- pipe.puts "a ** 2"
- pipe.puts "exit"
- pipe.readlines.map(&:chomp).reject(&:empty?)
- end
- end
-
- out.last(3).should == ["a ** 2", "100", "exit"]
- end
-end
diff --git a/spec/ruby/core/binding/shared/clone.rb b/spec/ruby/core/binding/shared/clone.rb
index 1224b8ec7d..2d854fce96 100644
--- a/spec/ruby/core/binding/shared/clone.rb
+++ b/spec/ruby/core/binding/shared/clone.rb
@@ -40,7 +40,7 @@ describe :binding_clone, shared: true do
end
it "copies the finalizer" do
- code = <<-RUBY
+ code = <<-'RUBY'
obj = binding
ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" })
diff --git a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb
index eaf311783a..13e066cc7f 100644
--- a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb
+++ b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb
@@ -46,6 +46,16 @@ describe "RUBY_ENGINE" do
end
end
+describe "RUBY_ENGINE_VERSION" do
+ it "is a String" do
+ RUBY_ENGINE_VERSION.should be_kind_of(String)
+ end
+
+ it "is frozen" do
+ RUBY_ENGINE_VERSION.should.frozen?
+ end
+end
+
describe "RUBY_PLATFORM" do
it "is a String" do
RUBY_PLATFORM.should be_kind_of(String)
@@ -75,3 +85,67 @@ describe "RUBY_REVISION" do
RUBY_REVISION.should.frozen?
end
end
+
+ruby_version_is "4.0" do
+ context "The constant" do
+ describe "Ruby" do
+ it "is a Module" do
+ Ruby.should.instance_of?(Module)
+ end
+ end
+
+ describe "Ruby::VERSION" do
+ it "is equal to RUBY_VERSION" do
+ Ruby::VERSION.should equal(RUBY_VERSION)
+ end
+ end
+
+ describe "RUBY::PATCHLEVEL" do
+ it "is equal to RUBY_PATCHLEVEL" do
+ Ruby::PATCHLEVEL.should equal(RUBY_PATCHLEVEL)
+ end
+ end
+
+ describe "Ruby::COPYRIGHT" do
+ it "is equal to RUBY_COPYRIGHT" do
+ Ruby::COPYRIGHT.should equal(RUBY_COPYRIGHT)
+ end
+ end
+
+ describe "Ruby::DESCRIPTION" do
+ it "is equal to RUBY_DESCRIPTION" do
+ Ruby::DESCRIPTION.should equal(RUBY_DESCRIPTION)
+ end
+ end
+
+ describe "Ruby::ENGINE" do
+ it "is equal to RUBY_ENGINE" do
+ Ruby::ENGINE.should equal(RUBY_ENGINE)
+ end
+ end
+
+ describe "Ruby::ENGINE_VERSION" do
+ it "is equal to RUBY_ENGINE_VERSION" do
+ Ruby::ENGINE_VERSION.should equal(RUBY_ENGINE_VERSION)
+ end
+ end
+
+ describe "Ruby::PLATFORM" do
+ it "is equal to RUBY_PLATFORM" do
+ Ruby::PLATFORM.should equal(RUBY_PLATFORM)
+ end
+ end
+
+ describe "Ruby::RELEASE_DATE" do
+ it "is equal to RUBY_RELEASE_DATE" do
+ Ruby::RELEASE_DATE.should equal(RUBY_RELEASE_DATE)
+ end
+ end
+
+ describe "Ruby::REVISION" do
+ it "is equal to RUBY_REVISION" do
+ Ruby::REVISION.should equal(RUBY_REVISION)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/class/attached_object_spec.rb b/spec/ruby/core/class/attached_object_spec.rb
index f1c0f63a44..8f8a0734c6 100644
--- a/spec/ruby/core/class/attached_object_spec.rb
+++ b/spec/ruby/core/class/attached_object_spec.rb
@@ -1,31 +1,29 @@
require_relative '../../spec_helper'
-ruby_version_is '3.2' do
- describe "Class#attached_object" do
- it "returns the object that is attached to a singleton class" do
- a = Class.new
+describe "Class#attached_object" do
+ it "returns the object that is attached to a singleton class" do
+ a = Class.new
- a_obj = a.new
- a_obj.singleton_class.attached_object.should == a_obj
- end
+ a_obj = a.new
+ a_obj.singleton_class.attached_object.should == a_obj
+ end
- it "returns the class object that is attached to a class's singleton class" do
- a = Class.new
- singleton_class = (class << a; self; end)
+ it "returns the class object that is attached to a class's singleton class" do
+ a = Class.new
+ singleton_class = (class << a; self; end)
- singleton_class.attached_object.should == a
- end
+ singleton_class.attached_object.should == a
+ end
- it "raises TypeError if the class is not a singleton class" do
- a = Class.new
+ it "raises TypeError if the class is not a singleton class" do
+ a = Class.new
- -> { a.attached_object }.should raise_error(TypeError, /is not a singleton class/)
- end
+ -> { a.attached_object }.should raise_error(TypeError, /is not a singleton class/)
+ end
- it "raises TypeError for special singleton classes" do
- -> { nil.singleton_class.attached_object }.should raise_error(TypeError, /[`']NilClass' is not a singleton class/)
- -> { true.singleton_class.attached_object }.should raise_error(TypeError, /[`']TrueClass' is not a singleton class/)
- -> { false.singleton_class.attached_object }.should raise_error(TypeError, /[`']FalseClass' is not a singleton class/)
- end
+ it "raises TypeError for special singleton classes" do
+ -> { nil.singleton_class.attached_object }.should raise_error(TypeError, /[`']NilClass' is not a singleton class/)
+ -> { true.singleton_class.attached_object }.should raise_error(TypeError, /[`']TrueClass' is not a singleton class/)
+ -> { false.singleton_class.attached_object }.should raise_error(TypeError, /[`']FalseClass' is not a singleton class/)
end
end
diff --git a/spec/ruby/core/class/dup_spec.rb b/spec/ruby/core/class/dup_spec.rb
index c09ed71b31..1ff9abf7b4 100644
--- a/spec/ruby/core/class/dup_spec.rb
+++ b/spec/ruby/core/class/dup_spec.rb
@@ -59,6 +59,8 @@ describe "Class#dup" do
it "stores the new name if assigned to a constant" do
CoreClassSpecs::RecordCopy = CoreClassSpecs::Record.dup
CoreClassSpecs::RecordCopy.name.should == "CoreClassSpecs::RecordCopy"
+ ensure
+ CoreClassSpecs.send(:remove_const, :RecordCopy)
end
it "raises TypeError if called on BasicObject" do
diff --git a/spec/ruby/core/class/inherited_spec.rb b/spec/ruby/core/class/inherited_spec.rb
index 8ef8bb8c35..2a8d1ff813 100644
--- a/spec/ruby/core/class/inherited_spec.rb
+++ b/spec/ruby/core/class/inherited_spec.rb
@@ -98,4 +98,21 @@ describe "Class.inherited" do
-> { Class.new(top) }.should_not raise_error
end
+ it "if the subclass is assigned to a constant, it is all set" do
+ ScratchPad.record []
+
+ parent = Class.new do
+ def self.inherited(subclass)
+ ScratchPad << defined?(self::C)
+ ScratchPad << const_defined?(:C)
+ ScratchPad << constants
+ ScratchPad << const_get(:C)
+ ScratchPad << subclass.name.match?(/\A#<Class:0x\w+>::C\z/)
+ end
+ end
+
+ class parent::C < parent; end
+
+ ScratchPad.recorded.should == ["constant", true, [:C], parent::C, true]
+ end
end
diff --git a/spec/ruby/core/class/new_spec.rb b/spec/ruby/core/class/new_spec.rb
index 93152a83ee..6fe54c3209 100644
--- a/spec/ruby/core/class/new_spec.rb
+++ b/spec/ruby/core/class/new_spec.rb
@@ -83,6 +83,8 @@ describe "Class.new" do
a = Class.new
MyClass::NestedClass = a
MyClass::NestedClass.name.should == "MyClass::NestedClass"
+ ensure
+ Object.send(:remove_const, :MyClass)
end
it "sets the new class' superclass to the given class" do
diff --git a/spec/ruby/core/class/subclasses_spec.rb b/spec/ruby/core/class/subclasses_spec.rb
index 50eb5358d9..f692152787 100644
--- a/spec/ruby/core/class/subclasses_spec.rb
+++ b/spec/ruby/core/class/subclasses_spec.rb
@@ -1,87 +1,85 @@
require_relative '../../spec_helper'
require_relative '../module/fixtures/classes'
-ruby_version_is '3.1' do
- describe "Class#subclasses" do
- it "returns a list of classes directly inheriting from self" do
- assert_subclasses(ModuleSpecs::Parent, [ModuleSpecs::Child, ModuleSpecs::Child2])
- end
+describe "Class#subclasses" do
+ it "returns a list of classes directly inheriting from self" do
+ assert_subclasses(ModuleSpecs::Parent, [ModuleSpecs::Child, ModuleSpecs::Child2])
+ end
- it "does not return included modules from the parent" do
- parent = Class.new
- child = Class.new(parent)
- mod = Module.new
- parent.include(mod)
+ it "does not return included modules from the parent" do
+ parent = Class.new
+ child = Class.new(parent)
+ mod = Module.new
+ parent.include(mod)
- assert_subclasses(parent, [child])
- end
-
- it "does not return included modules from the child" do
- parent = Class.new
- child = Class.new(parent)
- mod = Module.new
- parent.include(mod)
+ assert_subclasses(parent, [child])
+ end
- assert_subclasses(parent, [child])
- end
+ it "does not return included modules from the child" do
+ parent = Class.new
+ child = Class.new(parent)
+ mod = Module.new
+ parent.include(mod)
- it "does not return prepended modules from the parent" do
- parent = Class.new
- child = Class.new(parent)
- mod = Module.new
- parent.prepend(mod)
+ assert_subclasses(parent, [child])
+ end
- assert_subclasses(parent, [child])
- end
+ it "does not return prepended modules from the parent" do
+ parent = Class.new
+ child = Class.new(parent)
+ mod = Module.new
+ parent.prepend(mod)
- it "does not return prepended modules from the child" do
- parent = Class.new
- child = Class.new(parent)
- mod = Module.new
- child.prepend(mod)
+ assert_subclasses(parent, [child])
+ end
- assert_subclasses(parent, [child])
- end
+ it "does not return prepended modules from the child" do
+ parent = Class.new
+ child = Class.new(parent)
+ mod = Module.new
+ child.prepend(mod)
- it "does not return singleton classes" do
- a = Class.new
+ assert_subclasses(parent, [child])
+ end
- a_obj = a.new
- def a_obj.force_singleton_class
- 42
- end
+ it "does not return singleton classes" do
+ a = Class.new
- a.subclasses.should_not include(a_obj.singleton_class)
+ a_obj = a.new
+ def a_obj.force_singleton_class
+ 42
end
- it "has 1 entry per module or class" do
- ModuleSpecs::Parent.subclasses.should == ModuleSpecs::Parent.subclasses.uniq
- end
+ a.subclasses.should_not include(a_obj.singleton_class)
+ end
+
+ it "has 1 entry per module or class" do
+ ModuleSpecs::Parent.subclasses.should == ModuleSpecs::Parent.subclasses.uniq
+ end
- it "works when creating subclasses concurrently" do
- t = 16
- n = 1000
- go = false
- superclass = Class.new
-
- threads = t.times.map do
- Thread.new do
- Thread.pass until go
- n.times.map do
- Class.new(superclass)
- end
+ it "works when creating subclasses concurrently" do
+ t = 16
+ n = 1000
+ go = false
+ superclass = Class.new
+
+ threads = t.times.map do
+ Thread.new do
+ Thread.pass until go
+ n.times.map do
+ Class.new(superclass)
end
end
+ end
- go = true
- classes = threads.map(&:value)
+ go = true
+ classes = threads.map(&:value)
- superclass.subclasses.size.should == t * n
- superclass.subclasses.each { |c| c.should be_kind_of(Class) }
- end
+ superclass.subclasses.size.should == t * n
+ superclass.subclasses.each { |c| c.should be_kind_of(Class) }
+ end
- def assert_subclasses(mod,subclasses)
- mod.subclasses.sort_by(&:inspect).should == subclasses.sort_by(&:inspect)
- end
+ def assert_subclasses(mod,subclasses)
+ mod.subclasses.sort_by(&:inspect).should == subclasses.sort_by(&:inspect)
end
end
diff --git a/spec/ruby/core/comparable/clamp_spec.rb b/spec/ruby/core/comparable/clamp_spec.rb
index 796d4a18c1..18f616a997 100644
--- a/spec/ruby/core/comparable/clamp_spec.rb
+++ b/spec/ruby/core/comparable/clamp_spec.rb
@@ -24,7 +24,7 @@ describe 'Comparable#clamp' do
c.clamp(two, three).should equal(c)
end
- it 'returns the min parameter if smaller than it' do
+ it 'returns the min parameter if less than it' do
one = ComparableSpecs::WithOnlyCompareDefined.new(1)
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
c = ComparableSpecs::Weird.new(0)
@@ -40,6 +40,39 @@ describe 'Comparable#clamp' do
c.clamp(one, two).should equal(two)
end
+ context 'max is nil' do
+ it 'returns min if less than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(0)
+ c.clamp(one, nil).should equal(one)
+ end
+
+ it 'always returns self if greater than min' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+ c.clamp(one, nil).should equal(c)
+ end
+ end
+
+ context 'min is nil' do
+ it 'returns max if greater than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+ c.clamp(nil, one).should equal(one)
+ end
+
+ it 'always returns self if less than max' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(0)
+ c.clamp(nil, one).should equal(c)
+ end
+ end
+
+ it 'always returns self when min is nil and max is nil' do
+ c = ComparableSpecs::Weird.new(1)
+ c.clamp(nil, nil).should equal(c)
+ end
+
it 'returns self if within the given range parameters' do
one = ComparableSpecs::WithOnlyCompareDefined.new(1)
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
@@ -52,7 +85,7 @@ describe 'Comparable#clamp' do
c.clamp(two..three).should equal(c)
end
- it 'returns the minimum value of the range parameters if smaller than it' do
+ it 'returns the minimum value of the range parameters if less than it' do
one = ComparableSpecs::WithOnlyCompareDefined.new(1)
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
c = ComparableSpecs::Weird.new(0)
@@ -75,4 +108,116 @@ describe 'Comparable#clamp' do
-> { c.clamp(one...two) }.should raise_error(ArgumentError)
end
+
+ context 'with nil as the max argument' do
+ it 'returns min argument if less than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ zero = ComparableSpecs::WithOnlyCompareDefined.new(0)
+ c = ComparableSpecs::Weird.new(0)
+
+ c.clamp(one, nil).should equal(one)
+ c.clamp(zero, nil).should equal(c)
+ end
+
+ it 'always returns self if greater than min argument' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ two = ComparableSpecs::WithOnlyCompareDefined.new(2)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(one, nil).should equal(c)
+ c.clamp(two, nil).should equal(c)
+ end
+ end
+
+ context 'with endless range' do
+ it 'returns minimum value of the range parameters if less than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ zero = ComparableSpecs::WithOnlyCompareDefined.new(0)
+ c = ComparableSpecs::Weird.new(0)
+
+ c.clamp(one..).should equal(one)
+ c.clamp(zero..).should equal(c)
+ end
+
+ it 'always returns self if greater than minimum value of the range parameters' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ two = ComparableSpecs::WithOnlyCompareDefined.new(2)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(one..).should equal(c)
+ c.clamp(two..).should equal(c)
+ end
+
+ it 'works with exclusive range' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(one...).should equal(c)
+ end
+ end
+
+ context 'with nil as the min argument' do
+ it 'returns max argument if greater than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(nil, one).should equal(one)
+ end
+
+ it 'always returns self if less than max argument' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ zero = ComparableSpecs::WithOnlyCompareDefined.new(0)
+ c = ComparableSpecs::Weird.new(0)
+
+ c.clamp(nil, one).should equal(c)
+ c.clamp(nil, zero).should equal(c)
+ end
+ end
+
+ context 'with beginless range' do
+ it 'returns maximum value of the range parameters if greater than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(..one).should equal(one)
+ end
+
+ it 'always returns self if less than maximum value of the range parameters' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ zero = ComparableSpecs::WithOnlyCompareDefined.new(0)
+ c = ComparableSpecs::Weird.new(0)
+
+ c.clamp(..one).should equal(c)
+ c.clamp(..zero).should equal(c)
+ end
+
+ it 'raises an Argument error if the range parameter is exclusive' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ c = ComparableSpecs::Weird.new(0)
+
+ -> { c.clamp(...one) }.should raise_error(ArgumentError)
+ end
+ end
+
+ context 'with nil as the min and the max argument' do
+ it 'always returns self' do
+ c = ComparableSpecs::Weird.new(1)
+
+ c.clamp(nil, nil).should equal(c)
+ end
+ end
+
+ context 'with beginless-and-endless range' do
+ it 'always returns self' do
+ c = ComparableSpecs::Weird.new(1)
+
+ c.clamp(nil..nil).should equal(c)
+ end
+
+ it 'works with exclusive range' do
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(nil...nil).should equal(c)
+ end
+ end
end
diff --git a/spec/ruby/core/comparable/fixtures/classes.rb b/spec/ruby/core/comparable/fixtures/classes.rb
index 4239a47d2f..2bdabbf014 100644
--- a/spec/ruby/core/comparable/fixtures/classes.rb
+++ b/spec/ruby/core/comparable/fixtures/classes.rb
@@ -7,6 +7,7 @@ module ComparableSpecs
end
def <=>(other)
+ return nil if other.nil?
self.value <=> other.value
end
end
diff --git a/spec/ruby/core/complex/polar_spec.rb b/spec/ruby/core/complex/polar_spec.rb
index 3bb3751bc6..56335584ef 100644
--- a/spec/ruby/core/complex/polar_spec.rb
+++ b/spec/ruby/core/complex/polar_spec.rb
@@ -11,20 +11,18 @@ describe "Complex.polar" do
->{ Complex.polar(nil, nil) }.should raise_error(TypeError)
end
- ruby_bug "#19004", ""..."3.2" do
- it "computes the real values of the real & imaginary parts from the polar form" do
- a = Complex.polar(1.0+0.0i, Math::PI/2+0.0i)
- a.real.should be_close(0.0, TOLERANCE)
- a.imag.should be_close(1.0, TOLERANCE)
- a.real.real?.should be_true
- a.imag.real?.should be_true
+ it "computes the real values of the real & imaginary parts from the polar form" do
+ a = Complex.polar(1.0+0.0i, Math::PI/2+0.0i)
+ a.real.should be_close(0.0, TOLERANCE)
+ a.imag.should be_close(1.0, TOLERANCE)
+ a.real.real?.should be_true
+ a.imag.real?.should be_true
- b = Complex.polar(1+0.0i)
- b.real.should be_close(1.0, TOLERANCE)
- b.imag.should be_close(0.0, TOLERANCE)
- b.real.real?.should be_true
- b.imag.real?.should be_true
- end
+ b = Complex.polar(1+0.0i)
+ b.real.should be_close(1.0, TOLERANCE)
+ b.imag.should be_close(0.0, TOLERANCE)
+ b.real.real?.should be_true
+ b.imag.real?.should be_true
end
end
diff --git a/spec/ruby/core/complex/shared/rect.rb b/spec/ruby/core/complex/shared/rect.rb
index 9f5de1ffeb..4ac294e771 100644
--- a/spec/ruby/core/complex/shared/rect.rb
+++ b/spec/ruby/core/complex/shared/rect.rb
@@ -24,15 +24,15 @@ describe :complex_rect, shared: true do
end
it "returns the real part of self as the first element" do
- @numbers.each do |number|
- number.send(@method).first.should == number.real
- end
+ @numbers.each do |number|
+ number.send(@method).first.should == number.real
+ end
end
it "returns the imaginary part of self as the last element" do
- @numbers.each do |number|
- number.send(@method).last.should == number.imaginary
- end
+ @numbers.each do |number|
+ number.send(@method).last.should == number.imaginary
+ end
end
it "raises an ArgumentError if given any arguments" do
diff --git a/spec/ruby/core/data/constants_spec.rb b/spec/ruby/core/data/constants_spec.rb
index 2eb43d501e..ad0b1ddea7 100644
--- a/spec/ruby/core/data/constants_spec.rb
+++ b/spec/ruby/core/data/constants_spec.rb
@@ -1,21 +1,11 @@
require_relative '../../spec_helper'
-ruby_version_is ''...'3.2' do
- describe "Data" do
- it "does not exist anymore" do
- Object.should_not have_constant(:Data)
- end
+describe "Data" do
+ it "is a new constant" do
+ Data.superclass.should == Object
end
-end
-
-ruby_version_is '3.2' do
- describe "Data" do
- it "is a new constant" do
- Data.superclass.should == Object
- end
- it "is not deprecated" do
- -> { Data }.should_not complain
- end
+ it "is not deprecated" do
+ -> { Data }.should_not complain
end
end
diff --git a/spec/ruby/core/data/deconstruct_keys_spec.rb b/spec/ruby/core/data/deconstruct_keys_spec.rb
new file mode 100644
index 0000000000..df378f8b98
--- /dev/null
+++ b/spec/ruby/core/data/deconstruct_keys_spec.rb
@@ -0,0 +1,130 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Data#deconstruct_keys" do
+ it "returns a hash of attributes" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
+ end
+
+ it "requires one argument" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ -> {
+ d.deconstruct_keys
+ }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
+ end
+
+ it "returns only specified keys" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ d.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
+ d.deconstruct_keys([:x] ).should == {x: 1}
+ d.deconstruct_keys([] ).should == {}
+ end
+
+ it "accepts string attribute names" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ d.deconstruct_keys(['x', 'y']).should == {'x' => 1, 'y' => 2}
+ end
+
+ it "accepts argument position number as well but returns them as keys" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ d.deconstruct_keys([0, 1]).should == {0 => 1, 1 => 2}
+ d.deconstruct_keys([0] ).should == {0 => 1}
+ d.deconstruct_keys([-1] ).should == {-1 => 2}
+ end
+
+ it "ignores incorrect position numbers" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ d.deconstruct_keys([0, 3]).should == {0 => 1}
+ end
+
+ it "support mixing attribute names and argument position numbers" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ d.deconstruct_keys([0, :x]).should == {0 => 1, :x => 1}
+ end
+
+ it "returns an empty hash when there are more keys than attributes" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ d.deconstruct_keys([:x, :y, :x]).should == {}
+ end
+
+ it "returns at first not existing attribute name" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ d.deconstruct_keys([:a, :x]).should == {}
+ d.deconstruct_keys([:x, :a]).should == {x: 1}
+ end
+
+ it "returns at first not existing argument position number" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ d.deconstruct_keys([3, 0]).should == {}
+ d.deconstruct_keys([0, 3]).should == {0 => 1}
+ end
+
+ it "accepts nil argument and return all the attributes" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ d.deconstruct_keys(nil).should == {x: 1, y: 2}
+ end
+
+ it "tries to convert a key with #to_int if index is not a String nor a Symbol, but responds to #to_int" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ key = mock("to_int")
+ key.should_receive(:to_int).and_return(1)
+
+ d.deconstruct_keys([key]).should == { key => 2 }
+ end
+
+ it "raises a TypeError if the conversion with #to_int does not return an Integer" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ key = mock("to_int")
+ key.should_receive(:to_int).and_return("not an Integer")
+
+ -> {
+ d.deconstruct_keys([key])
+ }.should raise_error(TypeError, /can't convert MockObject to Integer/)
+ end
+
+ it "raises TypeError if index is not a String, a Symbol and not convertible to Integer " do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ -> {
+ d.deconstruct_keys([0, []])
+ }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
+ end
+
+ it "raise TypeError if passed anything except nil or array" do
+ klass = Data.define(:x, :y)
+ d = klass.new(1, 2)
+
+ -> { d.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/)
+ -> { d.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/)
+ -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/)
+ -> { d.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/)
+ end
+end
diff --git a/spec/ruby/core/data/deconstruct_spec.rb b/spec/ruby/core/data/deconstruct_spec.rb
new file mode 100644
index 0000000000..4ca0b87039
--- /dev/null
+++ b/spec/ruby/core/data/deconstruct_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Data#deconstruct" do
+ it "returns an array of attribute values" do
+ DataSpecs::Measure.new(42, "km").deconstruct.should == [42, "km"]
+ end
+end
diff --git a/spec/ruby/core/data/define_spec.rb b/spec/ruby/core/data/define_spec.rb
index 2aa2c50d4c..c0b4671e39 100644
--- a/spec/ruby/core/data/define_spec.rb
+++ b/spec/ruby/core/data/define_spec.rb
@@ -1,36 +1,34 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data.define" do
- it "accepts no arguments" do
- empty_data = Data.define
- empty_data.members.should == []
- end
+describe "Data.define" do
+ it "accepts no arguments" do
+ empty_data = Data.define
+ empty_data.members.should == []
+ end
- it "accepts symbols" do
- movie = Data.define(:title, :year)
- movie.members.should == [:title, :year]
- end
+ it "accepts symbols" do
+ movie = Data.define(:title, :year)
+ movie.members.should == [:title, :year]
+ end
- it "accepts strings" do
- movie = Data.define("title", "year")
- movie.members.should == [:title, :year]
- end
+ it "accepts strings" do
+ movie = Data.define("title", "year")
+ movie.members.should == [:title, :year]
+ end
- it "accepts a mix of strings and symbols" do
- movie = Data.define("title", :year, "genre")
- movie.members.should == [:title, :year, :genre]
- end
+ it "accepts a mix of strings and symbols" do
+ movie = Data.define("title", :year, "genre")
+ movie.members.should == [:title, :year, :genre]
+ end
- it "accepts a block" do
- movie = Data.define(:title, :year) do
- def title_with_year
- "#{title} (#{year})"
- end
+ it "accepts a block" do
+ movie = Data.define(:title, :year) do
+ def title_with_year
+ "#{title} (#{year})"
end
- movie.members.should == [:title, :year]
- movie.new("Matrix", 1999).title_with_year.should == "Matrix (1999)"
end
+ movie.members.should == [:title, :year]
+ movie.new("Matrix", 1999).title_with_year.should == "Matrix (1999)"
end
end
diff --git a/spec/ruby/core/data/eql_spec.rb b/spec/ruby/core/data/eql_spec.rb
new file mode 100644
index 0000000000..6958d5de4a
--- /dev/null
+++ b/spec/ruby/core/data/eql_spec.rb
@@ -0,0 +1,63 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Data#eql?" do
+ it "returns true if the other is the same object" do
+ a = DataSpecs::Measure.new(42, "km")
+ a.should.eql?(a)
+ end
+
+ it "returns true if the other has all the same fields" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42, "km")
+ a.should.eql?(b)
+ end
+
+ it "returns false if the other is a different object or has different fields" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42, "mi")
+ a.should_not.eql?(b)
+ end
+
+ it "returns false if other is of a different class" do
+ a = DataSpecs::Measure.new(42, "km")
+ klass = Data.define(*DataSpecs::Measure.members)
+ b = klass.new(42, "km")
+ a.should_not.eql?(b)
+ end
+
+ it "returns false if any corresponding elements are not equal with #eql?" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42.0, "mi")
+ a.should_not.eql?(b)
+ end
+
+ context "recursive structure" do
+ it "returns true the other is the same object" do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: 42, unit: a)
+
+ a.should.eql?(a)
+ end
+
+ it "returns true if the other has all the same fields" do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: 42, unit: a)
+
+ b = DataSpecs::Measure.allocate
+ b.send(:initialize, amount: 42, unit: b)
+
+ a.should.eql?(b)
+ end
+
+ it "returns false if any corresponding elements are not equal with #eql?" do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: a, unit: "km")
+
+ b = DataSpecs::Measure.allocate
+ b.send(:initialize, amount: b, unit: "mi")
+
+ a.should_not.eql?(b)
+ end
+ end
+end
diff --git a/spec/ruby/core/data/equal_value_spec.rb b/spec/ruby/core/data/equal_value_spec.rb
new file mode 100644
index 0000000000..d9a0dcff3e
--- /dev/null
+++ b/spec/ruby/core/data/equal_value_spec.rb
@@ -0,0 +1,63 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Data#==" do
+ it "returns true if the other is the same object" do
+ a = DataSpecs::Measure.new(42, "km")
+ a.should == a
+ end
+
+ it "returns true if the other has all the same fields" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42, "km")
+ a.should == b
+ end
+
+ it "returns false if the other is a different object or has different fields" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42, "mi")
+ a.should_not == b
+ end
+
+ it "returns false if other is of a different class" do
+ a = DataSpecs::Measure.new(42, "km")
+ klass = Data.define(*DataSpecs::Measure.members)
+ b = klass.new(42, "km")
+ a.should_not == b
+ end
+
+ it "returns false if any corresponding elements are not equal with #==" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42.0, "mi")
+ a.should_not == b
+ end
+
+ context "recursive structure" do
+ it "returns true the other is the same object" do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: 42, unit: a)
+
+ a.should == a
+ end
+
+ it "returns true if the other has all the same fields" do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: 42, unit: a)
+
+ b = DataSpecs::Measure.allocate
+ b.send(:initialize, amount: 42, unit: b)
+
+ a.should == b
+ end
+
+ it "returns false if any corresponding elements are not equal with #==" do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: a, unit: "km")
+
+ b = DataSpecs::Measure.allocate
+ b.send(:initialize, amount: b, unit: "mi")
+
+ a.should_not == b
+ end
+ end
+end
diff --git a/spec/ruby/core/data/fixtures/classes.rb b/spec/ruby/core/data/fixtures/classes.rb
index 46a6b48bb2..650c0b2a62 100644
--- a/spec/ruby/core/data/fixtures/classes.rb
+++ b/spec/ruby/core/data/fixtures/classes.rb
@@ -1,5 +1,34 @@
module DataSpecs
- guard -> { ruby_version_is "3.2" and Data.respond_to?(:define) } do
+ if Data.respond_to?(:define)
Measure = Data.define(:amount, :unit)
+
+ class MeasureWithOverriddenName < Measure
+ def self.name
+ "A"
+ end
+ end
+
+ class DataSubclass < Data; end
+
+ MeasureSubclass = Class.new(Measure) do
+ def initialize(amount:, unit:)
+ super
+ end
+ end
+
+ Empty = Data.define()
+
+ DataWithOverriddenInitialize = Data.define(:amount, :unit) do
+ def initialize(*rest, **kw)
+ super
+ ScratchPad.record [:initialize, rest, kw]
+ end
+ end
+
+ Area = Data.define(:width, :height, :area) do
+ def initialize(width:, height:)
+ super(width: width, height: height, area: width * height)
+ end
+ end
end
end
diff --git a/spec/ruby/core/data/hash_spec.rb b/spec/ruby/core/data/hash_spec.rb
new file mode 100644
index 0000000000..c23f08a71d
--- /dev/null
+++ b/spec/ruby/core/data/hash_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Data#hash" do
+ it "returns the same integer for objects with the same content" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42, "km")
+ a.hash.should == b.hash
+ a.hash.should be_an_instance_of(Integer)
+ end
+
+ it "returns different hashes for objects with different values" do
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(42, "ml")
+ a.hash.should_not == b.hash
+
+ a = DataSpecs::Measure.new(42, "km")
+ b = DataSpecs::Measure.new(13, "km")
+ a.hash.should_not == b.hash
+ end
+
+ it "returns different hashes for different classes" do
+ Data.define(:x).new(1).hash.should != Data.define(:x).new(1).hash
+ end
+end
diff --git a/spec/ruby/core/data/initialize_spec.rb b/spec/ruby/core/data/initialize_spec.rb
index 2c36bd3ac4..010c73b91b 100644
--- a/spec/ruby/core/data/initialize_spec.rb
+++ b/spec/ruby/core/data/initialize_spec.rb
@@ -1,65 +1,124 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data#initialize" do
- it "accepts positional arguments" do
- data = DataSpecs::Measure.new(42, "km")
+describe "Data#initialize" do
+ it "accepts positional arguments" do
+ data = DataSpecs::Measure.new(42, "km")
- data.amount.should == 42
- data.unit.should == "km"
- end
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
- it "accepts alternative positional arguments" do
- data = DataSpecs::Measure[42, "km"]
+ it "accepts alternative positional arguments" do
+ data = DataSpecs::Measure[42, "km"]
- data.amount.should == 42
- data.unit.should == "km"
- end
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
- it "accepts keyword arguments" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
+ it "accepts keyword arguments" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
- data.amount.should == 42
- data.unit.should == "km"
- end
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
+
+ it "accepts alternative keyword arguments" do
+ data = DataSpecs::Measure[amount: 42, unit: "km"]
- it "accepts alternative keyword arguments" do
- data = DataSpecs::Measure[amount: 42, unit: "km"]
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
+
+ it "accepts String keyword arguments" do
+ data = DataSpecs::Measure.new("amount" => 42, "unit" => "km")
+
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
- data.amount.should == 42
- data.unit.should == "km"
+ it "raises ArgumentError if no arguments are given" do
+ -> {
+ DataSpecs::Measure.new
+ }.should raise_error(ArgumentError) { |e|
+ e.message.should.include?("missing keywords: :amount, :unit")
+ }
+ end
+
+ it "raises ArgumentError if at least one argument is missing" do
+ -> {
+ DataSpecs::Measure.new(unit: "km")
+ }.should raise_error(ArgumentError) { |e|
+ e.message.should.include?("missing keyword: :amount")
+ }
+ end
+
+ it "raises ArgumentError if unknown keyword is given" do
+ -> {
+ DataSpecs::Measure.new(amount: 42, unit: "km", system: "metric")
+ }.should raise_error(ArgumentError) { |e|
+ e.message.should.include?("unknown keyword: :system")
+ }
+ end
+
+ it "supports super from a subclass" do
+ ms = DataSpecs::MeasureSubclass.new(amount: 1, unit: "km")
+
+ ms.amount.should == 1
+ ms.unit.should == "km"
+ end
+
+ it "supports Data with no fields" do
+ -> { DataSpecs::Empty.new }.should_not raise_error
+ end
+
+ it "can be overridden" do
+ ScratchPad.record []
+
+ measure_class = Data.define(:amount, :unit) do
+ def initialize(*, **)
+ super
+ ScratchPad << :initialize
+ end
end
- it "accepts String keyword arguments" do
- data = DataSpecs::Measure.new("amount" => 42, "unit" => "km")
+ measure_class.new(42, "m")
+ ScratchPad.recorded.should == [:initialize]
+ end
+
+ context "when it is overridden" do
+ it "is called with keyword arguments when given positional arguments" do
+ ScratchPad.clear
+ DataSpecs::DataWithOverriddenInitialize.new(42, "m")
+ ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}]
+ end
- data.amount.should == 42
- data.unit.should == "km"
+ it "is called with keyword arguments when given keyword arguments" do
+ ScratchPad.clear
+ DataSpecs::DataWithOverriddenInitialize.new(amount: 42, unit: "m")
+ ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}]
end
- it "raises ArgumentError if no arguments are given" do
- -> {
- DataSpecs::Measure.new
- }.should raise_error(ArgumentError) { |e|
- e.message.should.include?("missing keywords: :amount, :unit")
- }
+ it "is called with keyword arguments when given alternative positional arguments" do
+ ScratchPad.clear
+ DataSpecs::DataWithOverriddenInitialize[42, "m"]
+ ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}]
end
- it "raises ArgumentError if at least one argument is missing" do
- -> {
- DataSpecs::Measure.new(unit: "km")
- }.should raise_error(ArgumentError) { |e|
- e.message.should.include?("missing keyword: :amount")
- }
+ it "is called with keyword arguments when given alternative keyword arguments" do
+ ScratchPad.clear
+ DataSpecs::DataWithOverriddenInitialize[amount: 42, unit: "m"]
+ ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}]
end
- it "raises ArgumentError if unknown keyword is given" do
- -> {
- DataSpecs::Measure.new(amount: 42, unit: "km", system: "metric")
- }.should raise_error(ArgumentError) { |e|
- e.message.should.include?("unknown keyword: :system")
- }
+ # See https://github.com/ruby/psych/pull/765
+ it "can be deserialized by calling Data.instance_method(:initialize)" do
+ d1 = DataSpecs::Area.new(width: 2, height: 3)
+ d1.area.should == 6
+
+ d2 = DataSpecs::Area.allocate
+ Data.instance_method(:initialize).bind_call(d2, **d1.to_h)
+ d2.should == d1
end
end
end
diff --git a/spec/ruby/core/data/inspect_spec.rb b/spec/ruby/core/data/inspect_spec.rb
new file mode 100644
index 0000000000..38642910a0
--- /dev/null
+++ b/spec/ruby/core/data/inspect_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/inspect'
+
+describe "Data#inspect" do
+ it_behaves_like :data_inspect, :inspect
+end
diff --git a/spec/ruby/core/data/members_spec.rb b/spec/ruby/core/data/members_spec.rb
new file mode 100644
index 0000000000..457a90a0d6
--- /dev/null
+++ b/spec/ruby/core/data/members_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Data#members" do
+ it "returns an array of attribute names" do
+ measure = DataSpecs::Measure.new(amount: 42, unit: 'km')
+ measure.members.should == [:amount, :unit]
+ end
+end
+
+describe "DataClass#members" do
+ it "returns an array of attribute names" do
+ DataSpecs::Measure.members.should == [:amount, :unit]
+ end
+
+ context "class inheriting Data" do
+ it "isn't available in a subclass" do
+ DataSpecs::DataSubclass.should_not.respond_to?(:members)
+ end
+ end
+end
diff --git a/spec/ruby/core/data/shared/inspect.rb b/spec/ruby/core/data/shared/inspect.rb
new file mode 100644
index 0000000000..6cd5664da7
--- /dev/null
+++ b/spec/ruby/core/data/shared/inspect.rb
@@ -0,0 +1,62 @@
+require_relative '../fixtures/classes'
+
+describe :data_inspect, shared: true do
+ it "returns a string representation showing members and values" do
+ a = DataSpecs::Measure.new(42, "km")
+ a.send(@method).should == '#<data DataSpecs::Measure amount=42, unit="km">'
+ end
+
+ it "returns a string representation without the class name for anonymous structs" do
+ Data.define(:a).new("").send(@method).should == '#<data a="">'
+ end
+
+ it "returns a string representation without the class name for structs nested in anonymous classes" do
+ c = Class.new
+ c.class_eval <<~DOC
+ Foo = Data.define(:a)
+ DOC
+
+ c::Foo.new("").send(@method).should == '#<data a="">'
+ end
+
+ it "returns a string representation without the class name for structs nested in anonymous modules" do
+ m = Module.new
+ m.class_eval <<~DOC
+ Foo = Data.define(:a)
+ DOC
+
+ m::Foo.new("").send(@method).should == '#<data a="">'
+ end
+
+ it "does not call #name method" do
+ struct = DataSpecs::MeasureWithOverriddenName.new(42, "km")
+ struct.send(@method).should == '#<data DataSpecs::MeasureWithOverriddenName amount=42, unit="km">'
+ end
+
+ it "does not call #name method when struct is anonymous" do
+ klass = Class.new(DataSpecs::Measure) do
+ def self.name
+ "A"
+ end
+ end
+ struct = klass.new(42, "km")
+ struct.send(@method).should == '#<data amount=42, unit="km">'
+ end
+
+ context "recursive structure" do
+ it "returns string representation with recursive attribute replaced with ..." do
+ a = DataSpecs::Measure.allocate
+ a.send(:initialize, amount: 42, unit: a)
+
+ a.send(@method).should == "#<data DataSpecs::Measure amount=42, unit=#<data DataSpecs::Measure:...>>"
+ end
+
+ it "returns string representation with recursive attribute replaced with ... when an anonymous class" do
+ klass = Class.new(DataSpecs::Measure)
+ a = klass.allocate
+ a.send(:initialize, amount: 42, unit: a)
+
+ a.send(@method).should =~ /#<data amount=42, unit=#<data #<Class:0x.+?>:\.\.\.>>/
+ end
+ end
+end
diff --git a/spec/ruby/core/data/to_h_spec.rb b/spec/ruby/core/data/to_h_spec.rb
index 41d6960c97..64816b7251 100644
--- a/spec/ruby/core/data/to_h_spec.rb
+++ b/spec/ruby/core/data/to_h_spec.rb
@@ -1,65 +1,63 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data#to_h" do
- it "transforms the data object into a hash" do
+describe "Data#to_h" do
+ it "transforms the data object into a hash" do
+ data = DataSpecs::Measure.new(amount: 42, unit: 'km')
+ data.to_h.should == { amount: 42, unit: 'km' }
+ end
+
+ context "with block" do
+ it "transforms [key, value] pairs returned by the block into a hash" do
data = DataSpecs::Measure.new(amount: 42, unit: 'km')
- data.to_h.should == { amount: 42, unit: 'km' }
+ data.to_h { |key, value| [value, key] }.should == { 42 => :amount, 'km' => :unit }
end
- context "with block" do
- it "transforms [key, value] pairs returned by the block into a hash" do
- data = DataSpecs::Measure.new(amount: 42, unit: 'km')
- data.to_h { |key, value| [value, key] }.should == { 42 => :amount, 'km' => :unit }
- end
-
- it "passes to a block each pair's key and value as separate arguments" do
- ScratchPad.record []
- data = DataSpecs::Measure.new(amount: 42, unit: 'km')
- data.to_h { |k, v| ScratchPad << [k, v]; [k, v] }
- ScratchPad.recorded.sort.should == [[:amount, 42], [:unit, 'km']]
+ it "passes to a block each pair's key and value as separate arguments" do
+ ScratchPad.record []
+ data = DataSpecs::Measure.new(amount: 42, unit: 'km')
+ data.to_h { |k, v| ScratchPad << [k, v]; [k, v] }
+ ScratchPad.recorded.sort.should == [[:amount, 42], [:unit, 'km']]
- ScratchPad.record []
- data.to_h { |*args| ScratchPad << args; [args[0], args[1]] }
- ScratchPad.recorded.sort.should == [[:amount, 42], [:unit, 'km']]
- end
+ ScratchPad.record []
+ data.to_h { |*args| ScratchPad << args; [args[0], args[1]] }
+ ScratchPad.recorded.sort.should == [[:amount, 42], [:unit, 'km']]
+ end
- it "raises ArgumentError if block returns longer or shorter array" do
- data = DataSpecs::Measure.new(amount: 42, unit: 'km')
- -> do
- data.to_h { |k, v| [k.to_s, v*v, 1] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
+ it "raises ArgumentError if block returns longer or shorter array" do
+ data = DataSpecs::Measure.new(amount: 42, unit: 'km')
+ -> do
+ data.to_h { |k, v| [k.to_s, v*v, 1] }
+ end.should raise_error(ArgumentError, /element has wrong array length/)
- -> do
- data.to_h { |k, v| [k] }
- end.should raise_error(ArgumentError, /element has wrong array length/)
- end
+ -> do
+ data.to_h { |k, v| [k] }
+ end.should raise_error(ArgumentError, /element has wrong array length/)
+ end
- it "raises TypeError if block returns something other than Array" do
- data = DataSpecs::Measure.new(amount: 42, unit: 'km')
- -> do
- data.to_h { |k, v| "not-array" }
- end.should raise_error(TypeError, /wrong element type String/)
- end
+ it "raises TypeError if block returns something other than Array" do
+ data = DataSpecs::Measure.new(amount: 42, unit: 'km')
+ -> do
+ data.to_h { |k, v| "not-array" }
+ end.should raise_error(TypeError, /wrong element type String/)
+ end
- it "coerces returned pair to Array with #to_ary" do
- x = mock('x')
- x.stub!(:to_ary).and_return([:b, 'b'])
- data = DataSpecs::Measure.new(amount: 42, unit: 'km')
+ it "coerces returned pair to Array with #to_ary" do
+ x = mock('x')
+ x.stub!(:to_ary).and_return([:b, 'b'])
+ data = DataSpecs::Measure.new(amount: 42, unit: 'km')
- data.to_h { |k| x }.should == { :b => 'b' }
- end
+ data.to_h { |k| x }.should == { :b => 'b' }
+ end
- it "does not coerce returned pair to Array with #to_a" do
- x = mock('x')
- x.stub!(:to_a).and_return([:b, 'b'])
- data = DataSpecs::Measure.new(amount: 42, unit: 'km')
+ it "does not coerce returned pair to Array with #to_a" do
+ x = mock('x')
+ x.stub!(:to_a).and_return([:b, 'b'])
+ data = DataSpecs::Measure.new(amount: 42, unit: 'km')
- -> do
- data.to_h { |k| x }
- end.should raise_error(TypeError, /wrong element type MockObject/)
- end
+ -> do
+ data.to_h { |k| x }
+ end.should raise_error(TypeError, /wrong element type MockObject/)
end
end
end
diff --git a/spec/ruby/core/data/to_s_spec.rb b/spec/ruby/core/data/to_s_spec.rb
new file mode 100644
index 0000000000..2b4a670e8e
--- /dev/null
+++ b/spec/ruby/core/data/to_s_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/inspect'
+
+describe "Data#to_s" do
+ it_behaves_like :data_inspect, :to_s
+end
diff --git a/spec/ruby/core/data/with_spec.rb b/spec/ruby/core/data/with_spec.rb
index 97e34c951f..fd0a99d1fa 100644
--- a/spec/ruby/core/data/with_spec.rb
+++ b/spec/ruby/core/data/with_spec.rb
@@ -1,35 +1,57 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Data#with" do
- it "returns self if given no arguments" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
- data = data.with.should.equal?(data)
- end
+describe "Data#with" do
+ it "returns self if given no arguments" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
+ data = data.with.should.equal?(data)
+ end
- it "accepts keyword arguments" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
- data = data.with(amount: 4, unit: "m")
+ it "accepts keyword arguments" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
+ data = data.with(amount: 4, unit: "m")
- data.amount.should == 4
- data.unit.should == "m"
- end
+ data.amount.should == 4
+ data.unit.should == "m"
+ end
+
+ it "accepts String keyword arguments" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
+ data = data.with("amount" => 4, "unit" => "m")
+
+ data.amount.should == 4
+ data.unit.should == "m"
+ end
- it "accepts String keyword arguments" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
- data = data.with("amount" => 4, "unit" => "m")
+ it "raises ArgumentError if no keyword arguments are given" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
- data.amount.should == 4
- data.unit.should == "m"
+ -> {
+ data.with(4, "m")
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)")
+ end
+
+ it "does not depend on the Data.new method" do
+ subclass = Class.new(DataSpecs::Measure)
+ data = subclass.new(amount: 42, unit: "km")
+
+ def subclass.new(*)
+ raise "Data.new is called"
end
- it "raises ArgumentError if no keyword arguments are given" do
- data = DataSpecs::Measure.new(amount: 42, unit: "km")
+ data_copy = data.with(unit: "m")
+ data_copy.amount.should == 42
+ data_copy.unit.should == "m"
+ end
+
+ ruby_version_is "3.3" do
+ it "calls #initialize" do
+ data = DataSpecs::DataWithOverriddenInitialize.new(42, "m")
+ ScratchPad.clear
+
+ data.with(amount: 0)
- -> {
- data.with(4, "m")
- }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)")
+ ScratchPad.recorded.should == [:initialize, [], {amount: 0, unit: "m"}]
end
end
end
diff --git a/spec/ruby/core/dir/chdir_spec.rb b/spec/ruby/core/dir/chdir_spec.rb
index 7ced2a7057..015386a902 100644
--- a/spec/ruby/core/dir/chdir_spec.rb
+++ b/spec/ruby/core/dir/chdir_spec.rb
@@ -95,10 +95,10 @@ describe "Dir.chdir" do
end
it "raises an Errno::ENOENT if the original directory no longer exists" do
- dir1 = tmp('/testdir1')
- dir2 = tmp('/testdir2')
- File.should_not.exist?(dir1)
- File.should_not.exist?(dir2)
+ dir1 = tmp('testdir1')
+ dir2 = tmp('testdir2')
+ Dir.should_not.exist?(dir1)
+ Dir.should_not.exist?(dir2)
Dir.mkdir dir1
Dir.mkdir dir2
begin
@@ -108,8 +108,8 @@ describe "Dir.chdir" do
end
}.should raise_error(Errno::ENOENT)
ensure
- Dir.unlink dir1 if File.exist?(dir1)
- Dir.unlink dir2 if File.exist?(dir2)
+ Dir.unlink dir1 if Dir.exist?(dir1)
+ Dir.unlink dir2 if Dir.exist?(dir2)
end
end
@@ -124,3 +124,97 @@ describe "Dir.chdir" do
Dir.pwd.should == @original
end
end
+
+ruby_version_is '3.3' do
+ describe "Dir#chdir" do
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
+
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
+
+ before :each do
+ @original = Dir.pwd
+ end
+
+ after :each do
+ Dir.chdir(@original)
+ end
+
+ it "changes the current working directory to self" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir.chdir
+ Dir.pwd.should == DirSpecs.mock_dir
+ ensure
+ dir.close
+ end
+
+ it "changes the current working directory to self for duration of the block when a block is given" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ pwd_in_block = nil
+
+ dir.chdir { pwd_in_block = Dir.pwd }
+
+ pwd_in_block.should == DirSpecs.mock_dir
+ Dir.pwd.should == @original
+ ensure
+ dir.close
+ end
+
+ it "returns 0 when successfully changing directory" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir.chdir.should == 0
+ ensure
+ dir.close
+ end
+
+ it "returns the value of the block when a block is given" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir.chdir { :block_value }.should == :block_value
+ ensure
+ dir.close
+ end
+
+ platform_is_not :windows do
+ it "does not raise an Errno::ENOENT if the original directory no longer exists" do
+ dir_name1 = tmp('testdir1')
+ dir_name2 = tmp('testdir2')
+ Dir.should_not.exist?(dir_name1)
+ Dir.should_not.exist?(dir_name2)
+ Dir.mkdir dir_name1
+ Dir.mkdir dir_name2
+
+ dir2 = Dir.new(dir_name2)
+
+ begin
+ Dir.chdir(dir_name1) do
+ dir2.chdir { Dir.unlink dir_name1 }
+ end
+ Dir.pwd.should == @original
+ ensure
+ Dir.unlink dir_name1 if Dir.exist?(dir_name1)
+ Dir.unlink dir_name2 if Dir.exist?(dir_name2)
+ end
+ ensure
+ dir2.close
+ end
+ end
+
+ it "always returns to the original directory when given a block" do
+ dir = Dir.new(DirSpecs.mock_dir)
+
+ begin
+ dir.chdir do
+ raise StandardError, "something bad happened"
+ end
+ rescue StandardError
+ end
+
+ Dir.pwd.should == @original
+ ensure
+ dir.close
+ end
+ end
+end
diff --git a/spec/ruby/core/dir/close_spec.rb b/spec/ruby/core/dir/close_spec.rb
index 5fad5eecfb..f7cce318b8 100644
--- a/spec/ruby/core/dir/close_spec.rb
+++ b/spec/ruby/core/dir/close_spec.rb
@@ -11,9 +11,43 @@ describe "Dir#close" do
it "does not raise an IOError even if the Dir instance is closed" do
dir = Dir.open DirSpecs.mock_dir
- dir.close
- -> {
- dir.close
- }.should_not raise_error(IOError)
+ dir.close.should == nil
+ dir.close.should == nil
+
+ platform_is_not :windows do
+ -> { dir.fileno }.should raise_error(IOError, /closed directory/)
+ end
+ end
+
+ it "returns nil" do
+ dir = Dir.open DirSpecs.mock_dir
+ dir.close.should == nil
+ end
+
+ ruby_version_is '3.3'...'3.4' do
+ platform_is_not :windows do
+ it "does not raise an error even if the file descriptor is closed with another Dir instance" do
+ dir = Dir.open DirSpecs.mock_dir
+ dir_new = Dir.for_fd(dir.fileno)
+
+ dir.close
+ dir_new.close
+
+ -> { dir.fileno }.should raise_error(IOError, /closed directory/)
+ -> { dir_new.fileno }.should raise_error(IOError, /closed directory/)
+ end
+ end
+ end
+
+ ruby_version_is '3.4' do
+ platform_is_not :windows do
+ it "raises an error if the file descriptor is closed with another Dir instance" do
+ dir = Dir.open DirSpecs.mock_dir
+ dir_new = Dir.for_fd(dir.fileno)
+ dir.close
+
+ -> { dir_new.close }.should raise_error(Errno::EBADF, 'Bad file descriptor - closedir')
+ end
+ end
end
end
diff --git a/spec/ruby/core/dir/exist_spec.rb b/spec/ruby/core/dir/exist_spec.rb
index 9023de533f..0b8e521894 100644
--- a/spec/ruby/core/dir/exist_spec.rb
+++ b/spec/ruby/core/dir/exist_spec.rb
@@ -14,10 +14,8 @@ describe "Dir.exist?" do
it_behaves_like :dir_exist, :exist?
end
-ruby_version_is "3.2" do
- describe "Dir.exists?" do
- it "has been removed" do
- Dir.should_not.respond_to?(:exists?)
- end
+describe "Dir.exists?" do
+ it "has been removed" do
+ Dir.should_not.respond_to?(:exists?)
end
end
diff --git a/spec/ruby/core/dir/fchdir_spec.rb b/spec/ruby/core/dir/fchdir_spec.rb
index 429e569691..52600a95f2 100644
--- a/spec/ruby/core/dir/fchdir_spec.rb
+++ b/spec/ruby/core/dir/fchdir_spec.rb
@@ -2,7 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/common'
ruby_version_is '3.3' do
- guard -> { Dir.respond_to? :fchdir } do
+ platform_is_not :windows do
describe "Dir.fchdir" do
before :all do
DirSpecs.create_mock_dirs
@@ -13,51 +13,56 @@ ruby_version_is '3.3' do
end
before :each do
- @dirs = [Dir.new('.')]
- @original = @dirs.first.fileno
+ @original = Dir.pwd
end
after :each do
- Dir.fchdir(@original)
- @dirs.each(&:close)
+ Dir.chdir(@original)
end
- it "changes to the specified directory" do
+ it "changes the current working directory to the directory specified by the integer file descriptor" do
dir = Dir.new(DirSpecs.mock_dir)
- @dirs << dir
Dir.fchdir dir.fileno
Dir.pwd.should == DirSpecs.mock_dir
+ ensure
+ dir.close
end
it "returns 0 when successfully changing directory" do
- Dir.fchdir(@original).should == 0
+ dir = Dir.new(DirSpecs.mock_dir)
+ Dir.fchdir(dir.fileno).should == 0
+ ensure
+ dir.close
end
it "returns the value of the block when a block is given" do
- Dir.fchdir(@original) { :block_value }.should == :block_value
+ dir = Dir.new(DirSpecs.mock_dir)
+ Dir.fchdir(dir.fileno) { :block_value }.should == :block_value
+ ensure
+ dir.close
end
it "changes to the specified directory for the duration of the block" do
- pwd = Dir.pwd
dir = Dir.new(DirSpecs.mock_dir)
- @dirs << dir
Dir.fchdir(dir.fileno) { Dir.pwd }.should == DirSpecs.mock_dir
- Dir.pwd.should == pwd
+ Dir.pwd.should == @original
+ ensure
+ dir.close
end
it "raises a SystemCallError if the file descriptor given is not valid" do
- -> { Dir.fchdir(-1) }.should raise_error(SystemCallError)
- -> { Dir.fchdir(-1) { } }.should raise_error(SystemCallError)
+ -> { Dir.fchdir(-1) }.should raise_error(SystemCallError, "Bad file descriptor - fchdir")
+ -> { Dir.fchdir(-1) { } }.should raise_error(SystemCallError, "Bad file descriptor - fchdir")
end
it "raises a SystemCallError if the file descriptor given is not for a directory" do
- -> { Dir.fchdir $stdout.fileno }.should raise_error(SystemCallError)
- -> { Dir.fchdir($stdout.fileno) { } }.should raise_error(SystemCallError)
+ -> { Dir.fchdir $stdout.fileno }.should raise_error(SystemCallError, /(Not a directory|Invalid argument) - fchdir/)
+ -> { Dir.fchdir($stdout.fileno) { } }.should raise_error(SystemCallError, /(Not a directory|Invalid argument) - fchdir/)
end
end
end
- guard_not -> { Dir.respond_to? :fchdir } do
+ platform_is :windows do
describe "Dir.fchdir" do
it "raises NotImplementedError" do
-> { Dir.fchdir 1 }.should raise_error(NotImplementedError)
diff --git a/spec/ruby/core/dir/fixtures/common.rb b/spec/ruby/core/dir/fixtures/common.rb
index 087f46b331..848656c9b9 100644
--- a/spec/ruby/core/dir/fixtures/common.rb
+++ b/spec/ruby/core/dir/fixtures/common.rb
@@ -192,13 +192,7 @@ module DirSpecs
]
end
- if RUBY_VERSION > '3.1'
- def self.expected_glob_paths
- expected_paths - ['..']
- end
- else
- def self.expected_glob_paths
- expected_paths
- end
+ def self.expected_glob_paths
+ expected_paths - ['..']
end
end
diff --git a/spec/ruby/core/dir/for_fd_spec.rb b/spec/ruby/core/dir/for_fd_spec.rb
new file mode 100644
index 0000000000..ba467f2f86
--- /dev/null
+++ b/spec/ruby/core/dir/for_fd_spec.rb
@@ -0,0 +1,79 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/common'
+
+quarantine! do # leads to "Errno::EBADF: Bad file descriptor - closedir" in DirSpecs.delete_mock_dirs
+ruby_version_is '3.3' do
+ platform_is_not :windows do
+ describe "Dir.for_fd" do
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
+
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
+
+ before :each do
+ @original = Dir.pwd
+ end
+
+ after :each do
+ Dir.chdir(@original)
+ end
+
+ it "returns a new Dir object representing the directory specified by the given integer directory file descriptor" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir_new = Dir.for_fd(dir.fileno)
+
+ dir_new.should.instance_of?(Dir)
+ dir_new.children.should == dir.children
+ dir_new.fileno.should == dir.fileno
+ ensure
+ dir.close
+ end
+
+ it "returns a new Dir object without associated path" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ dir_new = Dir.for_fd(dir.fileno)
+
+ dir_new.path.should == nil
+ ensure
+ dir.close
+ end
+
+ it "calls #to_int to convert a value to an Integer" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ obj = mock("fd")
+ obj.should_receive(:to_int).and_return(dir.fileno)
+
+ dir_new = Dir.for_fd(obj)
+ dir_new.fileno.should == dir.fileno
+ ensure
+ dir.close
+ end
+
+ it "raises TypeError when value cannot be converted to Integer" do
+ -> {
+ Dir.for_fd(nil)
+ }.should raise_error(TypeError, "no implicit conversion from nil to integer")
+ end
+
+ it "raises a SystemCallError if the file descriptor given is not valid" do
+ -> { Dir.for_fd(-1) }.should raise_error(SystemCallError, "Bad file descriptor - fdopendir")
+ end
+
+ it "raises a SystemCallError if the file descriptor given is not for a directory" do
+ -> { Dir.for_fd $stdout.fileno }.should raise_error(SystemCallError, "Not a directory - fdopendir")
+ end
+ end
+ end
+
+ platform_is :windows do
+ describe "Dir.for_fd" do
+ it "raises NotImplementedError" do
+ -> { Dir.for_fd 1 }.should raise_error(NotImplementedError)
+ end
+ end
+ end
+end
+end
diff --git a/spec/ruby/core/dir/glob_spec.rb b/spec/ruby/core/dir/glob_spec.rb
index 32f515c81d..a60b233bc0 100644
--- a/spec/ruby/core/dir/glob_spec.rb
+++ b/spec/ruby/core/dir/glob_spec.rb
@@ -89,31 +89,15 @@ describe "Dir.glob" do
Dir.glob('**/', File::FNM_DOTMATCH).sort.should == expected
end
- ruby_version_is ''...'3.1' do
- it "recursively matches files and directories in nested dot subdirectory with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH" do
- expected = %w[
- nested/.
- nested/.dotsubir
- nested/.dotsubir/.
- nested/.dotsubir/.dotfile
- nested/.dotsubir/nondotfile
- ]
-
- Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort
- end
- end
-
- ruby_version_is '3.1' do
- it "recursively matches files and directories in nested dot subdirectory except . with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH" do
- expected = %w[
- nested/.
- nested/.dotsubir
- nested/.dotsubir/.dotfile
- nested/.dotsubir/nondotfile
- ]
+ it "recursively matches files and directories in nested dot subdirectory except . with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH" do
+ expected = %w[
+ nested/.
+ nested/.dotsubir
+ nested/.dotsubir/.dotfile
+ nested/.dotsubir/nondotfile
+ ]
- Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort
- end
+ Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort
end
# This is a separate case to check **/ coming after a constant
@@ -260,34 +244,31 @@ describe "Dir.glob" do
Dir.glob('**/.*', base: "deeply/nested").sort.should == expected
end
- # < 3.1 include a "." entry for every dir: ["directory/.", "directory/structure/.", ...]
- ruby_version_is '3.1' do
- it "handles **/.* with base keyword argument and FNM_DOTMATCH" do
- expected = %w[
- .
- .dotfile.ext
- directory/structure/.ext
- ].sort
+ it "handles **/.* with base keyword argument and FNM_DOTMATCH" do
+ expected = %w[
+ .
+ .dotfile.ext
+ directory/structure/.ext
+ ].sort
- Dir.glob('**/.*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
- end
+ Dir.glob('**/.*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
+ end
- it "handles **/** with base keyword argument and FNM_DOTMATCH" do
- expected = %w[
- .
- .dotfile.ext
- directory
- directory/structure
- directory/structure/.ext
- directory/structure/bar
- directory/structure/baz
- directory/structure/file_one
- directory/structure/file_one.ext
- directory/structure/foo
- ].sort
-
- Dir.glob('**/**', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
- end
+ it "handles **/** with base keyword argument and FNM_DOTMATCH" do
+ expected = %w[
+ .
+ .dotfile.ext
+ directory
+ directory/structure
+ directory/structure/.ext
+ directory/structure/bar
+ directory/structure/baz
+ directory/structure/file_one
+ directory/structure/file_one.ext
+ directory/structure/foo
+ ].sort
+
+ Dir.glob('**/**', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
end
it "handles **/*pattern* with base keyword argument and FNM_DOTMATCH" do
diff --git a/spec/ruby/core/dir/home_spec.rb b/spec/ruby/core/dir/home_spec.rb
index 3cf745ab46..966ac38af3 100644
--- a/spec/ruby/core/dir/home_spec.rb
+++ b/spec/ruby/core/dir/home_spec.rb
@@ -33,40 +33,32 @@ describe "Dir.home" do
end
platform_is :windows do
- ruby_version_is "3.2" do
- it "returns the home directory with forward slashs and as UTF-8" do
- ENV['HOME'] = "C:\\rubyspäc\\home"
- home = Dir.home
- home.should == "C:/rubyspäc/home"
- home.encoding.should == Encoding::UTF_8
- end
+ it "returns the home directory with forward slashs and as UTF-8" do
+ ENV['HOME'] = "C:\\rubyspäc\\home"
+ home = Dir.home
+ home.should == "C:/rubyspäc/home"
+ home.encoding.should == Encoding::UTF_8
+ end
- it "retrieves the directory from HOME, USERPROFILE, HOMEDRIVE/HOMEPATH and the WinAPI in that order" do
- old_dirs = [ENV.delete('HOME'), ENV.delete('USERPROFILE'), ENV.delete('HOMEDRIVE'), ENV.delete('HOMEPATH')]
+ it "retrieves the directory from HOME, USERPROFILE, HOMEDRIVE/HOMEPATH and the WinAPI in that order" do
+ old_dirs = [ENV.delete('HOME'), ENV.delete('USERPROFILE'), ENV.delete('HOMEDRIVE'), ENV.delete('HOMEPATH')]
- Dir.home.should == old_dirs[1].gsub("\\", "/")
- ENV['HOMEDRIVE'] = "C:"
- ENV['HOMEPATH'] = "\\rubyspec\\home1"
- Dir.home.should == "C:/rubyspec/home1"
- ENV['USERPROFILE'] = "C:\\rubyspec\\home2"
- Dir.home.should == "C:/rubyspec/home2"
- ENV['HOME'] = "C:\\rubyspec\\home3"
- Dir.home.should == "C:/rubyspec/home3"
- ensure
- ENV['HOME'], ENV['USERPROFILE'], ENV['HOMEDRIVE'], ENV['HOMEPATH'] = *old_dirs
- end
+ Dir.home.should == old_dirs[1].gsub("\\", "/")
+ ENV['HOMEDRIVE'] = "C:"
+ ENV['HOMEPATH'] = "\\rubyspec\\home1"
+ Dir.home.should == "C:/rubyspec/home1"
+ ENV['USERPROFILE'] = "C:\\rubyspec\\home2"
+ Dir.home.should == "C:/rubyspec/home2"
+ ENV['HOME'] = "C:\\rubyspec\\home3"
+ Dir.home.should == "C:/rubyspec/home3"
+ ensure
+ ENV['HOME'], ENV['USERPROFILE'], ENV['HOMEDRIVE'], ENV['HOMEPATH'] = *old_dirs
end
end
end
describe "when called with the current user name" do
- platform_is :solaris do
- it "returns the named user's home directory from the user database" do
- Dir.home(ENV['USER']).should == `getent passwd #{ENV['USER']}|cut -d: -f6`.chomp
- end
- end
-
- platform_is_not :windows, :solaris, :android, :wasi do
+ platform_is_not :windows, :android, :wasi do
it "returns the named user's home directory, from the user database" do
Dir.home(ENV['USER']).should == `echo ~#{ENV['USER']}`.chomp
end
diff --git a/spec/ruby/core/dir/shared/delete.rb b/spec/ruby/core/dir/shared/delete.rb
index 49e88360e8..a81b059759 100644
--- a/spec/ruby/core/dir/shared/delete.rb
+++ b/spec/ruby/core/dir/shared/delete.rb
@@ -17,20 +17,10 @@ describe :dir_delete, shared: true do
Dir.send(@method, p)
end
- platform_is_not :solaris do
- it "raises an Errno::ENOTEMPTY when trying to remove a nonempty directory" do
- -> do
- Dir.send @method, DirSpecs.mock_rmdir("nonempty")
- end.should raise_error(Errno::ENOTEMPTY)
- end
- end
-
- platform_is :solaris do
- it "raises an Errno::EEXIST when trying to remove a nonempty directory" do
- -> do
- Dir.send @method, DirSpecs.mock_rmdir("nonempty")
- end.should raise_error(Errno::EEXIST)
- end
+ it "raises an Errno::ENOTEMPTY when trying to remove a nonempty directory" do
+ -> do
+ Dir.send @method, DirSpecs.mock_rmdir("nonempty")
+ end.should raise_error(Errno::ENOTEMPTY)
end
it "raises an Errno::ENOENT when trying to remove a non-existing directory" do
diff --git a/spec/ruby/core/dir/shared/glob.rb b/spec/ruby/core/dir/shared/glob.rb
index 8db74881ba..b1fc924f08 100644
--- a/spec/ruby/core/dir/shared/glob.rb
+++ b/spec/ruby/core/dir/shared/glob.rb
@@ -42,25 +42,10 @@ describe :dir_glob, shared: true do
result.sort.should == Dir.send(@method, '*').sort
end
- ruby_version_is ""..."3.1" do
- it "result is sorted with any non false value of sort:" do
- result = Dir.send(@method, '*', sort: 0)
- result.should == result.sort
-
- result = Dir.send(@method, '*', sort: nil)
- result.should == result.sort
-
- result = Dir.send(@method, '*', sort: 'false')
- result.should == result.sort
- end
- end
-
- ruby_version_is "3.1" do
- it "raises an ArgumentError if sort: is not true or false" do
- -> { Dir.send(@method, '*', sort: 0) }.should raise_error ArgumentError, /expected true or false/
- -> { Dir.send(@method, '*', sort: nil) }.should raise_error ArgumentError, /expected true or false/
- -> { Dir.send(@method, '*', sort: 'false') }.should raise_error ArgumentError, /expected true or false/
- end
+ it "raises an ArgumentError if sort: is not true or false" do
+ -> { Dir.send(@method, '*', sort: 0) }.should raise_error ArgumentError, /expected true or false/
+ -> { Dir.send(@method, '*', sort: nil) }.should raise_error ArgumentError, /expected true or false/
+ -> { Dir.send(@method, '*', sort: 'false') }.should raise_error ArgumentError, /expected true or false/
end
it "matches non-dotfiles with '*'" do
@@ -151,16 +136,8 @@ describe :dir_glob, shared: true do
Dir.send(@method, 'special/test\{1\}/*').should == ['special/test{1}/file[1]']
end
- ruby_version_is ''...'3.1' do
- it "matches dotfiles with '.*'" do
- Dir.send(@method, '.*').sort.should == %w|. .. .dotfile .dotsubdir|.sort
- end
- end
-
- ruby_version_is '3.1' do
- it "matches dotfiles except .. with '.*'" do
- Dir.send(@method, '.*').sort.should == %w|. .dotfile .dotsubdir|.sort
- end
+ it "matches dotfiles except .. with '.*'" do
+ Dir.send(@method, '.*').sort.should == %w|. .dotfile .dotsubdir|.sort
end
it "matches non-dotfiles with '*<non-special characters>'" do
@@ -205,16 +182,8 @@ describe :dir_glob, shared: true do
Dir.send(@method, '**').sort.should == expected
end
- ruby_version_is ''...'3.1' do
- it "matches dotfiles in the current directory with '.**'" do
- Dir.send(@method, '.**').sort.should == %w|. .. .dotsubdir .dotfile|.sort
- end
- end
-
- ruby_version_is '3.1' do
- it "matches dotfiles in the current directory except .. with '.**'" do
- Dir.send(@method, '.**').sort.should == %w|. .dotsubdir .dotfile|.sort
- end
+ it "matches dotfiles in the current directory except .. with '.**'" do
+ Dir.send(@method, '.**').sort.should == %w|. .dotsubdir .dotfile|.sort
end
it "recursively matches any nondot subdirectories with '**/'" do
@@ -245,19 +214,9 @@ describe :dir_glob, shared: true do
Dir.send(@method, '**/*ory', base: 'deeply').sort.should == expected
end
- ruby_version_is ''...'3.1' do
- it "recursively matches any subdirectories including ./ and ../ with '.**/'" do
- Dir.chdir("#{DirSpecs.mock_dir}/subdir_one") do
- Dir.send(@method, '.**/').sort.should == %w|./ ../|.sort
- end
- end
- end
-
- ruby_version_is '3.1' do
- it "recursively matches any subdirectories including ./ with '.**/'" do
- Dir.chdir("#{DirSpecs.mock_dir}/subdir_one") do
- Dir.send(@method, '.**/').should == ['./']
- end
+ it "recursively matches any subdirectories including ./ with '.**/'" do
+ Dir.chdir("#{DirSpecs.mock_dir}/subdir_one") do
+ Dir.send(@method, '.**/').should == ['./']
end
end
diff --git a/spec/ruby/core/encoding/compatible_spec.rb b/spec/ruby/core/encoding/compatible_spec.rb
index 61a651893b..31376a3b75 100644
--- a/spec/ruby/core/encoding/compatible_spec.rb
+++ b/spec/ruby/core/encoding/compatible_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
@@ -171,7 +171,7 @@ describe "Encoding.compatible? String, String" do
# Use the following script to regenerate the matrix:
#
# ```
-# # -*- encoding: binary -*-
+# # encoding: binary
#
# ENCODINGS = [
# "US-ASCII",
diff --git a/spec/ruby/core/encoding/converter/convert_spec.rb b/spec/ruby/core/encoding/converter/convert_spec.rb
index 7f249d90a3..8533af4565 100644
--- a/spec/ruby/core/encoding/converter/convert_spec.rb
+++ b/spec/ruby/core/encoding/converter/convert_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
# frozen_string_literal: true
require_relative '../../../spec_helper'
diff --git a/spec/ruby/core/encoding/converter/finish_spec.rb b/spec/ruby/core/encoding/converter/finish_spec.rb
index 239243430b..22e66df38c 100644
--- a/spec/ruby/core/encoding/converter/finish_spec.rb
+++ b/spec/ruby/core/encoding/converter/finish_spec.rb
@@ -16,8 +16,8 @@ describe "Encoding::Converter#finish" do
end
it "returns the last part of the converted String if it hasn't already" do
- @ec.convert("\u{9999}").should == "\e$B9a".dup.force_encoding('iso-2022-jp')
- @ec.finish.should == "\e(B".dup.force_encoding('iso-2022-jp')
+ @ec.convert("\u{9999}").should == "\e$B9a".dup.force_encoding('iso-2022-jp')
+ @ec.finish.should == "\e(B".dup.force_encoding('iso-2022-jp')
end
it "returns a String in the destination encoding" do
diff --git a/spec/ruby/core/encoding/converter/last_error_spec.rb b/spec/ruby/core/encoding/converter/last_error_spec.rb
index 78779be70b..ff2a2b4cbe 100644
--- a/spec/ruby/core/encoding/converter/last_error_spec.rb
+++ b/spec/ruby/core/encoding/converter/last_error_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
describe "Encoding::Converter#last_error" do
diff --git a/spec/ruby/core/encoding/converter/new_spec.rb b/spec/ruby/core/encoding/converter/new_spec.rb
index db9c3364d7..a7bef53809 100644
--- a/spec/ruby/core/encoding/converter/new_spec.rb
+++ b/spec/ruby/core/encoding/converter/new_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
describe "Encoding::Converter.new" do
diff --git a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
index 63f25eddef..e4aeed103e 100644
--- a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
+++ b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
# frozen_string_literal: false
require_relative '../../../spec_helper'
diff --git a/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb b/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
index 668eb9a924..5ee8b1fecd 100644
--- a/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
+++ b/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
# frozen_string_literal: false
require_relative '../../../spec_helper'
diff --git a/spec/ruby/core/encoding/converter/putback_spec.rb b/spec/ruby/core/encoding/converter/putback_spec.rb
index e19fe6c314..04bb565655 100644
--- a/spec/ruby/core/encoding/converter/putback_spec.rb
+++ b/spec/ruby/core/encoding/converter/putback_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
describe "Encoding::Converter#putback" do
diff --git a/spec/ruby/core/encoding/converter/search_convpath_spec.rb b/spec/ruby/core/encoding/converter/search_convpath_spec.rb
index 0882af5539..59fe4520c0 100644
--- a/spec/ruby/core/encoding/converter/search_convpath_spec.rb
+++ b/spec/ruby/core/encoding/converter/search_convpath_spec.rb
@@ -23,8 +23,8 @@ describe "Encoding::Converter.search_convpath" do
end
it "raises an Encoding::ConverterNotFoundError if no conversion path exists" do
- -> do
- Encoding::Converter.search_convpath(Encoding::BINARY, Encoding::Emacs_Mule)
- end.should raise_error(Encoding::ConverterNotFoundError)
+ -> do
+ Encoding::Converter.search_convpath(Encoding::BINARY, Encoding::Emacs_Mule)
+ end.should raise_error(Encoding::ConverterNotFoundError)
end
end
diff --git a/spec/ruby/core/encoding/find_spec.rb b/spec/ruby/core/encoding/find_spec.rb
index 8a0873070f..9c34fe0e77 100644
--- a/spec/ruby/core/encoding/find_spec.rb
+++ b/spec/ruby/core/encoding/find_spec.rb
@@ -50,7 +50,7 @@ describe "Encoding.find" do
end
it "raises an ArgumentError if the given encoding does not exist" do
- -> { Encoding.find('dh2dh278d') }.should raise_error(ArgumentError)
+ -> { Encoding.find('dh2dh278d') }.should raise_error(ArgumentError, 'unknown encoding name - dh2dh278d')
end
# Not sure how to do a better test, since locale depends on weird platform-specific stuff
diff --git a/spec/ruby/core/encoding/fixtures/classes.rb b/spec/ruby/core/encoding/fixtures/classes.rb
index 12e9a4f348..943865e8d8 100644
--- a/spec/ruby/core/encoding/fixtures/classes.rb
+++ b/spec/ruby/core/encoding/fixtures/classes.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
module EncodingSpecs
class UndefinedConversionError
def self.exception
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb
index d2fc360dce..8b7e87960f 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb
index 8a3f3de69a..83606f77b4 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
describe "Encoding::InvalidByteSequenceError#incomplete_input?" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb
index a5e2824984..e5ad0a61bd 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
diff --git a/spec/ruby/core/encoding/replicate_spec.rb b/spec/ruby/core/encoding/replicate_spec.rb
index e22673db7d..2da998837f 100644
--- a/spec/ruby/core/encoding/replicate_spec.rb
+++ b/spec/ruby/core/encoding/replicate_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
describe "Encoding#replicate" do
@@ -67,7 +67,7 @@ describe "Encoding#replicate" do
end
end
- ruby_version_is "3.2"..."3.3" do
+ ruby_version_is ""..."3.3" do
it "warns about deprecation" do
-> {
Encoding::US_ASCII.replicate('MY-US-ASCII')
diff --git a/spec/ruby/core/enumerable/collect_concat_spec.rb b/spec/ruby/core/enumerable/collect_concat_spec.rb
index 6e34c9eb93..59317cfe34 100644
--- a/spec/ruby/core/enumerable/collect_concat_spec.rb
+++ b/spec/ruby/core/enumerable/collect_concat_spec.rb
@@ -3,5 +3,5 @@ require_relative 'fixtures/classes'
require_relative 'shared/collect_concat'
describe "Enumerable#collect_concat" do
- it_behaves_like :enumerable_collect_concat , :collect_concat
+ it_behaves_like :enumerable_collect_concat, :collect_concat
end
diff --git a/spec/ruby/core/enumerable/collect_spec.rb b/spec/ruby/core/enumerable/collect_spec.rb
index 1016b67798..cfa2895cce 100644
--- a/spec/ruby/core/enumerable/collect_spec.rb
+++ b/spec/ruby/core/enumerable/collect_spec.rb
@@ -3,5 +3,5 @@ require_relative 'fixtures/classes'
require_relative 'shared/collect'
describe "Enumerable#collect" do
- it_behaves_like :enumerable_collect , :collect
+ it_behaves_like :enumerable_collect, :collect
end
diff --git a/spec/ruby/core/enumerable/compact_spec.rb b/spec/ruby/core/enumerable/compact_spec.rb
index 86e95dce08..1895430c4e 100644
--- a/spec/ruby/core/enumerable/compact_spec.rb
+++ b/spec/ruby/core/enumerable/compact_spec.rb
@@ -1,11 +1,9 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is '3.1' do
- describe "Enumerable#compact" do
- it 'returns array without nil elements' do
- arr = EnumerableSpecs::Numerous.new(nil, 1, 2, nil, true)
- arr.compact.should == [1, 2, true]
- end
+describe "Enumerable#compact" do
+ it 'returns array without nil elements' do
+ arr = EnumerableSpecs::Numerous.new(nil, 1, 2, nil, true)
+ arr.compact.should == [1, 2, true]
end
end
diff --git a/spec/ruby/core/enumerable/detect_spec.rb b/spec/ruby/core/enumerable/detect_spec.rb
index e912134fed..6959aadc44 100644
--- a/spec/ruby/core/enumerable/detect_spec.rb
+++ b/spec/ruby/core/enumerable/detect_spec.rb
@@ -3,5 +3,5 @@ require_relative 'fixtures/classes'
require_relative 'shared/find'
describe "Enumerable#detect" do
- it_behaves_like :enumerable_find , :detect
+ it_behaves_like :enumerable_find, :detect
end
diff --git a/spec/ruby/core/enumerable/each_cons_spec.rb b/spec/ruby/core/enumerable/each_cons_spec.rb
index 8fb31fb925..ed77741862 100644
--- a/spec/ruby/core/enumerable/each_cons_spec.rb
+++ b/spec/ruby/core/enumerable/each_cons_spec.rb
@@ -56,10 +56,8 @@ describe "Enumerable#each_cons" do
multi.each_cons(2).to_a.should == [[[1, 2], [3, 4, 5]], [[3, 4, 5], [6, 7, 8, 9]]]
end
- ruby_version_is "3.1" do
- it "returns self when a block is given" do
- @enum.each_cons(3){}.should == @enum
- end
+ it "returns self when a block is given" do
+ @enum.each_cons(3){}.should == @enum
end
describe "when no block is given" do
diff --git a/spec/ruby/core/enumerable/each_slice_spec.rb b/spec/ruby/core/enumerable/each_slice_spec.rb
index a57a1dba81..47b8c9ba33 100644
--- a/spec/ruby/core/enumerable/each_slice_spec.rb
+++ b/spec/ruby/core/enumerable/each_slice_spec.rb
@@ -57,10 +57,8 @@ describe "Enumerable#each_slice" do
e.to_a.should == @sliced
end
- ruby_version_is "3.1" do
- it "returns self when a block is given" do
- @enum.each_slice(3){}.should == @enum
- end
+ it "returns self when a block is given" do
+ @enum.each_slice(3){}.should == @enum
end
it "gathers whole arrays as elements when each yields multiple" do
diff --git a/spec/ruby/core/enumerable/entries_spec.rb b/spec/ruby/core/enumerable/entries_spec.rb
index 83232cfa06..2de4fc756a 100644
--- a/spec/ruby/core/enumerable/entries_spec.rb
+++ b/spec/ruby/core/enumerable/entries_spec.rb
@@ -3,5 +3,5 @@ require_relative 'fixtures/classes'
require_relative 'shared/entries'
describe "Enumerable#entries" do
- it_behaves_like :enumerable_entries , :entries
+ it_behaves_like :enumerable_entries, :entries
end
diff --git a/spec/ruby/core/enumerable/filter_spec.rb b/spec/ruby/core/enumerable/filter_spec.rb
index 7e4f8c0b50..1c3a7e9ff5 100644
--- a/spec/ruby/core/enumerable/filter_spec.rb
+++ b/spec/ruby/core/enumerable/filter_spec.rb
@@ -3,5 +3,5 @@ require_relative 'fixtures/classes'
require_relative 'shared/find_all'
describe "Enumerable#filter" do
- it_behaves_like(:enumerable_find_all , :filter)
+ it_behaves_like :enumerable_find_all, :filter
end
diff --git a/spec/ruby/core/enumerable/find_all_spec.rb b/spec/ruby/core/enumerable/find_all_spec.rb
index ce9058fe77..9cd635f247 100644
--- a/spec/ruby/core/enumerable/find_all_spec.rb
+++ b/spec/ruby/core/enumerable/find_all_spec.rb
@@ -3,5 +3,5 @@ require_relative 'fixtures/classes'
require_relative 'shared/find_all'
describe "Enumerable#find_all" do
- it_behaves_like :enumerable_find_all , :find_all
+ it_behaves_like :enumerable_find_all, :find_all
end
diff --git a/spec/ruby/core/enumerable/find_spec.rb b/spec/ruby/core/enumerable/find_spec.rb
index 25aa3bf103..5ddebc05f8 100644
--- a/spec/ruby/core/enumerable/find_spec.rb
+++ b/spec/ruby/core/enumerable/find_spec.rb
@@ -3,5 +3,5 @@ require_relative 'fixtures/classes'
require_relative 'shared/find'
describe "Enumerable#find" do
- it_behaves_like :enumerable_find , :find
+ it_behaves_like :enumerable_find, :find
end
diff --git a/spec/ruby/core/enumerable/fixtures/classes.rb b/spec/ruby/core/enumerable/fixtures/classes.rb
index 2701c6999c..b5feafcfb7 100644
--- a/spec/ruby/core/enumerable/fixtures/classes.rb
+++ b/spec/ruby/core/enumerable/fixtures/classes.rb
@@ -38,12 +38,14 @@ module EnumerableSpecs
class Empty
include Enumerable
def each
+ self
end
end
class EmptyWithSize
include Enumerable
def each
+ self
end
def size
0
@@ -343,9 +345,6 @@ module EnumerableSpecs
end
end
- # Set is a core class since Ruby 3.2
- ruby_version_is '3.2' do
- class SetSubclass < Set
- end
+ class SetSubclass < Set
end
end # EnumerableSpecs utility classes
diff --git a/spec/ruby/core/enumerable/flat_map_spec.rb b/spec/ruby/core/enumerable/flat_map_spec.rb
index a294b9ddad..bd07eab6c5 100644
--- a/spec/ruby/core/enumerable/flat_map_spec.rb
+++ b/spec/ruby/core/enumerable/flat_map_spec.rb
@@ -3,5 +3,5 @@ require_relative 'fixtures/classes'
require_relative 'shared/collect_concat'
describe "Enumerable#flat_map" do
- it_behaves_like :enumerable_collect_concat , :flat_map
+ it_behaves_like :enumerable_collect_concat, :flat_map
end
diff --git a/spec/ruby/core/enumerable/map_spec.rb b/spec/ruby/core/enumerable/map_spec.rb
index d65aec238c..98a70781cf 100644
--- a/spec/ruby/core/enumerable/map_spec.rb
+++ b/spec/ruby/core/enumerable/map_spec.rb
@@ -3,5 +3,5 @@ require_relative 'fixtures/classes'
require_relative 'shared/collect'
describe "Enumerable#map" do
- it_behaves_like :enumerable_collect , :map
+ it_behaves_like :enumerable_collect, :map
end
diff --git a/spec/ruby/core/enumerable/select_spec.rb b/spec/ruby/core/enumerable/select_spec.rb
index 11168eb42e..7fc61926f9 100644
--- a/spec/ruby/core/enumerable/select_spec.rb
+++ b/spec/ruby/core/enumerable/select_spec.rb
@@ -3,5 +3,5 @@ require_relative 'fixtures/classes'
require_relative 'shared/find_all'
describe "Enumerable#select" do
- it_behaves_like :enumerable_find_all , :select
+ it_behaves_like :enumerable_find_all, :select
end
diff --git a/spec/ruby/core/enumerable/shared/inject.rb b/spec/ruby/core/enumerable/shared/inject.rb
index 92f220efa4..8fb7e98c2b 100644
--- a/spec/ruby/core/enumerable/shared/inject.rb
+++ b/spec/ruby/core/enumerable/shared/inject.rb
@@ -103,7 +103,7 @@ describe :enumerable_inject, shared: true do
it "without inject arguments(legacy rubycon)" do
# no inject argument
- EnumerableSpecs::EachDefiner.new(2).send(@method) {|acc,x| 999 } .should == 2
+ EnumerableSpecs::EachDefiner.new(2).send(@method) {|acc,x| 999 }.should == 2
EnumerableSpecs::EachDefiner.new(2).send(@method) {|acc,x| acc }.should == 2
EnumerableSpecs::EachDefiner.new(2).send(@method) {|acc,x| x }.should == 2
@@ -135,10 +135,8 @@ describe :enumerable_inject, shared: true do
actual.sort_by(&:to_s).should == expected.sort_by(&:to_s)
end
- ruby_bug '#18635', ''...'3.2' do
- it "raises an ArgumentError when no parameters or block is given" do
- -> { [1,2].send(@method) }.should raise_error(ArgumentError)
- -> { {one: 1, two: 2}.send(@method) }.should raise_error(ArgumentError)
- end
+ it "raises an ArgumentError when no parameters or block is given" do
+ -> { [1,2].send(@method) }.should raise_error(ArgumentError)
+ -> { {one: 1, two: 2}.send(@method) }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/core/enumerable/tally_spec.rb b/spec/ruby/core/enumerable/tally_spec.rb
index e0edc8dc75..95c64c1294 100644
--- a/spec/ruby/core/enumerable/tally_spec.rb
+++ b/spec/ruby/core/enumerable/tally_spec.rb
@@ -32,62 +32,60 @@ describe "Enumerable#tally" do
end
end
-ruby_version_is "3.1" do
- describe "Enumerable#tally with a hash" do
- before :each do
- ScratchPad.record []
- end
-
- it "returns a hash with counts according to the value" do
- enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
- enum.tally({ 'foo' => 1 }).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1}
- end
-
- it "returns the given hash" do
- enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
- hash = { 'foo' => 1 }
- enum.tally(hash).should equal(hash)
- end
-
- it "calls #to_hash to convert argument to Hash implicitly if passed not a Hash" do
- enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
- object = Object.new
- def object.to_hash; { 'foo' => 1 }; end
- enum.tally(object).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1}
- end
-
- it "raises a FrozenError and does not update the given hash when the hash is frozen" do
- enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
- hash = { 'foo' => 1 }.freeze
- -> { enum.tally(hash) }.should raise_error(FrozenError)
- hash.should == { 'foo' => 1 }
- end
-
- it "raises a FrozenError even if enumerable is empty" do
- enum = EnumerableSpecs::Numerous.new()
- hash = { 'foo' => 1 }.freeze
- -> { enum.tally(hash) }.should raise_error(FrozenError)
- end
-
- it "does not call given block" do
- enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
- enum.tally({ 'foo' => 1 }) { |v| ScratchPad << v }
- ScratchPad.recorded.should == []
- end
-
- it "ignores the default value" do
- enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
- enum.tally(Hash.new(100)).should == { 'foo' => 2, 'bar' => 1, 'baz' => 1}
- end
-
- it "ignores the default proc" do
- enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
- enum.tally(Hash.new {100}).should == { 'foo' => 2, 'bar' => 1, 'baz' => 1}
- end
-
- it "needs the values counting each elements to be an integer" do
- enum = EnumerableSpecs::Numerous.new('foo')
- -> { enum.tally({ 'foo' => 'bar' }) }.should raise_error(TypeError)
- end
+describe "Enumerable#tally with a hash" do
+ before :each do
+ ScratchPad.record []
+ end
+
+ it "returns a hash with counts according to the value" do
+ enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
+ enum.tally({ 'foo' => 1 }).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1}
+ end
+
+ it "returns the given hash" do
+ enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
+ hash = { 'foo' => 1 }
+ enum.tally(hash).should equal(hash)
+ end
+
+ it "calls #to_hash to convert argument to Hash implicitly if passed not a Hash" do
+ enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
+ object = Object.new
+ def object.to_hash; { 'foo' => 1 }; end
+ enum.tally(object).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1}
+ end
+
+ it "raises a FrozenError and does not update the given hash when the hash is frozen" do
+ enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
+ hash = { 'foo' => 1 }.freeze
+ -> { enum.tally(hash) }.should raise_error(FrozenError)
+ hash.should == { 'foo' => 1 }
+ end
+
+ it "raises a FrozenError even if enumerable is empty" do
+ enum = EnumerableSpecs::Numerous.new()
+ hash = { 'foo' => 1 }.freeze
+ -> { enum.tally(hash) }.should raise_error(FrozenError)
+ end
+
+ it "does not call given block" do
+ enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
+ enum.tally({ 'foo' => 1 }) { |v| ScratchPad << v }
+ ScratchPad.recorded.should == []
+ end
+
+ it "ignores the default value" do
+ enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
+ enum.tally(Hash.new(100)).should == { 'foo' => 2, 'bar' => 1, 'baz' => 1}
+ end
+
+ it "ignores the default proc" do
+ enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
+ enum.tally(Hash.new {100}).should == { 'foo' => 2, 'bar' => 1, 'baz' => 1}
+ end
+
+ it "needs the values counting each elements to be an integer" do
+ enum = EnumerableSpecs::Numerous.new('foo')
+ -> { enum.tally({ 'foo' => 'bar' }) }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/enumerable/to_a_spec.rb b/spec/ruby/core/enumerable/to_a_spec.rb
index 0f3060dc48..723f922574 100644
--- a/spec/ruby/core/enumerable/to_a_spec.rb
+++ b/spec/ruby/core/enumerable/to_a_spec.rb
@@ -3,5 +3,5 @@ require_relative 'fixtures/classes'
require_relative 'shared/entries'
describe "Enumerable#to_a" do
- it_behaves_like :enumerable_entries , :to_a
+ it_behaves_like :enumerable_entries, :to_a
end
diff --git a/spec/ruby/core/enumerable/to_set_spec.rb b/spec/ruby/core/enumerable/to_set_spec.rb
index c21a2772c4..c02ead11fa 100644
--- a/spec/ruby/core/enumerable/to_set_spec.rb
+++ b/spec/ruby/core/enumerable/to_set_spec.rb
@@ -1,29 +1,30 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.2" do
- describe "Enumerable#to_set" do
- it "returns a new Set created from self" do
- [1, 2, 3].to_set.should == Set[1, 2, 3]
- {a: 1, b: 2}.to_set.should == Set[[:b, 2], [:a, 1]]
- end
+describe "Enumerable#to_set" do
+ it "returns a new Set created from self" do
+ [1, 2, 3].to_set.should == Set[1, 2, 3]
+ {a: 1, b: 2}.to_set.should == Set[[:b, 2], [:a, 1]]
+ end
- it "passes down passed blocks" do
- [1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9]
- end
+ it "passes down passed blocks" do
+ [1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9]
+ end
+ ruby_version_is "4.0"..."4.1" do
it "instantiates an object of provided as the first argument set class" do
- set = [1, 2, 3].to_set(EnumerableSpecs::SetSubclass)
+ set = nil
+ proc{set = [1, 2, 3].to_set(EnumerableSpecs::SetSubclass)}.should complain(/Enumerable#to_set/)
set.should be_kind_of(EnumerableSpecs::SetSubclass)
set.to_a.sort.should == [1, 2, 3]
end
+ end
- it "does not need explicit `require 'set'`" do
- output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1')
- puts [1, 2, 3].to_set
- RUBY
-
- output.chomp.should == "#<Set: {1, 2, 3}>"
+ ruby_version_is ""..."4.0" do
+ it "instantiates an object of provided as the first argument set class" do
+ set = [1, 2, 3].to_set(EnumerableSpecs::SetSubclass)
+ set.should be_kind_of(EnumerableSpecs::SetSubclass)
+ set.to_a.sort.should == [1, 2, 3]
end
end
end
diff --git a/spec/ruby/core/enumerator/each_with_index_spec.rb b/spec/ruby/core/enumerator/each_with_index_spec.rb
index 271e61fec6..4898e86fa9 100644
--- a/spec/ruby/core/enumerator/each_with_index_spec.rb
+++ b/spec/ruby/core/enumerator/each_with_index_spec.rb
@@ -1,5 +1,5 @@
require_relative '../../spec_helper'
-require_relative '../../shared/enumerator/with_index'
+require_relative 'shared/with_index'
require_relative '../enumerable/shared/enumeratorized'
describe "Enumerator#each_with_index" do
diff --git a/spec/ruby/core/enumerator/each_with_object_spec.rb b/spec/ruby/core/enumerator/each_with_object_spec.rb
index 68524dc74a..84a45ae89d 100644
--- a/spec/ruby/core/enumerator/each_with_object_spec.rb
+++ b/spec/ruby/core/enumerator/each_with_object_spec.rb
@@ -1,5 +1,5 @@
require_relative '../../spec_helper'
-require_relative '../../shared/enumerator/with_object'
+require_relative 'shared/with_object'
describe "Enumerator#each_with_object" do
it_behaves_like :enum_with_object, :each_with_object
diff --git a/spec/ruby/core/enumerator/enum_for_spec.rb b/spec/ruby/core/enumerator/enum_for_spec.rb
index fd33f463bf..fbdf98545a 100644
--- a/spec/ruby/core/enumerator/enum_for_spec.rb
+++ b/spec/ruby/core/enumerator/enum_for_spec.rb
@@ -1,5 +1,5 @@
require_relative '../../spec_helper'
-require_relative '../../shared/enumerator/enum_for'
+require_relative 'shared/enum_for'
describe "Enumerator#enum_for" do
it_behaves_like :enum_for, :enum_for
diff --git a/spec/ruby/core/enumerator/fixtures/classes.rb b/spec/ruby/core/enumerator/fixtures/classes.rb
new file mode 100644
index 0000000000..6f285b8efa
--- /dev/null
+++ b/spec/ruby/core/enumerator/fixtures/classes.rb
@@ -0,0 +1,15 @@
+module EnumSpecs
+ class Numerous
+
+ include Enumerable
+
+ def initialize(*list)
+ @list = list.empty? ? [2, 5, 3, 6, 1, 4] : list
+ end
+
+ def each
+ @list.each { |i| yield i }
+ end
+ end
+
+end
diff --git a/spec/ruby/core/enumerator/lazy/compact_spec.rb b/spec/ruby/core/enumerator/lazy/compact_spec.rb
index e678bc71eb..65c544f062 100644
--- a/spec/ruby/core/enumerator/lazy/compact_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/compact_spec.rb
@@ -1,16 +1,14 @@
require_relative '../../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is '3.1' do
- describe "Enumerator::Lazy#compact" do
- it 'returns array without nil elements' do
- arr = [1, nil, 3, false, 5].to_enum.lazy.compact
- arr.should be_an_instance_of(Enumerator::Lazy)
- arr.force.should == [1, 3, false, 5]
- end
+describe "Enumerator::Lazy#compact" do
+ it 'returns array without nil elements' do
+ arr = [1, nil, 3, false, 5].to_enum.lazy.compact
+ arr.should be_an_instance_of(Enumerator::Lazy)
+ arr.force.should == [1, 3, false, 5]
+ end
- it "sets #size to nil" do
- Enumerator::Lazy.new(Object.new, 100) {}.compact.size.should == nil
- end
+ it "sets #size to nil" do
+ Enumerator::Lazy.new(Object.new, 100) {}.compact.size.should == nil
end
end
diff --git a/spec/ruby/core/enumerator/lazy/lazy_spec.rb b/spec/ruby/core/enumerator/lazy/lazy_spec.rb
index 0fb104e25a..b43864b673 100644
--- a/spec/ruby/core/enumerator/lazy/lazy_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/lazy_spec.rb
@@ -9,16 +9,11 @@ describe "Enumerator::Lazy" do
it "defines lazy versions of a whitelist of Enumerator methods" do
lazy_methods = [
- :chunk, :collect, :collect_concat, :drop, :drop_while, :enum_for,
+ :chunk, :chunk_while, :collect, :collect_concat, :compact, :drop, :drop_while, :enum_for,
:find_all, :flat_map, :force, :grep, :grep_v, :lazy, :map, :reject,
:select, :slice_after, :slice_before, :slice_when, :take, :take_while,
- :to_enum, :zip
+ :to_enum, :uniq, :zip
]
- lazy_methods += [:chunk_while, :uniq]
-
- ruby_version_is '3.1' do
- lazy_methods += [:compact]
- end
Enumerator::Lazy.instance_methods(false).should include(*lazy_methods)
end
diff --git a/spec/ruby/core/enumerator/product/each_spec.rb b/spec/ruby/core/enumerator/product/each_spec.rb
index cabeb9d93a..88f115a712 100644
--- a/spec/ruby/core/enumerator/product/each_spec.rb
+++ b/spec/ruby/core/enumerator/product/each_spec.rb
@@ -1,73 +1,71 @@
require_relative '../../../spec_helper'
require_relative '../../enumerable/shared/enumeratorized'
-ruby_version_is "3.2" do
- describe "Enumerator::Product#each" do
- it_behaves_like :enumeratorized_with_origin_size, :each, Enumerator::Product.new([1, 2], [:a, :b])
+describe "Enumerator::Product#each" do
+ it_behaves_like :enumeratorized_with_origin_size, :each, Enumerator::Product.new([1, 2], [:a, :b])
- it "yields each element of Cartesian product of enumerators" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- acc = []
- enum.each { |e| acc << e }
- acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
-
- it "calls #each_entry method on enumerators" do
- object1 = Object.new
- def object1.each_entry
- yield 1
- yield 2
- end
-
- object2 = Object.new
- def object2.each_entry
- yield :a
- yield :b
- end
+ it "yields each element of Cartesian product of enumerators" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ acc = []
+ enum.each { |e| acc << e }
+ acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
- enum = Enumerator::Product.new(object1, object2)
- acc = []
- enum.each { |e| acc << e }
- acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ it "calls #each_entry method on enumerators" do
+ object1 = Object.new
+ def object1.each_entry
+ yield 1
+ yield 2
end
- it "raises a NoMethodError if the object doesn't respond to #each_entry" do
- -> {
- Enumerator::Product.new(Object.new).each {}
- }.should raise_error(NoMethodError, /undefined method [`']each_entry' for/)
+ object2 = Object.new
+ def object2.each_entry
+ yield :a
+ yield :b
end
- it "returns enumerator if not given a block" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.each.should.kind_of?(Enumerator)
+ enum = Enumerator::Product.new(object1, object2)
+ acc = []
+ enum.each { |e| acc << e }
+ acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
+ it "raises a NoMethodError if the object doesn't respond to #each_entry" do
+ -> {
+ Enumerator::Product.new(Object.new).each {}
+ }.should raise_error(NoMethodError, /undefined method [`']each_entry' for/)
+ end
- it "returns self if given a block" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.each {}.should.equal?(enum)
- end
+ it "returns enumerator if not given a block" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ enum.each.should.kind_of?(Enumerator)
- it "doesn't accept arguments" do
- Enumerator::Product.instance_method(:each).arity.should == 0
- end
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
- it "yields each element to a block that takes multiple arguments" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
+ it "returns self if given a block" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ enum.each {}.should.equal?(enum)
+ end
- acc = []
- enum.each { |x, y| acc << x }
- acc.should == [1, 1, 2, 2]
+ it "doesn't accept arguments" do
+ Enumerator::Product.instance_method(:each).arity.should == 0
+ end
- acc = []
- enum.each { |x, y| acc << y }
- acc.should == [:a, :b, :a, :b]
+ it "yields each element to a block that takes multiple arguments" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
- acc = []
- enum.each { |x, y, z| acc << z }
- acc.should == [nil, nil, nil, nil]
- end
+ acc = []
+ enum.each { |x, y| acc << x }
+ acc.should == [1, 1, 2, 2]
+
+ acc = []
+ enum.each { |x, y| acc << y }
+ acc.should == [:a, :b, :a, :b]
+
+ acc = []
+ enum.each { |x, y, z| acc << z }
+ acc.should == [nil, nil, nil, nil]
end
end
diff --git a/spec/ruby/core/enumerator/product/initialize_copy_spec.rb b/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
index 46e8421322..b1b9f3ca9b 100644
--- a/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
+++ b/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
@@ -1,54 +1,52 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.2" do
- describe "Enumerator::Product#initialize_copy" do
- it "replaces content of the receiver with content of the other object" do
- enum = Enumerator::Product.new([true, false])
- enum2 = Enumerator::Product.new([1, 2], [:a, :b])
+describe "Enumerator::Product#initialize_copy" do
+ it "replaces content of the receiver with content of the other object" do
+ enum = Enumerator::Product.new([true, false])
+ enum2 = Enumerator::Product.new([1, 2], [:a, :b])
- enum.send(:initialize_copy, enum2)
- enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
+ enum.send(:initialize_copy, enum2)
+ enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
- it "returns self" do
- enum = Enumerator::Product.new([true, false])
- enum2 = Enumerator::Product.new([1, 2], [:a, :b])
+ it "returns self" do
+ enum = Enumerator::Product.new([true, false])
+ enum2 = Enumerator::Product.new([1, 2], [:a, :b])
- enum.send(:initialize_copy, enum2).should.equal?(enum)
- end
+ enum.send(:initialize_copy, enum2).should.equal?(enum)
+ end
- it "is a private method" do
- Enumerator::Product.should have_private_instance_method(:initialize_copy, false)
- end
+ it "is a private method" do
+ Enumerator::Product.should have_private_instance_method(:initialize_copy, false)
+ end
- it "does nothing if the argument is the same as the receiver" do
- enum = Enumerator::Product.new(1..2)
- enum.send(:initialize_copy, enum).should.equal?(enum)
+ it "does nothing if the argument is the same as the receiver" do
+ enum = Enumerator::Product.new(1..2)
+ enum.send(:initialize_copy, enum).should.equal?(enum)
- enum.freeze
- enum.send(:initialize_copy, enum).should.equal?(enum)
- end
+ enum.freeze
+ enum.send(:initialize_copy, enum).should.equal?(enum)
+ end
- it "raises FrozenError if the receiver is frozen" do
- enum = Enumerator::Product.new(1..2)
- enum2 = Enumerator::Product.new(3..4)
+ it "raises FrozenError if the receiver is frozen" do
+ enum = Enumerator::Product.new(1..2)
+ enum2 = Enumerator::Product.new(3..4)
- -> { enum.freeze.send(:initialize_copy, enum2) }.should raise_error(FrozenError)
- end
+ -> { enum.freeze.send(:initialize_copy, enum2) }.should raise_error(FrozenError)
+ end
- it "raises TypeError if the objects are of different class" do
- enum = Enumerator::Product.new(1..2)
- enum2 = Class.new(Enumerator::Product).new(3..4)
+ it "raises TypeError if the objects are of different class" do
+ enum = Enumerator::Product.new(1..2)
+ enum2 = Class.new(Enumerator::Product).new(3..4)
- -> { enum.send(:initialize_copy, enum2) }.should raise_error(TypeError, 'initialize_copy should take same class object')
- -> { enum2.send(:initialize_copy, enum) }.should raise_error(TypeError, 'initialize_copy should take same class object')
- end
+ -> { enum.send(:initialize_copy, enum2) }.should raise_error(TypeError, 'initialize_copy should take same class object')
+ -> { enum2.send(:initialize_copy, enum) }.should raise_error(TypeError, 'initialize_copy should take same class object')
+ end
- it "raises ArgumentError if the argument is not initialized yet" do
- enum = Enumerator::Product.new(1..2)
- enum2 = Enumerator::Product.allocate
+ it "raises ArgumentError if the argument is not initialized yet" do
+ enum = Enumerator::Product.new(1..2)
+ enum2 = Enumerator::Product.allocate
- -> { enum.send(:initialize_copy, enum2) }.should raise_error(ArgumentError, 'uninitialized product')
- end
+ -> { enum.send(:initialize_copy, enum2) }.should raise_error(ArgumentError, 'uninitialized product')
end
end
diff --git a/spec/ruby/core/enumerator/product/initialize_spec.rb b/spec/ruby/core/enumerator/product/initialize_spec.rb
index 4b60564240..ed2a8a2a13 100644
--- a/spec/ruby/core/enumerator/product/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/product/initialize_spec.rb
@@ -1,33 +1,31 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.2" do
- describe "Enumerator::Product#initialize" do
- before :each do
- @uninitialized = Enumerator::Product.allocate
- end
+describe "Enumerator::Product#initialize" do
+ before :each do
+ @uninitialized = Enumerator::Product.allocate
+ end
- it "is a private method" do
- Enumerator::Product.should have_private_instance_method(:initialize, false)
- end
+ it "is a private method" do
+ Enumerator::Product.should have_private_instance_method(:initialize, false)
+ end
- it "returns self" do
- @uninitialized.send(:initialize).should equal(@uninitialized)
- end
+ it "returns self" do
+ @uninitialized.send(:initialize).should equal(@uninitialized)
+ end
- it "accepts many arguments" do
- @uninitialized.send(:initialize, 0..1, 2..3, 4..5).should equal(@uninitialized)
- end
+ it "accepts many arguments" do
+ @uninitialized.send(:initialize, 0..1, 2..3, 4..5).should equal(@uninitialized)
+ end
- it "accepts arguments that are not Enumerable nor responding to :each_entry" do
- @uninitialized.send(:initialize, Object.new).should equal(@uninitialized)
- end
+ it "accepts arguments that are not Enumerable nor responding to :each_entry" do
+ @uninitialized.send(:initialize, Object.new).should equal(@uninitialized)
+ end
- describe "on frozen instance" do
- it "raises a FrozenError" do
- -> {
- @uninitialized.freeze.send(:initialize, 0..1)
- }.should raise_error(FrozenError)
- end
+ describe "on frozen instance" do
+ it "raises a FrozenError" do
+ -> {
+ @uninitialized.freeze.send(:initialize, 0..1)
+ }.should raise_error(FrozenError)
end
end
end
diff --git a/spec/ruby/core/enumerator/product/inspect_spec.rb b/spec/ruby/core/enumerator/product/inspect_spec.rb
index 1ea8e9c49b..e0d7441f26 100644
--- a/spec/ruby/core/enumerator/product/inspect_spec.rb
+++ b/spec/ruby/core/enumerator/product/inspect_spec.rb
@@ -1,22 +1,20 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.2" do
- describe "Enumerator::Product#inspect" do
- it "returns a String including enumerators" do
- enum = Enumerator::Product.new([1, 2], [:a, :b])
- enum.inspect.should == "#<Enumerator::Product: [[1, 2], [:a, :b]]>"
- end
+describe "Enumerator::Product#inspect" do
+ it "returns a String including enumerators" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ enum.inspect.should == "#<Enumerator::Product: [[1, 2], [:a, :b]]>"
+ end
- it "represents a recursive element with '[...]'" do
- enum = [1, 2]
- enum_recursive = Enumerator::Product.new(enum)
+ it "represents a recursive element with '[...]'" do
+ enum = [1, 2]
+ enum_recursive = Enumerator::Product.new(enum)
- enum << enum_recursive
- enum_recursive.inspect.should == "#<Enumerator::Product: [[1, 2, #<Enumerator::Product: ...>]]>"
- end
+ enum << enum_recursive
+ enum_recursive.inspect.should == "#<Enumerator::Product: [[1, 2, #<Enumerator::Product: ...>]]>"
+ end
- it "returns a not initialized representation if #initialized is not called yet" do
- Enumerator::Product.allocate.inspect.should == "#<Enumerator::Product: uninitialized>"
- end
+ it "returns a not initialized representation if #initialized is not called yet" do
+ Enumerator::Product.allocate.inspect.should == "#<Enumerator::Product: uninitialized>"
end
end
diff --git a/spec/ruby/core/enumerator/product/rewind_spec.rb b/spec/ruby/core/enumerator/product/rewind_spec.rb
index e8ee730239..2beffaf5c1 100644
--- a/spec/ruby/core/enumerator/product/rewind_spec.rb
+++ b/spec/ruby/core/enumerator/product/rewind_spec.rb
@@ -1,64 +1,62 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.2" do
- describe "Enumerator::Product#rewind" do
- before :each do
- @enum = Enumerator::Product.new([1, 2].each.to_enum, [:a, :b].each.to_enum)
- end
+describe "Enumerator::Product#rewind" do
+ before :each do
+ @enum = Enumerator::Product.new([1, 2].each.to_enum, [:a, :b].each.to_enum)
+ end
- it "resets the enumerator to its initial state" do
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- @enum.rewind
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
+ it "resets the enumerator to its initial state" do
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ @enum.rewind
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
- it "returns self" do
- @enum.rewind.should.equal? @enum
- end
+ it "returns self" do
+ @enum.rewind.should.equal? @enum
+ end
- it "has no effect on a new enumerator" do
- @enum.rewind
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
+ it "has no effect on a new enumerator" do
+ @enum.rewind
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
- it "has no effect if called multiple, consecutive times" do
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- @enum.rewind
- @enum.rewind
- @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
- end
+ it "has no effect if called multiple, consecutive times" do
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ @enum.rewind
+ @enum.rewind
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
- it "calls the enclosed object's rewind method if one exists" do
- obj = mock('rewinder')
- enum = Enumerator::Product.new(obj.to_enum)
+ it "calls the enclosed object's rewind method if one exists" do
+ obj = mock('rewinder')
+ enum = Enumerator::Product.new(obj.to_enum)
- obj.should_receive(:rewind)
- enum.rewind
- end
+ obj.should_receive(:rewind)
+ enum.rewind
+ end
- it "does nothing if the object doesn't have a #rewind method" do
- obj = mock('rewinder')
- enum = Enumerator::Product.new(obj.to_enum)
+ it "does nothing if the object doesn't have a #rewind method" do
+ obj = mock('rewinder')
+ enum = Enumerator::Product.new(obj.to_enum)
- enum.rewind.should == enum
- end
+ enum.rewind.should == enum
+ end
- it "calls a rewind method on each enumerable in direct order" do
- ScratchPad.record []
+ it "calls a rewind method on each enumerable in direct order" do
+ ScratchPad.record []
- object1 = Object.new
- def object1.rewind; ScratchPad << :object1; end
+ object1 = Object.new
+ def object1.rewind; ScratchPad << :object1; end
- object2 = Object.new
- def object2.rewind; ScratchPad << :object2; end
+ object2 = Object.new
+ def object2.rewind; ScratchPad << :object2; end
- object3 = Object.new
- def object3.rewind; ScratchPad << :object3; end
+ object3 = Object.new
+ def object3.rewind; ScratchPad << :object3; end
- enum = Enumerator::Product.new(object1, object2, object3)
- enum.rewind
+ enum = Enumerator::Product.new(object1, object2, object3)
+ enum.rewind
- ScratchPad.recorded.should == [:object1, :object2, :object3]
- end
+ ScratchPad.recorded.should == [:object1, :object2, :object3]
end
end
diff --git a/spec/ruby/core/enumerator/product/size_spec.rb b/spec/ruby/core/enumerator/product/size_spec.rb
index 46958b1a22..96632d6eee 100644
--- a/spec/ruby/core/enumerator/product/size_spec.rb
+++ b/spec/ruby/core/enumerator/product/size_spec.rb
@@ -1,56 +1,54 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.2" do
- describe "Enumerator::Product#size" do
- it "returns the total size of the enumerator product calculated by multiplying the sizes of enumerables in the product" do
- product = Enumerator::Product.new(1..2, 1..3, 1..4)
- product.size.should == 24 # 2 * 3 * 4
- end
-
- it "returns nil if any enumerable reports its size as nil" do
- enum = Object.new
- def enum.size; nil; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
-
- it "returns Float::INFINITY if any enumerable reports its size as Float::INFINITY" do
- enum = Object.new
- def enum.size; Float::INFINITY; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == Float::INFINITY
- end
-
- it "returns nil if any enumerable reports its size as Float::NAN" do
- enum = Object.new
- def enum.size; Float::NAN; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
-
- it "returns nil if any enumerable doesn't respond to #size" do
- enum = Object.new
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
-
- it "returns nil if any enumerable reports a not-convertible to Integer" do
- enum = Object.new
- def enum.size; :symbol; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
-
- it "returns nil if any enumerable reports a non-Integer but convertible to Integer size" do
- enum = Object.new
- def enum.size; 1.0; end
-
- product = Enumerator::Product.new(1..2, enum)
- product.size.should == nil
- end
+describe "Enumerator::Product#size" do
+ it "returns the total size of the enumerator product calculated by multiplying the sizes of enumerables in the product" do
+ product = Enumerator::Product.new(1..2, 1..3, 1..4)
+ product.size.should == 24 # 2 * 3 * 4
+ end
+
+ it "returns nil if any enumerable reports its size as nil" do
+ enum = Object.new
+ def enum.size; nil; end
+
+ product = Enumerator::Product.new(1..2, enum)
+ product.size.should == nil
+ end
+
+ it "returns Float::INFINITY if any enumerable reports its size as Float::INFINITY" do
+ enum = Object.new
+ def enum.size; Float::INFINITY; end
+
+ product = Enumerator::Product.new(1..2, enum)
+ product.size.should == Float::INFINITY
+ end
+
+ it "returns nil if any enumerable reports its size as Float::NAN" do
+ enum = Object.new
+ def enum.size; Float::NAN; end
+
+ product = Enumerator::Product.new(1..2, enum)
+ product.size.should == nil
+ end
+
+ it "returns nil if any enumerable doesn't respond to #size" do
+ enum = Object.new
+ product = Enumerator::Product.new(1..2, enum)
+ product.size.should == nil
+ end
+
+ it "returns nil if any enumerable reports a not-convertible to Integer" do
+ enum = Object.new
+ def enum.size; :symbol; end
+
+ product = Enumerator::Product.new(1..2, enum)
+ product.size.should == nil
+ end
+
+ it "returns nil if any enumerable reports a non-Integer but convertible to Integer size" do
+ enum = Object.new
+ def enum.size; 1.0; end
+
+ product = Enumerator::Product.new(1..2, enum)
+ product.size.should == nil
end
end
diff --git a/spec/ruby/core/enumerator/product_spec.rb b/spec/ruby/core/enumerator/product_spec.rb
index 0acca6690e..83c7cb8e0e 100644
--- a/spec/ruby/core/enumerator/product_spec.rb
+++ b/spec/ruby/core/enumerator/product_spec.rb
@@ -1,93 +1,91 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "Enumerator.product" do
- it "returns a Cartesian product of enumerators" do
- enum = Enumerator.product(1..2, ["A", "B"])
- enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
- end
-
- it "accepts a list of enumerators of any length" do
- enum = Enumerator.product(1..2)
- enum.to_a.should == [[1], [2]]
+describe "Enumerator.product" do
+ it "returns a Cartesian product of enumerators" do
+ enum = Enumerator.product(1..2, ["A", "B"])
+ enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
+ end
- enum = Enumerator.product(1..2, ["A"])
- enum.to_a.should == [[1, "A"], [2, "A"]]
+ it "accepts a list of enumerators of any length" do
+ enum = Enumerator.product(1..2)
+ enum.to_a.should == [[1], [2]]
- enum = Enumerator.product(1..2, ["A"], ["B"])
- enum.to_a.should == [[1, "A", "B"], [2, "A", "B"]]
+ enum = Enumerator.product(1..2, ["A"])
+ enum.to_a.should == [[1, "A"], [2, "A"]]
- enum = Enumerator.product(2..3, ["A"], ["B"], ["C"])
- enum.to_a.should == [[2, "A", "B", "C"], [3, "A", "B", "C"]]
- end
+ enum = Enumerator.product(1..2, ["A"], ["B"])
+ enum.to_a.should == [[1, "A", "B"], [2, "A", "B"]]
- it "returns an enumerator with an empty array when no arguments passed" do
- enum = Enumerator.product
- enum.to_a.should == [[]]
- end
+ enum = Enumerator.product(2..3, ["A"], ["B"], ["C"])
+ enum.to_a.should == [[2, "A", "B", "C"], [3, "A", "B", "C"]]
+ end
- it "returns an instance of Enumerator::Product" do
- enum = Enumerator.product
- enum.class.should == Enumerator::Product
- end
+ it "returns an enumerator with an empty array when no arguments passed" do
+ enum = Enumerator.product
+ enum.to_a.should == [[]]
+ end
- it "accepts infinite enumerators and returns infinite enumerator" do
- enum = Enumerator.product(1.., ["A", "B"])
- enum.take(5).should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"], [3, "A"]]
- enum.size.should == Float::INFINITY
- end
+ it "returns an instance of Enumerator::Product" do
+ enum = Enumerator.product
+ enum.class.should == Enumerator::Product
+ end
- it "accepts a block" do
- elems = []
- enum = Enumerator.product(1..2, ["X", "Y"]) { elems << _1 }
+ it "accepts infinite enumerators and returns infinite enumerator" do
+ enum = Enumerator.product(1.., ["A", "B"])
+ enum.take(5).should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"], [3, "A"]]
+ enum.size.should == Float::INFINITY
+ end
- elems.should == [[1, "X"], [1, "Y"], [2, "X"], [2, "Y"]]
- end
+ it "accepts a block" do
+ elems = []
+ enum = Enumerator.product(1..2, ["X", "Y"]) { elems << _1 }
- it "returns nil when a block passed" do
- Enumerator.product(1..2) {}.should == nil
- end
+ elems.should == [[1, "X"], [1, "Y"], [2, "X"], [2, "Y"]]
+ end
- # https://bugs.ruby-lang.org/issues/19829
- it "reject keyword arguments" do
- -> {
- Enumerator.product(1..3, foo: 1, bar: 2)
- }.should raise_error(ArgumentError, "unknown keywords: :foo, :bar")
- end
+ it "returns nil when a block passed" do
+ Enumerator.product(1..2) {}.should == nil
+ end
- it "calls only #each_entry method on arguments" do
- object = Object.new
- def object.each_entry
- yield 1
- yield 2
- end
+ # https://bugs.ruby-lang.org/issues/19829
+ it "reject keyword arguments" do
+ -> {
+ Enumerator.product(1..3, foo: 1, bar: 2)
+ }.should raise_error(ArgumentError, "unknown keywords: :foo, :bar")
+ end
- enum = Enumerator.product(object, ["A", "B"])
- enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
+ it "calls only #each_entry method on arguments" do
+ object = Object.new
+ def object.each_entry
+ yield 1
+ yield 2
end
- it "raises NoMethodError when argument doesn't respond to #each_entry" do
- -> {
- Enumerator.product(Object.new).to_a
- }.should raise_error(NoMethodError, /undefined method [`']each_entry' for/)
- end
+ enum = Enumerator.product(object, ["A", "B"])
+ enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
+ end
- it "calls #each_entry lazily" do
- Enumerator.product(Object.new).should be_kind_of(Enumerator)
- end
+ it "raises NoMethodError when argument doesn't respond to #each_entry" do
+ -> {
+ Enumerator.product(Object.new).to_a
+ }.should raise_error(NoMethodError, /undefined method [`']each_entry' for/)
+ end
+
+ it "calls #each_entry lazily" do
+ Enumerator.product(Object.new).should be_kind_of(Enumerator)
+ end
- it "iterates through consuming enumerator elements only once" do
- a = [1, 2, 3]
- i = 0
+ it "iterates through consuming enumerator elements only once" do
+ a = [1, 2, 3]
+ i = 0
- enum = Enumerator.new do |y|
- while i < a.size
- y << a[i]
- i += 1
- end
+ enum = Enumerator.new do |y|
+ while i < a.size
+ y << a[i]
+ i += 1
end
-
- Enumerator.product(['a', 'b'], enum).to_a.should == [["a", 1], ["a", 2], ["a", 3]]
end
+
+ Enumerator.product(['a', 'b'], enum).to_a.should == [["a", 1], ["a", 2], ["a", 3]]
end
end
diff --git a/spec/ruby/core/enumerator/shared/enum_for.rb b/spec/ruby/core/enumerator/shared/enum_for.rb
new file mode 100644
index 0000000000..a67a76c461
--- /dev/null
+++ b/spec/ruby/core/enumerator/shared/enum_for.rb
@@ -0,0 +1,57 @@
+describe :enum_for, shared: true do
+ it "is defined in Kernel" do
+ Kernel.method_defined?(@method).should be_true
+ end
+
+ it "returns a new enumerator" do
+ "abc".send(@method).should be_an_instance_of(Enumerator)
+ end
+
+ it "defaults the first argument to :each" do
+ enum = [1,2].send(@method)
+ enum.map { |v| v }.should == [1,2].each { |v| v }
+ end
+
+ it "sets regexp matches in the caller" do
+ "wawa".send(@method, :scan, /./).map {|o| $& }.should == ["w", "a", "w", "a"]
+ a = []
+ "wawa".send(@method, :scan, /./).each {|o| a << $& }
+ a.should == ["w", "a", "w", "a"]
+ end
+
+ it "exposes multi-arg yields as an array" do
+ o = Object.new
+ def o.each
+ yield :a
+ yield :b1, :b2
+ yield [:c]
+ yield :d1, :d2
+ yield :e1, :e2, :e3
+ end
+
+ enum = o.send(@method)
+ enum.next.should == :a
+ enum.next.should == [:b1, :b2]
+ enum.next.should == [:c]
+ enum.next.should == [:d1, :d2]
+ enum.next.should == [:e1, :e2, :e3]
+ end
+
+ it "uses the passed block's value to calculate the size of the enumerator" do
+ Object.new.enum_for { 100 }.size.should == 100
+ end
+
+ it "defers the evaluation of the passed block until #size is called" do
+ ScratchPad.record []
+
+ enum = Object.new.enum_for do
+ ScratchPad << :called
+ 100
+ end
+
+ ScratchPad.recorded.should be_empty
+
+ enum.size
+ ScratchPad.recorded.should == [:called]
+ end
+end
diff --git a/spec/ruby/core/enumerator/shared/with_index.rb b/spec/ruby/core/enumerator/shared/with_index.rb
new file mode 100644
index 0000000000..78771ffe82
--- /dev/null
+++ b/spec/ruby/core/enumerator/shared/with_index.rb
@@ -0,0 +1,33 @@
+require_relative '../../../spec_helper'
+
+describe :enum_with_index, shared: true do
+
+ require_relative '../fixtures/classes'
+
+ before :each do
+ @origin = [1, 2, 3, 4]
+ @enum = @origin.to_enum
+ end
+
+ it "passes each element and its index to block" do
+ a = []
+ @enum.send(@method) { |o, i| a << [o, i] }
+ a.should == [[1, 0], [2, 1], [3, 2], [4, 3]]
+ end
+
+ it "returns the object being enumerated when given a block" do
+ @enum.send(@method) { |o, i| :glark }.should equal(@origin)
+ end
+
+ it "binds splat arguments properly" do
+ acc = []
+ @enum.send(@method) { |*b| c,d = b; acc << c; acc << d }
+ [1, 0, 2, 1, 3, 2, 4, 3].should == acc
+ end
+
+ it "returns an enumerator if no block is supplied" do
+ ewi = @enum.send(@method)
+ ewi.should be_an_instance_of(Enumerator)
+ ewi.to_a.should == [[1, 0], [2, 1], [3, 2], [4, 3]]
+ end
+end
diff --git a/spec/ruby/core/enumerator/shared/with_object.rb b/spec/ruby/core/enumerator/shared/with_object.rb
new file mode 100644
index 0000000000..d8e9d8e9f7
--- /dev/null
+++ b/spec/ruby/core/enumerator/shared/with_object.rb
@@ -0,0 +1,42 @@
+require_relative '../../../spec_helper'
+
+describe :enum_with_object, shared: true do
+ before :each do
+ @enum = [:a, :b].to_enum
+ @memo = ''
+ @block_params = @enum.send(@method, @memo).to_a
+ end
+
+ it "receives an argument" do
+ @enum.method(@method).arity.should == 1
+ end
+
+ context "with block" do
+ it "returns the given object" do
+ ret = @enum.send(@method, @memo) do |elm, memo|
+ # nothing
+ end
+ ret.should equal(@memo)
+ end
+
+ context "the block parameter" do
+ it "passes each element to first parameter" do
+ @block_params[0][0].should equal(:a)
+ @block_params[1][0].should equal(:b)
+ end
+
+ it "passes the given object to last parameter" do
+ @block_params[0][1].should equal(@memo)
+ @block_params[1][1].should equal(@memo)
+ end
+ end
+ end
+
+ context "without block" do
+ it "returns new Enumerator" do
+ ret = @enum.send(@method, @memo)
+ ret.should be_an_instance_of(Enumerator)
+ ret.should_not equal(@enum)
+ end
+ end
+end
diff --git a/spec/ruby/core/enumerator/to_enum_spec.rb b/spec/ruby/core/enumerator/to_enum_spec.rb
index cadfcf6314..7fb73d0c3c 100644
--- a/spec/ruby/core/enumerator/to_enum_spec.rb
+++ b/spec/ruby/core/enumerator/to_enum_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../spec_helper'
-require_relative '../../shared/enumerator/enum_for'
+require_relative 'shared/enum_for'
describe "Enumerator#to_enum" do
- it_behaves_like :enum_for, :enum_for
+ it_behaves_like :enum_for, :to_enum
end
diff --git a/spec/ruby/core/enumerator/with_index_spec.rb b/spec/ruby/core/enumerator/with_index_spec.rb
index 3aeb3fc869..e49aa7a939 100644
--- a/spec/ruby/core/enumerator/with_index_spec.rb
+++ b/spec/ruby/core/enumerator/with_index_spec.rb
@@ -1,5 +1,5 @@
require_relative '../../spec_helper'
-require_relative '../../shared/enumerator/with_index'
+require_relative 'shared/with_index'
require_relative '../enumerable/shared/enumeratorized'
describe "Enumerator#with_index" do
diff --git a/spec/ruby/core/enumerator/with_object_spec.rb b/spec/ruby/core/enumerator/with_object_spec.rb
index e7ba83fd9f..58031fd765 100644
--- a/spec/ruby/core/enumerator/with_object_spec.rb
+++ b/spec/ruby/core/enumerator/with_object_spec.rb
@@ -1,5 +1,5 @@
require_relative '../../spec_helper'
-require_relative '../../shared/enumerator/with_object'
+require_relative 'shared/with_object'
describe "Enumerator#with_object" do
it_behaves_like :enum_with_object, :with_object
diff --git a/spec/ruby/core/env/clone_spec.rb b/spec/ruby/core/env/clone_spec.rb
index 991e4e6774..01a29c6ab4 100644
--- a/spec/ruby/core/env/clone_spec.rb
+++ b/spec/ruby/core/env/clone_spec.rb
@@ -13,11 +13,9 @@ describe "ENV#clone" do
}.should raise_error(ArgumentError)
end
- ruby_version_is "3.2" do
- it "raises TypeError" do
- -> {
- ENV.clone
- }.should raise_error(TypeError, /Cannot clone ENV, use ENV.to_h to get a copy of ENV as a hash/)
- end
+ it "raises TypeError" do
+ -> {
+ ENV.clone
+ }.should raise_error(TypeError, /Cannot clone ENV, use ENV.to_h to get a copy of ENV as a hash/)
end
end
diff --git a/spec/ruby/core/env/dup_spec.rb b/spec/ruby/core/env/dup_spec.rb
index 46d125aca8..ac66b455cd 100644
--- a/spec/ruby/core/env/dup_spec.rb
+++ b/spec/ruby/core/env/dup_spec.rb
@@ -1,11 +1,9 @@
require_relative '../../spec_helper'
describe "ENV#dup" do
- ruby_version_is "3.1" do
- it "raises TypeError" do
- -> {
- ENV.dup
- }.should raise_error(TypeError, /Cannot dup ENV, use ENV.to_h to get a copy of ENV as a hash/)
- end
+ it "raises TypeError" do
+ -> {
+ ENV.dup
+ }.should raise_error(TypeError, /Cannot dup ENV, use ENV.to_h to get a copy of ENV as a hash/)
end
end
diff --git a/spec/ruby/core/env/element_reference_spec.rb b/spec/ruby/core/env/element_reference_spec.rb
index 560c127a9c..66a9bc9690 100644
--- a/spec/ruby/core/env/element_reference_spec.rb
+++ b/spec/ruby/core/env/element_reference_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'fixtures/common'
diff --git a/spec/ruby/core/env/fetch_spec.rb b/spec/ruby/core/env/fetch_spec.rb
index b2e7a88cab..2c5d7cc3a0 100644
--- a/spec/ruby/core/env/fetch_spec.rb
+++ b/spec/ruby/core/env/fetch_spec.rb
@@ -47,7 +47,7 @@ describe "ENV.fetch" do
it "warns on block and default parameter given" do
-> do
- ENV.fetch("foo", "default") { "bar" }.should == "bar"
+ ENV.fetch("foo", "default") { "bar" }.should == "bar"
end.should complain(/block supersedes default value argument/)
end
diff --git a/spec/ruby/core/env/inspect_spec.rb b/spec/ruby/core/env/inspect_spec.rb
index 3c611c24a1..7dd92b120f 100644
--- a/spec/ruby/core/env/inspect_spec.rb
+++ b/spec/ruby/core/env/inspect_spec.rb
@@ -4,7 +4,7 @@ describe "ENV.inspect" do
it "returns a String that looks like a Hash with real data" do
ENV["foo"] = "bar"
- ENV.inspect.should =~ /\{.*"foo"=>"bar".*\}/
+ ENV.inspect.should =~ /\{.*"foo" *=> *"bar".*\}/
ENV.delete "foo"
end
diff --git a/spec/ruby/core/env/length_spec.rb b/spec/ruby/core/env/length_spec.rb
index 536af9edf5..c6f9062892 100644
--- a/spec/ruby/core/env/length_spec.rb
+++ b/spec/ruby/core/env/length_spec.rb
@@ -2,5 +2,5 @@ require_relative '../../spec_helper'
require_relative 'shared/length'
describe "ENV.length" do
- it_behaves_like :env_length, :length
+ it_behaves_like :env_length, :length
end
diff --git a/spec/ruby/core/env/shared/update.rb b/spec/ruby/core/env/shared/update.rb
index 7d4799955b..e1b1c9c290 100644
--- a/spec/ruby/core/env/shared/update.rb
+++ b/spec/ruby/core/env/shared/update.rb
@@ -15,12 +15,10 @@ describe :env_update, shared: true do
ENV["bar"].should == "1"
end
- ruby_version_is "3.2" do
- it "adds the multiple parameter hashes to ENV, returning ENV" do
- ENV.send(@method, {"foo" => "multi1"}, {"bar" => "multi2"}).should equal(ENV)
- ENV["foo"].should == "multi1"
- ENV["bar"].should == "multi2"
- end
+ it "adds the multiple parameter hashes to ENV, returning ENV" do
+ ENV.send(@method, {"foo" => "multi1"}, {"bar" => "multi2"}).should equal(ENV)
+ ENV["foo"].should == "multi1"
+ ENV["bar"].should == "multi2"
end
it "returns ENV when no block given" do
diff --git a/spec/ruby/core/env/size_spec.rb b/spec/ruby/core/env/size_spec.rb
index f050e9e5a9..7c8072481e 100644
--- a/spec/ruby/core/env/size_spec.rb
+++ b/spec/ruby/core/env/size_spec.rb
@@ -2,5 +2,5 @@ require_relative '../../spec_helper'
require_relative 'shared/length'
describe "ENV.size" do
- it_behaves_like :env_length, :size
+ it_behaves_like :env_length, :size
end
diff --git a/spec/ruby/core/exception/detailed_message_spec.rb b/spec/ruby/core/exception/detailed_message_spec.rb
index 8178278b2b..9df164a1cf 100644
--- a/spec/ruby/core/exception/detailed_message_spec.rb
+++ b/spec/ruby/core/exception/detailed_message_spec.rb
@@ -2,51 +2,49 @@ require_relative '../../spec_helper'
require_relative 'fixtures/common'
describe "Exception#detailed_message" do
- ruby_version_is "3.2" do
- it "returns decorated message" do
- RuntimeError.new("new error").detailed_message.should == "new error (RuntimeError)"
- end
+ it "returns decorated message" do
+ RuntimeError.new("new error").detailed_message.should == "new error (RuntimeError)"
+ end
- it "is called by #full_message to allow message customization" do
- exception = Exception.new("new error")
- def exception.detailed_message(**)
- "<prefix>#{message}<suffix>"
- end
- exception.full_message(highlight: false).should.include? "<prefix>new error<suffix>"
+ it "is called by #full_message to allow message customization" do
+ exception = Exception.new("new error")
+ def exception.detailed_message(**)
+ "<prefix>#{message}<suffix>"
end
+ exception.full_message(highlight: false).should.include? "<prefix>new error<suffix>"
+ end
- it "returns just a message if exception class is anonymous" do
- Class.new(RuntimeError).new("message").detailed_message.should == "message"
- end
+ it "returns just a message if exception class is anonymous" do
+ Class.new(RuntimeError).new("message").detailed_message.should == "message"
+ end
- it "returns 'unhandled exception' for an instance of RuntimeError with empty message" do
- RuntimeError.new("").detailed_message.should == "unhandled exception"
- end
+ it "returns 'unhandled exception' for an instance of RuntimeError with empty message" do
+ RuntimeError.new("").detailed_message.should == "unhandled exception"
+ end
- it "returns just class name for an instance other than RuntimeError with empty message" do
- DetailedMessageSpec::C.new("").detailed_message.should == "DetailedMessageSpec::C"
- StandardError.new("").detailed_message.should == "StandardError"
- end
+ it "returns just class name for an instance other than RuntimeError with empty message" do
+ DetailedMessageSpec::C.new("").detailed_message.should == "DetailedMessageSpec::C"
+ StandardError.new("").detailed_message.should == "StandardError"
+ end
- it "returns a generated class name for an instance of RuntimeError anonymous subclass with empty message" do
- klass = Class.new(RuntimeError)
- klass.new("").detailed_message.should =~ /\A#<Class:0x\h+>\z/
- end
+ it "returns a generated class name for an instance of RuntimeError anonymous subclass with empty message" do
+ klass = Class.new(RuntimeError)
+ klass.new("").detailed_message.should =~ /\A#<Class:0x\h+>\z/
+ end
- it "accepts highlight keyword argument and adds escape control sequences" do
- RuntimeError.new("new error").detailed_message(highlight: true).should == "\e[1mnew error (\e[1;4mRuntimeError\e[m\e[1m)\e[m"
- end
+ it "accepts highlight keyword argument and adds escape control sequences" do
+ RuntimeError.new("new error").detailed_message(highlight: true).should == "\e[1mnew error (\e[1;4mRuntimeError\e[m\e[1m)\e[m"
+ end
- it "accepts highlight keyword argument and adds escape control sequences for an instance of RuntimeError with empty message" do
- RuntimeError.new("").detailed_message(highlight: true).should == "\e[1;4munhandled exception\e[m"
- end
+ it "accepts highlight keyword argument and adds escape control sequences for an instance of RuntimeError with empty message" do
+ RuntimeError.new("").detailed_message(highlight: true).should == "\e[1;4munhandled exception\e[m"
+ end
- it "accepts highlight keyword argument and adds escape control sequences for an instance other than RuntimeError with empty message" do
- StandardError.new("").detailed_message(highlight: true).should == "\e[1;4mStandardError\e[m"
- end
+ it "accepts highlight keyword argument and adds escape control sequences for an instance other than RuntimeError with empty message" do
+ StandardError.new("").detailed_message(highlight: true).should == "\e[1;4mStandardError\e[m"
+ end
- it "allows and ignores other keyword arguments" do
- RuntimeError.new("new error").detailed_message(foo: true).should == "new error (RuntimeError)"
- end
+ it "allows and ignores other keyword arguments" do
+ RuntimeError.new("new error").detailed_message(foo: true).should == "new error (RuntimeError)"
end
end
diff --git a/spec/ruby/core/exception/errno_spec.rb b/spec/ruby/core/exception/errno_spec.rb
index a063e522ea..1ab4277700 100644
--- a/spec/ruby/core/exception/errno_spec.rb
+++ b/spec/ruby/core/exception/errno_spec.rb
@@ -29,6 +29,8 @@ describe "Errno::EMFILE" do
ExceptionSpecs::EMFILESub = Class.new(Errno::EMFILE)
exc = ExceptionSpecs::EMFILESub.new
exc.should be_an_instance_of(ExceptionSpecs::EMFILESub)
+ ensure
+ ExceptionSpecs.send(:remove_const, :EMFILESub)
end
end
diff --git a/spec/ruby/core/exception/fixtures/common.rb b/spec/ruby/core/exception/fixtures/common.rb
index 1e243098bd..3d8a3c3430 100644
--- a/spec/ruby/core/exception/fixtures/common.rb
+++ b/spec/ruby/core/exception/fixtures/common.rb
@@ -84,6 +84,9 @@ module NoMethodErrorSpecs
class InstanceException < Exception
end
+
+ class AClass; end
+ module AModule; end
end
class NameErrorSpecs
diff --git a/spec/ruby/core/exception/frozen_error_spec.rb b/spec/ruby/core/exception/frozen_error_spec.rb
index 979ec2ff98..af2e925661 100644
--- a/spec/ruby/core/exception/frozen_error_spec.rb
+++ b/spec/ruby/core/exception/frozen_error_spec.rb
@@ -21,6 +21,22 @@ describe "FrozenError#receiver" do
end
end
+describe "FrozenError#message" do
+ it "includes a receiver" do
+ object = Object.new
+ object.freeze
+
+ msg_class = ruby_version_is("4.0") ? "Object" : "object"
+
+ -> {
+ def object.x; end
+ }.should raise_error(FrozenError, "can't modify frozen #{msg_class}: #{object}")
+
+ object = [].freeze
+ -> { object << nil }.should raise_error(FrozenError, "can't modify frozen Array: []")
+ end
+end
+
describe "Modifying a frozen object" do
context "#inspect is redefined and modifies the object" do
it "returns ... instead of String representation of object" do
diff --git a/spec/ruby/core/exception/full_message_spec.rb b/spec/ruby/core/exception/full_message_spec.rb
index d752083db2..0761d2b40c 100644
--- a/spec/ruby/core/exception/full_message_spec.rb
+++ b/spec/ruby/core/exception/full_message_spec.rb
@@ -165,52 +165,62 @@ describe "Exception#full_message" do
exception.full_message.should include "origin exception"
end
- ruby_version_is "3.2" do
- it "relies on #detailed_message" do
- e = RuntimeError.new("new error")
- e.define_singleton_method(:detailed_message) { |**| "DETAILED MESSAGE" }
+ it "relies on #detailed_message" do
+ e = RuntimeError.new("new error")
+ e.define_singleton_method(:detailed_message) { |**| "DETAILED MESSAGE" }
- e.full_message.lines.first.should =~ /DETAILED MESSAGE/
+ e.full_message.lines.first.should =~ /DETAILED MESSAGE/
+ end
+
+ it "passes all its own keyword arguments (with :highlight default value and without :order default value) to #detailed_message" do
+ e = RuntimeError.new("new error")
+ options_passed = nil
+ e.define_singleton_method(:detailed_message) do |**options|
+ options_passed = options
+ "DETAILED MESSAGE"
end
- it "passes all its own keyword arguments (with :highlight default value and without :order default value) to #detailed_message" do
- e = RuntimeError.new("new error")
- options_passed = nil
- e.define_singleton_method(:detailed_message) do |**options|
- options_passed = options
- "DETAILED MESSAGE"
- end
+ e.full_message(foo: "bar")
+ options_passed.should == { foo: "bar", highlight: Exception.to_tty? }
+ end
- e.full_message(foo: "bar")
- options_passed.should == { foo: "bar", highlight: Exception.to_tty? }
- end
+ it "converts #detailed_message returned value to String if it isn't a String" do
+ message = Object.new
+ def message.to_str; "DETAILED MESSAGE"; end
- it "converts #detailed_message returned value to String if it isn't a String" do
- message = Object.new
- def message.to_str; "DETAILED MESSAGE"; end
+ e = RuntimeError.new("new error")
+ e.define_singleton_method(:detailed_message) { |**| message }
- e = RuntimeError.new("new error")
- e.define_singleton_method(:detailed_message) { |**| message }
+ e.full_message.lines.first.should =~ /DETAILED MESSAGE/
+ end
- e.full_message.lines.first.should =~ /DETAILED MESSAGE/
- end
+ it "uses class name if #detailed_message returns nil" do
+ e = RuntimeError.new("new error")
+ e.define_singleton_method(:detailed_message) { |**| nil }
- it "uses class name if #detailed_message returns nil" do
- e = RuntimeError.new("new error")
- e.define_singleton_method(:detailed_message) { |**| nil }
+ e.full_message(highlight: false).lines.first.should =~ /RuntimeError/
+ e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/
+ end
- e.full_message(highlight: false).lines.first.should =~ /RuntimeError/
- e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/
+ it "uses class name if exception object doesn't respond to #detailed_message" do
+ e = RuntimeError.new("new error")
+ class << e
+ undef :detailed_message
end
- it "uses class name if exception object doesn't respond to #detailed_message" do
- e = RuntimeError.new("new error")
- class << e
- undef :detailed_message
- end
+ e.full_message(highlight: false).lines.first.should =~ /RuntimeError/
+ e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/
+ end
- e.full_message(highlight: false).lines.first.should =~ /RuntimeError/
- e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/
+ it "allows cause with empty backtrace" do
+ begin
+ raise RuntimeError.new("Some runtime error"), cause: RuntimeError.new("Some other runtime error")
+ rescue => e
end
+
+ full_message = e.full_message
+ full_message.should include "RuntimeError"
+ full_message.should include "Some runtime error"
+ full_message.should include "Some other runtime error"
end
end
diff --git a/spec/ruby/core/exception/no_method_error_spec.rb b/spec/ruby/core/exception/no_method_error_spec.rb
index 26df3338e9..772c569f67 100644
--- a/spec/ruby/core/exception/no_method_error_spec.rb
+++ b/spec/ruby/core/exception/no_method_error_spec.rb
@@ -67,7 +67,7 @@ describe "NoMethodError#message" do
end
ruby_version_is ""..."3.3" do
- it "calls receiver.inspect only when calling Exception#message" do
+ it "calls #inspect when calling Exception#message" do
ScratchPad.record []
test_class = Class.new do
def inspect
@@ -76,19 +76,163 @@ describe "NoMethodError#message" do
end
end
instance = test_class.new
+
begin
instance.bar
- rescue Exception => e
- e.name.should == :bar
- ScratchPad.recorded.should == []
- e.message.should =~ /undefined method.+\bbar\b/
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for <inspect>:#<Class:0x\h+>$/
ScratchPad.recorded.should == [:inspect_called]
end
end
+
+ it "fallbacks to a simpler representation of the receiver when receiver.inspect raises an exception" do
+ test_class = Class.new do
+ def inspect
+ raise NoMethodErrorSpecs::InstanceException
+ end
+ end
+ instance = test_class.new
+
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ message = error.message
+ message.should =~ /undefined method.+\bbar\b/
+ message.should include test_class.inspect
+ end
+ end
+
+ it "uses #name to display the receiver if it is a class" do
+ klass = Class.new { def self.name; "MyClass"; end }
+
+ begin
+ klass.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for MyClass:Class$/
+ end
+ end
+
+ it "uses #name to display the receiver if it is a module" do
+ mod = Module.new { def self.name; "MyModule"; end }
+
+ begin
+ mod.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for MyModule:Module$/
+ end
+ end
end
ruby_version_is "3.3" do
- it "does not call receiver.inspect even when calling Exception#message" do
+ it "uses a literal name when receiver is nil" do
+ begin
+ nil.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for nil\Z/
+ end
+ end
+
+ it "uses a literal name when receiver is true" do
+ begin
+ true.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for true\Z/
+ end
+ end
+
+ it "uses a literal name when receiver is false" do
+ begin
+ false.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for false\Z/
+ end
+ end
+
+ it "uses #name when receiver is a class" do
+ klass = Class.new { def self.name; "MyClass"; end }
+
+ begin
+ klass.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for class MyClass\Z/
+ end
+ end
+
+ it "uses class' string representation when receiver is an anonymous class" do
+ klass = Class.new
+
+ begin
+ klass.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for class #<Class:0x\h+>\Z/
+ end
+ end
+
+ it "uses class' string representation when receiver is a singleton class" do
+ obj = Object.new
+ singleton_class = obj.singleton_class
+
+ begin
+ singleton_class.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for class #<Class:#<Object:0x\h+>>\Z/
+ end
+ end
+
+ it "uses #name when receiver is a module" do
+ mod = Module.new { def self.name; "MyModule"; end }
+
+ begin
+ mod.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for module MyModule\Z/
+ end
+ end
+
+ it "uses module's string representation when receiver is an anonymous module" do
+ m = Module.new
+
+ begin
+ m.foo
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for module #<Module:0x\h+>\Z/
+ end
+ end
+
+ it "uses class #name when receiver is an ordinary object" do
+ klass = Class.new { def self.name; "MyClass"; end }
+ instance = klass.new
+
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for an instance of MyClass\Z/
+ end
+ end
+
+ it "uses class string representation when receiver is an instance of anonymous class" do
+ klass = Class.new
+ instance = klass.new
+
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/
+ end
+ end
+
+ it "uses class name when receiver has a singleton class" do
+ instance = NoMethodErrorSpecs::NoMethodErrorA.new
+ def instance.foo; end
+
+ begin
+ instance.bar
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for #<NoMethodErrorSpecs::NoMethodErrorA:0x\h+>\Z/
+ end
+ end
+
+ it "does not call #inspect when calling Exception#message" do
ScratchPad.record []
test_class = Class.new do
def inspect
@@ -97,47 +241,29 @@ describe "NoMethodError#message" do
end
end
instance = test_class.new
+
begin
instance.bar
- rescue Exception => e
- e.name.should == :bar
- ScratchPad.recorded.should == []
- e.message.should =~ /undefined method.+\bbar\b/
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']bar' for an instance of #<Class:0x\h+>\Z/
ScratchPad.recorded.should == []
end
end
- end
- it "fallbacks to a simpler representation of the receiver when receiver.inspect raises an exception" do
- test_class = Class.new do
- def inspect
- raise NoMethodErrorSpecs::InstanceException
- end
- end
- instance = test_class.new
- begin
- instance.bar
- rescue Exception => e
- e.name.should == :bar
- message = e.message
- message.should =~ /undefined method.+\bbar\b/
- message.should include test_class.inspect
- end
- end
+ it "does not truncate long class names" do
+ class_name = 'ExceptionSpecs::A' + 'a'*100
- it "uses #name to display the receiver if it is a class or a module" do
- klass = Class.new { def self.name; "MyClass"; end }
- begin
- klass.foo
- rescue NoMethodError => error
- error.message.lines.first.chomp.should =~ /^undefined method [`']foo' for /
- end
+ begin
+ eval <<~RUBY
+ class #{class_name}
+ end
- mod = Module.new { def self.name; "MyModule"; end }
- begin
- mod.foo
- rescue NoMethodError => error
- error.message.lines.first.chomp.should =~ /^undefined method [`']foo' for /
+ obj = #{class_name}.new
+ obj.foo
+ RUBY
+ rescue NoMethodError => error
+ error.message.should =~ /\Aundefined method [`']foo' for an instance of #{class_name}\Z/
+ end
end
end
end
diff --git a/spec/ruby/core/exception/set_backtrace_spec.rb b/spec/ruby/core/exception/set_backtrace_spec.rb
index 12c1da919c..2cd93326ec 100644
--- a/spec/ruby/core/exception/set_backtrace_spec.rb
+++ b/spec/ruby/core/exception/set_backtrace_spec.rb
@@ -1,13 +1,8 @@
require_relative '../../spec_helper'
require_relative 'fixtures/common'
+require_relative 'shared/set_backtrace'
describe "Exception#set_backtrace" do
- it "accepts an Array of Strings" do
- err = RuntimeError.new
- err.set_backtrace ["unhappy"]
- err.backtrace.should == ["unhappy"]
- end
-
it "allows the user to set the backtrace from a rescued exception" do
bt = ExceptionSpecs::Backtrace.backtrace
err = RuntimeError.new
@@ -20,65 +15,9 @@ describe "Exception#set_backtrace" do
err.backtrace_locations.should == nil
end
- ruby_version_is "3.4" do
- it "allows the user to set backtrace locations from a rescued exception" do
- bt_locations = ExceptionSpecs::Backtrace.backtrace_locations
- err = RuntimeError.new
- err.backtrace.should == nil
- err.backtrace_locations.should == nil
-
- err.set_backtrace bt_locations
-
- err.backtrace_locations.size.should == bt_locations.size
- err.backtrace_locations.each_with_index do |loc, index|
- other_loc = bt_locations[index]
-
- loc.path.should == other_loc.path
- loc.label.should == other_loc.label
- loc.base_label.should == other_loc.base_label
- loc.lineno.should == other_loc.lineno
- loc.absolute_path.should == other_loc.absolute_path
- loc.to_s.should == other_loc.to_s
- end
- err.backtrace.size.should == err.backtrace_locations.size
- end
- end
-
- it "accepts an empty Array" do
- err = RuntimeError.new
- err.set_backtrace []
- err.backtrace.should == []
- end
-
- it "accepts a String" do
+ it_behaves_like :exception_set_backtrace, -> backtrace {
err = RuntimeError.new
- err.set_backtrace "unhappy"
- err.backtrace.should == ["unhappy"]
- end
-
- it "accepts nil" do
- err = RuntimeError.new
- err.set_backtrace nil
- err.backtrace.should be_nil
- end
-
- it "raises a TypeError when passed a Symbol" do
- err = RuntimeError.new
- -> { err.set_backtrace :unhappy }.should raise_error(TypeError)
- end
-
- it "raises a TypeError when the Array contains a Symbol" do
- err = RuntimeError.new
- -> { err.set_backtrace ["String", :unhappy] }.should raise_error(TypeError)
- end
-
- it "raises a TypeError when the array contains nil" do
- err = Exception.new
- -> { err.set_backtrace ["String", nil] }.should raise_error(TypeError)
- end
-
- it "raises a TypeError when the argument is a nested array" do
- err = Exception.new
- -> { err.set_backtrace ["String", ["String"]] }.should raise_error(TypeError)
- end
+ err.set_backtrace(backtrace)
+ err
+ }
end
diff --git a/spec/ruby/core/exception/shared/set_backtrace.rb b/spec/ruby/core/exception/shared/set_backtrace.rb
new file mode 100644
index 0000000000..c6213b42b4
--- /dev/null
+++ b/spec/ruby/core/exception/shared/set_backtrace.rb
@@ -0,0 +1,64 @@
+require_relative '../fixtures/common'
+
+describe :exception_set_backtrace, shared: true do
+ it "accepts an Array of Strings" do
+ err = @method.call(["unhappy"])
+ err.backtrace.should == ["unhappy"]
+ end
+
+ it "allows the user to set the backtrace from a rescued exception" do
+ bt = ExceptionSpecs::Backtrace.backtrace
+ err = @method.call(bt)
+ err.backtrace.should == bt
+ end
+
+ ruby_version_is "3.4" do
+ it "allows the user to set backtrace locations from a rescued exception" do
+ bt_locations = ExceptionSpecs::Backtrace.backtrace_locations
+ err = @method.call(bt_locations)
+ err.backtrace_locations.size.should == bt_locations.size
+ err.backtrace_locations.each_with_index do |loc, index|
+ other_loc = bt_locations[index]
+
+ loc.path.should == other_loc.path
+ loc.label.should == other_loc.label
+ loc.base_label.should == other_loc.base_label
+ loc.lineno.should == other_loc.lineno
+ loc.absolute_path.should == other_loc.absolute_path
+ loc.to_s.should == other_loc.to_s
+ end
+ err.backtrace.size.should == err.backtrace_locations.size
+ end
+ end
+
+ it "accepts an empty Array" do
+ err = @method.call([])
+ err.backtrace.should == []
+ end
+
+ it "accepts a String" do
+ err = @method.call("unhappy")
+ err.backtrace.should == ["unhappy"]
+ end
+
+ it "accepts nil" do
+ err = @method.call(nil)
+ err.backtrace.should be_nil
+ end
+
+ it "raises a TypeError when passed a Symbol" do
+ -> { @method.call(:unhappy) }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError when the Array contains a Symbol" do
+ -> { @method.call(["String", :unhappy]) }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError when the array contains nil" do
+ -> { @method.call(["String", nil]) }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError when the argument is a nested array" do
+ -> { @method.call(["String", ["String"]]) }.should raise_error(TypeError)
+ end
+end
diff --git a/spec/ruby/core/exception/syntax_error_spec.rb b/spec/ruby/core/exception/syntax_error_spec.rb
index 6cc8522de3..4c713a3507 100644
--- a/spec/ruby/core/exception/syntax_error_spec.rb
+++ b/spec/ruby/core/exception/syntax_error_spec.rb
@@ -1,27 +1,25 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "SyntaxError#path" do
- it "returns the file path provided to eval" do
- filename = "speccing.rb"
+describe "SyntaxError#path" do
+ it "returns the file path provided to eval" do
+ filename = "speccing.rb"
- -> {
- eval("if true", TOPLEVEL_BINDING, filename)
- }.should raise_error(SyntaxError) { |e|
- e.path.should == filename
- }
- end
+ -> {
+ eval("if true", TOPLEVEL_BINDING, filename)
+ }.should raise_error(SyntaxError) { |e|
+ e.path.should == filename
+ }
+ end
- it "returns the file path that raised an exception" do
- expected_path = fixture(__FILE__, "syntax_error.rb")
+ it "returns the file path that raised an exception" do
+ expected_path = fixture(__FILE__, "syntax_error.rb")
- -> {
- require_relative "fixtures/syntax_error"
- }.should raise_error(SyntaxError) { |e| e.path.should == expected_path }
- end
+ -> {
+ require_relative "fixtures/syntax_error"
+ }.should raise_error(SyntaxError) { |e| e.path.should == expected_path }
+ end
- it "returns nil when constructed directly" do
- SyntaxError.new.path.should == nil
- end
+ it "returns nil when constructed directly" do
+ SyntaxError.new.path.should == nil
end
end
diff --git a/spec/ruby/core/exception/system_call_error_spec.rb b/spec/ruby/core/exception/system_call_error_spec.rb
index f6995d3c5e..4fe51901c8 100644
--- a/spec/ruby/core/exception/system_call_error_spec.rb
+++ b/spec/ruby/core/exception/system_call_error_spec.rb
@@ -16,6 +16,8 @@ describe "SystemCallError" do
exc = ExceptionSpecs::SCESub.new
ScratchPad.recorded.should equal(:initialize)
exc.should be_an_instance_of(ExceptionSpecs::SCESub)
+ ensure
+ ExceptionSpecs.send(:remove_const, :SCESub)
end
end
@@ -25,6 +27,7 @@ describe "SystemCallError.new" do
@example_errno_class = Errno::EINVAL
@last_known_errno = Errno.constants.size - 1
@unknown_errno = Errno.constants.size
+ @some_human_readable = /[[:graph:]]+/
end
it "requires at least one argument" do
@@ -96,23 +99,11 @@ describe "SystemCallError.new" do
end
it "sets an 'unknown error' message when an unknown error number" do
- platform_is_not :windows do
- SystemCallError.new(-1).message.should =~ /Unknown error(:)? -1/
- end
-
- platform_is :windows do
- SystemCallError.new(-1).message.should == "The operation completed successfully."
- end
+ SystemCallError.new(-1).message.should =~ @some_human_readable
end
it "adds a custom error message to an 'unknown error' message when an unknown error number and a custom message specified" do
- platform_is_not :windows do
- SystemCallError.new("custom message", -1).message.should =~ /Unknown error(:)? -1 - custom message/
- end
-
- platform_is :windows do
- SystemCallError.new("custom message", -1).message.should == "The operation completed successfully. - custom message"
- end
+ SystemCallError.new("custom message", -1).message.should =~ /#{@some_human_readable}.* - custom message/
end
it "converts to Integer if errno is a Complex convertible to Integer" do
@@ -149,12 +140,7 @@ end
describe "SystemCallError#message" do
it "returns the default message when no message is given" do
- platform_is :aix do
- SystemCallError.new(2**28).message.should =~ /Error .*occurred/i
- end
- platform_is_not :aix do
- SystemCallError.new(2**28).message.should =~ /Unknown error/i
- end
+ SystemCallError.new(2**28).message.should =~ @some_human_readable
end
it "returns the message given as an argument to new" do
diff --git a/spec/ruby/core/fiber/alive_spec.rb b/spec/ruby/core/fiber/alive_spec.rb
new file mode 100644
index 0000000000..a1df582435
--- /dev/null
+++ b/spec/ruby/core/fiber/alive_spec.rb
@@ -0,0 +1,44 @@
+require_relative '../../spec_helper'
+
+describe "Fiber#alive?" do
+ it "returns true for a Fiber that hasn't had #resume called" do
+ fiber = Fiber.new { true }
+ fiber.alive?.should be_true
+ end
+
+ # FIXME: Better description?
+ it "returns true for a Fiber that's yielded to the caller" do
+ fiber = Fiber.new { Fiber.yield }
+ fiber.resume
+ fiber.alive?.should be_true
+ end
+
+ it "returns true when called from its Fiber" do
+ fiber = Fiber.new { fiber.alive?.should be_true }
+ fiber.resume
+ end
+
+ it "doesn't invoke the block associated with the Fiber" do
+ offthehook = mock('do not call')
+ offthehook.should_not_receive(:ring)
+ fiber = Fiber.new { offthehook.ring }
+ fiber.alive?
+ end
+
+ it "returns false for a Fiber that's dead" do
+ fiber = Fiber.new { true }
+ fiber.resume
+ -> { fiber.resume }.should raise_error(FiberError)
+ fiber.alive?.should be_false
+ end
+
+ it "always returns false for a dead Fiber" do
+ fiber = Fiber.new { true }
+ fiber.resume
+ -> { fiber.resume }.should raise_error(FiberError)
+ fiber.alive?.should be_false
+ -> { fiber.resume }.should raise_error(FiberError)
+ fiber.alive?.should be_false
+ fiber.alive?.should be_false
+ end
+end
diff --git a/spec/ruby/core/fiber/blocking_spec.rb b/spec/ruby/core/fiber/blocking_spec.rb
index ebefa116af..d5caf81fbe 100644
--- a/spec/ruby/core/fiber/blocking_spec.rb
+++ b/spec/ruby/core/fiber/blocking_spec.rb
@@ -1,8 +1,6 @@
require_relative '../../spec_helper'
require_relative 'shared/blocking'
-require "fiber"
-
describe "Fiber.blocking?" do
it_behaves_like :non_blocking_fiber, -> { Fiber.blocking? }
@@ -59,19 +57,17 @@ describe "Fiber#blocking?" do
end
end
-ruby_version_is "3.2" do
- describe "Fiber.blocking" do
- context "when fiber is non-blocking" do
- it "can become blocking" do
- fiber = Fiber.new(blocking: false) do
- Fiber.blocking do |f|
- f.blocking? ? :blocking : :non_blocking
- end
+describe "Fiber.blocking" do
+ context "when fiber is non-blocking" do
+ it "can become blocking" do
+ fiber = Fiber.new(blocking: false) do
+ Fiber.blocking do |f|
+ f.blocking? ? :blocking : :non_blocking
end
-
- blocking = fiber.resume
- blocking.should == :blocking
end
+
+ blocking = fiber.resume
+ blocking.should == :blocking
end
end
end
diff --git a/spec/ruby/core/fiber/current_spec.rb b/spec/ruby/core/fiber/current_spec.rb
new file mode 100644
index 0000000000..b93df77a89
--- /dev/null
+++ b/spec/ruby/core/fiber/current_spec.rb
@@ -0,0 +1,50 @@
+require_relative '../../spec_helper'
+
+describe "Fiber.current" do
+ it "returns the root Fiber when called outside of a Fiber" do
+ root = Fiber.current
+ root.should be_an_instance_of(Fiber)
+ # We can always transfer to the root Fiber; it will never die
+ 5.times do
+ root.transfer.should be_nil
+ root.alive?.should be_true
+ end
+ end
+
+ it "returns the current Fiber when called from a Fiber" do
+ fiber = Fiber.new do
+ this = Fiber.current
+ this.should be_an_instance_of(Fiber)
+ this.should == fiber
+ this.alive?.should be_true
+ end
+ fiber.resume
+ end
+
+ it "returns the current Fiber when called from a Fiber that transferred to another" do
+ states = []
+ fiber = Fiber.new do
+ states << :fiber
+ this = Fiber.current
+ this.should be_an_instance_of(Fiber)
+ this.should == fiber
+ this.alive?.should be_true
+ end
+
+ fiber2 = Fiber.new do
+ states << :fiber2
+ fiber.transfer
+ flunk
+ end
+
+ fiber3 = Fiber.new do
+ states << :fiber3
+ fiber2.transfer
+ states << :fiber3_terminated
+ end
+
+ fiber3.resume
+
+ states.should == [:fiber3, :fiber2, :fiber, :fiber3_terminated]
+ end
+end
diff --git a/spec/ruby/core/fiber/fixtures/classes.rb b/spec/ruby/core/fiber/fixtures/classes.rb
index c00facd6e1..6b0e0fbc42 100644
--- a/spec/ruby/core/fiber/fixtures/classes.rb
+++ b/spec/ruby/core/fiber/fixtures/classes.rb
@@ -1,10 +1,20 @@
module FiberSpecs
class NewFiberToRaise
- def self.raise(*args)
- fiber = Fiber.new { Fiber.yield }
+ def self.raise(*args, **kwargs, &block)
+ fiber = Fiber.new do
+ if block_given?
+ block.call do
+ Fiber.yield
+ end
+ else
+ Fiber.yield
+ end
+ end
+
fiber.resume
- fiber.raise(*args)
+
+ fiber.raise(*args, **kwargs)
end
end
diff --git a/spec/ruby/core/fiber/fixtures/scheduler.rb b/spec/ruby/core/fiber/fixtures/scheduler.rb
new file mode 100644
index 0000000000..16bd2f6b44
--- /dev/null
+++ b/spec/ruby/core/fiber/fixtures/scheduler.rb
@@ -0,0 +1,35 @@
+module FiberSpecs
+
+ class LoggingScheduler
+ attr_reader :events
+ def initialize
+ @events = []
+ end
+
+ def block(*args)
+ @events << { event: :block, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+
+ def io_wait(*args)
+ @events << { event: :io_wait, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+
+ def kernel_sleep(*args)
+ @events << { event: :kernel_sleep, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+
+ def unblock(*args)
+ @events << { event: :unblock, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+
+ def fiber_interrupt(*args)
+ @events << { event: :fiber_interrupt, fiber: Fiber.current, args: args }
+ Fiber.yield
+ end
+ end
+
+end
diff --git a/spec/ruby/core/fiber/inspect_spec.rb b/spec/ruby/core/fiber/inspect_spec.rb
index f20a153fc2..fcfef20716 100644
--- a/spec/ruby/core/fiber/inspect_spec.rb
+++ b/spec/ruby/core/fiber/inspect_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require 'fiber'
describe "Fiber#inspect" do
describe "status" do
diff --git a/spec/ruby/core/fiber/raise_spec.rb b/spec/ruby/core/fiber/raise_spec.rb
index 2f2baa4a12..896f760290 100644
--- a/spec/ruby/core/fiber/raise_spec.rb
+++ b/spec/ruby/core/fiber/raise_spec.rb
@@ -4,6 +4,7 @@ require_relative '../../shared/kernel/raise'
describe "Fiber#raise" do
it_behaves_like :kernel_raise, :raise, FiberSpecs::NewFiberToRaise
+ it_behaves_like :kernel_raise_across_contexts, :raise, FiberSpecs::NewFiberToRaise
end
describe "Fiber#raise" do
@@ -130,7 +131,6 @@ end
describe "Fiber#raise" do
it "transfers and raises on a transferring fiber" do
- require "fiber"
root = Fiber.current
fiber = Fiber.new { root.transfer }
fiber.transfer
diff --git a/spec/ruby/core/fiber/resume_spec.rb b/spec/ruby/core/fiber/resume_spec.rb
index ab9a6799ab..4b20f4b4bf 100644
--- a/spec/ruby/core/fiber/resume_spec.rb
+++ b/spec/ruby/core/fiber/resume_spec.rb
@@ -1,5 +1,5 @@
require_relative '../../spec_helper'
-require_relative '../../shared/fiber/resume'
+require_relative 'shared/resume'
describe "Fiber#resume" do
it_behaves_like :fiber_resume, :resume
@@ -67,4 +67,17 @@ describe "Fiber#resume" do
ruby_exe(code).should == "ensure executed\n"
end
+
+ it "can work with Fiber#transfer" do
+ fiber1 = Fiber.new { true }
+ fiber2 = Fiber.new { fiber1.transfer; Fiber.yield 10 ; Fiber.yield 20; raise }
+ fiber2.resume.should == 10
+ fiber2.resume.should == 20
+ end
+
+ it "raises a FiberError if the Fiber attempts to resume a resuming fiber" do
+ root_fiber = Fiber.current
+ fiber1 = Fiber.new { root_fiber.resume }
+ -> { fiber1.resume }.should raise_error(FiberError, /attempt to resume a resuming fiber/)
+ end
end
diff --git a/spec/ruby/core/fiber/scheduler_spec.rb b/spec/ruby/core/fiber/scheduler_spec.rb
new file mode 100644
index 0000000000..15a03c1479
--- /dev/null
+++ b/spec/ruby/core/fiber/scheduler_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'shared/scheduler'
+
+require "fiber"
+
+describe "Fiber.scheduler" do
+ it_behaves_like :scheduler, :scheduler
+end
diff --git a/spec/ruby/core/fiber/set_scheduler_spec.rb b/spec/ruby/core/fiber/set_scheduler_spec.rb
new file mode 100644
index 0000000000..82f6acbe86
--- /dev/null
+++ b/spec/ruby/core/fiber/set_scheduler_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'shared/scheduler'
+
+require "fiber"
+
+describe "Fiber.scheduler" do
+ it_behaves_like :scheduler, :set_scheduler
+end
diff --git a/spec/ruby/core/fiber/shared/resume.rb b/spec/ruby/core/fiber/shared/resume.rb
new file mode 100644
index 0000000000..5ee27d1d24
--- /dev/null
+++ b/spec/ruby/core/fiber/shared/resume.rb
@@ -0,0 +1,58 @@
+describe :fiber_resume, shared: true do
+ it "can be invoked from the root Fiber" do
+ fiber = Fiber.new { :fiber }
+ fiber.send(@method).should == :fiber
+ end
+
+ it "raises a FiberError if invoked from a different Thread" do
+ fiber = Fiber.new { 42 }
+ Thread.new do
+ -> {
+ fiber.send(@method)
+ }.should raise_error(FiberError)
+ end.join
+
+ # Check the Fiber can still be used
+ fiber.send(@method).should == 42
+ end
+
+ it "passes control to the beginning of the block on first invocation" do
+ invoked = false
+ fiber = Fiber.new { invoked = true }
+ fiber.send(@method)
+ invoked.should be_true
+ end
+
+ it "returns the last value encountered on first invocation" do
+ fiber = Fiber.new { 1+1; true }
+ fiber.send(@method).should be_true
+ end
+
+ it "runs until the end of the block" do
+ obj = mock('obj')
+ obj.should_receive(:do).once
+ fiber = Fiber.new { 1 + 2; a = "glark"; obj.do }
+ fiber.send(@method)
+ end
+
+ it "accepts any number of arguments" do
+ fiber = Fiber.new { |a| }
+ -> { fiber.send(@method, *(1..10).to_a) }.should_not raise_error
+ end
+
+ it "raises a FiberError if the Fiber is dead" do
+ fiber = Fiber.new { true }
+ fiber.send(@method)
+ -> { fiber.send(@method) }.should raise_error(FiberError)
+ end
+
+ it "raises a LocalJumpError if the block includes a return statement" do
+ fiber = Fiber.new { return; }
+ -> { fiber.send(@method) }.should raise_error(LocalJumpError)
+ end
+
+ it "raises a LocalJumpError if the block includes a break statement" do
+ fiber = Fiber.new { break; }
+ -> { fiber.send(@method) }.should raise_error(LocalJumpError)
+ end
+end
diff --git a/spec/ruby/core/fiber/shared/scheduler.rb b/spec/ruby/core/fiber/shared/scheduler.rb
new file mode 100644
index 0000000000..19bfb75e3e
--- /dev/null
+++ b/spec/ruby/core/fiber/shared/scheduler.rb
@@ -0,0 +1,51 @@
+describe :scheduler, shared: true do
+ it "validates the scheduler for required methods" do
+ required_methods = [:block, :unblock, :kernel_sleep, :io_wait]
+ required_methods.each do |missing_method|
+ scheduler = Object.new
+ required_methods.difference([missing_method]).each do |method|
+ scheduler.define_singleton_method(method) {}
+ end
+ -> {
+ suppress_warning { Fiber.set_scheduler(scheduler) }
+ }.should raise_error(ArgumentError, /Scheduler must implement ##{missing_method}/)
+ end
+ end
+
+ it "can set and get the scheduler" do
+ required_methods = [:block, :unblock, :kernel_sleep, :io_wait]
+ scheduler = Object.new
+ required_methods.each do |method|
+ scheduler.define_singleton_method(method) {}
+ end
+ suppress_warning { Fiber.set_scheduler(scheduler) }
+ Fiber.scheduler.should == scheduler
+ end
+
+ it "returns the scheduler after setting it" do
+ required_methods = [:block, :unblock, :kernel_sleep, :io_wait]
+ scheduler = Object.new
+ required_methods.each do |method|
+ scheduler.define_singleton_method(method) {}
+ end
+ result = suppress_warning { Fiber.set_scheduler(scheduler) }
+ result.should == scheduler
+ end
+
+ it "can remove the scheduler" do
+ required_methods = [:block, :unblock, :kernel_sleep, :io_wait]
+ scheduler = Object.new
+ required_methods.each do |method|
+ scheduler.define_singleton_method(method) {}
+ end
+ suppress_warning { Fiber.set_scheduler(scheduler) }
+ Fiber.set_scheduler(nil)
+ Fiber.scheduler.should be_nil
+ end
+
+ it "can assign a nil scheduler multiple times" do
+ Fiber.set_scheduler(nil)
+ Fiber.set_scheduler(nil)
+ Fiber.scheduler.should be_nil
+ end
+end
diff --git a/spec/ruby/core/fiber/storage_spec.rb b/spec/ruby/core/fiber/storage_spec.rb
index c9a7818293..015caaf3bb 100644
--- a/spec/ruby/core/fiber/storage_spec.rb
+++ b/spec/ruby/core/fiber/storage_spec.rb
@@ -1,160 +1,181 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "Fiber.new(storage:)" do
- it "creates a Fiber with the given storage" do
- storage = {life: 42}
- fiber = Fiber.new(storage: storage) { Fiber.current.storage }
- fiber.resume.should == storage
- end
+describe "Fiber.new(storage:)" do
+ it "creates a Fiber with the given storage" do
+ storage = {life: 42}
+ fiber = Fiber.new(storage: storage) { Fiber.current.storage }
+ fiber.resume.should == storage
+ end
- it "creates a fiber with lazily initialized storage" do
- Fiber.new(storage: nil) { Fiber[:x] = 10; Fiber.current.storage }.resume.should == {x: 10}
- end
+ it "creates a fiber with lazily initialized storage" do
+ Fiber.new(storage: nil) { Fiber[:x] = 10; Fiber.current.storage }.resume.should == {x: 10}
+ end
- it "creates a fiber by inheriting the storage of the parent fiber" do
- fiber = Fiber.new(storage: {life: 42}) do
- Fiber.new { Fiber.current.storage }.resume
- end
- fiber.resume.should == {life: 42}
+ it "creates a fiber by inheriting the storage of the parent fiber" do
+ fiber = Fiber.new(storage: {life: 42}) do
+ Fiber.new { Fiber.current.storage }.resume
end
+ fiber.resume.should == {life: 42}
+ end
- it "cannot create a fiber with non-hash storage" do
- -> { Fiber.new(storage: 42) {} }.should raise_error(TypeError)
- end
+ it "cannot create a fiber with non-hash storage" do
+ -> { Fiber.new(storage: 42) {} }.should raise_error(TypeError)
+ end
- it "cannot create a fiber with a frozen hash as storage" do
- -> { Fiber.new(storage: {life: 43}.freeze) {} }.should raise_error(FrozenError)
- end
+ it "cannot create a fiber with a frozen hash as storage" do
+ -> { Fiber.new(storage: {life: 43}.freeze) {} }.should raise_error(FrozenError)
+ end
- it "cannot create a fiber with a storage hash with non-symbol keys" do
- -> { Fiber.new(storage: {life: 43, Object.new => 44}) {} }.should raise_error(TypeError)
- end
+ it "cannot create a fiber with a storage hash with non-symbol keys" do
+ -> { Fiber.new(storage: {life: 43, Object.new => 44}) {} }.should raise_error(TypeError)
end
+end
- describe "Fiber#storage" do
- it "cannot be accessed from a different fiber" do
- f = Fiber.new(storage: {life: 42}) { nil }
- -> {
- f.storage
- }.should raise_error(ArgumentError, /Fiber storage can only be accessed from the Fiber it belongs to/)
- end
+describe "Fiber#storage" do
+ it "cannot be accessed from a different fiber" do
+ f = Fiber.new(storage: {life: 42}) { nil }
+ -> {
+ f.storage
+ }.should raise_error(ArgumentError, /Fiber storage can only be accessed from the Fiber it belongs to/)
end
+end
- describe "Fiber#storage=" do
- it "can clear the storage of the fiber" do
- fiber = Fiber.new(storage: {life: 42}) do
- Fiber.current.storage = nil
- Fiber[:x] = 10
- Fiber.current.storage
- end
- fiber.resume.should == {x: 10}
+describe "Fiber#storage=" do
+ it "can clear the storage of the fiber" do
+ fiber = Fiber.new(storage: {life: 42}) do
+ Fiber.current.storage = nil
+ Fiber[:x] = 10
+ Fiber.current.storage
end
+ fiber.resume.should == {x: 10}
+ end
- it "can set the storage of the fiber" do
- fiber = Fiber.new(storage: {life: 42}) do
- Fiber.current.storage = {life: 43}
- Fiber.current.storage
- end
- fiber.resume.should == {life: 43}
+ it "can set the storage of the fiber" do
+ fiber = Fiber.new(storage: {life: 42}) do
+ Fiber.current.storage = {life: 43}
+ Fiber.current.storage
end
+ fiber.resume.should == {life: 43}
+ end
- it "can't set the storage of the fiber to non-hash" do
- -> { Fiber.current.storage = 42 }.should raise_error(TypeError)
- end
+ it "can't set the storage of the fiber to non-hash" do
+ -> { Fiber.current.storage = 42 }.should raise_error(TypeError)
+ end
- it "can't set the storage of the fiber to a frozen hash" do
- -> { Fiber.current.storage = {life: 43}.freeze }.should raise_error(FrozenError)
- end
+ it "can't set the storage of the fiber to a frozen hash" do
+ -> { Fiber.current.storage = {life: 43}.freeze }.should raise_error(FrozenError)
+ end
- it "can't set the storage of the fiber to a hash with non-symbol keys" do
- -> { Fiber.current.storage = {life: 43, Object.new => 44} }.should raise_error(TypeError)
- end
+ it "can't set the storage of the fiber to a hash with non-symbol keys" do
+ -> { Fiber.current.storage = {life: 43, Object.new => 44} }.should raise_error(TypeError)
end
+end
- describe "Fiber.[]" do
- it "returns the value of the given key in the storage of the current fiber" do
- Fiber.new(storage: {life: 42}) { Fiber[:life] }.resume.should == 42
- end
+describe "Fiber.[]" do
+ it "returns the value of the given key in the storage of the current fiber" do
+ Fiber.new(storage: {life: 42}) { Fiber[:life] }.resume.should == 42
+ end
- it "returns nil if the key is not present in the storage of the current fiber" do
- Fiber.new(storage: {life: 42}) { Fiber[:death] }.resume.should be_nil
- end
+ it "returns nil if the key is not present in the storage of the current fiber" do
+ Fiber.new(storage: {life: 42}) { Fiber[:death] }.resume.should be_nil
+ end
+
+ it "returns nil if the current fiber has no storage" do
+ Fiber.new { Fiber[:life] }.resume.should be_nil
+ end
- it "returns nil if the current fiber has no storage" do
- Fiber.new { Fiber[:life] }.resume.should be_nil
+ ruby_version_is "3.2.3" do
+ it "can use dynamically defined keys" do
+ key = :"#{self.class.name}#.#{self.object_id}"
+ Fiber.new { Fiber[key] = 42; Fiber[key] }.resume.should == 42
end
- ruby_version_is "3.2.3" do
- it "can use dynamically defined keys" do
- key = :"#{self.class.name}#.#{self.object_id}"
- Fiber.new { Fiber[key] = 42; Fiber[key] }.resume.should == 42
+ it "can't use invalid keys" do
+ invalid_keys = [Object.new, 12]
+ invalid_keys.each do |key|
+ -> { Fiber[key] }.should raise_error(TypeError)
end
end
+ end
- ruby_bug "#20978", "3.2.3"..."3.4" do
- it "can use keys as strings" do
- key = Object.new
- def key.to_str; "Foo"; end
- Fiber[key] = 42
- Fiber["Foo"].should == 42
- end
+ ruby_bug "#20978", ""..."3.4" do
+ it "can use keys as strings" do
+ key = Object.new
+ def key.to_str; "Foo"; end
+ Fiber.new { Fiber[key] = 42; Fiber["Foo"] }.resume.should == 42
end
- it "can access the storage of the parent fiber" do
- f = Fiber.new(storage: {life: 42}) do
- Fiber.new { Fiber[:life] }.resume
- end
- f.resume.should == 42
+ it "converts a String key into a Symbol" do
+ Fiber.new { Fiber["key"] = 42; Fiber[:key] }.resume.should == 42
+ Fiber.new { Fiber[:key] = 42; Fiber["key"] }.resume.should == 42
end
- it "can't access the storage of the fiber with non-symbol keys" do
- -> { Fiber[Object.new] }.should raise_error(TypeError)
+ it "can use any object that responds to #to_str as a key" do
+ key = mock("key")
+ key.should_receive(:to_str).twice.and_return("key")
+ Fiber.new { Fiber[key] = 42; Fiber[key] }.resume.should == 42
end
end
- describe "Fiber.[]=" do
- it "sets the value of the given key in the storage of the current fiber" do
- Fiber.new(storage: {life: 42}) { Fiber[:life] = 43; Fiber[:life] }.resume.should == 43
- end
+ it "does not call #to_sym on the key" do
+ key = mock("key")
+ key.should_not_receive(:to_sym)
+ -> { Fiber[key] }.should raise_error(TypeError)
+ end
- it "sets the value of the given key in the storage of the current fiber" do
- Fiber.new(storage: {life: 42}) { Fiber[:death] = 43; Fiber[:death] }.resume.should == 43
+ it "can access the storage of the parent fiber" do
+ f = Fiber.new(storage: {life: 42}) do
+ Fiber.new { Fiber[:life] }.resume
end
+ f.resume.should == 42
+ end
- it "sets the value of the given key in the storage of the current fiber" do
- Fiber.new { Fiber[:life] = 43; Fiber[:life] }.resume.should == 43
- end
+ it "can't access the storage of the fiber with non-symbol keys" do
+ -> { Fiber[Object.new] }.should raise_error(TypeError)
+ end
+end
- it "does not overwrite the storage of the parent fiber" do
- f = Fiber.new(storage: {life: 42}) do
- Fiber.yield Fiber.new { Fiber[:life] = 43; Fiber[:life] }.resume
- Fiber[:life]
- end
- f.resume.should == 43 # Value of the inner fiber
- f.resume.should == 42 # Value of the outer fiber
- end
+describe "Fiber.[]=" do
+ it "sets the value of the given key in the storage of the current fiber" do
+ Fiber.new(storage: {life: 42}) { Fiber[:life] = 43; Fiber[:life] }.resume.should == 43
+ end
+
+ it "sets the value of the given key in the storage of the current fiber" do
+ Fiber.new(storage: {life: 42}) { Fiber[:death] = 43; Fiber[:death] }.resume.should == 43
+ end
- it "can't access the storage of the fiber with non-symbol keys" do
- -> { Fiber[Object.new] = 44 }.should raise_error(TypeError)
+ it "sets the value of the given key in the storage of the current fiber" do
+ Fiber.new { Fiber[:life] = 43; Fiber[:life] }.resume.should == 43
+ end
+
+ it "does not overwrite the storage of the parent fiber" do
+ f = Fiber.new(storage: {life: 42}) do
+ Fiber.yield Fiber.new { Fiber[:life] = 43; Fiber[:life] }.resume
+ Fiber[:life]
end
+ f.resume.should == 43 # Value of the inner fiber
+ f.resume.should == 42 # Value of the outer fiber
+ end
- ruby_version_is "3.3" do
- it "deletes the fiber storage key when assigning nil" do
- Fiber.new(storage: {life: 42}) {
- Fiber[:life] = nil
- Fiber.current.storage
- }.resume.should == {}
- end
+ it "can't access the storage of the fiber with non-symbol keys" do
+ -> { Fiber[Object.new] = 44 }.should raise_error(TypeError)
+ end
+
+ ruby_version_is "3.3" do
+ it "deletes the fiber storage key when assigning nil" do
+ Fiber.new(storage: {life: 42}) {
+ Fiber[:life] = nil
+ Fiber.current.storage
+ }.resume.should == {}
end
end
+end
- describe "Thread.new" do
- it "creates a thread with the storage of the current fiber" do
- fiber = Fiber.new(storage: {life: 42}) do
- Thread.new { Fiber.current.storage }.value
- end
- fiber.resume.should == {life: 42}
+describe "Thread.new" do
+ it "creates a thread with the storage of the current fiber" do
+ fiber = Fiber.new(storage: {life: 42}) do
+ Thread.new { Fiber.current.storage }.value
end
+ fiber.resume.should == {life: 42}
end
end
diff --git a/spec/ruby/core/fiber/transfer_spec.rb b/spec/ruby/core/fiber/transfer_spec.rb
new file mode 100644
index 0000000000..238721475d
--- /dev/null
+++ b/spec/ruby/core/fiber/transfer_spec.rb
@@ -0,0 +1,84 @@
+require_relative '../../spec_helper'
+require_relative 'shared/resume'
+
+describe "Fiber#transfer" do
+ it_behaves_like :fiber_resume, :transfer
+end
+
+describe "Fiber#transfer" do
+ it "transfers control from one Fiber to another when called from a Fiber" do
+ fiber1 = Fiber.new { :fiber1 }
+ fiber2 = Fiber.new { fiber1.transfer; :fiber2 }
+ fiber2.resume.should == :fiber2
+ end
+
+ it "returns to the root Fiber when finished" do
+ f1 = Fiber.new { :fiber_1 }
+ f2 = Fiber.new { f1.transfer; :fiber_2 }
+
+ f2.transfer.should == :fiber_1
+ f2.transfer.should == :fiber_2
+ end
+
+ it "can be invoked from the same Fiber it transfers control to" do
+ states = []
+ fiber = Fiber.new { states << :start; fiber.transfer; states << :end }
+ fiber.transfer
+ states.should == [:start, :end]
+
+ states = []
+ fiber = Fiber.new { states << :start; fiber.transfer; states << :end }
+ fiber.resume
+ states.should == [:start, :end]
+ end
+
+ it "can not transfer control to a Fiber that has suspended by Fiber.yield" do
+ states = []
+ fiber1 = Fiber.new { states << :fiber1 }
+ fiber2 = Fiber.new { states << :fiber2_start; Fiber.yield fiber1.transfer; states << :fiber2_end}
+ fiber2.resume.should == [:fiber2_start, :fiber1]
+ -> { fiber2.transfer }.should raise_error(FiberError)
+ end
+
+ it "raises a FiberError when transferring to a Fiber which resumes itself" do
+ fiber = Fiber.new { fiber.resume }
+ -> { fiber.transfer }.should raise_error(FiberError)
+ end
+
+ it "works if Fibers in different Threads each transfer to a Fiber in the same Thread" do
+ # This catches a bug where Fibers are running on a thread-pool
+ # and Fibers from a different Ruby Thread reuse the same native thread.
+ # Caching the Ruby Thread based on the native thread is not correct in that case,
+ # and the check for "fiber called across threads" in Fiber#transfer
+ # might be incorrect based on that.
+ 2.times do
+ Thread.new do
+ io_fiber = Fiber.new do |calling_fiber|
+ calling_fiber.transfer
+ end
+ io_fiber.transfer(Fiber.current)
+ value = Object.new
+ io_fiber.transfer(value).should equal value
+ end.join
+ end
+ end
+
+ it "transfers control between a non-main thread's root fiber to a child fiber and back again" do
+ states = []
+ thread = Thread.new do
+ f1 = Fiber.new do |f0|
+ states << 0
+ value2 = f0.transfer(1)
+ states << value2
+ 3
+ end
+
+ value1 = f1.transfer(Fiber.current)
+ states << value1
+ value3 = f1.transfer(2)
+ states << value3
+ end
+ thread.join
+ states.should == [0, 1, 2, 3]
+ end
+end
diff --git a/spec/ruby/core/file/basename_spec.rb b/spec/ruby/core/file/basename_spec.rb
index 989409d76b..87695ab97b 100644
--- a/spec/ruby/core/file/basename_spec.rb
+++ b/spec/ruby/core/file/basename_spec.rb
@@ -151,8 +151,34 @@ describe "File.basename" do
File.basename("c:\\bar.txt", ".*").should == "bar"
File.basename("c:\\bar.txt.exe", ".*").should == "bar.txt"
end
+
+ it "handles Shift JIS 0x5C (\\) as second byte of a multi-byte sequence" do
+ # dir\fileソname.txt
+ path = "dir\\file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS)
+ path.valid_encoding?.should be_true
+ File.basename(path).should == "file\x83\x5cname.txt".b.force_encoding(Encoding::SHIFT_JIS)
+ end
end
+ it "rejects strings encoded with non ASCII-compatible encodings" do
+ Encoding.list.reject(&:ascii_compatible?).reject(&:dummy?).each do |enc|
+ begin
+ path = "/foo/bar".encode(enc)
+ rescue Encoding::ConverterNotFoundError
+ next
+ end
+
+ -> {
+ File.basename(path)
+ }.should raise_error(Encoding::CompatibilityError)
+ end
+ end
+
+ it "works with all ASCII-compatible encodings" do
+ Encoding.list.select(&:ascii_compatible?).each do |enc|
+ File.basename("/foo/bar".encode(enc)).should == "bar".encode(enc)
+ end
+ end
it "returns the extension for a multibyte filename" do
File.basename('/path/ОфиÑ.m4a').should == "ОфиÑ.m4a"
diff --git a/spec/ruby/core/file/birthtime_spec.rb b/spec/ruby/core/file/birthtime_spec.rb
index 755601df64..f82eaf7cca 100644
--- a/spec/ruby/core/file/birthtime_spec.rb
+++ b/spec/ruby/core/file/birthtime_spec.rb
@@ -1,60 +1,56 @@
require_relative '../../spec_helper'
-describe "File.birthtime" do
- before :each do
- @file = __FILE__
- end
+platform_is :windows, :darwin, :freebsd, :netbsd, :linux do
+ not_implemented_messages = [
+ "birthtime() function is unimplemented", # unsupported OS/version
+ "birthtime is unimplemented", # unsupported filesystem
+ ]
+
+ describe "File.birthtime" do
+ before :each do
+ @file = __FILE__
+ end
- after :each do
- @file = nil
- end
+ after :each do
+ @file = nil
+ end
- platform_is :windows, :darwin, :freebsd, :netbsd do
it "returns the birth time for the named file as a Time object" do
File.birthtime(@file)
File.birthtime(@file).should be_kind_of(Time)
+ rescue NotImplementedError => e
+ e.message.should.start_with?(*not_implemented_messages)
end
it "accepts an object that has a #to_path method" do
+ File.birthtime(@file) # Avoid to failure of mock object with old Kernel and glibc
File.birthtime(mock_to_path(@file))
+ rescue NotImplementedError => e
+ e.message.should.start_with?(*not_implemented_messages)
end
it "raises an Errno::ENOENT exception if the file is not found" do
-> { File.birthtime('bogus') }.should raise_error(Errno::ENOENT)
+ rescue NotImplementedError => e
+ e.message.should.start_with?(*not_implemented_messages)
end
end
- platform_is :openbsd do
- it "raises an NotImplementedError" do
- -> { File.birthtime(@file) }.should raise_error(NotImplementedError)
+ describe "File#birthtime" do
+ before :each do
+ @file = File.open(__FILE__)
end
- end
-
- # TODO: depends on Linux kernel version
-end
-describe "File#birthtime" do
- before :each do
- @file = File.open(__FILE__)
- end
-
- after :each do
- @file.close
- @file = nil
- end
+ after :each do
+ @file.close
+ @file = nil
+ end
- platform_is :windows, :darwin, :freebsd, :netbsd do
it "returns the birth time for self" do
@file.birthtime
@file.birthtime.should be_kind_of(Time)
+ rescue NotImplementedError => e
+ e.message.should.start_with?(*not_implemented_messages)
end
end
-
- platform_is :openbsd do
- it "raises an NotImplementedError" do
- -> { @file.birthtime }.should raise_error(NotImplementedError)
- end
- end
-
- # TODO: depends on Linux kernel version
end
diff --git a/spec/ruby/core/file/constants/constants_spec.rb b/spec/ruby/core/file/constants/constants_spec.rb
index 86946822c5..bba248c21e 100644
--- a/spec/ruby/core/file/constants/constants_spec.rb
+++ b/spec/ruby/core/file/constants/constants_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../../spec_helper'
"FNM_DOTMATCH", "FNM_EXTGLOB", "FNM_NOESCAPE", "FNM_PATHNAME",
"FNM_SYSCASE", "LOCK_EX", "LOCK_NB", "LOCK_SH",
"LOCK_UN", "NONBLOCK", "RDONLY",
- "RDWR", "TRUNC", "WRONLY"].each do |const|
+ "RDWR", "TRUNC", "WRONLY", "SHARE_DELETE"].each do |const|
describe "File::Constants::#{const}" do
it "is defined" do
File::Constants.const_defined?(const).should be_true
diff --git a/spec/ruby/core/file/dirname_spec.rb b/spec/ruby/core/file/dirname_spec.rb
index 8dd6c4ca88..8e6016ce6f 100644
--- a/spec/ruby/core/file/dirname_spec.rb
+++ b/spec/ruby/core/file/dirname_spec.rb
@@ -11,34 +11,32 @@ describe "File.dirname" do
File.dirname('/foo/foo').should == '/foo'
end
- ruby_version_is '3.1' do
- context "when level is passed" do
- it "returns all the components of filename except the last parts by the level" do
- File.dirname('/home/jason', 2).should == '/'
- File.dirname('/home/jason/poot.txt', 2).should == '/home'
- end
-
- it "returns the same String if the level is 0" do
- File.dirname('poot.txt', 0).should == 'poot.txt'
- File.dirname('/', 0).should == '/'
- end
-
- it "raises ArgumentError if the level is negative" do
- -> {
- File.dirname('/home/jason', -1)
- }.should raise_error(ArgumentError, "negative level: -1")
- end
-
- it "returns '/' when level exceeds the number of segments in the path" do
- File.dirname("/home/jason", 100).should == '/'
- end
-
- it "calls #to_int if passed not numeric value" do
- object = Object.new
- def object.to_int; 2; end
-
- File.dirname("/a/b/c/d", object).should == '/a/b'
- end
+ context "when level is passed" do
+ it "returns all the components of filename except the last parts by the level" do
+ File.dirname('/home/jason', 2).should == '/'
+ File.dirname('/home/jason/poot.txt', 2).should == '/home'
+ end
+
+ it "returns the same String if the level is 0" do
+ File.dirname('poot.txt', 0).should == 'poot.txt'
+ File.dirname('/', 0).should == '/'
+ end
+
+ it "raises ArgumentError if the level is negative" do
+ -> {
+ File.dirname('/home/jason', -1)
+ }.should raise_error(ArgumentError, "negative level: -1")
+ end
+
+ it "returns '/' when level exceeds the number of segments in the path" do
+ File.dirname("/home/jason", 100).should == '/'
+ end
+
+ it "calls #to_int if passed not numeric value" do
+ object = Object.new
+ def object.to_int; 2; end
+
+ File.dirname("/a/b/c/d", object).should == '/a/b'
end
end
@@ -65,19 +63,19 @@ describe "File.dirname" do
end
it "returns all the components of filename except the last one (edge cases on all platforms)" do
- File.dirname("").should == "."
- File.dirname(".").should == "."
- File.dirname("./").should == "."
- File.dirname("./b/./").should == "./b"
- File.dirname("..").should == "."
- File.dirname("../").should == "."
- File.dirname("/").should == "/"
- File.dirname("/.").should == "/"
- File.dirname("/foo/").should == "/"
- File.dirname("/foo/.").should == "/foo"
- File.dirname("/foo/./").should == "/foo"
- File.dirname("/foo/../.").should == "/foo/.."
- File.dirname("foo/../").should == "foo"
+ File.dirname("").should == "."
+ File.dirname(".").should == "."
+ File.dirname("./").should == "."
+ File.dirname("./b/./").should == "./b"
+ File.dirname("..").should == "."
+ File.dirname("../").should == "."
+ File.dirname("/").should == "/"
+ File.dirname("/.").should == "/"
+ File.dirname("/foo/").should == "/"
+ File.dirname("/foo/.").should == "/foo"
+ File.dirname("/foo/./").should == "/foo"
+ File.dirname("/foo/../.").should == "/foo/.."
+ File.dirname("foo/../").should == "foo"
end
platform_is_not :windows do
diff --git a/spec/ruby/core/file/empty_spec.rb b/spec/ruby/core/file/empty_spec.rb
index 77f132303e..e8c9941676 100644
--- a/spec/ruby/core/file/empty_spec.rb
+++ b/spec/ruby/core/file/empty_spec.rb
@@ -4,10 +4,4 @@ require_relative '../../shared/file/zero'
describe "File.empty?" do
it_behaves_like :file_zero, :empty?, File
it_behaves_like :file_zero_missing, :empty?, File
-
- platform_is :solaris do
- it "returns false for /dev/null" do
- File.empty?('/dev/null').should == true
- end
- end
end
diff --git a/spec/ruby/core/file/exist_spec.rb b/spec/ruby/core/file/exist_spec.rb
index 2633376880..b5600e5b07 100644
--- a/spec/ruby/core/file/exist_spec.rb
+++ b/spec/ruby/core/file/exist_spec.rb
@@ -5,10 +5,8 @@ describe "File.exist?" do
it_behaves_like :file_exist, :exist?, File
end
-ruby_version_is "3.2" do
- describe "File.exists?" do
- it "has been removed" do
- File.should_not.respond_to?(:exists?)
- end
+describe "File.exists?" do
+ it "has been removed" do
+ File.should_not.respond_to?(:exists?)
end
end
diff --git a/spec/ruby/core/file/flock_spec.rb b/spec/ruby/core/file/flock_spec.rb
index 070d830bc4..23ddf89ed8 100644
--- a/spec/ruby/core/file/flock_spec.rb
+++ b/spec/ruby/core/file/flock_spec.rb
@@ -72,35 +72,3 @@ describe "File#flock" do
end
end
end
-
-platform_is :solaris do
- describe "File#flock on Solaris" do
- before :each do
- @name = tmp("flock_test")
- touch(@name)
-
- @read_file = File.open @name, "r"
- @write_file = File.open @name, "w"
- end
-
- after :each do
- @read_file.flock File::LOCK_UN
- @read_file.close
- @write_file.flock File::LOCK_UN
- @write_file.close
- rm_r @name
- end
-
- it "fails with EBADF acquiring exclusive lock on read-only File" do
- -> do
- @read_file.flock File::LOCK_EX
- end.should raise_error(Errno::EBADF)
- end
-
- it "fails with EBADF acquiring shared lock on read-only File" do
- -> do
- @write_file.flock File::LOCK_SH
- end.should raise_error(Errno::EBADF)
- end
- end
-end
diff --git a/spec/ruby/core/file/lchmod_spec.rb b/spec/ruby/core/file/lchmod_spec.rb
index 7420b95e4a..3c44374983 100644
--- a/spec/ruby/core/file/lchmod_spec.rb
+++ b/spec/ruby/core/file/lchmod_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
describe "File.lchmod" do
- platform_is_not :linux, :windows, :openbsd, :solaris, :aix do
+ platform_is_not :linux, :windows, :openbsd, :aix do
before :each do
@fname = tmp('file_chmod_test')
@lname = @fname + '.lnk'
diff --git a/spec/ruby/core/file/path_spec.rb b/spec/ruby/core/file/path_spec.rb
index dfa0c4ec02..726febcc2b 100644
--- a/spec/ruby/core/file/path_spec.rb
+++ b/spec/ruby/core/file/path_spec.rb
@@ -37,4 +37,45 @@ describe "File.path" do
path.should_receive(:to_path).and_return("abc")
File.path(path).should == "abc"
end
+
+ it "raises TypeError when #to_path result is not a string" do
+ path = mock("path")
+ path.should_receive(:to_path).and_return(nil)
+ -> { File.path(path) }.should raise_error TypeError
+
+ path = mock("path")
+ path.should_receive(:to_path).and_return(42)
+ -> { File.path(path) }.should raise_error TypeError
+ end
+
+ it "raises ArgumentError for string argument contains NUL character" do
+ -> { File.path("\0") }.should raise_error ArgumentError
+ -> { File.path("a\0") }.should raise_error ArgumentError
+ -> { File.path("a\0c") }.should raise_error ArgumentError
+ end
+
+ it "raises ArgumentError when #to_path result contains NUL character" do
+ path = mock("path")
+ path.should_receive(:to_path).and_return("\0")
+ -> { File.path(path) }.should raise_error ArgumentError
+
+ path = mock("path")
+ path.should_receive(:to_path).and_return("a\0")
+ -> { File.path(path) }.should raise_error ArgumentError
+
+ path = mock("path")
+ path.should_receive(:to_path).and_return("a\0c")
+ -> { File.path(path) }.should raise_error ArgumentError
+ end
+
+ it "raises Encoding::CompatibilityError for ASCII-incompatible string argument" do
+ path = "abc".encode(Encoding::UTF_32BE)
+ -> { File.path(path) }.should raise_error Encoding::CompatibilityError
+ end
+
+ it "raises Encoding::CompatibilityError when #to_path result is ASCII-incompatible" do
+ path = mock("path")
+ path.should_receive(:to_path).and_return("abc".encode(Encoding::UTF_32BE))
+ -> { File.path(path) }.should raise_error Encoding::CompatibilityError
+ end
end
diff --git a/spec/ruby/core/file/setuid_spec.rb b/spec/ruby/core/file/setuid_spec.rb
index 281ef01ab9..9e5e86df61 100644
--- a/spec/ruby/core/file/setuid_spec.rb
+++ b/spec/ruby/core/file/setuid_spec.rb
@@ -26,10 +26,6 @@ describe "File.setuid?" do
platform_is_not :windows do
it "returns true when the gid bit is set" do
- platform_is :solaris do
- # Solaris requires execute bit before setting suid
- system "chmod u+x #{@name}"
- end
system "chmod u+s #{@name}"
File.setuid?(@name).should == true
diff --git a/spec/ruby/core/file/shared/path.rb b/spec/ruby/core/file/shared/path.rb
index aa2a64cf25..5a9fe1b0c5 100644
--- a/spec/ruby/core/file/shared/path.rb
+++ b/spec/ruby/core/file/shared/path.rb
@@ -77,18 +77,6 @@ describe :file_path, shared: true do
after :each do
rm_r @dir
end
-
- ruby_version_is ""..."3.1" do
- it "raises IOError if file was opened with File::TMPFILE" do
- begin
- File.open(@dir, File::RDWR | File::TMPFILE) do |f|
- -> { f.send(@method) }.should raise_error(IOError)
- end
- rescue Errno::EOPNOTSUPP, Errno::EINVAL, Errno::EISDIR
- skip "no support from the filesystem"
- end
- end
- end
end
end
end
diff --git a/spec/ruby/core/file/socket_spec.rb b/spec/ruby/core/file/socket_spec.rb
index 5d12e21f55..d3f4eb013a 100644
--- a/spec/ruby/core/file/socket_spec.rb
+++ b/spec/ruby/core/file/socket_spec.rb
@@ -1,42 +1,10 @@
require_relative '../../spec_helper'
require_relative '../../shared/file/socket'
-require 'socket'
describe "File.socket?" do
it_behaves_like :file_socket, :socket?, File
-end
-describe "File.socket?" do
it "returns false if file does not exist" do
File.socket?("I_am_a_bogus_file").should == false
end
-
- it "returns false if the file is not a socket" do
- filename = tmp("i_exist")
- touch(filename)
-
- File.socket?(filename).should == false
-
- rm_r filename
- end
-end
-
-platform_is_not :windows do
- describe "File.socket?" do
- before :each do
- # We need a really short name here.
- # On Linux the path length is limited to 107, see unix(7).
- @name = tmp("s")
- @server = UNIXServer.new @name
- end
-
- after :each do
- @server.close
- rm_r @name
- end
-
- it "returns true if the file is a socket" do
- File.socket?(@name).should == true
- end
- end
end
diff --git a/spec/ruby/core/file/stat/birthtime_spec.rb b/spec/ruby/core/file/stat/birthtime_spec.rb
index a727bbe566..9aa39297b2 100644
--- a/spec/ruby/core/file/stat/birthtime_spec.rb
+++ b/spec/ruby/core/file/stat/birthtime_spec.rb
@@ -1,27 +1,29 @@
require_relative '../../../spec_helper'
-describe "File::Stat#birthtime" do
- before :each do
- @file = tmp('i_exist')
- touch(@file) { |f| f.write "rubinius" }
- end
+platform_is(:windows, :darwin, :freebsd, :netbsd,
+ *ruby_version_is("4.0") { :linux },
+ ) do
+ not_implemented_messages = [
+ "birthtime() function is unimplemented", # unsupported OS/version
+ "birthtime is unimplemented", # unsupported filesystem
+ ]
- after :each do
- rm_r @file
- end
+ describe "File::Stat#birthtime" do
+ before :each do
+ @file = tmp('i_exist')
+ touch(@file) { |f| f.write "rubinius" }
+ end
+
+ after :each do
+ rm_r @file
+ end
- platform_is :windows, :darwin, :freebsd, :netbsd do
it "returns the birthtime of a File::Stat object" do
st = File.stat(@file)
st.birthtime.should be_kind_of(Time)
st.birthtime.should <= Time.now
- end
- end
-
- platform_is :linux, :openbsd do
- it "raises an NotImplementedError" do
- st = File.stat(@file)
- -> { st.birthtime }.should raise_error(NotImplementedError)
+ rescue NotImplementedError => e
+ e.message.should.start_with?(*not_implemented_messages)
end
end
end
diff --git a/spec/ruby/core/file/stat/rdev_major_spec.rb b/spec/ruby/core/file/stat/rdev_major_spec.rb
index f8a8d1b107..e08d19c03a 100644
--- a/spec/ruby/core/file/stat/rdev_major_spec.rb
+++ b/spec/ruby/core/file/stat/rdev_major_spec.rb
@@ -2,19 +2,12 @@ require_relative '../../../spec_helper'
describe "File::Stat#rdev_major" do
before :each do
- platform_is :solaris do
- @name = "/dev/zfs"
- end
- platform_is_not :solaris do
- @name = tmp("file.txt")
- touch(@name)
- end
+ @name = tmp("file.txt")
+ touch(@name)
end
after :each do
- platform_is_not :solaris do
- rm_r @name
- end
+ rm_r @name
end
platform_is_not :windows do
diff --git a/spec/ruby/core/file/stat/rdev_minor_spec.rb b/spec/ruby/core/file/stat/rdev_minor_spec.rb
index dc30c1f56c..ace5b8a732 100644
--- a/spec/ruby/core/file/stat/rdev_minor_spec.rb
+++ b/spec/ruby/core/file/stat/rdev_minor_spec.rb
@@ -2,19 +2,12 @@ require_relative '../../../spec_helper'
describe "File::Stat#rdev_minor" do
before :each do
- platform_is :solaris do
- @name = "/dev/zfs"
- end
- platform_is_not :solaris do
- @name = tmp("file.txt")
- touch(@name)
- end
+ @name = tmp("file.txt")
+ touch(@name)
end
after :each do
- platform_is_not :solaris do
- rm_r @name
- end
+ rm_r @name
end
platform_is_not :windows do
diff --git a/spec/ruby/core/file/zero_spec.rb b/spec/ruby/core/file/zero_spec.rb
index 63dd85ee46..01c7505ef2 100644
--- a/spec/ruby/core/file/zero_spec.rb
+++ b/spec/ruby/core/file/zero_spec.rb
@@ -4,10 +4,4 @@ require_relative '../../shared/file/zero'
describe "File.zero?" do
it_behaves_like :file_zero, :zero?, File
it_behaves_like :file_zero_missing, :zero?, File
-
- platform_is :solaris do
- it "returns false for /dev/null" do
- File.zero?('/dev/null').should == true
- end
- end
end
diff --git a/spec/ruby/core/filetest/exist_spec.rb b/spec/ruby/core/filetest/exist_spec.rb
index a95d3f91a1..612ffa9fcb 100644
--- a/spec/ruby/core/filetest/exist_spec.rb
+++ b/spec/ruby/core/filetest/exist_spec.rb
@@ -5,10 +5,8 @@ describe "FileTest.exist?" do
it_behaves_like :file_exist, :exist?, FileTest
end
-ruby_version_is "3.2" do
- describe "FileTest.exists?" do
- it "has been removed" do
- FileTest.should_not.respond_to?(:exists?)
- end
+describe "FileTest.exists?" do
+ it "has been removed" do
+ FileTest.should_not.respond_to?(:exists?)
end
end
diff --git a/spec/ruby/core/filetest/socket_spec.rb b/spec/ruby/core/filetest/socket_spec.rb
index 63a6a31ecb..f274be6318 100644
--- a/spec/ruby/core/filetest/socket_spec.rb
+++ b/spec/ruby/core/filetest/socket_spec.rb
@@ -3,4 +3,8 @@ require_relative '../../shared/file/socket'
describe "FileTest.socket?" do
it_behaves_like :file_socket, :socket?, FileTest
+
+ it "returns false if file does not exist" do
+ FileTest.socket?("I_am_a_bogus_file").should == false
+ end
end
diff --git a/spec/ruby/core/filetest/zero_spec.rb b/spec/ruby/core/filetest/zero_spec.rb
index dd6a164ec9..92cab67f1b 100644
--- a/spec/ruby/core/filetest/zero_spec.rb
+++ b/spec/ruby/core/filetest/zero_spec.rb
@@ -4,10 +4,4 @@ require_relative '../../shared/file/zero'
describe "FileTest.zero?" do
it_behaves_like :file_zero, :zero?, FileTest
it_behaves_like :file_zero_missing, :zero?, FileTest
-
- platform_is :solaris do
- it "returns false for /dev/null" do
- File.zero?('/dev/null').should == true
- end
- end
end
diff --git a/spec/ruby/core/float/comparison_spec.rb b/spec/ruby/core/float/comparison_spec.rb
index d2e47937ff..0cd290f4ad 100644
--- a/spec/ruby/core/float/comparison_spec.rb
+++ b/spec/ruby/core/float/comparison_spec.rb
@@ -91,7 +91,7 @@ describe "Float#<=>" do
it "returns 1 when self is Infinity and other is infinite?=nil (which means finite)" do
obj = Object.new
def obj.infinite?
- nil
+ nil
end
(infinity_value <=> obj).should == 1
end
diff --git a/spec/ruby/core/float/round_spec.rb b/spec/ruby/core/float/round_spec.rb
index 9b4c307f9d..7e8c792051 100644
--- a/spec/ruby/core/float/round_spec.rb
+++ b/spec/ruby/core/float/round_spec.rb
@@ -30,6 +30,11 @@ describe "Float#round" do
12.345678.round(3.999).should == 12.346
end
+ it "correctly rounds exact floats with a numerous digits in a fraction part" do
+ 0.8241000000000004.round(10).should == 0.8241
+ 0.8241000000000002.round(10).should == 0.8241
+ end
+
it "returns zero when passed a negative argument with magnitude greater than magnitude of the whole number portion of the Float" do
0.8346268.round(-1).should eql(0)
end
@@ -68,6 +73,10 @@ describe "Float#round" do
0.42.round(2.0**30).should == 0.42
end
+ it "returns rounded values for not so big argument" do
+ 0.42.round(2.0**23).should == 0.42
+ end
+
it "returns big values rounded to nearest" do
+2.5e20.round(-20).should eql( +3 * 10 ** 20 )
-2.5e20.round(-20).should eql( -3 * 10 ** 20 )
diff --git a/spec/ruby/core/gc/config_spec.rb b/spec/ruby/core/gc/config_spec.rb
new file mode 100644
index 0000000000..e20e8e4a16
--- /dev/null
+++ b/spec/ruby/core/gc/config_spec.rb
@@ -0,0 +1,83 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.4" do
+ describe "GC.config" do
+ context "without arguments" do
+ it "returns a hash of current settings" do
+ GC.config.should be_kind_of(Hash)
+ end
+
+ it "includes the name of currently loaded GC implementation as a global key" do
+ GC.config.should include(:implementation)
+ GC.config[:implementation].should be_kind_of(String)
+ end
+ end
+
+ context "with a hash of options" do
+ it "allows to set GC implementation's options, returning the new config" do
+ config = GC.config({})
+ # Try to find a boolean setting to reliably test changing it.
+ key, _value = config.find { |_k, v| v == true }
+ skip unless key
+
+ GC.config(key => false).should == config.merge(key => false)
+ GC.config[key].should == false
+ GC.config(key => true).should == config
+ GC.config[key].should == true
+ ensure
+ GC.config(config.except(:implementation))
+ end
+
+ it "does not change settings that aren't present in the hash" do
+ previous = GC.config
+ GC.config({})
+ GC.config.should == previous
+ end
+
+ it "ignores unknown keys" do
+ previous = GC.config
+ GC.config(foo: "bar")
+ GC.config.should == previous
+ end
+
+ it "raises an ArgumentError if options include global keys" do
+ -> { GC.config(implementation: "default") }.should raise_error(ArgumentError, 'Attempting to set read-only key "Implementation"')
+ end
+ end
+
+ context "with a non-hash argument" do
+ it "returns current settings if argument is nil" do
+ GC.config(nil).should == GC.config
+ end
+
+ it "raises ArgumentError for all other arguments" do
+ -> { GC.config([]) }.should raise_error(ArgumentError)
+ -> { GC.config("default") }.should raise_error(ArgumentError)
+ -> { GC.config(1) }.should raise_error(ArgumentError)
+ end
+ end
+
+ guard -> { PlatformGuard.standard? && GC.config[:implementation] == "default" } do
+ context "with default GC implementation on MRI" do
+ before do
+ @default_config = GC.config({})
+ end
+
+ after do
+ GC.config(@default_config.except(:implementation))
+ end
+
+ it "includes :rgengc_allow_full_mark option, true by default" do
+ GC.config.should include(:rgengc_allow_full_mark)
+ GC.config[:rgengc_allow_full_mark].should be_true
+ end
+
+ it "allows to set :rgengc_allow_full_mark" do
+ # This key maps truthy and falsey values to true and false.
+ GC.config(rgengc_allow_full_mark: nil).should == @default_config.merge(rgengc_allow_full_mark: false)
+ GC.config(rgengc_allow_full_mark: 1.23).should == @default_config.merge(rgengc_allow_full_mark: true)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/gc/measure_total_time_spec.rb b/spec/ruby/core/gc/measure_total_time_spec.rb
index 05d4598ebc..f5377c18fd 100644
--- a/spec/ruby/core/gc/measure_total_time_spec.rb
+++ b/spec/ruby/core/gc/measure_total_time_spec.rb
@@ -1,19 +1,17 @@
require_relative '../../spec_helper'
-ruby_version_is "3.1" do
- describe "GC.measure_total_time" do
- before :each do
- @default = GC.measure_total_time
- end
+describe "GC.measure_total_time" do
+ before :each do
+ @default = GC.measure_total_time
+ end
- after :each do
- GC.measure_total_time = @default
- end
+ after :each do
+ GC.measure_total_time = @default
+ end
- it "can set and get a boolean value" do
- original = GC.measure_total_time
- GC.measure_total_time = !original
- GC.measure_total_time.should == !original
- end
+ it "can set and get a boolean value" do
+ original = GC.measure_total_time
+ GC.measure_total_time = !original
+ GC.measure_total_time.should == !original
end
end
diff --git a/spec/ruby/core/gc/total_time_spec.rb b/spec/ruby/core/gc/total_time_spec.rb
index fcc8f45a83..a8430fbe9a 100644
--- a/spec/ruby/core/gc/total_time_spec.rb
+++ b/spec/ruby/core/gc/total_time_spec.rb
@@ -1,15 +1,13 @@
require_relative '../../spec_helper'
-ruby_version_is "3.1" do
- describe "GC.total_time" do
- it "returns an Integer" do
- GC.total_time.should be_kind_of(Integer)
- end
+describe "GC.total_time" do
+ it "returns an Integer" do
+ GC.total_time.should be_kind_of(Integer)
+ end
- it "increases as collections are run" do
- time_before = GC.total_time
- GC.start
- GC.total_time.should >= time_before
- end
+ it "increases as collections are run" do
+ time_before = GC.total_time
+ GC.start
+ GC.total_time.should >= time_before
end
end
diff --git a/spec/ruby/core/hash/compact_spec.rb b/spec/ruby/core/hash/compact_spec.rb
index 76aa43949d..13371bce43 100644
--- a/spec/ruby/core/hash/compact_spec.rb
+++ b/spec/ruby/core/hash/compact_spec.rb
@@ -35,7 +35,7 @@ describe "Hash#compact" do
hash.compact.default_proc.should == pr
end
- it "retains compare_by_identity_flag" do
+ it "retains compare_by_identity flag" do
hash = {}.compare_by_identity
hash.compact.compare_by_identity?.should == true
hash[:a] = 1
diff --git a/spec/ruby/core/hash/constructor_spec.rb b/spec/ruby/core/hash/constructor_spec.rb
index 8d29773909..0f97f7b40e 100644
--- a/spec/ruby/core/hash/constructor_spec.rb
+++ b/spec/ruby/core/hash/constructor_spec.rb
@@ -103,14 +103,14 @@ describe "Hash.[]" do
HashSpecs::MyInitializerHash[Hash[1, 2]].should be_an_instance_of(HashSpecs::MyInitializerHash)
end
- it "removes the default value" do
+ it "does not retain the default value" do
hash = Hash.new(1)
Hash[hash].default.should be_nil
hash[:a] = 1
Hash[hash].default.should be_nil
end
- it "removes the default_proc" do
+ it "does not retain the default_proc" do
hash = Hash.new { |h, k| h[k] = [] }
Hash[hash].default_proc.should be_nil
hash[:a] = 1
@@ -118,10 +118,11 @@ describe "Hash.[]" do
end
ruby_version_is '3.3' do
- it "does not retain compare_by_identity_flag" do
- hash = {}.compare_by_identity
+ it "does not retain compare_by_identity flag" do
+ hash = { a: 1 }.compare_by_identity
Hash[hash].compare_by_identity?.should == false
- hash[:a] = 1
+
+ hash = {}.compare_by_identity
Hash[hash].compare_by_identity?.should == false
end
end
diff --git a/spec/ruby/core/hash/except_spec.rb b/spec/ruby/core/hash/except_spec.rb
index ac84f9975c..026e454b13 100644
--- a/spec/ruby/core/hash/except_spec.rb
+++ b/spec/ruby/core/hash/except_spec.rb
@@ -19,14 +19,24 @@ describe "Hash#except" do
@hash.except(:a, :chunky_bacon).should == { b: 2, c: 3 }
end
- it "always returns a Hash without a default" do
- klass = Class.new(Hash)
- h = klass.new(:default)
- h[:bar] = 12
- h[:foo] = 42
- r = h.except(:foo)
- r.should == {bar: 12}
- r.class.should == Hash
- r.default.should == nil
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.except(:a).default.should be_nil
+ h[:a] = 1
+ h.except(:a).default.should be_nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.except(:a).default_proc.should be_nil
+ h[:a] = 1
+ h.except(:a).default_proc.should be_nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.except(:a)
+ h2.compare_by_identity?.should == true
end
end
diff --git a/spec/ruby/core/hash/hash_spec.rb b/spec/ruby/core/hash/hash_spec.rb
index 9b47d4b2bf..cd67f7a652 100644
--- a/spec/ruby/core/hash/hash_spec.rb
+++ b/spec/ruby/core/hash/hash_spec.rb
@@ -42,12 +42,10 @@ describe "Hash#hash" do
# Like above, because h.eql?(x: [h])
end
- ruby_version_is "3.1" do
- it "allows omitting values" do
- a = 1
- b = 2
+ it "allows omitting values" do
+ a = 1
+ b = 2
- eval('{a:, b:}.should == { a: 1, b: 2 }')
- end
+ {a:, b:}.should == { a: 1, b: 2 }
end
end
diff --git a/spec/ruby/core/hash/invert_spec.rb b/spec/ruby/core/hash/invert_spec.rb
index 73377a9e97..c06e15ff7c 100644
--- a/spec/ruby/core/hash/invert_spec.rb
+++ b/spec/ruby/core/hash/invert_spec.rb
@@ -24,4 +24,25 @@ describe "Hash#invert" do
HashSpecs::MyHash[1 => 2, 3 => 4].invert.class.should == Hash
HashSpecs::MyHash[].invert.class.should == Hash
end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.invert.default.should be_nil
+ h[:a] = 1
+ h.invert.default.should be_nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.invert.default_proc.should be_nil
+ h[:a] = 1
+ h.invert.default_proc.should be_nil
+ end
+
+ it "does not retain compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.invert
+ h2.compare_by_identity?.should == false
+ end
end
diff --git a/spec/ruby/core/hash/merge_spec.rb b/spec/ruby/core/hash/merge_spec.rb
index 5521864297..6710d121ef 100644
--- a/spec/ruby/core/hash/merge_spec.rb
+++ b/spec/ruby/core/hash/merge_spec.rb
@@ -93,6 +93,29 @@ describe "Hash#merge" do
merged.should eql(hash)
merged.should_not equal(hash)
end
+
+ it "retains the default value" do
+ h = Hash.new(1)
+ h.merge(b: 1, d: 2).default.should == 1
+ end
+
+ it "retains the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.merge(b: 1, d: 2).default_proc.should == pr
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.merge(b: 1, d: 2)
+ h2.compare_by_identity?.should == true
+ end
+
+ it "ignores compare_by_identity flag of an argument" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = { b: 1, d: 2 }.merge(h)
+ h2.compare_by_identity?.should == false
+ end
end
describe "Hash#merge!" do
diff --git a/spec/ruby/core/hash/reject_spec.rb b/spec/ruby/core/hash/reject_spec.rb
index dd8e817237..8381fc7fc1 100644
--- a/spec/ruby/core/hash/reject_spec.rb
+++ b/spec/ruby/core/hash/reject_spec.rb
@@ -44,6 +44,27 @@ describe "Hash#reject" do
reject_pairs.should == reject_bang_pairs
end
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.reject { false }.default.should be_nil
+ h[:a] = 1
+ h.reject { false }.default.should be_nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.reject { false }.default_proc.should be_nil
+ h[:a] = 1
+ h.reject { false }.default_proc.should be_nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.reject { |k, _| k == :a }
+ h2.compare_by_identity?.should == true
+ end
+
it_behaves_like :hash_iteration_no_block, :reject
it_behaves_like :enumeratorized_with_origin_size, :reject, { 1 => 2, 3 => 4, 5 => 6 }
end
diff --git a/spec/ruby/core/hash/replace_spec.rb b/spec/ruby/core/hash/replace_spec.rb
index a26a31f5f9..db30145e1a 100644
--- a/spec/ruby/core/hash/replace_spec.rb
+++ b/spec/ruby/core/hash/replace_spec.rb
@@ -23,39 +23,48 @@ describe "Hash#replace" do
h.should == { 1 => 2 }
end
- it "transfers the compare_by_identity flag" do
- hash_a = { a: 1 }
- hash_b = { b: 2 }
- hash_b.compare_by_identity
- hash_a.should_not.compare_by_identity?
- hash_a.replace(hash_b)
- hash_a.should.compare_by_identity?
+ it "does not retain the default value" do
+ hash = Hash.new(1)
+ hash.replace(b: 2).default.should be_nil
+ end
- hash_a = { a: 1 }
- hash_b = { b: 2 }
- hash_a.compare_by_identity
- hash_a.should.compare_by_identity?
- hash_a.replace(hash_b)
- hash_a.should_not.compare_by_identity?
+ it "transfers the default value of an argument" do
+ hash = Hash.new(1)
+ { a: 1 }.replace(hash).default.should == 1
end
- it "does not transfer default values" do
- hash_a = {}
- hash_b = Hash.new(5)
- hash_a.replace(hash_b)
- hash_a.default.should == 5
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ hash = Hash.new(&pr)
+ hash.replace(b: 2).default_proc.should be_nil
+ end
- hash_a = {}
- hash_b = Hash.new { |h, k| k * 2 }
- hash_a.replace(hash_b)
- hash_a.default(5).should == 10
+ it "transfers the default_proc of an argument" do
+ pr = proc { |h, k| h[k] = [] }
+ hash = Hash.new(&pr)
+ { a: 1 }.replace(hash).default_proc.should == pr
+ end
+ it "does not call the default_proc of an argument" do
hash_a = Hash.new { |h, k| k * 5 }
hash_b = Hash.new(-> { raise "Should not invoke lambda" })
hash_a.replace(hash_b)
hash_a.default.should == hash_b.default
end
+ it "transfers compare_by_identity flag of an argument" do
+ h = { a: 1, c: 3 }
+ h2 = { b: 2, d: 4 }.compare_by_identity
+ h.replace(h2)
+ h.compare_by_identity?.should == true
+ end
+
+ it "does not retain compare_by_identity flag" do
+ h = { a: 1, c: 3 }.compare_by_identity
+ h.replace(b: 2, d: 4)
+ h.compare_by_identity?.should == false
+ end
+
it "raises a FrozenError if called on a frozen instance that would not be modified" do
-> do
HashSpecs.frozen_hash.replace(HashSpecs.frozen_hash)
diff --git a/spec/ruby/core/hash/shared/select.rb b/spec/ruby/core/hash/shared/select.rb
index 5170af50d6..fbeff07330 100644
--- a/spec/ruby/core/hash/shared/select.rb
+++ b/spec/ruby/core/hash/shared/select.rb
@@ -40,6 +40,27 @@ describe :hash_select, shared: true do
@empty.send(@method).should be_an_instance_of(Enumerator)
end
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.send(@method) { true }.default.should be_nil
+ h[:a] = 1
+ h.send(@method) { true }.default.should be_nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.send(@method) { true }.default_proc.should be_nil
+ h[:a] = 1
+ h.send(@method) { true }.default_proc.should be_nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.send(@method) { |k, _| k == :a }
+ h2.compare_by_identity?.should == true
+ end
+
it_should_behave_like :hash_iteration_no_block
before :each do
diff --git a/spec/ruby/core/hash/shared/store.rb b/spec/ruby/core/hash/shared/store.rb
index dd1bb52bac..72a462a42f 100644
--- a/spec/ruby/core/hash/shared/store.rb
+++ b/spec/ruby/core/hash/shared/store.rb
@@ -91,9 +91,9 @@ describe :hash_store, shared: true do
end
it "does not raise an exception if changing the value of an existing key during iteration" do
- hash = {1 => 2, 3 => 4, 5 => 6}
- hash.each { hash.send(@method, 1, :foo) }
- hash.should == {1 => :foo, 3 => 4, 5 => 6}
+ hash = {1 => 2, 3 => 4, 5 => 6}
+ hash.each { hash.send(@method, 1, :foo) }
+ hash.should == {1 => :foo, 3 => 4, 5 => 6}
end
it "does not dispatch to hash for Boolean, Integer, Float, String, or Symbol" do
diff --git a/spec/ruby/core/hash/shared/to_s.rb b/spec/ruby/core/hash/shared/to_s.rb
index 5f0a8f97fd..e116b8878b 100644
--- a/spec/ruby/core/hash/shared/to_s.rb
+++ b/spec/ruby/core/hash/shared/to_s.rb
@@ -84,4 +84,10 @@ describe :hash_to_s, shared: true do
expected = ruby_version_is("3.4") ? "{true => false}" : "{true=>false}"
{ true => false }.to_s.should == expected
end
+
+ ruby_version_is "3.4" do
+ it "adds quotes to symbol keys that are not valid symbol literals" do
+ { "needs-quotes": 1 }.send(@method).should == '{"needs-quotes": 1}'
+ end
+ end
end
diff --git a/spec/ruby/core/hash/shift_spec.rb b/spec/ruby/core/hash/shift_spec.rb
index ea36488a04..3f31b9864c 100644
--- a/spec/ruby/core/hash/shift_spec.rb
+++ b/spec/ruby/core/hash/shift_spec.rb
@@ -30,45 +30,22 @@ describe "Hash#shift" do
h.should == {}
end
- ruby_version_is '3.2' do
- it "returns nil if the Hash is empty" do
- h = {}
- def h.default(key)
- raise
- end
- h.shift.should == nil
- end
- end
-
- ruby_version_is ''...'3.2' do
- it "calls #default with nil if the Hash is empty" do
- h = {}
- def h.default(key)
- key.should == nil
- :foo
- end
- h.shift.should == :foo
+ it "returns nil if the Hash is empty" do
+ h = {}
+ def h.default(key)
+ raise
end
+ h.shift.should == nil
end
it "returns nil from an empty hash" do
{}.shift.should == nil
end
- ruby_version_is '3.2' do
- it "returns nil for empty hashes with defaults and default procs" do
- Hash.new(5).shift.should == nil
- h = Hash.new { |*args| args }
- h.shift.should == nil
- end
- end
-
- ruby_version_is ''...'3.2' do
- it "returns (computed) default for empty hashes" do
- Hash.new(5).shift.should == 5
- h = Hash.new { |*args| args }
- h.shift.should == [h, nil]
- end
+ it "returns nil for empty hashes with defaults and default procs" do
+ Hash.new(5).shift.should == nil
+ h = Hash.new { |*args| args }
+ h.shift.should == nil
end
it "preserves Hash invariants when removing the last item" do
diff --git a/spec/ruby/core/hash/slice_spec.rb b/spec/ruby/core/hash/slice_spec.rb
index e3046d83d7..4fcc01f9a6 100644
--- a/spec/ruby/core/hash/slice_spec.rb
+++ b/spec/ruby/core/hash/slice_spec.rb
@@ -50,4 +50,25 @@ describe "Hash#slice" do
ScratchPad.recorded.should == []
end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.slice(:a).default.should be_nil
+ h[:a] = 1
+ h.slice(:a).default.should be_nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.slice(:a).default_proc.should be_nil
+ h[:a] = 1
+ h.slice(:a).default_proc.should be_nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.slice(:a)
+ h2.compare_by_identity?.should == true
+ end
end
diff --git a/spec/ruby/core/hash/to_h_spec.rb b/spec/ruby/core/hash/to_h_spec.rb
index e17ca7e671..f84fd7b503 100644
--- a/spec/ruby/core/hash/to_h_spec.rb
+++ b/spec/ruby/core/hash/to_h_spec.rb
@@ -19,17 +19,22 @@ describe "Hash#to_h" do
@h[:foo].should == :bar
end
- it "copies the default" do
+ it "retains the default" do
@h.default = 42
@h.to_h.default.should == 42
@h[:hello].should == 42
end
- it "copies the default_proc" do
+ it "retains the default_proc" do
@h.default_proc = prc = Proc.new{ |h, k| h[k] = 2 * k }
@h.to_h.default_proc.should == prc
@h[42].should == 84
end
+
+ it "retains compare_by_identity flag" do
+ @h.compare_by_identity
+ @h.to_h.compare_by_identity?.should == true
+ end
end
context "with block" do
@@ -78,5 +83,24 @@ describe "Hash#to_h" do
{ a: 1 }.to_h { |k| x }
end.should raise_error(TypeError, /wrong element type MockObject/)
end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h2 = h.to_h { |k, v| [k.to_s, v*v]}
+ h2.default.should be_nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h2 = h.to_h { |k, v| [k.to_s, v*v]}
+ h2.default_proc.should be_nil
+ end
+
+ it "does not retain compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.to_h { |k, v| [k.to_s, v*v]}
+ h2.compare_by_identity?.should == false
+ end
end
end
diff --git a/spec/ruby/core/hash/transform_keys_spec.rb b/spec/ruby/core/hash/transform_keys_spec.rb
index 2fbb17a8e2..e2eeab1813 100644
--- a/spec/ruby/core/hash/transform_keys_spec.rb
+++ b/spec/ruby/core/hash/transform_keys_spec.rb
@@ -54,6 +54,27 @@ describe "Hash#transform_keys" do
it "allows a combination of hash and block argument" do
@hash.transform_keys({ a: :A }, &:to_s).should == { A: 1, 'b' => 2, 'c' => 3 }
end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.transform_keys(&:succ).default.should be_nil
+ h[:a] = 1
+ h.transform_keys(&:succ).default.should be_nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.transform_values(&:succ).default_proc.should be_nil
+ h[:a] = 1
+ h.transform_values(&:succ).default_proc.should be_nil
+ end
+
+ it "does not retain compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.transform_keys(&:succ)
+ h2.compare_by_identity?.should == false
+ end
end
describe "Hash#transform_keys!" do
@@ -76,24 +97,12 @@ describe "Hash#transform_keys!" do
@hash.should == { b: 1, c: 2, d: 3, e: 4 }
end
- ruby_version_is ""..."3.0.2" do # https://bugs.ruby-lang.org/issues/17735
- it "returns the processed keys if we break from the block" do
- @hash.transform_keys! do |v|
- break if v == :c
- v.succ
- end
- @hash.should == { b: 1, c: 2 }
- end
- end
-
- ruby_version_is "3.0.2" do
- it "returns the processed keys and non evaluated keys if we break from the block" do
- @hash.transform_keys! do |v|
- break if v == :c
- v.succ
- end
- @hash.should == { b: 1, c: 2, d: 4 }
+ it "returns the processed keys and non evaluated keys if we break from the block" do
+ @hash.transform_keys! do |v|
+ break if v == :c
+ v.succ
end
+ @hash.should == { b: 1, c: 2, d: 4 }
end
it "keeps later pair if new keys conflict" do
@@ -129,7 +138,7 @@ describe "Hash#transform_keys!" do
end
it "raises a FrozenError on hash argument" do
- ->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should raise_error(FrozenError)
+ ->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should raise_error(FrozenError)
end
context "when no block is given" do
diff --git a/spec/ruby/core/hash/transform_values_spec.rb b/spec/ruby/core/hash/transform_values_spec.rb
index acb469416a..4a0ae8a5a5 100644
--- a/spec/ruby/core/hash/transform_values_spec.rb
+++ b/spec/ruby/core/hash/transform_values_spec.rb
@@ -39,6 +39,27 @@ describe "Hash#transform_values" do
r[:foo].should == 84
r.class.should == Hash
end
+
+ it "does not retain the default value" do
+ h = Hash.new(1)
+ h.transform_values(&:succ).default.should be_nil
+ h[:a] = 1
+ h.transform_values(&:succ).default.should be_nil
+ end
+
+ it "does not retain the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ h = Hash.new(&pr)
+ h.transform_values(&:succ).default_proc.should be_nil
+ h[:a] = 1
+ h.transform_values(&:succ).default_proc.should be_nil
+ end
+
+ it "retains compare_by_identity flag" do
+ h = { a: 9, c: 4 }.compare_by_identity
+ h2 = h.transform_values(&:succ)
+ h2.compare_by_identity?.should == true
+ end
end
describe "Hash#transform_values!" do
diff --git a/spec/ruby/core/integer/ceildiv_spec.rb b/spec/ruby/core/integer/ceildiv_spec.rb
index 18d07c66d0..c6e22a457d 100644
--- a/spec/ruby/core/integer/ceildiv_spec.rb
+++ b/spec/ruby/core/integer/ceildiv_spec.rb
@@ -1,22 +1,20 @@
require_relative '../../spec_helper'
describe "Integer#ceildiv" do
- ruby_version_is '3.2' do
- it "returns a quotient of division which is rounded up to the nearest integer" do
- 0.ceildiv(3).should eql(0)
- 1.ceildiv(3).should eql(1)
- 3.ceildiv(3).should eql(1)
- 4.ceildiv(3).should eql(2)
+ it "returns a quotient of division which is rounded up to the nearest integer" do
+ 0.ceildiv(3).should eql(0)
+ 1.ceildiv(3).should eql(1)
+ 3.ceildiv(3).should eql(1)
+ 4.ceildiv(3).should eql(2)
- 4.ceildiv(-3).should eql(-1)
- -4.ceildiv(3).should eql(-1)
- -4.ceildiv(-3).should eql(2)
+ 4.ceildiv(-3).should eql(-1)
+ -4.ceildiv(3).should eql(-1)
+ -4.ceildiv(-3).should eql(2)
- 3.ceildiv(1.2).should eql(3)
- 3.ceildiv(6/5r).should eql(3)
+ 3.ceildiv(1.2).should eql(3)
+ 3.ceildiv(6/5r).should eql(3)
- (10**100-11).ceildiv(10**99-1).should eql(10)
- (10**100-9).ceildiv(10**99-1).should eql(11)
- end
+ (10**100-11).ceildiv(10**99-1).should eql(10)
+ (10**100-9).ceildiv(10**99-1).should eql(11)
end
end
diff --git a/spec/ruby/core/integer/constants_spec.rb b/spec/ruby/core/integer/constants_spec.rb
index 2077ad451e..937806c72f 100644
--- a/spec/ruby/core/integer/constants_spec.rb
+++ b/spec/ruby/core/integer/constants_spec.rb
@@ -1,41 +1,13 @@
require_relative '../../spec_helper'
describe "Fixnum" do
- ruby_version_is ""..."3.2" do
- it "is unified into Integer" do
- suppress_warning do
- Fixnum.should equal(Integer)
- end
- end
-
- it "is deprecated" do
- -> { Fixnum }.should complain(/constant ::Fixnum is deprecated/)
- end
- end
-
- ruby_version_is "3.2" do
- it "is no longer defined" do
- Object.should_not.const_defined?(:Fixnum)
- end
+ it "is no longer defined" do
+ Object.should_not.const_defined?(:Fixnum)
end
end
describe "Bignum" do
- ruby_version_is ""..."3.2" do
- it "is unified into Integer" do
- suppress_warning do
- Bignum.should equal(Integer)
- end
- end
-
- it "is deprecated" do
- -> { Bignum }.should complain(/constant ::Bignum is deprecated/)
- end
- end
-
- ruby_version_is "3.2" do
- it "is no longer defined" do
- Object.should_not.const_defined?(:Bignum)
- end
+ it "is no longer defined" do
+ Object.should_not.const_defined?(:Bignum)
end
end
diff --git a/spec/ruby/core/integer/divide_spec.rb b/spec/ruby/core/integer/divide_spec.rb
index a878c4668c..0d5e16e986 100644
--- a/spec/ruby/core/integer/divide_spec.rb
+++ b/spec/ruby/core/integer/divide_spec.rb
@@ -12,6 +12,17 @@ describe "Integer#/" do
it "supports dividing negative numbers" do
(-1 / 10).should == -1
+ (-1 / 10**10).should == -1
+ (-1 / 10**20).should == -1
+ end
+
+ it "preservers sign correctly" do
+ (4 / 3).should == 1
+ (4 / -3).should == -2
+ (-4 / 3).should == -2
+ (-4 / -3).should == 1
+ (0 / -3).should == 0
+ (0 / 3).should == 0
end
it "returns result the same class as the argument" do
@@ -58,6 +69,15 @@ describe "Integer#/" do
((10**50) / -(10**40 + 1)).should == -10000000000
end
+ it "preservers sign correctly" do
+ (4 / bignum_value).should == 0
+ (4 / -bignum_value).should == -1
+ (-4 / bignum_value).should == -1
+ (-4 / -bignum_value).should == 0
+ (0 / bignum_value).should == 0
+ (0 / -bignum_value).should == 0
+ end
+
it "returns self divided by Float" do
not_supported_on :opal do
(bignum_value(88) / 4294967295.0).should be_close(4294967297.0, TOLERANCE)
@@ -86,4 +106,21 @@ describe "Integer#/" do
-> { @bignum / :symbol }.should raise_error(TypeError)
end
end
+
+ it "coerces the RHS and calls #coerce" do
+ obj = mock("integer plus")
+ obj.should_receive(:coerce).with(6).and_return([6, 3])
+ (6 / obj).should == 2
+ end
+
+ it "coerces the RHS and calls #coerce even if it's private" do
+ obj = Object.new
+ class << obj
+ private def coerce(n)
+ [n, 3]
+ end
+ end
+
+ (6 / obj).should == 2
+ end
end
diff --git a/spec/ruby/core/integer/left_shift_spec.rb b/spec/ruby/core/integer/left_shift_spec.rb
index 0781371d93..86c2b18ae2 100644
--- a/spec/ruby/core/integer/left_shift_spec.rb
+++ b/spec/ruby/core/integer/left_shift_spec.rb
@@ -181,10 +181,8 @@ describe "Integer#<< (with n << m)" do
(bignum_value << -(2**40)).should == 0
end
- ruby_bug "#18517", ""..."3.2" do
- it "returns 0 when m > 0 long and n == 0" do
- (0 << (2**40)).should == 0
- end
+ it "returns 0 when m > 0 long and n == 0" do
+ (0 << (2**40)).should == 0
end
it "returns 0 when m > 0 bignum and n == 0" do
diff --git a/spec/ruby/core/integer/minus_spec.rb b/spec/ruby/core/integer/minus_spec.rb
index aadf416a05..6072ba7c8b 100644
--- a/spec/ruby/core/integer/minus_spec.rb
+++ b/spec/ruby/core/integer/minus_spec.rb
@@ -40,4 +40,21 @@ describe "Integer#-" do
-> { @bignum - :symbol }.should raise_error(TypeError)
end
end
+
+ it "coerces the RHS and calls #coerce" do
+ obj = mock("integer plus")
+ obj.should_receive(:coerce).with(5).and_return([5, 10])
+ (5 - obj).should == -5
+ end
+
+ it "coerces the RHS and calls #coerce even if it's private" do
+ obj = Object.new
+ class << obj
+ private def coerce(n)
+ [n, 10]
+ end
+ end
+
+ (5 - obj).should == -5
+ end
end
diff --git a/spec/ruby/core/integer/plus_spec.rb b/spec/ruby/core/integer/plus_spec.rb
index d01a76ab58..38428e56c5 100644
--- a/spec/ruby/core/integer/plus_spec.rb
+++ b/spec/ruby/core/integer/plus_spec.rb
@@ -55,4 +55,21 @@ describe "Integer#+" do
RUBY
ruby_exe(code).should == "-1"
end
+
+ it "coerces the RHS and calls #coerce" do
+ obj = mock("integer plus")
+ obj.should_receive(:coerce).with(6).and_return([6, 3])
+ (6 + obj).should == 9
+ end
+
+ it "coerces the RHS and calls #coerce even if it's private" do
+ obj = Object.new
+ class << obj
+ private def coerce(n)
+ [n, 3]
+ end
+ end
+
+ (6 + obj).should == 9
+ end
end
diff --git a/spec/ruby/core/integer/right_shift_spec.rb b/spec/ruby/core/integer/right_shift_spec.rb
index e91613d8d1..c902674e2f 100644
--- a/spec/ruby/core/integer/right_shift_spec.rb
+++ b/spec/ruby/core/integer/right_shift_spec.rb
@@ -203,10 +203,8 @@ describe "Integer#>> (with n >> m)" do
(bignum_value >> (2**40)).should == 0
end
- ruby_bug "#18517", ""..."3.2" do
- it "returns 0 when m < 0 long and n == 0" do
- (0 >> -(2**40)).should == 0
- end
+ it "returns 0 when m < 0 long and n == 0" do
+ (0 >> -(2**40)).should == 0
end
it "returns 0 when m < 0 bignum and n == 0" do
diff --git a/spec/ruby/core/integer/shared/modulo.rb b/spec/ruby/core/integer/shared/modulo.rb
index f678a10806..d91af1e924 100644
--- a/spec/ruby/core/integer/shared/modulo.rb
+++ b/spec/ruby/core/integer/shared/modulo.rb
@@ -1,6 +1,12 @@
describe :integer_modulo, shared: true do
context "fixnum" do
it "returns the modulus obtained from dividing self by the given argument" do
+ # test all possible combinations:
+ # - integer/double/bignum argument
+ # - positive/negative argument
+ # - positive/negative self
+ # - self greater/smaller than argument
+
13.send(@method, 4).should == 1
4.send(@method, 13).should == 4
@@ -16,8 +22,22 @@ describe :integer_modulo, shared: true do
(200).send(@method, -256).should == -56
(1000).send(@method, -512).should == -24
+ 13.send(@method, -4.0).should == -3.0
+ 4.send(@method, -13.0).should == -9.0
+
+ -13.send(@method, -4.0).should == -1.0
+ -4.send(@method, -13.0).should == -4.0
+
+ -13.send(@method, 4.0).should == 3.0
+ -4.send(@method, 13.0).should == 9.0
+
1.send(@method, 2.0).should == 1.0
200.send(@method, bignum_value).should == 200
+
+ 4.send(@method, bignum_value(10)).should == 4
+ 4.send(@method, -bignum_value(10)).should == -18446744073709551622
+ -4.send(@method, bignum_value(10)).should == 18446744073709551622
+ -4.send(@method, -bignum_value(10)).should == -4
end
it "raises a ZeroDivisionError when the given argument is 0" do
@@ -44,15 +64,35 @@ describe :integer_modulo, shared: true do
context "bignum" do
before :each do
- @bignum = bignum_value
+ @bignum = bignum_value(10)
end
it "returns the modulus obtained from dividing self by the given argument" do
+ # test all possible combinations:
+ # - integer/double/bignum argument
+ # - positive/negative argument
+ # - positive/negative self
+ # - self greater/smaller than argument
+
@bignum.send(@method, 5).should == 1
@bignum.send(@method, -5).should == -4
- @bignum.send(@method, -100).should == -84
+ (-@bignum).send(@method, 5).should == 4
+ (-@bignum).send(@method, -5).should == -1
+
@bignum.send(@method, 2.22).should be_close(1.5603603603605034, TOLERANCE)
- @bignum.send(@method, bignum_value(10)).should == 18446744073709551616
+ @bignum.send(@method, -2.22).should be_close(-0.6596396396394968, TOLERANCE)
+ (-@bignum).send(@method, 2.22).should be_close(0.6596396396394968, TOLERANCE)
+ (-@bignum).send(@method, -2.22).should be_close(-1.5603603603605034, TOLERANCE)
+
+ @bignum.send(@method, @bignum + 10).should == 18446744073709551626
+ @bignum.send(@method, -(@bignum + 10)).should == -10
+ (-@bignum).send(@method, @bignum + 10).should == 10
+ (-@bignum).send(@method, -(@bignum + 10)).should == -18446744073709551626
+
+ (@bignum + 10).send(@method, @bignum).should == 10
+ (@bignum + 10).send(@method, -@bignum).should == -18446744073709551616
+ (-(@bignum + 10)).send(@method, @bignum).should == 18446744073709551616
+ (-(@bignum + 10)).send(@method, -@bignum).should == -10
end
it "raises a ZeroDivisionError when the given argument is 0" do
diff --git a/spec/ruby/core/integer/try_convert_spec.rb b/spec/ruby/core/integer/try_convert_spec.rb
index 4bc7d3851a..8a0ca671a9 100644
--- a/spec/ruby/core/integer/try_convert_spec.rb
+++ b/spec/ruby/core/integer/try_convert_spec.rb
@@ -1,50 +1,48 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.1" do
- describe "Integer.try_convert" do
- it "returns the argument if it's an Integer" do
- x = 42
- Integer.try_convert(x).should equal(x)
- end
+describe "Integer.try_convert" do
+ it "returns the argument if it's an Integer" do
+ x = 42
+ Integer.try_convert(x).should equal(x)
+ end
- it "returns nil when the argument does not respond to #to_int" do
- Integer.try_convert(Object.new).should be_nil
- end
+ it "returns nil when the argument does not respond to #to_int" do
+ Integer.try_convert(Object.new).should be_nil
+ end
- it "sends #to_int to the argument and returns the result if it's nil" do
- obj = mock("to_int")
- obj.should_receive(:to_int).and_return(nil)
- Integer.try_convert(obj).should be_nil
- end
+ it "sends #to_int to the argument and returns the result if it's nil" do
+ obj = mock("to_int")
+ obj.should_receive(:to_int).and_return(nil)
+ Integer.try_convert(obj).should be_nil
+ end
- it "sends #to_int to the argument and returns the result if it's an Integer" do
- x = 234
- obj = mock("to_int")
- obj.should_receive(:to_int).and_return(x)
- Integer.try_convert(obj).should equal(x)
- end
+ it "sends #to_int to the argument and returns the result if it's an Integer" do
+ x = 234
+ obj = mock("to_int")
+ obj.should_receive(:to_int).and_return(x)
+ Integer.try_convert(obj).should equal(x)
+ end
- it "sends #to_int to the argument and raises TypeError if it's not a kind of Integer" do
- obj = mock("to_int")
- obj.should_receive(:to_int).and_return(Object.new)
- -> {
- Integer.try_convert obj
- }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Object)")
- end
+ it "sends #to_int to the argument and raises TypeError if it's not a kind of Integer" do
+ obj = mock("to_int")
+ obj.should_receive(:to_int).and_return(Object.new)
+ -> {
+ Integer.try_convert obj
+ }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Object)")
+ end
- it "responds with a different error message when it raises a TypeError, depending on the type of the non-Integer object :to_int returns" do
- obj = mock("to_int")
- obj.should_receive(:to_int).and_return("A String")
- -> {
- Integer.try_convert obj
- }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives String)")
- end
+ it "responds with a different error message when it raises a TypeError, depending on the type of the non-Integer object :to_int returns" do
+ obj = mock("to_int")
+ obj.should_receive(:to_int).and_return("A String")
+ -> {
+ Integer.try_convert obj
+ }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives String)")
+ end
- it "does not rescue exceptions raised by #to_int" do
- obj = mock("to_int")
- obj.should_receive(:to_int).and_raise(RuntimeError)
- -> { Integer.try_convert obj }.should raise_error(RuntimeError)
- end
+ it "does not rescue exceptions raised by #to_int" do
+ obj = mock("to_int")
+ obj.should_receive(:to_int).and_raise(RuntimeError)
+ -> { Integer.try_convert obj }.should raise_error(RuntimeError)
end
end
diff --git a/spec/ruby/core/io/binread_spec.rb b/spec/ruby/core/io/binread_spec.rb
index 418e89213b..9e36b84da9 100644
--- a/spec/ruby/core/io/binread_spec.rb
+++ b/spec/ruby/core/io/binread_spec.rb
@@ -45,7 +45,7 @@ describe "IO.binread" do
-> { IO.binread @fname, 0, -1 }.should raise_error(Errno::EINVAL)
end
- ruby_version_is "3.3" do
+ ruby_version_is "3.3"..."4.0" do
# https://bugs.ruby-lang.org/issues/19630
it "warns about deprecation given a path with a pipe" do
cmd = "|echo ok"
diff --git a/spec/ruby/core/io/buffer/empty_spec.rb b/spec/ruby/core/io/buffer/empty_spec.rb
new file mode 100644
index 0000000000..e1fd4ab6a2
--- /dev/null
+++ b/spec/ruby/core/io/buffer/empty_spec.rb
@@ -0,0 +1,29 @@
+require_relative '../../../spec_helper'
+require_relative 'shared/null_and_empty'
+
+describe "IO::Buffer#empty?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it_behaves_like :io_buffer_null_and_empty, :empty?
+
+ it "is true for a 0-length String-backed buffer created with .for" do
+ @buffer = IO::Buffer.for("")
+ @buffer.empty?.should be_true
+ end
+
+ ruby_version_is "3.3" do
+ it "is true for a 0-length String-backed buffer created with .string" do
+ IO::Buffer.string(0) do |buffer|
+ buffer.empty?.should be_true
+ end
+ end
+ end
+
+ it "is true for a 0-length slice of a buffer with size > 0" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice(3, 0).empty?.should be_true
+ end
+end
diff --git a/spec/ruby/core/io/buffer/external_spec.rb b/spec/ruby/core/io/buffer/external_spec.rb
new file mode 100644
index 0000000000..4377a38357
--- /dev/null
+++ b/spec/ruby/core/io/buffer/external_spec.rb
@@ -0,0 +1,108 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#external?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "with a buffer created with .new" do
+ it "is false for an internal buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.external?.should be_false
+ end
+
+ it "is false for a mapped buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ @buffer.external?.should be_false
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "is true for a regular mapping" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.external?.should be_true
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "is false for a private mapping" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE)
+ @buffer.external?.should be_false
+ end
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ it "is true for a buffer created without a block" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.external?.should be_true
+ end
+
+ it "is true for a buffer created with a block" do
+ IO::Buffer.for(+"test") do |buffer|
+ buffer.external?.should be_true
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ context "with a String-backed buffer created with .string" do
+ it "is true" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.external?.should be_true
+ end
+ end
+ end
+ end
+
+ # Always false for slices
+ context "with a slice of a buffer" do
+ context "created with .new" do
+ it "is false when slicing an internal buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice.external?.should be_false
+ end
+
+ it "is false when slicing a mapped buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ @buffer.slice.external?.should be_false
+ end
+ end
+
+ context "created with .map" do
+ it "is false" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.slice.external?.should be_false
+ end
+ end
+ end
+
+ context "created with .for" do
+ it "is false when slicing a buffer created without a block" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.slice.external?.should be_false
+ end
+
+ it "is false when slicing a buffer created with a block" do
+ IO::Buffer.for(+"test") do |buffer|
+ buffer.slice.external?.should be_false
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ context "created with .string" do
+ it "is false" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.slice.external?.should be_false
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/free_spec.rb b/spec/ruby/core/io/buffer/free_spec.rb
new file mode 100644
index 0000000000..f3a4918978
--- /dev/null
+++ b/spec/ruby/core/io/buffer/free_spec.rb
@@ -0,0 +1,104 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#free" do
+ context "with a buffer created with .new" do
+ it "frees internal memory and nullifies the buffer" do
+ buffer = IO::Buffer.new(4)
+ buffer.free
+ buffer.null?.should be_true
+ end
+
+ it "frees mapped memory and nullifies the buffer" do
+ buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ buffer.free
+ buffer.null?.should be_true
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "frees mapped memory and nullifies the buffer" do
+ File.open(__FILE__, "r") do |file|
+ buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ buffer.free
+ buffer.null?.should be_true
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ context "without a block" do
+ it "disassociates the buffer from the string and nullifies the buffer" do
+ string = +"test"
+ buffer = IO::Buffer.for(string)
+ # Read-only buffer, can't modify the string.
+ buffer.free
+ buffer.null?.should be_true
+ end
+ end
+
+ context "with a block" do
+ it "disassociates the buffer from the string and nullifies the buffer" do
+ string = +"test"
+ IO::Buffer.for(string) do |buffer|
+ buffer.set_string("meat")
+ buffer.free
+ buffer.null?.should be_true
+ end
+ string.should == "meat"
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ context "with a String-backed buffer created with .string" do
+ it "disassociates the buffer from the string and nullifies the buffer" do
+ string =
+ IO::Buffer.string(4) do |buffer|
+ buffer.set_string("meat")
+ buffer.free
+ buffer.null?.should be_true
+ end
+ string.should == "meat"
+ end
+ end
+ end
+
+ it "can be called repeatedly without an error" do
+ buffer = IO::Buffer.new(4)
+ buffer.free
+ buffer.null?.should be_true
+ buffer.free
+ buffer.null?.should be_true
+ end
+
+ it "is disallowed while locked, raising IO::Buffer::LockedError" do
+ buffer = IO::Buffer.new(4)
+ buffer.locked do
+ -> { buffer.free }.should raise_error(IO::Buffer::LockedError, "Buffer is locked!")
+ end
+ buffer.free
+ buffer.null?.should be_true
+ end
+
+ context "with a slice of a buffer" do
+ it "nullifies the slice, not touching the buffer" do
+ buffer = IO::Buffer.new(4)
+ slice = buffer.slice(0, 2)
+
+ slice.free
+ slice.null?.should be_true
+ buffer.null?.should be_false
+
+ buffer.free
+ end
+
+ it "nullifies buffer, invalidating the slice" do
+ buffer = IO::Buffer.new(4)
+ slice = buffer.slice(0, 2)
+
+ buffer.free
+ slice.null?.should be_false
+ slice.valid?.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/initialize_spec.rb b/spec/ruby/core/io/buffer/initialize_spec.rb
new file mode 100644
index 0000000000..c86d1e7f1d
--- /dev/null
+++ b/spec/ruby/core/io/buffer/initialize_spec.rb
@@ -0,0 +1,103 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#initialize" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "creates a new zero-filled buffer with default size" do
+ @buffer = IO::Buffer.new
+ @buffer.size.should == IO::Buffer::DEFAULT_SIZE
+ @buffer.each(:U8).should.all? { |_offset, value| value.eql?(0) }
+ end
+
+ it "creates a buffer with default state" do
+ @buffer = IO::Buffer.new
+ @buffer.should_not.shared?
+ @buffer.should_not.readonly?
+
+ @buffer.should_not.empty?
+ @buffer.should_not.null?
+
+ # This is run-time state, set by #locked.
+ @buffer.should_not.locked?
+ end
+
+ context "with size argument" do
+ it "creates a new internal buffer if size is less than IO::Buffer::PAGE_SIZE" do
+ size = IO::Buffer::PAGE_SIZE - 1
+ @buffer = IO::Buffer.new(size)
+ @buffer.size.should == size
+ @buffer.should.internal?
+ @buffer.should_not.mapped?
+ @buffer.should_not.empty?
+ end
+
+ it "creates a new mapped buffer if size is greater than or equal to IO::Buffer::PAGE_SIZE" do
+ size = IO::Buffer::PAGE_SIZE
+ @buffer = IO::Buffer.new(size)
+ @buffer.size.should == size
+ @buffer.should_not.internal?
+ @buffer.should.mapped?
+ @buffer.should_not.empty?
+ end
+
+ it "creates a null buffer if size is 0" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.size.should.zero?
+ @buffer.should_not.internal?
+ @buffer.should_not.mapped?
+ @buffer.should.null?
+ @buffer.should.empty?
+ end
+
+ it "raises TypeError if size is not an Integer" do
+ -> { IO::Buffer.new(nil) }.should raise_error(TypeError, "not an Integer")
+ -> { IO::Buffer.new(10.0) }.should raise_error(TypeError, "not an Integer")
+ end
+
+ it "raises ArgumentError if size is negative" do
+ -> { IO::Buffer.new(-1) }.should raise_error(ArgumentError, "Size can't be negative!")
+ end
+ end
+
+ context "with size and flags arguments" do
+ it "forces mapped buffer with IO::Buffer::MAPPED flag" do
+ @buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE - 1, IO::Buffer::MAPPED)
+ @buffer.should.mapped?
+ @buffer.should_not.internal?
+ @buffer.should_not.empty?
+ end
+
+ it "forces internal buffer with IO::Buffer::INTERNAL flag" do
+ @buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE, IO::Buffer::INTERNAL)
+ @buffer.should.internal?
+ @buffer.should_not.mapped?
+ @buffer.should_not.empty?
+ end
+
+ it "raises IO::Buffer::AllocationError if neither IO::Buffer::MAPPED nor IO::Buffer::INTERNAL is given" do
+ -> { IO::Buffer.new(10, IO::Buffer::READONLY) }.should raise_error(IO::Buffer::AllocationError, "Could not allocate buffer!")
+ -> { IO::Buffer.new(10, 0) }.should raise_error(IO::Buffer::AllocationError, "Could not allocate buffer!")
+ end
+
+ ruby_version_is "3.3" do
+ it "raises ArgumentError if flags is negative" do
+ -> { IO::Buffer.new(10, -1) }.should raise_error(ArgumentError, "Flags can't be negative!")
+ end
+ end
+
+ ruby_version_is ""..."3.3" do
+ it "raises IO::Buffer::AllocationError with non-Integer flags" do
+ -> { IO::Buffer.new(10, 0.0) }.should raise_error(IO::Buffer::AllocationError, "Could not allocate buffer!")
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raises TypeError with non-Integer flags" do
+ -> { IO::Buffer.new(10, 0.0) }.should raise_error(TypeError, "not an Integer")
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/internal_spec.rb b/spec/ruby/core/io/buffer/internal_spec.rb
new file mode 100644
index 0000000000..409699cc3c
--- /dev/null
+++ b/spec/ruby/core/io/buffer/internal_spec.rb
@@ -0,0 +1,108 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#internal?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "with a buffer created with .new" do
+ it "is true for an internal buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.internal?.should be_true
+ end
+
+ it "is false for a mapped buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ @buffer.internal?.should be_false
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "is false for a regular mapping" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.internal?.should be_false
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "is false for a private mapping" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE)
+ @buffer.internal?.should be_false
+ end
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ it "is false for a buffer created without a block" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.internal?.should be_false
+ end
+
+ it "is false for a buffer created with a block" do
+ IO::Buffer.for(+"test") do |buffer|
+ buffer.internal?.should be_false
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ context "with a String-backed buffer created with .string" do
+ it "is false" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.internal?.should be_false
+ end
+ end
+ end
+ end
+
+ # Always false for slices
+ context "with a slice of a buffer" do
+ context "created with .new" do
+ it "is false when slicing an internal buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice.internal?.should be_false
+ end
+
+ it "is false when slicing a mapped buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ @buffer.slice.internal?.should be_false
+ end
+ end
+
+ context "created with .map" do
+ it "is false" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.slice.internal?.should be_false
+ end
+ end
+ end
+
+ context "created with .for" do
+ it "is false when slicing a buffer created without a block" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.slice.internal?.should be_false
+ end
+
+ it "is false when slicing a buffer created with a block" do
+ IO::Buffer.for(+"test") do |buffer|
+ buffer.slice.internal?.should be_false
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ context "created with .string" do
+ it "is false" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.slice.internal?.should be_false
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/locked_spec.rb b/spec/ruby/core/io/buffer/locked_spec.rb
new file mode 100644
index 0000000000..4ffa569fd2
--- /dev/null
+++ b/spec/ruby/core/io/buffer/locked_spec.rb
@@ -0,0 +1,75 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#locked" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "when buffer is locked" do
+ it "allows reading and writing operations on the buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.set_string("test")
+ @buffer.locked do
+ @buffer.get_string.should == "test"
+ @buffer.set_string("meat")
+ end
+ @buffer.get_string.should == "meat"
+ end
+
+ it "disallows operations changing buffer itself, raising IO::Buffer::LockedError" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ # Just an example, each method is responsible for checking the lock state.
+ -> { @buffer.resize(8) }.should raise_error(IO::Buffer::LockedError)
+ end
+ end
+ end
+
+ it "disallows reentrant locking, raising IO::Buffer::LockedError" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ -> { @buffer.locked {} }.should raise_error(IO::Buffer::LockedError, "Buffer already locked!")
+ end
+ end
+
+ it "does not propagate to buffer's slices" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(0, 2)
+ @buffer.locked do
+ @buffer.locked?.should be_true
+ slice.locked?.should be_false
+ slice.locked { slice.locked?.should be_true }
+ end
+ end
+
+ it "does not propagate backwards from buffer's slices" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(0, 2)
+ slice.locked do
+ slice.locked?.should be_true
+ @buffer.locked?.should be_false
+ @buffer.locked { @buffer.locked?.should be_true }
+ end
+ end
+end
+
+describe "IO::Buffer#locked?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it "is false by default" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked?.should be_false
+ end
+
+ it "is true only inside of #locked block" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ @buffer.locked?.should be_true
+ end
+ @buffer.locked?.should be_false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/mapped_spec.rb b/spec/ruby/core/io/buffer/mapped_spec.rb
new file mode 100644
index 0000000000..b3610207ff
--- /dev/null
+++ b/spec/ruby/core/io/buffer/mapped_spec.rb
@@ -0,0 +1,108 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#mapped?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "with a buffer created with .new" do
+ it "is false for an internal buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.mapped?.should be_false
+ end
+
+ it "is true for a mapped buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ @buffer.mapped?.should be_true
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "is true for a regular mapping" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.mapped?.should be_true
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "is true for a private mapping" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE)
+ @buffer.mapped?.should be_true
+ end
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ it "is false for a buffer created without a block" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.mapped?.should be_false
+ end
+
+ it "is false for a buffer created with a block" do
+ IO::Buffer.for(+"test") do |buffer|
+ buffer.mapped?.should be_false
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ context "with a String-backed buffer created with .string" do
+ it "is false" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.mapped?.should be_false
+ end
+ end
+ end
+ end
+
+ # Always false for slices
+ context "with a slice of a buffer" do
+ context "created with .new" do
+ it "is false when slicing an internal buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice.mapped?.should be_false
+ end
+
+ it "is false when slicing a mapped buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ @buffer.slice.mapped?.should be_false
+ end
+ end
+
+ context "created with .map" do
+ it "is false" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.slice.mapped?.should be_false
+ end
+ end
+ end
+
+ context "created with .for" do
+ it "is false when slicing a buffer created without a block" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.slice.mapped?.should be_false
+ end
+
+ it "is false when slicing a buffer created with a block" do
+ IO::Buffer.for(+"test") do |buffer|
+ buffer.slice.mapped?.should be_false
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ context "created with .string" do
+ it "is false" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.slice.mapped?.should be_false
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/null_spec.rb b/spec/ruby/core/io/buffer/null_spec.rb
new file mode 100644
index 0000000000..3fb1144d0e
--- /dev/null
+++ b/spec/ruby/core/io/buffer/null_spec.rb
@@ -0,0 +1,29 @@
+require_relative '../../../spec_helper'
+require_relative 'shared/null_and_empty'
+
+describe "IO::Buffer#null?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ it_behaves_like :io_buffer_null_and_empty, :null?
+
+ it "is false for a 0-length String-backed buffer created with .for" do
+ @buffer = IO::Buffer.for("")
+ @buffer.null?.should be_false
+ end
+
+ ruby_version_is "3.3" do
+ it "is false for a 0-length String-backed buffer created with .string" do
+ IO::Buffer.string(0) do |buffer|
+ buffer.null?.should be_false
+ end
+ end
+ end
+
+ it "is false for a 0-length slice of a buffer with size > 0" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice(3, 0).null?.should be_false
+ end
+end
diff --git a/spec/ruby/core/io/buffer/private_spec.rb b/spec/ruby/core/io/buffer/private_spec.rb
new file mode 100644
index 0000000000..7aa308997b
--- /dev/null
+++ b/spec/ruby/core/io/buffer/private_spec.rb
@@ -0,0 +1,111 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is "3.3" do
+ describe "IO::Buffer#private?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "with a buffer created with .new" do
+ it "is false for an internal buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::INTERNAL)
+ @buffer.private?.should be_false
+ end
+
+ it "is false for a mapped buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ @buffer.private?.should be_false
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "is false for a regular mapping" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.private?.should be_false
+ end
+ end
+
+ it "is true for a private mapping" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE)
+ @buffer.private?.should be_true
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ it "is false for a buffer created without a block" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.private?.should be_false
+ end
+
+ it "is false for a buffer created with a block" do
+ IO::Buffer.for(+"test") do |buffer|
+ buffer.private?.should be_false
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .string" do
+ it "is false" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.private?.should be_false
+ end
+ end
+ end
+
+ # Always false for slices
+ context "with a slice of a buffer" do
+ context "created with .new" do
+ it "is false when slicing an internal buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice.private?.should be_false
+ end
+
+ it "is false when slicing a mapped buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ @buffer.slice.private?.should be_false
+ end
+ end
+
+ context "created with .map" do
+ it "is false when slicing a regular file-backed buffer" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.slice.private?.should be_false
+ end
+ end
+
+ it "is false when slicing a private file-backed buffer" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE)
+ @buffer.slice.private?.should be_false
+ end
+ end
+ end
+
+ context "created with .for" do
+ it "is false when slicing a buffer created without a block" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.slice.private?.should be_false
+ end
+
+ it "is false when slicing a buffer created with a block" do
+ IO::Buffer.for(+"test") do |buffer|
+ buffer.slice.private?.should be_false
+ end
+ end
+ end
+
+ context "created with .string" do
+ it "is false" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.slice.private?.should be_false
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/readonly_spec.rb b/spec/ruby/core/io/buffer/readonly_spec.rb
new file mode 100644
index 0000000000..0014a876ed
--- /dev/null
+++ b/spec/ruby/core/io/buffer/readonly_spec.rb
@@ -0,0 +1,143 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#readonly?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "with a buffer created with .new" do
+ it "is false for an internal buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::INTERNAL)
+ @buffer.readonly?.should be_false
+ end
+
+ it "is false for a mapped buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ @buffer.readonly?.should be_false
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "is false for a writable mapping" do
+ File.open(__FILE__, "r+") do |file|
+ @buffer = IO::Buffer.map(file)
+ @buffer.readonly?.should be_false
+ end
+ end
+
+ it "is true for a readonly mapping" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.readonly?.should be_true
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "is false for a private mapping" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE)
+ @buffer.readonly?.should be_false
+ end
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ it "is true for a buffer created without a block" do
+ @buffer = IO::Buffer.for(+"test")
+ @buffer.readonly?.should be_true
+ end
+
+ it "is false for a buffer created with a block" do
+ IO::Buffer.for(+"test") do |buffer|
+ buffer.readonly?.should be_false
+ end
+ end
+
+ it "is true for a buffer created with a block from a frozen string" do
+ IO::Buffer.for(-"test") do |buffer|
+ buffer.readonly?.should be_true
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ context "with a String-backed buffer created with .string" do
+ it "is false" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.readonly?.should be_false
+ end
+ end
+ end
+ end
+
+ # This seems to be the only flag propagated from the source buffer to the slice.
+ context "with a slice of a buffer" do
+ context "created with .new" do
+ it "is false when slicing an internal buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice.readonly?.should be_false
+ end
+
+ it "is false when slicing a mapped buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ @buffer.slice.readonly?.should be_false
+ end
+ end
+
+ context "created with .map" do
+ it "is false when slicing a read-write file-backed buffer" do
+ File.open(__FILE__, "r+") do |file|
+ @buffer = IO::Buffer.map(file)
+ @buffer.slice.readonly?.should be_false
+ end
+ end
+
+ it "is true when slicing a readonly file-backed buffer" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.slice.readonly?.should be_true
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "is false when slicing a private file-backed buffer" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE)
+ @buffer.slice.readonly?.should be_false
+ end
+ end
+ end
+ end
+
+ context "created with .for" do
+ it "is true when slicing a buffer created without a block" do
+ @buffer = IO::Buffer.for(+"test")
+ @buffer.slice.readonly?.should be_true
+ end
+
+ it "is false when slicing a buffer created with a block" do
+ IO::Buffer.for(+"test") do |buffer|
+ buffer.slice.readonly?.should be_false
+ end
+ end
+
+ it "is true when slicing a buffer created with a block from a frozen string" do
+ IO::Buffer.for(-"test") do |buffer|
+ buffer.slice.readonly?.should be_true
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ context "created with .string" do
+ it "is false" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.slice.readonly?.should be_false
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/resize_spec.rb b/spec/ruby/core/io/buffer/resize_spec.rb
new file mode 100644
index 0000000000..0da3a23356
--- /dev/null
+++ b/spec/ruby/core/io/buffer/resize_spec.rb
@@ -0,0 +1,155 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#resize" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "with a buffer created with .new" do
+ it "resizes internal buffer, preserving type" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.resize(IO::Buffer::PAGE_SIZE)
+ @buffer.size.should == IO::Buffer::PAGE_SIZE
+ @buffer.internal?.should be_true
+ @buffer.mapped?.should be_false
+ end
+
+ platform_is :linux do
+ it "resizes mapped buffer, preserving type" do
+ @buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE, IO::Buffer::MAPPED)
+ @buffer.resize(4)
+ @buffer.size.should == 4
+ @buffer.internal?.should be_false
+ @buffer.mapped?.should be_true
+ end
+ end
+
+ platform_is_not :linux do
+ it "resizes mapped buffer, changing type to internal" do
+ @buffer = IO::Buffer.new(IO::Buffer::PAGE_SIZE, IO::Buffer::MAPPED)
+ @buffer.resize(4)
+ @buffer.size.should == 4
+ @buffer.internal?.should be_true
+ @buffer.mapped?.should be_false
+ end
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "disallows resizing shared buffer, raising IO::Buffer::AccessError" do
+ File.open(__FILE__, "r+") do |file|
+ @buffer = IO::Buffer.map(file)
+ -> { @buffer.resize(10) }.should raise_error(IO::Buffer::AccessError, "Cannot resize external buffer!")
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "resizes private buffer, discarding excess contents" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::PRIVATE)
+ @buffer.resize(10)
+ @buffer.size.should == 10
+ @buffer.get_string.should == "require_re"
+ @buffer.resize(12)
+ @buffer.size.should == 12
+ @buffer.get_string.should == "require_re\0\0"
+ end
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ context "without a block" do
+ it "disallows resizing, raising IO::Buffer::AccessError" do
+ @buffer = IO::Buffer.for(+"test")
+ -> { @buffer.resize(10) }.should raise_error(IO::Buffer::AccessError, "Cannot resize external buffer!")
+ end
+ end
+
+ context "with a block" do
+ it "disallows resizing, raising IO::Buffer::AccessError" do
+ IO::Buffer.for(+'test') do |buffer|
+ -> { buffer.resize(10) }.should raise_error(IO::Buffer::AccessError, "Cannot resize external buffer!")
+ end
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ context "with a String-backed buffer created with .string" do
+ it "disallows resizing, raising IO::Buffer::AccessError" do
+ IO::Buffer.string(4) do |buffer|
+ -> { buffer.resize(10) }.should raise_error(IO::Buffer::AccessError, "Cannot resize external buffer!")
+ end
+ end
+ end
+ end
+
+ context "with a null buffer" do
+ it "allows resizing a 0-sized buffer, creating a regular buffer according to new size" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.resize(IO::Buffer::PAGE_SIZE)
+ @buffer.size.should == IO::Buffer::PAGE_SIZE
+ @buffer.internal?.should be_false
+ @buffer.mapped?.should be_true
+ end
+
+ it "allows resizing after a free, creating a regular buffer according to new size" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.free
+ @buffer.resize(10)
+ @buffer.size.should == 10
+ @buffer.internal?.should be_true
+ @buffer.mapped?.should be_false
+ end
+ end
+
+ it "allows resizing to 0, freeing memory" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.resize(0)
+ @buffer.null?.should be_true
+ end
+
+ it "can be called repeatedly" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.resize(10)
+ @buffer.resize(27)
+ @buffer.resize(1)
+ @buffer.size.should == 1
+ end
+
+ it "always clears extra memory" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.set_string("test")
+ # This should not cause a re-allocation, just a technical resizing,
+ # even with very aggressive memory allocation.
+ @buffer.resize(2)
+ @buffer.resize(4)
+ @buffer.get_string.should == "te\0\0"
+ end
+
+ it "is disallowed while locked, raising IO::Buffer::LockedError" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ -> { @buffer.resize(10) }.should raise_error(IO::Buffer::LockedError, "Cannot resize locked buffer!")
+ end
+ end
+
+ it "raises ArgumentError if size is negative" do
+ @buffer = IO::Buffer.new(4)
+ -> { @buffer.resize(-1) }.should raise_error(ArgumentError, "Size can't be negative!")
+ end
+
+ it "raises TypeError if size is not an Integer" do
+ @buffer = IO::Buffer.new(4)
+ -> { @buffer.resize(nil) }.should raise_error(TypeError, "not an Integer")
+ -> { @buffer.resize(10.0) }.should raise_error(TypeError, "not an Integer")
+ end
+
+ context "with a slice of a buffer" do
+ # Current behavior of slice resizing seems unintended (it's undocumented, too).
+ # It either creates a completely new buffer, or breaks the slice on size 0.
+ it "needs to be reviewed for spec completeness"
+ end
+end
diff --git a/spec/ruby/core/io/buffer/shared/null_and_empty.rb b/spec/ruby/core/io/buffer/shared/null_and_empty.rb
new file mode 100644
index 0000000000..c8fe9e5e46
--- /dev/null
+++ b/spec/ruby/core/io/buffer/shared/null_and_empty.rb
@@ -0,0 +1,59 @@
+describe :io_buffer_null_and_empty, shared: true do
+ it "is false for a buffer with size > 0" do
+ @buffer = IO::Buffer.new(1)
+ @buffer.send(@method).should be_false
+ end
+
+ it "is false for a slice with length > 0" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice(1, 2).send(@method).should be_false
+ end
+
+ it "is false for a file-mapped buffer" do
+ File.open(__FILE__, "rb") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.send(@method).should be_false
+ end
+ end
+
+ it "is false for a non-empty String-backed buffer created with .for" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.send(@method).should be_false
+ end
+
+ ruby_version_is "3.3" do
+ it "is false for a non-empty String-backed buffer created with .string" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.send(@method).should be_false
+ end
+ end
+ end
+
+ it "is true for a 0-sized buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.send(@method).should be_true
+ end
+
+ it "is true for a slice of a 0-sized buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.slice(0, 0).send(@method).should be_true
+ end
+
+ it "is true for a freed buffer" do
+ @buffer = IO::Buffer.new(1)
+ @buffer.free
+ @buffer.send(@method).should be_true
+ end
+
+ it "is true for a buffer resized to 0" do
+ @buffer = IO::Buffer.new(1)
+ @buffer.resize(0)
+ @buffer.send(@method).should be_true
+ end
+
+ it "is true for a buffer whose memory was transferred" do
+ buffer = IO::Buffer.new(1)
+ @buffer = buffer.transfer
+ buffer.send(@method).should be_true
+ end
+end
diff --git a/spec/ruby/core/io/buffer/shared_spec.rb b/spec/ruby/core/io/buffer/shared_spec.rb
new file mode 100644
index 0000000000..f2a638cf39
--- /dev/null
+++ b/spec/ruby/core/io/buffer/shared_spec.rb
@@ -0,0 +1,117 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#shared?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "with a buffer created with .new" do
+ it "is false for an internal buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::INTERNAL)
+ @buffer.shared?.should be_false
+ end
+
+ it "is false for a mapped buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ @buffer.shared?.should be_false
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "is true for a regular mapping" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.shared?.should be_true
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "is false for a private mapping" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE)
+ @buffer.shared?.should be_false
+ end
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ it "is false for a buffer created without a block" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.shared?.should be_false
+ end
+
+ it "is false for a buffer created with a block" do
+ IO::Buffer.for(+"test") do |buffer|
+ buffer.shared?.should be_false
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ context "with a String-backed buffer created with .string" do
+ it "is false" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.shared?.should be_false
+ end
+ end
+ end
+ end
+
+ # Always false for slices
+ context "with a slice of a buffer" do
+ context "created with .new" do
+ it "is false when slicing an internal buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.slice.shared?.should be_false
+ end
+
+ it "is false when slicing a mapped buffer" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ @buffer.slice.shared?.should be_false
+ end
+ end
+
+ context "created with .map" do
+ it "is false when slicing a regular file-backed buffer" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.slice.shared?.should be_false
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "is false when slicing a private file-backed buffer" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY | IO::Buffer::PRIVATE)
+ @buffer.slice.shared?.should be_false
+ end
+ end
+ end
+ end
+
+ context "created with .for" do
+ it "is false when slicing a buffer created without a block" do
+ @buffer = IO::Buffer.for("test")
+ @buffer.slice.shared?.should be_false
+ end
+
+ it "is false when slicing a buffer created with a block" do
+ IO::Buffer.for(+"test") do |buffer|
+ buffer.slice.shared?.should be_false
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ context "created with .string" do
+ it "is false" do
+ IO::Buffer.string(4) do |buffer|
+ buffer.slice.shared?.should be_false
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/transfer_spec.rb b/spec/ruby/core/io/buffer/transfer_spec.rb
new file mode 100644
index 0000000000..cb8c843ff2
--- /dev/null
+++ b/spec/ruby/core/io/buffer/transfer_spec.rb
@@ -0,0 +1,118 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#transfer" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ context "with a buffer created with .new" do
+ it "transfers internal memory to a new buffer, nullifying the original" do
+ buffer = IO::Buffer.new(4)
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should be_true
+ end
+
+ it "transfers mapped memory to a new buffer, nullifying the original" do
+ buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should be_true
+ end
+ end
+
+ context "with a file-backed buffer created with .map" do
+ it "transfers mapped memory to a new buffer, nullifying the original" do
+ File.open(__FILE__, "r") do |file|
+ buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should be_true
+ end
+ end
+ end
+
+ context "with a String-backed buffer created with .for" do
+ context "without a block" do
+ it "transfers memory to a new buffer, nullifying the original" do
+ buffer = IO::Buffer.for("test")
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should be_true
+ end
+ end
+
+ context "with a block" do
+ it "transfers memory to a new buffer, breaking the transaction by nullifying the original" do
+ IO::Buffer.for(+"test") do |buffer|
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should be_true
+ end
+ @buffer.null?.should be_false
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ context "with a String-backed buffer created with .string" do
+ it "transfers memory to a new buffer, breaking the transaction by nullifying the original" do
+ IO::Buffer.string(4) do |buffer|
+ info = buffer.to_s
+ @buffer = buffer.transfer
+ @buffer.to_s.should == info
+ buffer.null?.should be_true
+ end
+ @buffer.null?.should be_false
+ end
+ end
+ end
+
+ it "allows multiple transfers" do
+ buffer_1 = IO::Buffer.new(4)
+ buffer_2 = buffer_1.transfer
+ @buffer = buffer_2.transfer
+ buffer_1.null?.should be_true
+ buffer_2.null?.should be_true
+ @buffer.null?.should be_false
+ end
+
+ it "is disallowed while locked, raising IO::Buffer::LockedError" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.locked do
+ -> { @buffer.transfer }.should raise_error(IO::Buffer::LockedError, "Cannot transfer ownership of locked buffer!")
+ end
+ end
+
+ context "with a slice of a buffer" do
+ it "transfers source to a new slice, not touching the buffer" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(0, 2)
+ @buffer.set_string("test")
+
+ new_slice = slice.transfer
+ slice.null?.should be_true
+ new_slice.null?.should be_false
+ @buffer.null?.should be_false
+
+ new_slice.set_string("ea")
+ @buffer.get_string.should == "east"
+ end
+
+ it "nullifies buffer, invalidating the slice" do
+ buffer = IO::Buffer.new(4)
+ slice = buffer.slice(0, 2)
+ @buffer = buffer.transfer
+
+ slice.null?.should be_false
+ slice.valid?.should be_false
+ -> { slice.get_string }.should raise_error(IO::Buffer::InvalidatedError, "Buffer has been invalidated!")
+ end
+ end
+end
diff --git a/spec/ruby/core/io/buffer/valid_spec.rb b/spec/ruby/core/io/buffer/valid_spec.rb
new file mode 100644
index 0000000000..680a35ae9a
--- /dev/null
+++ b/spec/ruby/core/io/buffer/valid_spec.rb
@@ -0,0 +1,110 @@
+require_relative '../../../spec_helper'
+
+describe "IO::Buffer#valid?" do
+ after :each do
+ @buffer&.free
+ @buffer = nil
+ end
+
+ # Non-slices are always valid
+ context "with a non-slice buffer" do
+ it "is true for a regular buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.valid?.should be_true
+ end
+
+ it "is true for a 0-size buffer" do
+ @buffer = IO::Buffer.new(0)
+ @buffer.valid?.should be_true
+ end
+
+ it "is true for a freed buffer" do
+ @buffer = IO::Buffer.new(4)
+ @buffer.free
+ @buffer.valid?.should be_true
+ end
+
+ it "is true for a freed file-backed buffer" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ @buffer.valid?.should be_true
+ @buffer.free
+ @buffer.valid?.should be_true
+ end
+ end
+
+ it "is true for a freed string-backed buffer" do
+ @buffer = IO::Buffer.for("hello")
+ @buffer.valid?.should be_true
+ @buffer.free
+ @buffer.valid?.should be_true
+ end
+ end
+
+ # "A buffer becomes invalid if it is a slice of another buffer (or string)
+ # which has been freed or re-allocated at a different address."
+ context "with a slice" do
+ it "is true for a slice of a live buffer" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(0, 2)
+ slice.valid?.should be_true
+ end
+
+ context "when buffer is resized" do
+ it "is false when slice becomes outside the buffer" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(2, 2)
+ @buffer.resize(3)
+ slice.valid?.should be_false
+ end
+
+ platform_is_not :linux do
+ # This test does not cause a copy-resize on Linux.
+ # `#resize` MAY cause the buffer to move, but there is no guarantee.
+ it "is false when buffer is copied on resize" do
+ @buffer = IO::Buffer.new(4, IO::Buffer::MAPPED)
+ slice = @buffer.slice(0, 2)
+ @buffer.resize(8)
+ slice.valid?.should be_false
+ end
+ end
+ end
+
+ it "is false for a slice of a transferred buffer" do
+ buffer = IO::Buffer.new(4)
+ slice = buffer.slice(0, 2)
+ @buffer = buffer.transfer
+ slice.valid?.should be_false
+ end
+
+ it "is false for a slice of a freed buffer" do
+ @buffer = IO::Buffer.new(4)
+ slice = @buffer.slice(0, 2)
+ @buffer.free
+ slice.valid?.should be_false
+ end
+
+ it "is false for a slice of a freed file-backed buffer" do
+ File.open(__FILE__, "r") do |file|
+ @buffer = IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)
+ slice = @buffer.slice(0, 2)
+ slice.valid?.should be_true
+ @buffer.free
+ slice.valid?.should be_false
+ end
+ end
+
+ it "is true for a slice of a freed string-backed buffer while string is alive" do
+ @buffer = IO::Buffer.for("alive")
+ slice = @buffer.slice(0, 2)
+ slice.valid?.should be_true
+ @buffer.free
+ slice.valid?.should be_true
+ end
+
+ # There probably should be a test with a garbage-collected string,
+ # but it's not clear how to force that.
+
+ it "needs to be reviewed for spec completeness"
+ end
+end
diff --git a/spec/ruby/core/io/external_encoding_spec.rb b/spec/ruby/core/io/external_encoding_spec.rb
index 2fcf1c7218..7765c6c0f5 100644
--- a/spec/ruby/core/io/external_encoding_spec.rb
+++ b/spec/ruby/core/io/external_encoding_spec.rb
@@ -94,12 +94,10 @@ describe "IO#external_encoding" do
rm_r @name
end
- ruby_version_is '3.1' do
- it "can be retrieved from a closed stream" do
- io = IOSpecs.io_fixture("lines.txt", "r")
- io.close
- io.external_encoding.should equal(Encoding.default_external)
- end
+ it "can be retrieved from a closed stream" do
+ io = IOSpecs.io_fixture("lines.txt", "r")
+ io.close
+ io.external_encoding.should equal(Encoding.default_external)
end
describe "with 'r' mode" do
diff --git a/spec/ruby/core/io/foreach_spec.rb b/spec/ruby/core/io/foreach_spec.rb
index c361d27879..6abe8901ba 100644
--- a/spec/ruby/core/io/foreach_spec.rb
+++ b/spec/ruby/core/io/foreach_spec.rb
@@ -14,33 +14,35 @@ describe "IO.foreach" do
IO.foreach(@name) { $..should == @count += 1 }
end
- describe "when the filename starts with |" do
- it "gets data from the standard out of the subprocess" do
- cmd = "|sh -c 'echo hello;echo line2'"
- platform_is :windows do
- cmd = "|cmd.exe /C echo hello&echo line2"
- end
+ ruby_version_is ""..."4.0" do
+ describe "when the filename starts with |" do
+ it "gets data from the standard out of the subprocess" do
+ cmd = "|sh -c 'echo hello;echo line2'"
+ platform_is :windows do
+ cmd = "|cmd.exe /C echo hello&echo line2"
+ end
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.foreach(cmd) { |l| ScratchPad << l }
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.foreach(cmd) { |l| ScratchPad << l }
+ end
+ ScratchPad.recorded.should == ["hello\n", "line2\n"]
end
- ScratchPad.recorded.should == ["hello\n", "line2\n"]
- end
- platform_is_not :windows do
- it "gets data from a fork when passed -" do
- parent_pid = $$
+ platform_is_not :windows do
+ it "gets data from a fork when passed -" do
+ parent_pid = $$
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.foreach("|-") { |l| ScratchPad << l }
- end
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.foreach("|-") { |l| ScratchPad << l }
+ end
- if $$ == parent_pid
- ScratchPad.recorded.should == ["hello\n", "from a fork\n"]
- else # child
- puts "hello"
- puts "from a fork"
- exit!
+ if $$ == parent_pid
+ ScratchPad.recorded.should == ["hello\n", "from a fork\n"]
+ else # child
+ puts "hello"
+ puts "from a fork"
+ exit!
+ end
end
end
end
diff --git a/spec/ruby/core/io/internal_encoding_spec.rb b/spec/ruby/core/io/internal_encoding_spec.rb
index 60afaf2ebd..7a583d4bcb 100644
--- a/spec/ruby/core/io/internal_encoding_spec.rb
+++ b/spec/ruby/core/io/internal_encoding_spec.rb
@@ -113,12 +113,10 @@ describe "IO#internal_encoding" do
Encoding.default_internal = @internal
end
- ruby_version_is '3.1' do
- it "can be retrieved from a closed stream" do
- io = IOSpecs.io_fixture("lines.txt", "r")
- io.close
- io.internal_encoding.should equal(Encoding.default_internal)
- end
+ it "can be retrieved from a closed stream" do
+ io = IOSpecs.io_fixture("lines.txt", "r")
+ io.close
+ io.internal_encoding.should equal(Encoding.default_internal)
end
describe "with 'r' mode" do
diff --git a/spec/ruby/core/io/path_spec.rb b/spec/ruby/core/io/path_spec.rb
index 8145c32f39..798adb2163 100644
--- a/spec/ruby/core/io/path_spec.rb
+++ b/spec/ruby/core/io/path_spec.rb
@@ -1,14 +1,12 @@
require_relative '../../spec_helper'
describe "IO#path" do
- ruby_version_is "3.2" do
- it "returns the path of the file associated with the IO object" do
- path = tmp("io_path.txt")
- File.open(path, "w") do |file|
- IO.new(file.fileno, path: file.path, autoclose: false).path.should == file.path
- end
- ensure
- File.unlink(path)
+ it "returns the path of the file associated with the IO object" do
+ path = tmp("io_path.txt")
+ File.open(path, "w") do |file|
+ IO.new(file.fileno, path: file.path, autoclose: false).path.should == file.path
end
+ ensure
+ File.unlink(path)
end
end
diff --git a/spec/ruby/core/io/popen_spec.rb b/spec/ruby/core/io/popen_spec.rb
index e9d32c5c7d..6043862614 100644
--- a/spec/ruby/core/io/popen_spec.rb
+++ b/spec/ruby/core/io/popen_spec.rb
@@ -95,6 +95,22 @@ describe "IO.popen" do
@io = IO.popen(ruby_cmd('exit 0'), mode)
end
+ it "accepts a path using the chdir: keyword argument" do
+ path = File.dirname(@fname)
+
+ @io = IO.popen(ruby_cmd("puts Dir.pwd"), "r", chdir: path)
+ @io.read.chomp.should == path
+ end
+
+ it "accepts a path using the chdir: keyword argument and a coercible path" do
+ path = File.dirname(@fname)
+ object = mock("path")
+ object.should_receive(:to_path).and_return(path)
+
+ @io = IO.popen(ruby_cmd("puts Dir.pwd"), "r", chdir: object)
+ @io.read.chomp.should == path
+ end
+
describe "with a block" do
it "yields an open IO to the block" do
IO.popen(ruby_cmd('exit'), "r") do |io|
diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb
index 567daa55df..988ec2ce30 100644
--- a/spec/ruby/core/io/read_spec.rb
+++ b/spec/ruby/core/io/read_spec.rb
@@ -168,76 +168,78 @@ describe "IO.read" do
end
end
-describe "IO.read from a pipe" do
- it "runs the rest as a subprocess and returns the standard output" do
- cmd = "|sh -c 'echo hello'"
- platform_is :windows do
- cmd = "|cmd.exe /C echo hello"
- end
-
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.read(cmd).should == "hello\n"
- end
- end
-
- platform_is_not :windows do
- it "opens a pipe to a fork if the rest is -" do
- str = nil
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- str = IO.read("|-")
+ruby_version_is ""..."4.0" do
+ describe "IO.read from a pipe" do
+ it "runs the rest as a subprocess and returns the standard output" do
+ cmd = "|sh -c 'echo hello'"
+ platform_is :windows do
+ cmd = "|cmd.exe /C echo hello"
end
- if str # parent
- str.should == "hello from child\n"
- else #child
- puts "hello from child"
- exit!
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.read(cmd).should == "hello\n"
end
end
- end
- it "reads only the specified number of bytes requested" do
- cmd = "|sh -c 'echo hello'"
- platform_is :windows do
- cmd = "|cmd.exe /C echo hello"
- end
+ platform_is_not :windows do
+ it "opens a pipe to a fork if the rest is -" do
+ str = nil
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ str = IO.read("|-")
+ end
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.read(cmd, 1).should == "h"
+ if str # parent
+ str.should == "hello from child\n"
+ else #child
+ puts "hello from child"
+ exit!
+ end
+ end
end
- end
- platform_is_not :windows do
- it "raises Errno::ESPIPE if passed an offset" do
- -> {
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.read("|sh -c 'echo hello'", 1, 1)
- end
- }.should raise_error(Errno::ESPIPE)
+ it "reads only the specified number of bytes requested" do
+ cmd = "|sh -c 'echo hello'"
+ platform_is :windows do
+ cmd = "|cmd.exe /C echo hello"
+ end
+
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.read(cmd, 1).should == "h"
+ end
end
- end
- quarantine! do # The process tried to write to a nonexistent pipe.
- platform_is :windows do
- # TODO: It should raise Errno::ESPIPE on Windows as well
- # once https://bugs.ruby-lang.org/issues/12230 is fixed.
- it "raises Errno::EINVAL if passed an offset" do
+ platform_is_not :windows do
+ it "raises Errno::ESPIPE if passed an offset" do
-> {
suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- IO.read("|cmd.exe /C echo hello", 1, 1)
+ IO.read("|sh -c 'echo hello'", 1, 1)
end
- }.should raise_error(Errno::EINVAL)
+ }.should raise_error(Errno::ESPIPE)
end
end
- end
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19630
- it "warns about deprecation given a path with a pipe" do
- cmd = "|echo ok"
- -> {
- IO.read(cmd)
- }.should complain(/IO process creation with a leading '\|'/)
+ quarantine! do # The process tried to write to a nonexistent pipe.
+ platform_is :windows do
+ # TODO: It should raise Errno::ESPIPE on Windows as well
+ # once https://bugs.ruby-lang.org/issues/12230 is fixed.
+ it "raises Errno::EINVAL if passed an offset" do
+ -> {
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.read("|cmd.exe /C echo hello", 1, 1)
+ end
+ }.should raise_error(Errno::EINVAL)
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ # https://bugs.ruby-lang.org/issues/19630
+ it "warns about deprecation" do
+ cmd = "|echo ok"
+ -> {
+ IO.read(cmd)
+ }.should complain(/IO process creation with a leading '\|'/)
+ end
end
end
end
diff --git a/spec/ruby/core/io/readlines_spec.rb b/spec/ruby/core/io/readlines_spec.rb
index 3a6ff3d0f3..b4770775d1 100644
--- a/spec/ruby/core/io/readlines_spec.rb
+++ b/spec/ruby/core/io/readlines_spec.rb
@@ -174,45 +174,47 @@ describe "IO.readlines" do
$_.should == "test"
end
- describe "when passed a string that starts with a |" do
- it "gets data from the standard out of the subprocess" do
- cmd = "|sh -c 'echo hello;echo line2'"
- platform_is :windows do
- cmd = "|cmd.exe /C echo hello&echo line2"
- end
-
- lines = nil
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- lines = IO.readlines(cmd)
- end
- lines.should == ["hello\n", "line2\n"]
- end
+ ruby_version_is ""..."4.0" do
+ describe "when passed a string that starts with a |" do
+ it "gets data from the standard out of the subprocess" do
+ cmd = "|sh -c 'echo hello;echo line2'"
+ platform_is :windows do
+ cmd = "|cmd.exe /C echo hello&echo line2"
+ end
- platform_is_not :windows do
- it "gets data from a fork when passed -" do
lines = nil
suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- lines = IO.readlines("|-")
+ lines = IO.readlines(cmd)
end
+ lines.should == ["hello\n", "line2\n"]
+ end
- if lines # parent
- lines.should == ["hello\n", "from a fork\n"]
- else
- puts "hello"
- puts "from a fork"
- exit!
+ platform_is_not :windows do
+ it "gets data from a fork when passed -" do
+ lines = nil
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ lines = IO.readlines("|-")
+ end
+
+ if lines # parent
+ lines.should == ["hello\n", "from a fork\n"]
+ else
+ puts "hello"
+ puts "from a fork"
+ exit!
+ end
end
end
end
- end
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19630
- it "warns about deprecation given a path with a pipe" do
- cmd = "|echo ok"
- -> {
- IO.readlines(cmd)
- }.should complain(/IO process creation with a leading '\|'/)
+ ruby_version_is "3.3" do
+ # https://bugs.ruby-lang.org/issues/19630
+ it "warns about deprecation given a path with a pipe" do
+ cmd = "|echo ok"
+ -> {
+ IO.readlines(cmd)
+ }.should complain(/IO process creation with a leading '\|'/)
+ end
end
end
diff --git a/spec/ruby/core/io/readpartial_spec.rb b/spec/ruby/core/io/readpartial_spec.rb
index 0852f20b2d..176c33cf9e 100644
--- a/spec/ruby/core/io/readpartial_spec.rb
+++ b/spec/ruby/core/io/readpartial_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -93,12 +93,15 @@ describe "IO#readpartial" do
@rd.readpartial(0).should == ""
end
- ruby_bug "#18421", ""..."3.0.4" do
- it "clears and returns the given buffer if the length argument is 0" do
- buffer = +"existing content"
- @rd.readpartial(0, buffer).should == buffer
- buffer.should == ""
- end
+ it "raises IOError if the stream is closed and the length argument is 0" do
+ @rd.close
+ -> { @rd.readpartial(0) }.should raise_error(IOError, "closed stream")
+ end
+
+ it "clears and returns the given buffer if the length argument is 0" do
+ buffer = +"existing content"
+ @rd.readpartial(0, buffer).should == buffer
+ buffer.should == ""
end
it "preserves the encoding of the given buffer" do
diff --git a/spec/ruby/core/io/shared/each.rb b/spec/ruby/core/io/shared/each.rb
index aca622834f..0747f31b8a 100644
--- a/spec/ruby/core/io/shared/each.rb
+++ b/spec/ruby/core/io/shared/each.rb
@@ -202,20 +202,10 @@ describe :io_each, shared: true do
end
describe "when passed chomp and nil as a separator" do
- ruby_version_is "3.2" do
- it "yields self's content" do
- @io.pos = 100
- @io.send(@method, nil, chomp: true) { |s| ScratchPad << s }
- ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six.\n"]
- end
- end
-
- ruby_version_is ""..."3.2" do
- it "yields self's content without trailing new line character" do
- @io.pos = 100
- @io.send(@method, nil, chomp: true) { |s| ScratchPad << s }
- ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six."]
- end
+ it "yields self's content" do
+ @io.pos = 100
+ @io.send(@method, nil, chomp: true) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six.\n"]
end
end
diff --git a/spec/ruby/core/io/shared/gets_ascii.rb b/spec/ruby/core/io/shared/gets_ascii.rb
index 2a8fe3c9a5..2bd5470d99 100644
--- a/spec/ruby/core/io/shared/gets_ascii.rb
+++ b/spec/ruby/core/io/shared/gets_ascii.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :io_gets_ascii, shared: true do
describe "with ASCII separator" do
before :each do
diff --git a/spec/ruby/core/io/shared/new.rb b/spec/ruby/core/io/shared/new.rb
index cba5f33ebf..e84133493c 100644
--- a/spec/ruby/core/io/shared/new.rb
+++ b/spec/ruby/core/io/shared/new.rb
@@ -208,6 +208,26 @@ describe :io_new, shared: true do
@io.internal_encoding.to_s.should == 'IBM866'
end
+ it "does not use binary encoding when mode encoding is specified along with binmode: true option" do
+ @io = IO.send(@method, @fd, 'w:iso-8859-1', binmode: true)
+ @io.external_encoding.to_s.should == 'ISO-8859-1'
+ end
+
+ it "does not use textmode argument when mode encoding is specified" do
+ @io = IO.send(@method, @fd, 'w:ascii-8bit', textmode: true)
+ @io.external_encoding.to_s.should == 'ASCII-8BIT'
+ end
+
+ it "does not use binmode argument when external encoding is specified via the :external_encoding option" do
+ @io = IO.send(@method, @fd, 'w', binmode: true, external_encoding: 'iso-8859-1')
+ @io.external_encoding.to_s.should == 'ISO-8859-1'
+ end
+
+ it "does not use textmode argument when external encoding is specified via the :external_encoding option" do
+ @io = IO.send(@method, @fd, 'w', textmode: true, external_encoding: 'ascii-8bit')
+ @io.external_encoding.to_s.should == 'ASCII-8BIT'
+ end
+
it "raises ArgumentError for nil options" do
-> {
IO.send(@method, @fd, 'w', nil)
@@ -325,6 +345,9 @@ describe :io_new_errors, shared: true do
@io = IO.send(@method, @fd, 'w:ISO-8859-1', external_encoding: 'ISO-8859-1')
}.should raise_error(ArgumentError)
-> {
+ @io = IO.send(@method, @fd, 'w:ISO-8859-1', internal_encoding: 'ISO-8859-1')
+ }.should raise_error(ArgumentError)
+ -> {
@io = IO.send(@method, @fd, 'w:ISO-8859-1:UTF-8', internal_encoding: 'ISO-8859-1')
}.should raise_error(ArgumentError)
end
diff --git a/spec/ruby/core/io/sysread_spec.rb b/spec/ruby/core/io/sysread_spec.rb
index 8851214283..d56a27b3af 100644
--- a/spec/ruby/core/io/sysread_spec.rb
+++ b/spec/ruby/core/io/sysread_spec.rb
@@ -131,9 +131,7 @@ describe "IO#sysread" do
@read.sysread(3).should == "ab"
end
- guard_not -> { platform_is :windows and ruby_version_is ""..."3.2" } do # https://bugs.ruby-lang.org/issues/18880
- it "raises ArgumentError when length is less than 0" do
- -> { @read.sysread(-1) }.should raise_error(ArgumentError)
- end
+ it "raises ArgumentError when length is less than 0" do
+ -> { @read.sysread(-1) }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/core/io/write_nonblock_spec.rb b/spec/ruby/core/io/write_nonblock_spec.rb
index c403c864fd..5bfc690f9b 100644
--- a/spec/ruby/core/io/write_nonblock_spec.rb
+++ b/spec/ruby/core/io/write_nonblock_spec.rb
@@ -43,7 +43,7 @@ platform_is_not :windows do
it "checks if the file is writable if writing zero bytes" do
-> {
- @readonly_file.write_nonblock("")
+ @readonly_file.write_nonblock("")
}.should raise_error(IOError)
end
end
diff --git a/spec/ruby/core/io/write_spec.rb b/spec/ruby/core/io/write_spec.rb
index 4a26f8dbaf..e58100f846 100644
--- a/spec/ruby/core/io/write_spec.rb
+++ b/spec/ruby/core/io/write_spec.rb
@@ -220,7 +220,7 @@ describe "IO.write" do
end
end
- ruby_version_is "3.3" do
+ ruby_version_is "3.3"..."4.0" do
# https://bugs.ruby-lang.org/issues/19630
it "warns about deprecation given a path with a pipe" do
-> {
diff --git a/spec/ruby/core/kernel/Float_spec.rb b/spec/ruby/core/kernel/Float_spec.rb
index 0f83cb5824..9c436b05f7 100644
--- a/spec/ruby/core/kernel/Float_spec.rb
+++ b/spec/ruby/core/kernel/Float_spec.rb
@@ -157,6 +157,26 @@ describe :kernel_float, shared: true do
@object.send(:Float, "1\t\n").should == 1.0
end
+ ruby_version_is ""..."3.4" do
+ it "raises ArgumentError if a fractional part is missing" do
+ -> { @object.send(:Float, "1.") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "+1.") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "-1.") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1.e+0") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "1.e-2") }.should raise_error(ArgumentError)
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "allows String representation without a fractional part" do
+ @object.send(:Float, "1.").should == 1.0
+ @object.send(:Float, "+1.").should == 1.0
+ @object.send(:Float, "-1.").should == -1.0
+ @object.send(:Float, "1.e+0").should == 1.0
+ @object.send(:Float, "1.e-2").should be_close(0.01, TOLERANCE)
+ end
+ end
+
%w(e E).each do |e|
it "raises an ArgumentError if #{e} is the trailing character" do
-> { @object.send(:Float, "2#{e}") }.should raise_error(ArgumentError)
@@ -204,59 +224,107 @@ describe :kernel_float, shared: true do
end
end
- describe "for hexadecimal literals with binary exponent" do
- %w(p P).each do |p|
- it "interprets the fractional part (on the left side of '#{p}') in hexadecimal" do
- @object.send(:Float, "0x10#{p}0").should == 16.0
- end
-
- it "interprets the exponent (on the right of '#{p}') in decimal" do
- @object.send(:Float, "0x1#{p}10").should == 1024.0
- end
-
- it "raises an ArgumentError if #{p} is the trailing character" do
- -> { @object.send(:Float, "0x1#{p}") }.should raise_error(ArgumentError)
- end
-
- it "raises an ArgumentError if #{p} is the leading character" do
- -> { @object.send(:Float, "0x#{p}1") }.should raise_error(ArgumentError)
- end
+ context "for hexadecimal literals" do
+ it "interprets the 0x prefix as hexadecimal" do
+ @object.send(:Float, "0x10").should == 16.0
+ @object.send(:Float, "0x0F").should == 15.0
+ @object.send(:Float, "0x0f").should == 15.0
+ end
- it "returns Infinity for '0x1#{p}10000'" do
- @object.send(:Float, "0x1#{p}10000").should == Float::INFINITY
- end
+ it "interprets negative hex value" do
+ @object.send(:Float, "-0x10").should == -16.0
+ end
- it "returns 0 for '0x1#{p}-10000'" do
- @object.send(:Float, "0x1#{p}-10000").should == 0
- end
+ it "accepts embedded _ if the number does not contain a-f" do
+ @object.send(:Float, "0x1_0").should == 16.0
+ end
- it "allows embedded _ in a number on either side of the #{p}" do
- @object.send(:Float, "0x1_0#{p}10").should == 16384.0
- @object.send(:Float, "0x10#{p}1_0").should == 16384.0
- @object.send(:Float, "0x1_0#{p}1_0").should == 16384.0
+ ruby_version_is ""..."3.4.3" do
+ it "does not accept embedded _ if the number contains a-f" do
+ -> { @object.send(:Float, "0x1_0a") }.should raise_error(ArgumentError)
+ @object.send(:Float, "0x1_0a", exception: false).should be_nil
end
+ end
- it "raises an exception if a space is embedded on either side of the '#{p}'" do
- -> { @object.send(:Float, "0x1 0#{p}10") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "0x10#{p}1 0") }.should raise_error(ArgumentError)
+ ruby_version_is "3.4.3" do
+ it "accepts embedded _ if the number contains a-f" do
+ @object.send(:Float, "0x1_0a").should == 0x10a.to_f
end
+ end
- it "raises an exception if there's a leading _ on either side of the '#{p}'" do
- -> { @object.send(:Float, "0x_10#{p}10") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "0x10#{p}_10") }.should raise_error(ArgumentError)
- end
+ it "does not accept _ before, after or inside the 0x prefix" do
+ -> { @object.send(:Float, "_0x10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0_x10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0x_10") }.should raise_error(ArgumentError)
+ @object.send(:Float, "_0x10", exception: false).should be_nil
+ @object.send(:Float, "0_x10", exception: false).should be_nil
+ @object.send(:Float, "0x_10", exception: false).should be_nil
+ end
- it "raises an exception if there's a trailing _ on either side of the '#{p}'" do
- -> { @object.send(:Float, "0x10_#{p}10") }.should raise_error(ArgumentError)
- -> { @object.send(:Float, "0x10#{p}10_") }.should raise_error(ArgumentError)
- end
+ it "parses negative hexadecimal string as negative float" do
+ @object.send(:Float, "-0x7b").should == -123.0
+ end
- it "allows hexadecimal points on the left side of the '#{p}'" do
- @object.send(:Float, "0x1.8#{p}0").should == 1.5
+ ruby_version_is "3.4" do
+ it "accepts a fractional part" do
+ @object.send(:Float, "0x0.8").should == 0.5
end
+ end
- it "raises an ArgumentError if there's a decimal point on the right side of the '#{p}'" do
- -> { @object.send(:Float, "0x1#{p}1.0") }.should raise_error(ArgumentError)
+ describe "with binary exponent" do
+ %w(p P).each do |p|
+ it "interprets the fractional part (on the left side of '#{p}') in hexadecimal" do
+ @object.send(:Float, "0x10#{p}0").should == 16.0
+ end
+
+ it "interprets the exponent (on the right of '#{p}') in decimal" do
+ @object.send(:Float, "0x1#{p}10").should == 1024.0
+ end
+
+ it "raises an ArgumentError if #{p} is the trailing character" do
+ -> { @object.send(:Float, "0x1#{p}") }.should raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError if #{p} is the leading character" do
+ -> { @object.send(:Float, "0x#{p}1") }.should raise_error(ArgumentError)
+ end
+
+ it "returns Infinity for '0x1#{p}10000'" do
+ @object.send(:Float, "0x1#{p}10000").should == Float::INFINITY
+ end
+
+ it "returns 0 for '0x1#{p}-10000'" do
+ @object.send(:Float, "0x1#{p}-10000").should == 0
+ end
+
+ it "allows embedded _ in a number on either side of the #{p}" do
+ @object.send(:Float, "0x1_0#{p}10").should == 16384.0
+ @object.send(:Float, "0x10#{p}1_0").should == 16384.0
+ @object.send(:Float, "0x1_0#{p}1_0").should == 16384.0
+ end
+
+ it "raises an exception if a space is embedded on either side of the '#{p}'" do
+ -> { @object.send(:Float, "0x1 0#{p}10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0x10#{p}1 0") }.should raise_error(ArgumentError)
+ end
+
+ it "raises an exception if there's a leading _ on either side of the '#{p}'" do
+ -> { @object.send(:Float, "0x_10#{p}10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0x10#{p}_10") }.should raise_error(ArgumentError)
+ end
+
+ it "raises an exception if there's a trailing _ on either side of the '#{p}'" do
+ -> { @object.send(:Float, "0x10_#{p}10") }.should raise_error(ArgumentError)
+ -> { @object.send(:Float, "0x10#{p}10_") }.should raise_error(ArgumentError)
+ end
+
+ it "allows hexadecimal points on the left side of the '#{p}'" do
+ @object.send(:Float, "0x1.8#{p}0").should == 1.5
+ end
+
+ it "raises an ArgumentError if there's a decimal point on the right side of the '#{p}'" do
+ -> { @object.send(:Float, "0x1#{p}1.0") }.should raise_error(ArgumentError)
+ end
end
end
end
@@ -280,7 +348,7 @@ describe :kernel_float, shared: true do
nan2.should equal(nan)
end
- it "returns the identical Infinity if to_f is called and it returns Infinity" do
+ it "returns the identical Infinity if #to_f is called and it returns Infinity" do
infinity = infinity_value
(infinity_to_f = mock('Infinity')).should_receive(:to_f).once.and_return(infinity)
infinity2 = @object.send(:Float, infinity_to_f)
diff --git a/spec/ruby/core/kernel/Rational_spec.rb b/spec/ruby/core/kernel/Rational_spec.rb
index 2d1051db7f..cc11a35451 100644
--- a/spec/ruby/core/kernel/Rational_spec.rb
+++ b/spec/ruby/core/kernel/Rational_spec.rb
@@ -1,6 +1,236 @@
require_relative '../../spec_helper'
-require_relative '../../shared/rational/Rational'
+require_relative '../rational/fixtures/rational'
describe "Kernel.Rational" do
- it_behaves_like :kernel_Rational, :Rational
+ describe "passed Integer" do
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ it "returns a new Rational number with 1 as the denominator" do
+ Rational(1).should eql(Rational(1, 1))
+ Rational(-3).should eql(Rational(-3, 1))
+ Rational(bignum_value).should eql(Rational(bignum_value, 1))
+ end
+ end
+ end
+
+ describe "passed two integers" do
+ it "returns a new Rational number" do
+ rat = Rational(1, 2)
+ rat.numerator.should == 1
+ rat.denominator.should == 2
+ rat.should be_an_instance_of(Rational)
+
+ rat = Rational(-3, -5)
+ rat.numerator.should == 3
+ rat.denominator.should == 5
+ rat.should be_an_instance_of(Rational)
+
+ rat = Rational(bignum_value, 3)
+ rat.numerator.should == bignum_value
+ rat.denominator.should == 3
+ rat.should be_an_instance_of(Rational)
+ end
+
+ it "reduces the Rational" do
+ rat = Rational(2, 4)
+ rat.numerator.should == 1
+ rat.denominator.should == 2
+
+ rat = Rational(3, 9)
+ rat.numerator.should == 1
+ rat.denominator.should == 3
+ end
+ end
+
+ describe "when passed a String" do
+ it "converts the String to a Rational using the same method as String#to_r" do
+ r = Rational(13, 25)
+ s_r = ".52".to_r
+ r_s = Rational(".52")
+
+ r_s.should == r
+ r_s.should == s_r
+ end
+
+ it "scales the Rational value of the first argument by the Rational value of the second" do
+ Rational(".52", ".6").should == Rational(13, 15)
+ Rational(".52", "1.6").should == Rational(13, 40)
+ end
+
+ it "does not use the same method as Float#to_r" do
+ r = Rational(3, 5)
+ f_r = 0.6.to_r
+ r_s = Rational("0.6")
+
+ r_s.should == r
+ r_s.should_not == f_r
+ end
+ end
+
+ describe "when passed a Numeric" do
+ it "calls #to_r to convert the first argument to a Rational" do
+ num = RationalSpecs::SubNumeric.new(2)
+
+ Rational(num).should == Rational(2)
+ end
+ end
+
+ describe "when passed a Complex" do
+ context "[Complex]" do
+ it "returns a Rational from the real part if the imaginary part is 0" do
+ Rational(Complex(1, 0)).should == Rational(1)
+ end
+
+ it "raises a RangeError if the imaginary part is not 0" do
+ -> { Rational(Complex(1, 2)) }.should raise_error(RangeError, "can't convert 1+2i into Rational")
+ end
+ end
+
+ context "[Numeric, Complex]" do
+ it "uses the real part if the imaginary part is 0" do
+ Rational(1, Complex(2, 0)).should == Rational(1, 2)
+ end
+
+ it "divides a numerator by the Complex denominator if the imaginary part is not 0" do
+ Rational(1, Complex(2, 1)).should == Complex(2/5r, -1/5r)
+ end
+ end
+ end
+
+ context "when passed neither a Numeric nor a String" do
+ it "converts to Rational with #to_r method" do
+ obj = Object.new
+ def obj.to_r; 1/2r; end
+
+ Rational(obj).should == 1/2r
+ end
+
+ it "tries to convert to Integer with #to_int method if it does not respond to #to_r" do
+ obj = Object.new
+ def obj.to_int; 1; end
+
+ Rational(obj).should == 1r
+ end
+
+ it "raises TypeError if it neither responds to #to_r nor #to_int method" do
+ -> { Rational([]) }.should raise_error(TypeError, "can't convert Array into Rational")
+ -> { Rational({}) }.should raise_error(TypeError, "can't convert Hash into Rational")
+ -> { Rational(nil) }.should raise_error(TypeError, "can't convert nil into Rational")
+ end
+
+ it "swallows exception raised in #to_int method" do
+ object = Object.new
+ def object.to_int() raise NoMethodError; end
+
+ -> { Rational(object) }.should raise_error(TypeError)
+ -> { Rational(object, 1) }.should raise_error(TypeError)
+ -> { Rational(1, object) }.should raise_error(TypeError)
+ end
+
+ it "raises TypeError if #to_r does not return Rational" do
+ obj = Object.new
+ def obj.to_r; []; end
+
+ -> { Rational(obj) }.should raise_error(TypeError, "can't convert Object to Rational (Object#to_r gives Array)")
+ end
+ end
+
+ it "raises a ZeroDivisionError if the second argument is 0" do
+ -> { Rational(1, 0) }.should raise_error(ZeroDivisionError, "divided by 0")
+ -> { Rational(1, 0.0) }.should raise_error(ZeroDivisionError, "divided by 0")
+ end
+
+ it "raises a TypeError if the first argument is nil" do
+ -> { Rational(nil) }.should raise_error(TypeError, "can't convert nil into Rational")
+ end
+
+ it "raises a TypeError if the second argument is nil" do
+ -> { Rational(1, nil) }.should raise_error(TypeError, "can't convert nil into Rational")
+ end
+
+ it "raises a TypeError if the first argument is a Symbol" do
+ -> { Rational(:sym) }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError if the second argument is a Symbol" do
+ -> { Rational(1, :sym) }.should raise_error(TypeError)
+ end
+
+ describe "when passed exception: false" do
+ describe "and [non-Numeric]" do
+ it "swallows an error" do
+ Rational(:sym, exception: false).should == nil
+ Rational("abc", exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_r" do
+ obj = Object.new
+ def obj.to_r; raise; end
+ Rational(obj, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_int" do
+ obj = Object.new
+ def obj.to_int; raise; end
+ Rational(obj, exception: false).should == nil
+ end
+ end
+
+ describe "and [non-Numeric, Numeric]" do
+ it "swallows an error" do
+ Rational(:sym, 1, exception: false).should == nil
+ Rational("abc", 1, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_r" do
+ obj = Object.new
+ def obj.to_r; raise; end
+ Rational(obj, 1, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_int" do
+ obj = Object.new
+ def obj.to_int; raise; end
+ Rational(obj, 1, exception: false).should == nil
+ end
+ end
+
+ describe "and [anything, non-Numeric]" do
+ it "swallows an error" do
+ Rational(:sym, :sym, exception: false).should == nil
+ Rational("abc", :sym, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_r" do
+ obj = Object.new
+ def obj.to_r; raise; end
+ Rational(obj, obj, exception: false).should == nil
+ end
+
+ it "swallows an exception raised in #to_int" do
+ obj = Object.new
+ def obj.to_int; raise; end
+ Rational(obj, obj, exception: false).should == nil
+ end
+ end
+
+ describe "and non-Numeric String arguments" do
+ it "swallows an error" do
+ Rational("a", "b", exception: false).should == nil
+ Rational("a", 0, exception: false).should == nil
+ Rational(0, "b", exception: false).should == nil
+ end
+ end
+
+ describe "and nil arguments" do
+ it "swallows an error" do
+ Rational(nil, exception: false).should == nil
+ Rational(nil, nil, exception: false).should == nil
+ end
+ end
+ end
+
+ it "freezes its result" do
+ Rational(1).frozen?.should == true
+ end
end
diff --git a/spec/ruby/core/kernel/autoload_spec.rb b/spec/ruby/core/kernel/autoload_spec.rb
index 0404caec6d..5edb70541d 100644
--- a/spec/ruby/core/kernel/autoload_spec.rb
+++ b/spec/ruby/core/kernel/autoload_spec.rb
@@ -7,7 +7,9 @@ require_relative 'fixtures/classes'
autoload :KSAutoloadA, "autoload_a.rb"
autoload :KSAutoloadB, fixture(__FILE__, "autoload_b.rb")
-autoload :KSAutoloadCallsRequire, "main_autoload_not_exist.rb"
+define_autoload_KSAutoloadCallsRequire = -> {
+ autoload :KSAutoloadCallsRequire, "main_autoload_not_exist.rb"
+}
def check_autoload(const)
autoload? const
@@ -43,6 +45,7 @@ describe "Kernel#autoload" do
end
it "calls main.require(path) to load the file" do
+ define_autoload_KSAutoloadCallsRequire.call
main = TOPLEVEL_BINDING.eval("self")
main.should_receive(:require).with("main_autoload_not_exist.rb")
# The constant won't be defined since require is mocked to do nothing
diff --git a/spec/ruby/core/kernel/block_given_spec.rb b/spec/ruby/core/kernel/block_given_spec.rb
index b00bfabfc3..aece4c821d 100644
--- a/spec/ruby/core/kernel/block_given_spec.rb
+++ b/spec/ruby/core/kernel/block_given_spec.rb
@@ -5,15 +5,20 @@ describe :kernel_block_given, shared: true do
it "returns true if and only if a block is supplied" do
@object.accept_block {}.should == true
@object.accept_block_as_argument {}.should == true
+ @object.accept_block_inside_block {}.should == true
+ @object.accept_block_as_argument_inside_block {}.should == true
@object.accept_block.should == false
@object.accept_block_as_argument.should == false
+ @object.accept_block_inside_block.should == false
+ @object.accept_block_as_argument_inside_block.should == false
end
# Clarify: Based on http://www.ruby-forum.com/topic/137822 it appears
# that Matz wanted this to be true in 1.9.
it "returns false when a method defined by define_method is called with a block" do
@object.defined_block {}.should == false
+ @object.defined_block_inside_block {}.should == false
end
end
diff --git a/spec/ruby/core/kernel/caller_locations_spec.rb b/spec/ruby/core/kernel/caller_locations_spec.rb
index aaacd9a910..a917dba504 100644
--- a/spec/ruby/core/kernel/caller_locations_spec.rb
+++ b/spec/ruby/core/kernel/caller_locations_spec.rb
@@ -83,7 +83,7 @@ describe 'Kernel#caller_locations' do
end
end
- ruby_version_is "3.4" do
+ ruby_version_is "3.4"..."4.0" do
it "includes core library methods defined in Ruby" do
file, line = Kernel.instance_method(:tap).source_location
file.should.start_with?('<internal:')
@@ -94,5 +94,17 @@ describe 'Kernel#caller_locations' do
loc.path.should.start_with? "<internal:"
end
end
+
+ ruby_version_is "4.0" do
+ it "does not include core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller_locations(1, 1)[0] }
+ loc.label.should == "Kernel#tap"
+ loc.path.should == __FILE__
+ end
+ end
end
end
diff --git a/spec/ruby/core/kernel/caller_spec.rb b/spec/ruby/core/kernel/caller_spec.rb
index 33c7929a31..7cd703de5a 100644
--- a/spec/ruby/core/kernel/caller_spec.rb
+++ b/spec/ruby/core/kernel/caller_spec.rb
@@ -84,13 +84,26 @@ describe 'Kernel#caller' do
end
guard -> { Kernel.instance_method(:tap).source_location } do
- it "includes core library methods defined in Ruby" do
- file, line = Kernel.instance_method(:tap).source_location
- file.should.start_with?('<internal:')
+ ruby_version_is ""..."4.0" do
+ it "includes core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller(1, 1)[0] }
+ loc.should =~ /\A<internal:.*in [`'](?:Kernel#)?tap'\z/
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "includes core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
- loc = nil
- tap { loc = caller(1, 1)[0] }
- loc.should =~ /\A<internal:.*in [`'](?:Kernel#)?tap'\z/
+ loc = nil
+ tap { loc = caller(1, 1)[0] }
+ loc.should =~ /\A#{ __FILE__ }:.*in [`'](?:Kernel#)?tap'\z/
+ end
end
end
end
diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb
index 5f4cd27da0..e027294347 100644
--- a/spec/ruby/core/kernel/eval_spec.rb
+++ b/spec/ruby/core/kernel/eval_spec.rb
@@ -175,6 +175,75 @@ describe "Kernel#eval" do
end
end
+ context "parameter forwarding" do
+ it "allows anonymous rest parameter forwarding" do
+ object = Object.new
+ def object.foo(a, b, c)
+ [a, b, c]
+ end
+ def object.bar(*)
+ eval "foo(*)"
+ end
+
+ object.bar(1, 2, 3).should == [1, 2, 3]
+ end
+
+ it "allows anonymous keyword parameters forwarding" do
+ object = Object.new
+ def object.foo(a:, b:, c:)
+ [a, b, c]
+ end
+ def object.bar(**)
+ eval "foo(**)"
+ end
+
+ object.bar(a: 1, b: 2, c: 3).should == [1, 2, 3]
+ end
+
+ it "allows anonymous block parameter forwarding" do
+ object = Object.new
+ def object.foo(&block)
+ block.call
+ end
+ def object.bar(&)
+ eval "foo(&)"
+ end
+
+ object.bar { :foobar }.should == :foobar
+ end
+
+ it "allows ... forwarding" do
+ object = Object.new
+ def object.foo(a, b:, &block)
+ [a, b, block.call]
+ end
+ def object.bar(...)
+ eval "foo(...)"
+ end
+
+ object.bar(1, b: 2) { 3 }.should == [1, 2, 3]
+ end
+
+ it "allows parameter forwarding to super" do
+ m = Module.new do
+ def foo(a, b:, &block)
+ [a, b, block.call]
+ end
+ end
+
+ c = Class.new do
+ include m
+
+ def foo(a, b:, &block)
+ eval "super"
+ end
+ end
+
+ object = c.new
+ object.foo(1, b: 2) { 3 }.should == [1, 2, 3]
+ end
+ end
+
ruby_version_is "3.3" do
it "uses (eval at __FILE__:__LINE__) if none is provided" do
eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})"
@@ -313,6 +382,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"VÏ€")
EvalSpecs::VÏ€.should == 3.14
+ ensure
+ EvalSpecs.send(:remove_const, :VÏ€)
end
it "allows an emacs-style magic comment encoding" do
@@ -326,6 +397,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"VÏ€emacs")
EvalSpecs::VÏ€emacs.should == 3.14
+ ensure
+ EvalSpecs.send(:remove_const, :VÏ€emacs)
end
it "allows spaces before the magic encoding comment" do
@@ -339,6 +412,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"VÏ€spaces")
EvalSpecs::VÏ€spaces.should == 3.14
+ ensure
+ EvalSpecs.send(:remove_const, :VÏ€spaces)
end
it "allows a shebang line before the magic encoding comment" do
@@ -353,6 +428,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"VÏ€shebang")
EvalSpecs::VÏ€shebang.should == 3.14
+ ensure
+ EvalSpecs.send(:remove_const, :VÏ€shebang)
end
it "allows a shebang line and some spaces before the magic encoding comment" do
@@ -367,6 +444,8 @@ CODE
eval(code)
EvalSpecs.constants(false).should include(:"VÏ€shebang_spaces")
EvalSpecs::VÏ€shebang_spaces.should == 3.14
+ ensure
+ EvalSpecs.send(:remove_const, :VÏ€shebang_spaces)
end
it "allows a magic encoding comment and a subsequent frozen_string_literal magic comment" do
@@ -385,6 +464,8 @@ CODE
EvalSpecs::VÏ€string.should == "frozen"
EvalSpecs::VÏ€string.encoding.should == Encoding::UTF_8
EvalSpecs::VÏ€string.frozen?.should == !frozen_string_default
+ ensure
+ EvalSpecs.send(:remove_const, :VÏ€string)
end
it "allows a magic encoding comment and a frozen_string_literal magic comment on the same line in emacs style" do
@@ -400,6 +481,8 @@ CODE
EvalSpecs::VÏ€same_line.should == "frozen"
EvalSpecs::VÏ€same_line.encoding.should == Encoding::UTF_8
EvalSpecs::VÏ€same_line.frozen?.should be_true
+ ensure
+ EvalSpecs.send(:remove_const, :VÏ€same_line)
end
it "ignores the magic encoding comment if it is after a frozen_string_literal magic comment" do
@@ -420,6 +503,8 @@ CODE
value.should == "frozen"
value.encoding.should == Encoding::BINARY
value.frozen?.should == !frozen_string_default
+ ensure
+ EvalSpecs.send(:remove_const, binary_constant)
end
it "ignores the frozen_string_literal magic comment if it appears after a token and warns if $VERBOSE is true" do
diff --git a/spec/ruby/core/kernel/fixtures/classes.rb b/spec/ruby/core/kernel/fixtures/classes.rb
index 541a4c075e..0e2b81988f 100644
--- a/spec/ruby/core/kernel/fixtures/classes.rb
+++ b/spec/ruby/core/kernel/fixtures/classes.rb
@@ -219,10 +219,28 @@ module KernelSpecs
block_given?
end
+ def self.accept_block_inside_block()
+ yield_self {
+ block_given?
+ }
+ end
+
+ def self.accept_block_as_argument_inside_block(&block)
+ yield_self {
+ block_given?
+ }
+ end
+
class << self
define_method(:defined_block) do
block_given?
end
+
+ define_method(:defined_block_inside_block) do
+ yield_self {
+ block_given?
+ }
+ end
end
end
@@ -235,10 +253,28 @@ module KernelSpecs
self.send(:block_given?)
end
+ def self.accept_block_inside_block
+ yield_self {
+ self.send(:block_given?)
+ }
+ end
+
+ def self.accept_block_as_argument_inside_block(&block)
+ yield_self {
+ self.send(:block_given?)
+ }
+ end
+
class << self
define_method(:defined_block) do
self.send(:block_given?)
end
+
+ define_method(:defined_block_inside_block) do
+ yield_self {
+ self.send(:block_given?)
+ }
+ end
end
end
@@ -251,10 +287,28 @@ module KernelSpecs
Kernel.block_given?
end
+ def self.accept_block_inside_block
+ yield_self {
+ Kernel.block_given?
+ }
+ end
+
+ def self.accept_block_as_argument_inside_block(&block)
+ yield_self {
+ Kernel.block_given?
+ }
+ end
+
class << self
define_method(:defined_block) do
Kernel.block_given?
end
+
+ define_method(:defined_block_inside_block) do
+ yield_self {
+ Kernel.block_given?
+ }
+ end
end
end
diff --git a/spec/ruby/core/kernel/inspect_spec.rb b/spec/ruby/core/kernel/inspect_spec.rb
index 1f9ce834ab..1fa66cab98 100644
--- a/spec/ruby/core/kernel/inspect_spec.rb
+++ b/spec/ruby/core/kernel/inspect_spec.rb
@@ -28,4 +28,63 @@ describe "Kernel#inspect" do
end
obj.inspect.should be_kind_of(String)
end
+
+ ruby_version_is "4.0" do
+ it "calls #instance_variables_to_inspect private method to know which variables to display" do
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = %i[@host @user @does_not_exist]
+ end
+
+ inspected = obj.inspect.sub(/^#<Object:0x[0-9a-f]+/, '#<Object:0x00')
+ inspected.should == '#<Object:0x00 @host="localhost", @user="root">'
+
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = []
+ end
+
+ inspected = obj.inspect.sub(/^#<Object:0x[0-9a-f]+/, '#<Object:0x00')
+ inspected.should == "#<Object:0x00>"
+ end
+
+ it "displays all instance variables if #instance_variables_to_inspect returns nil" do
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = nil
+ end
+
+ inspected = obj.inspect.sub(/^#<Object:0x[0-9a-f]+/, '#<Object:0x00')
+ inspected.should == %{#<Object:0x00 @host="localhost", @user="root", @password="hunter2">}
+ end
+
+ it "raises an error if #instance_variables_to_inspect returns an invalid value" do
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = {}
+ end
+
+ ->{ obj.inspect }.should raise_error(TypeError, "Expected #instance_variables_to_inspect to return an Array or nil, but it returned Hash")
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/is_a_spec.rb b/spec/ruby/core/kernel/is_a_spec.rb
index dc69766f83..bd8c96529a 100644
--- a/spec/ruby/core/kernel/is_a_spec.rb
+++ b/spec/ruby/core/kernel/is_a_spec.rb
@@ -2,5 +2,5 @@ require_relative '../../spec_helper'
require_relative 'shared/kind_of'
describe "Kernel#is_a?" do
- it_behaves_like :kernel_kind_of , :is_a?
+ it_behaves_like :kernel_kind_of, :is_a?
end
diff --git a/spec/ruby/core/kernel/kind_of_spec.rb b/spec/ruby/core/kernel/kind_of_spec.rb
index 734035620c..c988edccb5 100644
--- a/spec/ruby/core/kernel/kind_of_spec.rb
+++ b/spec/ruby/core/kernel/kind_of_spec.rb
@@ -2,5 +2,5 @@ require_relative '../../spec_helper'
require_relative 'shared/kind_of'
describe "Kernel#kind_of?" do
- it_behaves_like :kernel_kind_of , :kind_of?
+ it_behaves_like :kernel_kind_of, :kind_of?
end
diff --git a/spec/ruby/core/kernel/match_spec.rb b/spec/ruby/core/kernel/match_spec.rb
index aa25006163..cd6330fe91 100644
--- a/spec/ruby/core/kernel/match_spec.rb
+++ b/spec/ruby/core/kernel/match_spec.rb
@@ -1,30 +1,7 @@
require_relative '../../spec_helper'
describe "Kernel#=~" do
- ruby_version_is ''...'3.2' do
- it "returns nil matching any object" do
- o = Object.new
-
- suppress_warning do
- (o =~ /Object/).should be_nil
- (o =~ 'Object').should be_nil
- (o =~ Object).should be_nil
- (o =~ Object.new).should be_nil
- (o =~ nil).should be_nil
- (o =~ true).should be_nil
- end
- end
-
- it "is deprecated" do
- -> do
- Object.new =~ /regexp/
- end.should complain(/deprecated Object#=~ is called on Object/, verbose: true)
- end
- end
-
- ruby_version_is '3.2' do
- it "is no longer defined" do
- Object.new.should_not.respond_to?(:=~)
- end
+ it "is no longer defined" do
+ Object.new.should_not.respond_to?(:=~)
end
end
diff --git a/spec/ruby/core/kernel/not_match_spec.rb b/spec/ruby/core/kernel/not_match_spec.rb
index f8dd82fad8..082e56fed7 100644
--- a/spec/ruby/core/kernel/not_match_spec.rb
+++ b/spec/ruby/core/kernel/not_match_spec.rb
@@ -14,18 +14,8 @@ describe "Kernel#!~" do
(obj !~ :foo).should == false
end
- ruby_version_is ""..."3.2" do
- it "returns true if self does not respond to #=~" do
- suppress_warning do
- (Object.new !~ :foo).should == true
- end
- end
- end
-
- ruby_version_is "3.2" do
- it "raises NoMethodError if self does not respond to #=~" do
- -> { Object.new !~ :foo }.should raise_error(NoMethodError)
- end
+ it "raises NoMethodError if self does not respond to #=~" do
+ -> { Object.new !~ :foo }.should raise_error(NoMethodError)
end
it 'can be overridden in subclasses' do
diff --git a/spec/ruby/core/kernel/open_spec.rb b/spec/ruby/core/kernel/open_spec.rb
index bb42c31f31..b967d5044b 100644
--- a/spec/ruby/core/kernel/open_spec.rb
+++ b/spec/ruby/core/kernel/open_spec.rb
@@ -27,64 +27,66 @@ describe "Kernel#open" do
open(@name, "r") { |f| f.gets }.should == @content
end
- platform_is_not :windows, :wasi do
- it "opens an io when path starts with a pipe" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- @io = open("|date")
+ ruby_version_is ""..."4.0" do
+ platform_is_not :windows, :wasi do
+ it "opens an io when path starts with a pipe" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @io = open("|date")
+ end
+ begin
+ @io.should be_kind_of(IO)
+ @io.read
+ ensure
+ @io.close
+ end
end
- begin
- @io.should be_kind_of(IO)
- @io.read
- ensure
- @io.close
- end
- end
- it "opens an io when called with a block" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- @output = open("|date") { |f| f.read }
+ it "opens an io when called with a block" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @output = open("|date") { |f| f.read }
+ end
+ @output.should_not == ''
end
- @output.should_not == ''
- end
- it "opens an io for writing" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- -> {
- bytes = open("|cat", "w") { |io| io.write(".") }
- bytes.should == 1
- }.should output_to_fd(".")
+ it "opens an io for writing" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ -> {
+ bytes = open("|cat", "w") { |io| io.write(".") }
+ bytes.should == 1
+ }.should output_to_fd(".")
+ end
end
end
- end
- platform_is :windows do
- it "opens an io when path starts with a pipe" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- @io = open("|date /t")
+ platform_is :windows do
+ it "opens an io when path starts with a pipe" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @io = open("|date /t")
+ end
+ begin
+ @io.should be_kind_of(IO)
+ @io.read
+ ensure
+ @io.close
+ end
end
- begin
- @io.should be_kind_of(IO)
- @io.read
- ensure
- @io.close
- end
- end
- it "opens an io when called with a block" do
- suppress_warning do # https://bugs.ruby-lang.org/issues/19630
- @output = open("|date /t") { |f| f.read }
+ it "opens an io when called with a block" do
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @output = open("|date /t") { |f| f.read }
+ end
+ @output.should_not == ''
end
- @output.should_not == ''
end
- end
- ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19630
- it "warns about deprecation given a path with a pipe" do
- cmd = "|echo ok"
- -> {
- open(cmd) { |f| f.read }
- }.should complain(/Kernel#open with a leading '\|'/)
+ ruby_version_is "3.3" do
+ # https://bugs.ruby-lang.org/issues/19630
+ it "warns about deprecation given a path with a pipe" do
+ cmd = "|echo ok"
+ -> {
+ open(cmd) { |f| f.read }
+ }.should complain(/Kernel#open with a leading '\|'/)
+ end
end
end
@@ -106,7 +108,7 @@ describe "Kernel#open" do
ScratchPad.clear
end
- it "calls #to_path to covert the argument to a String before calling #to_str" do
+ it "calls #to_path to convert the argument to a String before calling #to_str" do
obj = mock("open to_path")
obj.should_receive(:to_path).at_least(1).times.and_return(@name)
obj.should_not_receive(:to_str)
diff --git a/spec/ruby/core/kernel/raise_spec.rb b/spec/ruby/core/kernel/raise_spec.rb
index a038dcf031..fcd011d4e6 100644
--- a/spec/ruby/core/kernel/raise_spec.rb
+++ b/spec/ruby/core/kernel/raise_spec.rb
@@ -44,7 +44,53 @@ describe "Kernel#raise" do
it "raises an ArgumentError when only cause is given" do
cause = StandardError.new
- -> { raise(cause: cause) }.should raise_error(ArgumentError)
+ -> { raise(cause: cause) }.should raise_error(ArgumentError, "only cause is given with no arguments")
+ end
+
+ it "raises an ArgumentError when only cause is given even if it has nil value" do
+ -> { raise(cause: nil) }.should raise_error(ArgumentError, "only cause is given with no arguments")
+ end
+
+ it "raises a TypeError when given cause is not an instance of Exception" do
+ -> { raise "message", cause: Object.new }.should raise_error(TypeError, "exception object expected")
+ end
+
+ it "doesn't raise a TypeError when given cause is nil" do
+ -> { raise "message", cause: nil }.should raise_error(RuntimeError, "message")
+ end
+
+ it "allows cause equal an exception" do
+ e = RuntimeError.new("message")
+ -> { raise e, cause: e }.should raise_error(e)
+ end
+
+ it "doesn't set given cause when it equals an exception" do
+ e = RuntimeError.new("message")
+
+ begin
+ raise e, cause: e
+ rescue
+ end
+
+ e.cause.should == nil
+ end
+
+ it "raises ArgumentError when exception is part of the cause chain" do
+ -> {
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ raise "Error 2"
+ rescue => e2
+ begin
+ raise "Error 3"
+ rescue => e3
+ raise e1, cause: e3
+ end
+ end
+ end
+ }.should raise_error(ArgumentError, "circular causes")
end
it "re-raises a rescued exception" do
@@ -62,6 +108,179 @@ describe "Kernel#raise" do
end
end.should raise_error(StandardError, "aaa")
end
+
+ it "re-raises a previously rescued exception without overwriting the cause" do
+ begin
+ begin
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ raise "Error 2"
+ end
+ rescue => e2
+ raise "Error 3"
+ end
+ rescue
+ e2.cause.should == e1
+ raise e2
+ end
+ rescue => e
+ e.cause.should == e1
+ end
+ end
+
+ it "re-raises a previously rescued exception with overwriting the cause when it's explicitly specified with :cause option" do
+ e4 = RuntimeError.new("Error 4")
+
+ begin
+ begin
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ raise "Error 2"
+ end
+ rescue => e2
+ raise "Error 3"
+ end
+ rescue
+ e2.cause.should == e1
+ raise e2, cause: e4
+ end
+ rescue => e
+ e.cause.should == e4
+ end
+ end
+
+ it "re-raises a previously rescued exception without overwriting the cause when it's explicitly specified with :cause option and has nil value" do
+ begin
+ begin
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ raise "Error 2"
+ end
+ rescue => e2
+ raise "Error 3"
+ end
+ rescue
+ e2.cause.should == e1
+ raise e2, cause: nil
+ end
+ rescue => e
+ e.cause.should == e1
+ end
+ end
+
+ it "re-raises a previously rescued exception without setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ raise
+ end
+ rescue => e
+ e.should == e1
+ e.cause.should == nil
+ end
+ end
+
+ it "re-raises a previously rescued exception that has a cause without setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ raise "Error 2"
+ rescue => e2
+ raise
+ end
+ end
+ rescue => e
+ e.should == e2
+ e.cause.should == e1
+ end
+ end
+
+ it "re-raises a previously rescued exception that doesn't have a cause and isn't a cause of any other exception with setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ raise "Error 2"
+ rescue => e2
+ raise "Error 3"
+ end
+ end
+ rescue => e
+ e.message.should == "Error 3"
+ e.cause.should == e2
+ end
+ end
+
+ it "re-raises a previously rescued exception that doesn't have a cause and is a cause of other exception without setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ raise "Error 2"
+ rescue => e2
+ e1.cause.should == nil
+ e2.cause.should == e1
+ raise e1
+ end
+ end
+ rescue => e
+ e.should == e1
+ e.cause.should == nil
+ end
+ end
+
+ it "re-raises a previously rescued exception that doesn't have a cause and is a cause of other exception (that wasn't raised explicitly) without setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ foo # raises NameError
+ rescue => e2
+ e1.cause.should == nil
+ e2.cause.should == e1
+ raise e1
+ end
+ end
+ rescue => e
+ e.should == e1
+ e.cause.should == nil
+ end
+ end
+
+ it "re-raises a previously rescued exception that has a cause but isn't a cause of any other exception without setting a cause implicitly" do
+ begin
+ begin
+ raise "Error 1"
+ rescue => e1
+ begin
+ raise "Error 2"
+ rescue => e2
+ begin
+ raise "Error 3", cause: RuntimeError.new("Error 4")
+ rescue => e3
+ e2.cause.should == e1
+ e3.cause.should_not == e2
+ raise e2
+ end
+ end
+ end
+ rescue => e
+ e.should == e2
+ e.cause.should == e1
+ end
+ end
end
describe "Kernel#raise" do
diff --git a/spec/ruby/core/kernel/require_spec.rb b/spec/ruby/core/kernel/require_spec.rb
index 4029e68725..60d17242fe 100644
--- a/spec/ruby/core/kernel/require_spec.rb
+++ b/spec/ruby/core/kernel/require_spec.rb
@@ -16,9 +16,10 @@ describe "Kernel#require" do
Kernel.should have_private_instance_method(:require)
end
- provided = %w[complex enumerator rational thread ruby2_keywords]
- ruby_version_is "3.1" do
- provided << "fiber"
+ provided = %w[complex enumerator fiber rational thread ruby2_keywords]
+ ruby_version_is "4.0" do
+ provided << "set"
+ provided << "pathname"
end
it "#{provided.join(', ')} are already required" do
@@ -31,9 +32,14 @@ describe "Kernel#require" do
features.sort.should == provided.sort
- code = provided.map { |f| "puts require #{f.inspect}\n" }.join
+ requires = provided
+ ruby_version_is "4.0" do
+ requires = requires.map { |f| f == "pathname" ? "pathname.so" : f }
+ end
+
+ code = requires.map { |f| "puts require #{f.inspect}\n" }.join
required = ruby_exe(code, options: '--disable-gems')
- required.should == "false\n" * provided.size
+ required.should == "false\n" * requires.size
end
it_behaves_like :kernel_require_basic, :require, CodeLoadingSpecs::Method.new
diff --git a/spec/ruby/core/kernel/shared/load.rb b/spec/ruby/core/kernel/shared/load.rb
index 0fe2d5ce16..62c5c7be9b 100644
--- a/spec/ruby/core/kernel/shared/load.rb
+++ b/spec/ruby/core/kernel/shared/load.rb
@@ -165,37 +165,35 @@ describe :kernel_load, shared: true do
end
describe "when passed a module for 'wrap'" do
- ruby_version_is "3.1" do
- it "sets the enclosing scope to the supplied module" do
- path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
- mod = Module.new
- @object.load(path, mod)
+ it "sets the enclosing scope to the supplied module" do
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
+ mod = Module.new
+ @object.load(path, mod)
- Object.const_defined?(:LoadSpecWrap).should be_false
- mod.const_defined?(:LoadSpecWrap).should be_true
+ Object.const_defined?(:LoadSpecWrap).should be_false
+ mod.const_defined?(:LoadSpecWrap).should be_true
- wrap_module = ScratchPad.recorded[1]
- wrap_module.should == mod
- end
+ wrap_module = ScratchPad.recorded[1]
+ wrap_module.should == mod
+ end
- it "makes constants and instance methods in the source file reachable with the supplied module" do
- path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
- mod = Module.new
- @object.load(path, mod)
+ it "makes constants and instance methods in the source file reachable with the supplied module" do
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
+ mod = Module.new
+ @object.load(path, mod)
- mod::LOAD_WRAP_SPECS_TOP_LEVEL_CONSTANT.should == 1
- obj = Object.new
- obj.extend(mod)
- obj.send(:load_wrap_specs_top_level_method).should == :load_wrap_specs_top_level_method
- end
+ mod::LOAD_WRAP_SPECS_TOP_LEVEL_CONSTANT.should == 1
+ obj = Object.new
+ obj.extend(mod)
+ obj.send(:load_wrap_specs_top_level_method).should == :load_wrap_specs_top_level_method
+ end
- it "makes instance methods in the source file private" do
- path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
- mod = Module.new
- @object.load(path, mod)
+ it "makes instance methods in the source file private" do
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
+ mod = Module.new
+ @object.load(path, mod)
- mod.private_instance_methods.include?(:load_wrap_specs_top_level_method).should == true
- end
+ mod.private_instance_methods.include?(:load_wrap_specs_top_level_method).should == true
end
end
diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb
index 250813191b..52f86f73e5 100644
--- a/spec/ruby/core/kernel/shared/require.rb
+++ b/spec/ruby/core/kernel/shared/require.rb
@@ -223,7 +223,7 @@ describe :kernel_require, shared: true do
it "loads c-extension file when passed absolute path without extension when no .rb is present" do
# the error message is specific to what dlerror() returns
path = File.join CODE_LOADING_DIR, "a", "load_fixture"
- -> { @object.send(@method, path) }.should raise_error(Exception, /file too short|not a mach-o file/)
+ -> { @object.send(@method, path) }.should raise_error(LoadError)
end
end
@@ -231,7 +231,7 @@ describe :kernel_require, shared: true do
it "loads .bundle file when passed absolute path with .so" do
# the error message is specific to what dlerror() returns
path = File.join CODE_LOADING_DIR, "a", "load_fixture.so"
- -> { @object.send(@method, path) }.should raise_error(Exception, /load_fixture\.bundle.+(file too short|not a mach-o file)/)
+ -> { @object.send(@method, path) }.should raise_error(LoadError)
end
end
@@ -296,6 +296,16 @@ describe :kernel_require, shared: true do
$LOAD_PATH.replace [File.expand_path("b", CODE_LOADING_DIR), CODE_LOADING_DIR]
@object.require("load_fixture").should be_false
end
+
+ it "stores the missing path in a LoadError object" do
+ path = "abcd1234"
+
+ -> {
+ @object.send(@method, path)
+ }.should raise_error(LoadError) { |e|
+ e.path.should == path
+ }
+ end
end
describe "(file extensions)" do
@@ -815,4 +825,24 @@ describe :kernel_require, shared: true do
e.path.should == path
}
end
+
+ platform_is :linux, :darwin do
+ it "does not store the missing path in a LoadError object when c-extension file exists but loading fails and passed absolute path without extension" do
+ # the error message is specific to what dlerror() returns
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture"
+ -> { @object.send(@method, path) }.should raise_error(LoadError) { |e|
+ e.path.should == nil
+ }
+ end
+ end
+
+ platform_is :darwin do
+ it "does not store the missing path in a LoadError object when c-extension file exists but loading fails and passed absolute path with extension" do
+ # the error message is specific to what dlerror() returns
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture.bundle"
+ -> { @object.send(@method, path) }.should raise_error(LoadError) { |e|
+ e.path.should == nil
+ }
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/shared/sprintf.rb b/spec/ruby/core/kernel/shared/sprintf.rb
index 13dc6e97f0..2b2c6c9b63 100644
--- a/spec/ruby/core/kernel/shared/sprintf.rb
+++ b/spec/ruby/core/kernel/shared/sprintf.rb
@@ -22,6 +22,7 @@ describe :kernel_sprintf, shared: true do
@method.call("%d", "112").should == "112"
@method.call("%d", "0127").should == "87"
@method.call("%d", "0xc4").should == "196"
+ @method.call("%d", "0").should == "0"
end
it "raises TypeError exception if cannot convert to Integer" do
@@ -57,6 +58,11 @@ describe :kernel_sprintf, shared: true do
it "works well with large numbers" do
@method.call("%#{f}", 1234567890987654321).should == "1234567890987654321"
end
+
+ it "converts to the empty string if precision is 0 and value is 0" do
+ @method.call("%.#{f}", 0).should == ""
+ @method.call("%.0#{f}", 0).should == ""
+ end
end
end
@@ -289,28 +295,12 @@ describe :kernel_sprintf, shared: true do
@method.call("%c", "a").should == "a"
end
- ruby_version_is ""..."3.2" do
- it "raises ArgumentError if argument is a string of several characters" do
- -> {
- @method.call("%c", "abc")
- }.should raise_error(ArgumentError, /%c requires a character/)
- end
-
- it "raises ArgumentError if argument is an empty string" do
- -> {
- @method.call("%c", "")
- }.should raise_error(ArgumentError, /%c requires a character/)
- end
+ it "displays only the first character if argument is a string of several characters" do
+ @method.call("%c", "abc").should == "a"
end
- ruby_version_is "3.2" do
- it "displays only the first character if argument is a string of several characters" do
- @method.call("%c", "abc").should == "a"
- end
-
- it "displays no characters if argument is an empty string" do
- @method.call("%c", "").should == ""
- end
+ it "displays no characters if argument is an empty string" do
+ @method.call("%c", "").should == ""
end
it "raises TypeError if argument is not String or Integer and cannot be converted to them" do
@@ -372,6 +362,10 @@ describe :kernel_sprintf, shared: true do
obj.should_receive(:inspect).and_return("<inspect-result>")
@method.call("%p", obj).should == "<inspect-result>"
end
+
+ it "substitutes 'nil' for nil" do
+ @method.call("%p", nil).should == "nil"
+ end
end
describe "s" do
@@ -455,7 +449,7 @@ describe :kernel_sprintf, shared: true do
it "is escaped by %" do
@method.call("%%").should == "%"
- @method.call("%%d", 10).should == "%d"
+ @method.call("%%d").should == "%d"
end
end
end
diff --git a/spec/ruby/core/kernel/singleton_method_spec.rb b/spec/ruby/core/kernel/singleton_method_spec.rb
index 0bdf125ad8..7d63fa7cc6 100644
--- a/spec/ruby/core/kernel/singleton_method_spec.rb
+++ b/spec/ruby/core/kernel/singleton_method_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
describe "Kernel#singleton_method" do
- it "find a method defined on the singleton class" do
+ it "finds a method defined on the singleton class" do
obj = Object.new
def obj.foo; end
obj.singleton_method(:foo).should be_an_instance_of(Method)
@@ -38,4 +38,48 @@ describe "Kernel#singleton_method" do
e.class.should == NameError
}
end
+
+ ruby_bug "#20620", ""..."3.4" do
+ it "finds a method defined in a module included in the singleton class" do
+ m = Module.new do
+ def foo
+ :foo
+ end
+ end
+
+ obj = Object.new
+ obj.singleton_class.include(m)
+
+ obj.singleton_method(:foo).should be_an_instance_of(Method)
+ obj.singleton_method(:foo).call.should == :foo
+ end
+
+ it "finds a method defined in a module prepended in the singleton class" do
+ m = Module.new do
+ def foo
+ :foo
+ end
+ end
+
+ obj = Object.new
+ obj.singleton_class.prepend(m)
+
+ obj.singleton_method(:foo).should be_an_instance_of(Method)
+ obj.singleton_method(:foo).call.should == :foo
+ end
+
+ it "finds a method defined in a module that an object is extended with" do
+ m = Module.new do
+ def foo
+ :foo
+ end
+ end
+
+ obj = Object.new
+ obj.extend(m)
+
+ obj.singleton_method(:foo).should be_an_instance_of(Method)
+ obj.singleton_method(:foo).call.should == :foo
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/sleep_spec.rb b/spec/ruby/core/kernel/sleep_spec.rb
index 4401e54256..e9c600aac4 100644
--- a/spec/ruby/core/kernel/sleep_spec.rb
+++ b/spec/ruby/core/kernel/sleep_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative '../fiber/fixtures/scheduler'
describe "Kernel#sleep" do
it "is a private method" do
@@ -84,6 +85,40 @@ describe "Kernel#sleep" do
t.value.should == 5
end
end
+
+ context "Kernel.sleep with Fiber scheduler" do
+ before :each do
+ Fiber.set_scheduler(FiberSpecs::LoggingScheduler.new)
+ end
+
+ after :each do
+ Fiber.set_scheduler(nil)
+ end
+
+ it "calls the scheduler without arguments when no duration is given" do
+ sleeper = Fiber.new(blocking: false) do
+ sleep
+ end
+ sleeper.resume
+ Fiber.scheduler.events.should == [{ event: :kernel_sleep, fiber: sleeper, args: [] }]
+ end
+
+ it "calls the scheduler with the given duration" do
+ sleeper = Fiber.new(blocking: false) do
+ sleep(0.01)
+ end
+ sleeper.resume
+ Fiber.scheduler.events.should == [{ event: :kernel_sleep, fiber: sleeper, args: [0.01] }]
+ end
+
+ it "does not call the scheduler if the fiber is blocking" do
+ sleeper = Fiber.new(blocking: true) do
+ sleep(0.01)
+ end
+ sleeper.resume
+ Fiber.scheduler.events.should == []
+ end
+ end
end
describe "Kernel.sleep" do
diff --git a/spec/ruby/core/kernel/sprintf_spec.rb b/spec/ruby/core/kernel/sprintf_spec.rb
index 9ef7f86f16..5a4a90ff7a 100644
--- a/spec/ruby/core/kernel/sprintf_spec.rb
+++ b/spec/ruby/core/kernel/sprintf_spec.rb
@@ -13,28 +13,52 @@ end
describe "Kernel#sprintf" do
it_behaves_like :kernel_sprintf, -> format, *args {
- sprintf(format, *args)
+ r = nil
+ -> {
+ r = sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
it_behaves_like :kernel_sprintf_encoding, -> format, *args {
- sprintf(format, *args)
+ r = nil
+ -> {
+ r = sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
it_behaves_like :kernel_sprintf_to_str, -> format, *args {
- sprintf(format, *args)
+ r = nil
+ -> {
+ r = sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
end
describe "Kernel.sprintf" do
it_behaves_like :kernel_sprintf, -> format, *args {
- Kernel.sprintf(format, *args)
+ r = nil
+ -> {
+ r = Kernel.sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
it_behaves_like :kernel_sprintf_encoding, -> format, *args {
- Kernel.sprintf(format, *args)
+ r = nil
+ -> {
+ r = Kernel.sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
it_behaves_like :kernel_sprintf_to_str, -> format, *args {
- Kernel.sprintf(format, *args)
+ r = nil
+ -> {
+ r = Kernel.sprintf(format, *args)
+ }.should_not complain(verbose: true)
+ r
}
end
diff --git a/spec/ruby/core/kernel/taint_spec.rb b/spec/ruby/core/kernel/taint_spec.rb
index 0c16b1dbbf..9a2efbaea0 100644
--- a/spec/ruby/core/kernel/taint_spec.rb
+++ b/spec/ruby/core/kernel/taint_spec.rb
@@ -2,26 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#taint" do
- ruby_version_is ""..."3.2" do
- it "is a no-op" do
- suppress_warning do
- o = Object.new
- o.taint
- o.should_not.tainted?
- end
- end
-
- it "warns in verbose mode" do
- -> {
- obj = mock("tainted")
- obj.taint
- }.should complain(/Object#taint is deprecated and will be removed in Ruby 3.2/, verbose: true)
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:taint)
- end
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:taint)
end
end
diff --git a/spec/ruby/core/kernel/tainted_spec.rb b/spec/ruby/core/kernel/tainted_spec.rb
index fcae433069..837eb1dafb 100644
--- a/spec/ruby/core/kernel/tainted_spec.rb
+++ b/spec/ruby/core/kernel/tainted_spec.rb
@@ -2,28 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#tainted?" do
- ruby_version_is ""..."3.2" do
- it "is a no-op" do
- suppress_warning do
- o = mock('o')
- p = mock('p')
- p.taint
- o.should_not.tainted?
- p.should_not.tainted?
- end
- end
-
- it "warns in verbose mode" do
- -> {
- o = mock('o')
- o.tainted?
- }.should complain(/Object#tainted\? is deprecated and will be removed in Ruby 3.2/, verbose: true)
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:tainted?)
- end
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:tainted?)
end
end
diff --git a/spec/ruby/core/kernel/trust_spec.rb b/spec/ruby/core/kernel/trust_spec.rb
index db6f17e0fb..ef3fa9a3e1 100644
--- a/spec/ruby/core/kernel/trust_spec.rb
+++ b/spec/ruby/core/kernel/trust_spec.rb
@@ -2,27 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#trust" do
- ruby_version_is ""..."3.2" do
- it "is a no-op" do
- suppress_warning do
- o = Object.new.untrust
- o.should_not.untrusted?
- o.trust
- o.should_not.untrusted?
- end
- end
-
- it "warns in verbose mode" do
- -> {
- o = Object.new.untrust
- o.trust
- }.should complain(/Object#trust is deprecated and will be removed in Ruby 3.2/, verbose: true)
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:trust)
- end
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:trust)
end
end
diff --git a/spec/ruby/core/kernel/untaint_spec.rb b/spec/ruby/core/kernel/untaint_spec.rb
index 26b2aabbe9..47e8544bd4 100644
--- a/spec/ruby/core/kernel/untaint_spec.rb
+++ b/spec/ruby/core/kernel/untaint_spec.rb
@@ -2,27 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untaint" do
- ruby_version_is ""..."3.2" do
- it "is a no-op" do
- suppress_warning do
- o = Object.new.taint
- o.should_not.tainted?
- o.untaint
- o.should_not.tainted?
- end
- end
-
- it "warns in verbose mode" do
- -> {
- o = Object.new.taint
- o.untaint
- }.should complain(/Object#untaint is deprecated and will be removed in Ruby 3.2/, verbose: true)
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:untaint)
- end
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untaint)
end
end
diff --git a/spec/ruby/core/kernel/untrust_spec.rb b/spec/ruby/core/kernel/untrust_spec.rb
index 5310cd8eb4..8787ab3fc9 100644
--- a/spec/ruby/core/kernel/untrust_spec.rb
+++ b/spec/ruby/core/kernel/untrust_spec.rb
@@ -2,26 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untrust" do
- ruby_version_is ""..."3.2" do
- it "is a no-op" do
- suppress_warning do
- o = Object.new
- o.untrust
- o.should_not.untrusted?
- end
- end
-
- it "warns in verbose mode" do
- -> {
- o = Object.new
- o.untrust
- }.should complain(/Object#untrust is deprecated and will be removed in Ruby 3.2/, verbose: true)
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:untrust)
- end
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untrust)
end
end
diff --git a/spec/ruby/core/kernel/untrusted_spec.rb b/spec/ruby/core/kernel/untrusted_spec.rb
index ea36d6c98c..29261be9c4 100644
--- a/spec/ruby/core/kernel/untrusted_spec.rb
+++ b/spec/ruby/core/kernel/untrusted_spec.rb
@@ -2,27 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untrusted?" do
- ruby_version_is ""..."3.2" do
- it "is a no-op" do
- suppress_warning do
- o = mock('o')
- o.should_not.untrusted?
- o.untrust
- o.should_not.untrusted?
- end
- end
-
- it "warns in verbose mode" do
- -> {
- o = mock('o')
- o.untrusted?
- }.should complain(/Object#untrusted\? is deprecated and will be removed in Ruby 3.2/, verbose: true)
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- Object.new.should_not.respond_to?(:untrusted?)
- end
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untrusted?)
end
end
diff --git a/spec/ruby/core/kernel/warn_spec.rb b/spec/ruby/core/kernel/warn_spec.rb
index 00164ad90b..e03498c6dc 100644
--- a/spec/ruby/core/kernel/warn_spec.rb
+++ b/spec/ruby/core/kernel/warn_spec.rb
@@ -112,6 +112,12 @@ describe "Kernel#warn" do
ruby_exe(file, options: "-rrubygems", args: "2>&1").should == "#{file}:2: warning: warn-require-warning\n"
end
+ it "doesn't show the caller when the uplevel is `nil`" do
+ w = KernelSpecs::WarnInNestedCall.new
+
+ -> { w.f4("foo", nil) }.should output(nil, "foo\n")
+ end
+
guard -> { Kernel.instance_method(:tap).source_location } do
it "skips <internal: core library methods defined in Ruby" do
file, line = Kernel.instance_method(:tap).source_location
diff --git a/spec/ruby/core/main/private_spec.rb b/spec/ruby/core/main/private_spec.rb
index e8c1f3f44c..76895fd649 100644
--- a/spec/ruby/core/main/private_spec.rb
+++ b/spec/ruby/core/main/private_spec.rb
@@ -30,16 +30,8 @@ describe "main#private" do
end
end
- ruby_version_is ''...'3.1' do
- it "returns Object" do
- eval("private :main_public_method", TOPLEVEL_BINDING).should equal(Object)
- end
- end
-
- ruby_version_is '3.1' do
- it "returns argument" do
- eval("private :main_public_method", TOPLEVEL_BINDING).should equal(:main_public_method)
- end
+ it "returns argument" do
+ eval("private :main_public_method", TOPLEVEL_BINDING).should equal(:main_public_method)
end
it "raises a NameError when at least one of given method names is undefined" do
diff --git a/spec/ruby/core/main/public_spec.rb b/spec/ruby/core/main/public_spec.rb
index 31baad4583..3c77798fbc 100644
--- a/spec/ruby/core/main/public_spec.rb
+++ b/spec/ruby/core/main/public_spec.rb
@@ -30,16 +30,8 @@ describe "main#public" do
end
end
- ruby_version_is ''...'3.1' do
- it "returns Object" do
- eval("public :main_private_method", TOPLEVEL_BINDING).should equal(Object)
- end
- end
-
- ruby_version_is '3.1' do
- it "returns argument" do
- eval("public :main_private_method", TOPLEVEL_BINDING).should equal(:main_private_method)
- end
+ it "returns argument" do
+ eval("public :main_private_method", TOPLEVEL_BINDING).should equal(:main_private_method)
end
diff --git a/spec/ruby/core/main/using_spec.rb b/spec/ruby/core/main/using_spec.rb
index 8a23970c4b..5b9a751595 100644
--- a/spec/ruby/core/main/using_spec.rb
+++ b/spec/ruby/core/main/using_spec.rb
@@ -142,11 +142,9 @@ describe "main.using" do
end.should raise_error(RuntimeError)
end
- ruby_version_is "3.2" do
- it "does not raise error when wrapped with module" do
- -> do
- load File.expand_path('../fixtures/using.rb', __FILE__), true
- end.should_not raise_error
- end
+ it "does not raise error when wrapped with module" do
+ -> do
+ load File.expand_path('../fixtures/using.rb', __FILE__), true
+ end.should_not raise_error
end
end
diff --git a/spec/ruby/core/marshal/dump_spec.rb b/spec/ruby/core/marshal/dump_spec.rb
index 05e473c64e..ff9b9214fa 100644
--- a/spec/ruby/core/marshal/dump_spec.rb
+++ b/spec/ruby/core/marshal/dump_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'fixtures/marshal_data'
@@ -47,6 +47,11 @@ describe "Marshal.dump" do
Marshal.dump(-2**31 - 1).should == "\x04\bl-\a\x01\x00\x00\x80"
end
end
+
+ it "does not use object links for objects repeatedly dumped" do
+ Marshal.dump([0, 0]).should == "\x04\b[\ai\x00i\x00"
+ Marshal.dump([2**16, 2**16]).should == "\x04\b[\ai\x03\x00\x00\x01i\x03\x00\x00\x01"
+ end
end
describe "with a Symbol" do
@@ -93,6 +98,11 @@ describe "Marshal.dump" do
value = [*value, value[0]]
Marshal.dump(value).should == "\x04\b[\b#{symbol1}#{symbol2};\x00"
end
+
+ it "uses symbol links for objects repeatedly dumped" do
+ symbol = :foo
+ Marshal.dump([symbol, symbol]).should == "\x04\b[\a:\bfoo;\x00" # ;\x00 is a link to the symbol object
+ end
end
describe "with an object responding to #marshal_dump" do
@@ -108,6 +118,20 @@ describe "Marshal.dump" do
it "raises TypeError if an Object is an instance of an anonymous class" do
-> { Marshal.dump(Class.new(UserMarshal).new) }.should raise_error(TypeError, /can't dump anonymous class/)
end
+
+ it "uses object links for objects repeatedly dumped" do
+ obj = UserMarshal.new
+ Marshal.dump([obj, obj]).should == "\x04\b[\aU:\x10UserMarshal:\tdata@\x06" # @\x06 is a link to the object
+ end
+
+ it "adds instance variables of a dumped object after the object itself into the objects table" do
+ value = "<foo>"
+ obj = MarshalSpec::UserMarshalDumpWithIvar.new("string", value)
+
+ # expect a link to the object (@\x06, that means Integer 1) is smaller than a link
+ # to the instance variable value (@\t, that means Integer 4)
+ Marshal.dump([obj, obj, value]).should == "\x04\b[\bU:)MarshalSpec::UserMarshalDumpWithIvarI[\x06\"\vstring\x06:\t@foo\"\n<foo>@\x06@\t"
+ end
end
describe "with an object responding to #_dump" do
@@ -166,6 +190,20 @@ describe "Marshal.dump" do
Marshal.dump([a, a]).should == "\x04\b[\aIu:\x17MarshalSpec::M1::A\v<dump>\x06:\t@foo\"\bbar#{reference}"
end
+ it "uses object links for objects repeatedly dumped" do
+ obj = UserDefined.new
+ Marshal.dump([obj, obj]).should == "\x04\b[\au:\x10UserDefined\x12\x04\b[\a:\nstuff;\x00@\x06" # @\x06 is a link to the object
+ end
+
+ it "adds instance variables of a dumped String before the object itself into the objects table" do
+ value = "<foo>"
+ obj = MarshalSpec::UserDefinedDumpWithIVars.new(+"string", value)
+
+ # expect a link to the object (@\a, that means Integer 2) is greater than a link
+ # to the instance variable value (@\x06, that means Integer 1)
+ Marshal.dump([obj, obj, value]).should == "\x04\b[\bIu:*MarshalSpec::UserDefinedDumpWithIVars\vstring\x06:\t@foo\"\n<foo>@\a@\x06"
+ end
+
describe "Core library classes with #_dump returning a String with instance variables" do
it "indexes instance variables and then a Time object itself" do
t = Time.utc(2022)
@@ -193,9 +231,16 @@ describe "Marshal.dump" do
Marshal.dump(MarshalSpec::ClassWithOverriddenName).should == "\x04\bc)MarshalSpec::ClassWithOverriddenName"
end
- it "dumps a class with multibyte characters in name" do
- source_object = eval("MarshalSpec::Multibyteãã‚ãƒã„Class".dup.force_encoding(Encoding::UTF_8))
- Marshal.dump(source_object).should == "\x04\bc,MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Class"
+ ruby_version_is "4.0" do
+ it "dumps a class with multibyte characters in name" do
+ source_object = eval("MarshalSpec::Multibyteãã‚ãƒã„Class".dup.force_encoding(Encoding::UTF_8))
+ Marshal.dump(source_object).should == "\x04\bIc,MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Class\x06:\x06ET"
+ Marshal.load(Marshal.dump(source_object)) == source_object
+ end
+ end
+
+ it "uses object links for objects repeatedly dumped" do
+ Marshal.dump([String, String]).should == "\x04\b[\ac\vString@\x06" # @\x06 is a link to the object
end
it "raises TypeError with an anonymous Class" do
@@ -216,9 +261,16 @@ describe "Marshal.dump" do
Marshal.dump(MarshalSpec::ModuleWithOverriddenName).should == "\x04\bc*MarshalSpec::ModuleWithOverriddenName"
end
- it "dumps a module with multibyte characters in name" do
- source_object = eval("MarshalSpec::Multibyteã‘ã’ã“ã”Module".dup.force_encoding(Encoding::UTF_8))
- Marshal.dump(source_object).should == "\x04\bm-MarshalSpec::Multibyte\xE3\x81\x91\xE3\x81\x92\xE3\x81\x93\xE3\x81\x94Module"
+ ruby_version_is "4.0" do
+ it "dumps a module with multibyte characters in name" do
+ source_object = eval("MarshalSpec::Multibyteã‘ã’ã“ã”Module".dup.force_encoding(Encoding::UTF_8))
+ Marshal.dump(source_object).should == "\x04\bIm-MarshalSpec::Multibyte\xE3\x81\x91\xE3\x81\x92\xE3\x81\x93\xE3\x81\x94Module\x06:\x06ET"
+ Marshal.load(Marshal.dump(source_object)) == source_object
+ end
+ end
+
+ it "uses object links for objects repeatedly dumped" do
+ Marshal.dump([Marshal, Marshal]).should == "\x04\b[\am\fMarshal@\x06" # @\x06 is a link to the object
end
it "raises TypeError with an anonymous Module" do
@@ -239,6 +291,23 @@ describe "Marshal.dump" do
[Marshal, nan_value, "\004\bf\bnan"],
].should be_computed_by(:dump)
end
+
+ it "may or may not use object links for objects repeatedly dumped" do
+ # it's an MRI implementation detail - on x86 architecture object links
+ # aren't used for Float values but on amd64 - object links are used
+
+ dump = Marshal.dump([0.0, 0.0])
+ ["\x04\b[\af\x060@\x06", "\x04\b[\af\x060f\x060"].should.include?(dump)
+
+ # if object links aren't used - entries in the objects table are still
+ # occupied by Float values
+ if dump == "\x04\b[\af\x060f\x060"
+ s = "string"
+ # an index of "string" ("@\b") in the object table equals 3 (`"\b".ord - 5`),
+ # so `0.0, 0,0` elements occupied indices 1 and 2
+ Marshal.dump([0.0, 0.0, s, s]).should == "\x04\b[\tf\x060f\x060\"\vstring@\b"
+ end
+ end
end
describe "with a Bignum" do
@@ -256,6 +325,11 @@ describe "Marshal.dump" do
].should be_computed_by(:dump)
end
+ it "uses object links for objects repeatedly dumped" do
+ n = 2**64
+ Marshal.dump([n, n]).should == "\x04\b[\al+\n\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00@\x06" # @\x06 is a link to the object
+ end
+
it "increases the object links counter" do
obj = Object.new
object_1_link = "\x06" # representing of (0-based) index=1 (by adding 5 for small Integers)
@@ -275,33 +349,46 @@ describe "Marshal.dump" do
it "dumps a Rational" do
Marshal.dump(Rational(2, 3)).should == "\x04\bU:\rRational[\ai\ai\b"
end
+
+ it "uses object links for objects repeatedly dumped" do
+ r = Rational(2, 3)
+ Marshal.dump([r, r]).should == "\x04\b[\aU:\rRational[\ai\ai\b@\x06" # @\x06 is a link to the object
+ end
end
describe "with a Complex" do
it "dumps a Complex" do
Marshal.dump(Complex(2, 3)).should == "\x04\bU:\fComplex[\ai\ai\b"
end
+
+ it "uses object links for objects repeatedly dumped" do
+ c = Complex(2, 3)
+ Marshal.dump([c, c]).should == "\x04\b[\aU:\fComplex[\ai\ai\b@\x06" # @\x06 is a link to the object
+ end
end
- ruby_version_is "3.2" do
- describe "with a Data" do
- it "dumps a Data" do
- Marshal.dump(MarshalSpec::DataSpec::Measure.new(100, 'km')).should == "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
- end
+ describe "with a Data" do
+ it "dumps a Data" do
+ Marshal.dump(MarshalSpec::DataSpec::Measure.new(100, 'km')).should == "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
+ end
- it "dumps an extended Data" do
- obj = MarshalSpec::DataSpec::MeasureExtended.new(100, "km")
- Marshal.dump(obj).should == "\x04\bS:+MarshalSpec::DataSpec::MeasureExtended\a:\vamountii:\tunit\"\akm"
- end
+ it "dumps an extended Data" do
+ obj = MarshalSpec::DataSpec::MeasureExtended.new(100, "km")
+ Marshal.dump(obj).should == "\x04\bS:+MarshalSpec::DataSpec::MeasureExtended\a:\vamountii:\tunit\"\akm"
+ end
- it "ignores overridden name method" do
- obj = MarshalSpec::DataSpec::MeasureWithOverriddenName.new(100, "km")
- Marshal.dump(obj).should == "\x04\bS:5MarshalSpec::DataSpec::MeasureWithOverriddenName\a:\vamountii:\tunit\"\akm"
- end
+ it "ignores overridden name method" do
+ obj = MarshalSpec::DataSpec::MeasureWithOverriddenName.new(100, "km")
+ Marshal.dump(obj).should == "\x04\bS:5MarshalSpec::DataSpec::MeasureWithOverriddenName\a:\vamountii:\tunit\"\akm"
+ end
- it "raises TypeError with an anonymous Struct" do
- -> { Marshal.dump(Data.define(:a).new(1)) }.should raise_error(TypeError, /can't dump anonymous class/)
- end
+ it "uses object links for objects repeatedly dumped" do
+ d = MarshalSpec::DataSpec::Measure.new(100, 'km')
+ Marshal.dump([d, d]).should == "\x04\b[\aS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm@\x06" # @\x06 is a link to the object
+ end
+
+ it "raises TypeError with an anonymous Struct" do
+ -> { Marshal.dump(Data.define(:a).new(1)) }.should raise_error(TypeError, /can't dump anonymous class/)
end
end
@@ -360,6 +447,21 @@ describe "Marshal.dump" do
it "dumps multiple strings using symlinks for the :E (encoding) symbol" do
Marshal.dump(["".encode("us-ascii"), "".encode("utf-8")]).should == "\x04\b[\aI\"\x00\x06:\x06EFI\"\x00\x06;\x00T"
end
+
+ it "uses object links for objects repeatedly dumped" do
+ s = "string"
+ Marshal.dump([s, s]).should == "\x04\b[\a\"\vstring@\x06" # @\x06 is a link to the object
+ end
+
+ it "adds instance variables after the object itself into the objects table" do
+ obj = +"string"
+ value = "<foo>"
+ obj.instance_variable_set :@foo, value
+
+ # expect a link to the object (@\x06, that means Integer 1) is smaller than a link
+ # to the instance variable value (@\a, that means Integer 2)
+ Marshal.dump([obj, obj, value]).should == "\x04\b[\bI\"\vstring\x06:\t@foo\"\n<foo>@\x06@\a"
+ end
end
describe "with a Regexp" do
@@ -427,6 +529,11 @@ describe "Marshal.dump" do
obj = MarshalSpec::RegexpWithOverriddenName.new("")
Marshal.dump(obj).should == "\x04\bIC:*MarshalSpec::RegexpWithOverriddenName/\x00\x00\x06:\x06EF"
end
+
+ it "uses object links for objects repeatedly dumped" do
+ r = /\A.\Z/
+ Marshal.dump([r, r]).should == "\x04\b[\aI/\n\\A.\\Z\x00\x06:\x06EF@\x06" # @\x06 is a link to the object
+ end
end
describe "with an Array" do
@@ -462,6 +569,21 @@ describe "Marshal.dump" do
obj = MarshalSpec::ArrayWithOverriddenName.new
Marshal.dump(obj).should == "\x04\bC:)MarshalSpec::ArrayWithOverriddenName[\x00"
end
+
+ it "uses object links for objects repeatedly dumped" do
+ a = [1]
+ Marshal.dump([a, a]).should == "\x04\b[\a[\x06i\x06@\x06" # @\x06 is a link to the object
+ end
+
+ it "adds instance variables after the object itself into the objects table" do
+ obj = []
+ value = "<foo>"
+ obj.instance_variable_set :@foo, value
+
+ # expect a link to the object (@\x06, that means Integer 1) is smaller than a link
+ # to the instance variable value (@\a, that means Integer 2)
+ Marshal.dump([obj, obj, value]).should == "\x04\b[\bI[\x00\x06:\t@foo\"\n<foo>@\x06@\a"
+ end
end
describe "with a Hash" do
@@ -481,20 +603,18 @@ describe "Marshal.dump" do
Marshal.dump(Hash.new(1)).should == "\004\b}\000i\006"
end
- ruby_version_is "3.1" do
- it "dumps a Hash with compare_by_identity" do
- h = {}
- h.compare_by_identity
+ it "dumps a Hash with compare_by_identity" do
+ h = {}
+ h.compare_by_identity
- Marshal.dump(h).should == "\004\bC:\tHash{\x00"
- end
+ Marshal.dump(h).should == "\004\bC:\tHash{\x00"
+ end
- it "dumps a Hash subclass with compare_by_identity" do
- h = UserHash.new
- h.compare_by_identity
+ it "dumps a Hash subclass with compare_by_identity" do
+ h = UserHash.new
+ h.compare_by_identity
- Marshal.dump(h).should == "\x04\bC:\rUserHashC:\tHash{\x00"
- end
+ Marshal.dump(h).should == "\x04\bC:\rUserHashC:\tHash{\x00"
end
it "raises a TypeError with hash having default proc" do
@@ -519,6 +639,21 @@ describe "Marshal.dump" do
obj = MarshalSpec::HashWithOverriddenName.new
Marshal.dump(obj).should == "\x04\bC:(MarshalSpec::HashWithOverriddenName{\x00"
end
+
+ it "uses object links for objects repeatedly dumped" do
+ h = {a: 1}
+ Marshal.dump([h, h]).should == "\x04\b[\a{\x06:\x06ai\x06@\x06" # @\x06 is a link to the object
+ end
+
+ it "adds instance variables after the object itself into the objects table" do
+ obj = {}
+ value = "<foo>"
+ obj.instance_variable_set :@foo, value
+
+ # expect a link to the object (@\x06, that means Integer 1) is smaller than a link
+ # to the instance variable value (@\a, that means Integer 2)
+ Marshal.dump([obj, obj, value]).should == "\x04\b[\bI{\x00\x06:\t@foo\"\n<foo>@\x06@\a"
+ end
end
describe "with a Struct" do
@@ -553,9 +688,24 @@ describe "Marshal.dump" do
Marshal.dump(obj).should == "\x04\bS:*MarshalSpec::StructWithOverriddenName\x06:\x06a\"\vmember"
end
+ it "uses object links for objects repeatedly dumped" do
+ s = Struct::Pyramid.new
+ Marshal.dump([s, s]).should == "\x04\b[\aS:\x14Struct::Pyramid\x00@\x06" # @\x06 is a link to the object
+ end
+
it "raises TypeError with an anonymous Struct" do
-> { Marshal.dump(Struct.new(:a).new(1)) }.should raise_error(TypeError, /can't dump anonymous class/)
end
+
+ it "adds instance variables after the object itself into the objects table" do
+ obj = Struct::Pyramid.new
+ value = "<foo>"
+ obj.instance_variable_set :@foo, value
+
+ # expect a link to the object (@\x06, that means Integer 1) is smaller than a link
+ # to the instance variable value (@\a, that means Integer 2)
+ Marshal.dump([obj, obj, value]).should == "\x04\b[\bIS:\x14Struct::Pyramid\x00\x06:\t@foo\"\n<foo>@\x06@\a"
+ end
end
describe "with an Object" do
@@ -645,21 +795,45 @@ describe "Marshal.dump" do
ObjectSpace.define_finalizer(obj, finalizer.method(:noop))
Marshal.load(Marshal.dump(obj)).class.should == Object
end
+
+ it "uses object links for objects repeatedly dumped" do
+ obj = Object.new
+ Marshal.dump([obj, obj]).should == "\x04\b[\ao:\vObject\x00@\x06" # @\x06 is a link to the object
+ end
+
+ it "adds instance variables after the object itself into the objects table" do
+ obj = Object.new
+ value = "<foo>"
+ obj.instance_variable_set :@foo, value
+
+ # expect a link to the object (@\x06, that means Integer 1) is smaller than a link
+ # to the instance variable value (@\a, that means Integer 2)
+ Marshal.dump([obj, obj, value]).should == "\x04\b[\bo:\vObject\x06:\t@foo\"\n<foo>@\x06@\a"
+ end
end
describe "with a Range" do
- it "dumps a Range inclusive of end (with indeterminant order)" do
+ it "dumps a Range inclusive of end" do
dump = Marshal.dump(1..2)
+ dump.should == "\x04\bo:\nRange\b:\texclF:\nbegini\x06:\bendi\a"
+
load = Marshal.load(dump)
load.should == (1..2)
end
- it "dumps a Range exclusive of end (with indeterminant order)" do
+ it "dumps a Range exclusive of end" do
dump = Marshal.dump(1...2)
+ dump.should == "\x04\bo:\nRange\b:\texclT:\nbegini\x06:\bendi\a"
+
load = Marshal.load(dump)
load.should == (1...2)
end
+ it "uses object links for objects repeatedly dumped" do
+ r = 1..2
+ Marshal.dump([r, r]).should == "\x04\b[\ao:\nRange\b:\texclF:\nbegini\x06:\bendi\a@\x06" # @\x06 is a link to the object
+ end
+
it "raises TypeError with an anonymous Range subclass" do
-> { Marshal.dump(Class.new(Range).new(1, 2)) }.should raise_error(TypeError, /can't dump anonymous class/)
end
@@ -706,9 +880,32 @@ describe "Marshal.dump" do
Marshal.dump(obj).should include("MarshalSpec::TimeWithOverriddenName")
end
- it "dumps a Time subclass with multibyte characters in name" do
- source_object = eval("MarshalSpec::Multibyteãã‚ãƒã„Time".dup.force_encoding(Encoding::UTF_8))
- Marshal.dump(source_object).should == "\x04\bc+MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Time"
+ ruby_version_is "4.0" do
+ it "dumps a Time subclass with multibyte characters in name" do
+ source_object = eval("MarshalSpec::Multibyteãã‚ãƒã„Time".dup.force_encoding(Encoding::UTF_8))
+ Marshal.dump(source_object).should == "\x04\bIc+MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Time\x06:\x06ET"
+ Marshal.load(Marshal.dump(source_object)) == source_object
+ end
+ end
+
+ it "uses object links for objects repeatedly dumped" do
+ # order of the offset and zone instance variables is a subject to change
+ # and may be different on different CRuby versions
+ base = Regexp.quote("\x04\b[\aIu:\tTime\r\xF5\xEF\e\x80\x00\x00\x00\x00\a")
+ offset = Regexp.quote(":\voffseti\x020*:\tzoneI\"\bAST\x06:\x06EF")
+ zone = Regexp.quote(":\tzoneI\"\bAST\x06:\x06EF:\voffseti\x020*")
+ instance_variables = /#{offset}|#{zone}/
+ Marshal.dump([@t, @t]).should =~ /\A#{base}#{instance_variables}@\a\Z/ # @\a is a link to the object
+ end
+
+ it "adds instance variables before the object itself into the objects table" do
+ obj = @utc
+ value = "<foo>"
+ obj.instance_variable_set :@foo, value
+
+ # expect a link to the object (@\b, that means Integer 3) is greater than a link
+ # to the instance variable value (@\x06, that means Integer 1)
+ Marshal.dump([obj, obj, value]).should == "\x04\b[\bIu:\tTime\r \x00\x1C\xC0\x00\x00\x00\x00\a:\t@foo\"\n<foo>:\tzoneI\"\bUTC\x06:\x06EF@\b@\x06"
end
it "raises TypeError with an anonymous Time subclass" do
@@ -765,6 +962,21 @@ describe "Marshal.dump" do
Marshal.dump(e).should =~ /undefined method [`']foo' for ("":String|an instance of String)/
end
+ it "uses object links for objects repeatedly dumped" do
+ e = Exception.new
+ Marshal.dump([e, e]).should == "\x04\b[\ao:\x0EException\a:\tmesg0:\abt0@\x06" # @\x\a is a link to the object
+ end
+
+ it "adds instance variables after the object itself into the objects table" do
+ obj = Exception.new
+ value = "<foo>"
+ obj.instance_variable_set :@foo, value
+
+ # expect a link to the object (@\x06, that means Integer 1) is smaller than a link
+ # to the instance variable value (@\a, that means Integer 2)
+ Marshal.dump([obj, obj, value]).should == "\x04\b[\bo:\x0EException\b:\tmesg0:\abt0:\t@foo\"\n<foo>@\x06@\a"
+ end
+
it "raises TypeError if an Object is an instance of an anonymous class" do
anonymous_class = Class.new(Exception)
obj = anonymous_class.new
diff --git a/spec/ruby/core/marshal/fixtures/marshal_data.rb b/spec/ruby/core/marshal/fixtures/marshal_data.rb
index 97fd78b2d7..c16d9e4bb6 100644
--- a/spec/ruby/core/marshal/fixtures/marshal_data.rb
+++ b/spec/ruby/core/marshal/fixtures/marshal_data.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative 'marshal_multibyte_data'
@@ -97,6 +97,25 @@ class UserDefinedString
end
end
+module MarshalSpec
+ class UserDefinedDumpWithIVars
+ attr_reader :string
+
+ def initialize(string, ivar_value)
+ @string = string
+ @string.instance_variable_set(:@foo, ivar_value)
+ end
+
+ def _dump(depth)
+ @string
+ end
+
+ def self._load(data)
+ new(data)
+ end
+ end
+end
+
class UserPreviouslyDefinedWithInitializedIvar
attr_accessor :field1, :field2
end
@@ -139,6 +158,32 @@ class UserMarshalWithIvar
end
end
+module MarshalSpec
+ class UserMarshalDumpWithIvar
+ attr_reader :data
+
+ def initialize(data, ivar_value)
+ @data = data
+ @ivar_value = ivar_value
+ end
+
+ def marshal_dump
+ obj = [data]
+ obj.instance_variable_set(:@foo, @ivar_value)
+ obj
+ end
+
+ def marshal_load(o)
+ @data = o[0]
+ end
+
+ def ==(other)
+ self.class === other and
+ @data = other.data
+ end
+ end
+end
+
class UserArray < Array
end
@@ -487,18 +532,16 @@ module MarshalSpec
"Random" => random_data,
}
- if defined? Data # TODO: remove the condition when minimal supported version is 3.2
- module DataSpec
- Measure = Data.define(:amount, :unit)
- Empty = Data.define
+ module DataSpec
+ Measure = Data.define(:amount, :unit)
+ Empty = Data.define
- MeasureExtended = Class.new(Measure)
- MeasureExtended.extend(Enumerable)
+ MeasureExtended = Class.new(Measure)
+ MeasureExtended.extend(Enumerable)
- class MeasureWithOverriddenName < Measure
- def self.name
- "Foo"
- end
+ class MeasureWithOverriddenName < Measure
+ def self.name
+ "Foo"
end
end
end
diff --git a/spec/ruby/core/marshal/shared/load.rb b/spec/ruby/core/marshal/shared/load.rb
index fd6490153c..204a4d34e3 100644
--- a/spec/ruby/core/marshal/shared/load.rb
+++ b/spec/ruby/core/marshal/shared/load.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../fixtures/marshal_data'
describe :marshal_load, shared: true do
@@ -23,250 +23,164 @@ describe :marshal_load, shared: true do
-> { Marshal.send(@method, kaboom) }.should raise_error(ArgumentError)
end
- ruby_version_is "3.1" do
- describe "when called with freeze: true" do
- it "returns frozen strings" do
- string = Marshal.send(@method, Marshal.dump("foo"), freeze: true)
- string.should == "foo"
- string.should.frozen?
-
- utf8_string = "foo".encode(Encoding::UTF_8)
- string = Marshal.send(@method, Marshal.dump(utf8_string), freeze: true)
- string.should == utf8_string
- string.should.frozen?
- end
-
- it "returns frozen arrays" do
- array = Marshal.send(@method, Marshal.dump([1, 2, 3]), freeze: true)
- array.should == [1, 2, 3]
- array.should.frozen?
- end
-
- it "returns frozen hashes" do
- hash = Marshal.send(@method, Marshal.dump({foo: 42}), freeze: true)
- hash.should == {foo: 42}
- hash.should.frozen?
- end
-
- it "returns frozen regexps" do
- regexp = Marshal.send(@method, Marshal.dump(/foo/), freeze: true)
- regexp.should == /foo/
- regexp.should.frozen?
- end
+ describe "when called with freeze: true" do
+ it "returns frozen strings" do
+ string = Marshal.send(@method, Marshal.dump("foo"), freeze: true)
+ string.should == "foo"
+ string.should.frozen?
- it "returns frozen structs" do
- struct = Marshal.send(@method, Marshal.dump(MarshalSpec::StructToDump.new(1, 2)), freeze: true)
- struct.should == MarshalSpec::StructToDump.new(1, 2)
- struct.should.frozen?
- end
+ utf8_string = "foo".encode(Encoding::UTF_8)
+ string = Marshal.send(@method, Marshal.dump(utf8_string), freeze: true)
+ string.should == utf8_string
+ string.should.frozen?
+ end
- it "returns frozen objects" do
- source_object = Object.new
+ it "returns frozen arrays" do
+ array = Marshal.send(@method, Marshal.dump([1, 2, 3]), freeze: true)
+ array.should == [1, 2, 3]
+ array.should.frozen?
+ end
- object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
- object.should.frozen?
- end
+ it "returns frozen hashes" do
+ hash = Marshal.send(@method, Marshal.dump({foo: 42}), freeze: true)
+ hash.should == {foo: 42}
+ hash.should.frozen?
+ end
- describe "deep freezing" do
- it "returns hashes with frozen keys and values" do
- key = Object.new
- value = Object.new
- source_object = {key => value}
+ it "returns frozen regexps" do
+ regexp = Marshal.send(@method, Marshal.dump(/foo/), freeze: true)
+ regexp.should == /foo/
+ regexp.should.frozen?
+ end
- hash = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
- hash.size.should == 1
- hash.keys[0].should.frozen?
- hash.values[0].should.frozen?
- end
+ it "returns frozen structs" do
+ struct = Marshal.send(@method, Marshal.dump(MarshalSpec::StructToDump.new(1, 2)), freeze: true)
+ struct.should == MarshalSpec::StructToDump.new(1, 2)
+ struct.should.frozen?
+ end
- it "returns arrays with frozen elements" do
- object = Object.new
- source_object = [object]
+ it "returns frozen objects" do
+ source_object = Object.new
- array = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
- array.size.should == 1
- array[0].should.frozen?
- end
+ object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ object.should.frozen?
+ end
- it "returns structs with frozen members" do
- object1 = Object.new
- object2 = Object.new
- source_object = MarshalSpec::StructToDump.new(object1, object2)
+ describe "deep freezing" do
+ it "returns hashes with frozen keys and values" do
+ key = Object.new
+ value = Object.new
+ source_object = {key => value}
- struct = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
- struct.a.should.frozen?
- struct.b.should.frozen?
- end
+ hash = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ hash.size.should == 1
+ hash.keys[0].should.frozen?
+ hash.values[0].should.frozen?
+ end
- it "returns objects with frozen instance variables" do
- source_object = Object.new
- instance_variable = Object.new
- source_object.instance_variable_set(:@a, instance_variable)
+ it "returns arrays with frozen elements" do
+ object = Object.new
+ source_object = [object]
- object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
- object.instance_variable_get(:@a).should != nil
- object.instance_variable_get(:@a).should.frozen?
- end
+ array = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ array.size.should == 1
+ array[0].should.frozen?
+ end
- it "deduplicates frozen strings" do
- source_object = ["foo" + "bar", "foobar"]
- object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ it "returns structs with frozen members" do
+ object1 = Object.new
+ object2 = Object.new
+ source_object = MarshalSpec::StructToDump.new(object1, object2)
- object[0].should equal(object[1])
- end
+ struct = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ struct.a.should.frozen?
+ struct.b.should.frozen?
end
- it "does not freeze modules" do
- object = Marshal.send(@method, Marshal.dump(Kernel), freeze: true)
- object.should_not.frozen?
- Kernel.should_not.frozen?
- end
+ it "returns objects with frozen instance variables" do
+ source_object = Object.new
+ instance_variable = Object.new
+ source_object.instance_variable_set(:@a, instance_variable)
- it "does not freeze classes" do
- object = Marshal.send(@method, Marshal.dump(Object), freeze: true)
- object.should_not.frozen?
- Object.should_not.frozen?
+ object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ object.instance_variable_get(:@a).should != nil
+ object.instance_variable_get(:@a).should.frozen?
end
- ruby_bug "#19427", ""..."3.3" do
- it "does freeze extended objects" do
- object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", freeze: true)
- object.should.frozen?
- end
+ it "deduplicates frozen strings" do
+ source_object = ["foo" + "bar", "foobar"]
+ object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
- it "does freeze extended objects with instance variables" do
- object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x06:\n@ivarT", freeze: true)
- object.should.frozen?
- end
+ object[0].should equal(object[1])
end
+ end
- ruby_bug "#19427", "3.1"..."3.3" do
- it "returns frozen object having #_dump method" do
- object = Marshal.send(@method, Marshal.dump(UserDefined.new), freeze: true)
- object.should.frozen?
- end
-
- it "returns frozen object responding to #marshal_dump and #marshal_load" do
- object = Marshal.send(@method, Marshal.dump(UserMarshal.new), freeze: true)
- object.should.frozen?
- end
+ it "does not freeze modules" do
+ object = Marshal.send(@method, Marshal.dump(Kernel), freeze: true)
+ object.should_not.frozen?
+ Kernel.should_not.frozen?
+ end
- it "returns frozen object extended by a module" do
- object = Object.new
- object.extend(MarshalSpec::ModuleToExtendBy)
+ it "does not freeze classes" do
+ object = Marshal.send(@method, Marshal.dump(Object), freeze: true)
+ object.should_not.frozen?
+ Object.should_not.frozen?
+ end
- object = Marshal.send(@method, Marshal.dump(object), freeze: true)
- object.should.frozen?
- end
+ ruby_bug "#19427", ""..."3.3" do
+ it "does freeze extended objects" do
+ object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", freeze: true)
+ object.should.frozen?
end
- it "does not call freeze method" do
- object = MarshalSpec::ObjectWithFreezeRaisingException.new
- object = Marshal.send(@method, Marshal.dump(object), freeze: true)
+ it "does freeze extended objects with instance variables" do
+ object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x06:\n@ivarT", freeze: true)
object.should.frozen?
end
+ end
- it "returns frozen object even if object does not respond to freeze method" do
- object = MarshalSpec::ObjectWithoutFreeze.new
- object = Marshal.send(@method, Marshal.dump(object), freeze: true)
+ ruby_bug "#19427", ""..."3.3" do
+ it "returns frozen object having #_dump method" do
+ object = Marshal.send(@method, Marshal.dump(UserDefined.new), freeze: true)
object.should.frozen?
end
- it "returns a frozen object when is an instance of String/Array/Regexp/Hash subclass and has instance variables" do
- source_object = UserString.new
- source_object.instance_variable_set(:@foo, "bar")
-
- object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ it "returns frozen object responding to #marshal_dump and #marshal_load" do
+ object = Marshal.send(@method, Marshal.dump(UserMarshal.new), freeze: true)
object.should.frozen?
end
- describe "when called with a proc" do
- it "call the proc with frozen objects" do
- arr = []
- s = +'hi'
- s.instance_variable_set(:@foo, 5)
- st = Struct.new("Brittle", :a).new
- st.instance_variable_set(:@clue, 'none')
- st.a = 0.0
- h = Hash.new('def')
- h['nine'] = 9
- a = [:a, :b, :c]
- a.instance_variable_set(:@two, 2)
- obj = [s, 10, s, s, st, a]
- obj.instance_variable_set(:@zoo, 'ant')
- proc = Proc.new { |o| arr << o; o}
-
- Marshal.send(
- @method,
- "\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F",
- proc,
- freeze: true,
- )
-
- arr.should == [
- false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st,
- :b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]],
- ]
-
- arr.each do |v|
- v.should.frozen?
- end
-
- Struct.send(:remove_const, :Brittle)
- end
+ it "returns frozen object extended by a module" do
+ object = Object.new
+ object.extend(MarshalSpec::ModuleToExtendBy)
- it "does not freeze the object returned by the proc" do
- string = Marshal.send(@method, Marshal.dump("foo"), proc { |o| o.upcase }, freeze: true)
- string.should == "FOO"
- string.should_not.frozen?
- end
+ object = Marshal.send(@method, Marshal.dump(object), freeze: true)
+ object.should.frozen?
end
end
- end
- describe "when called with a proc" do
- ruby_bug "#18141", ""..."3.1" do
- it "call the proc with fully initialized strings" do
- utf8_string = "foo".encode(Encoding::UTF_8)
- Marshal.send(@method, Marshal.dump(utf8_string), proc { |arg|
- if arg.is_a?(String)
- arg.should == utf8_string
- arg.encoding.should == Encoding::UTF_8
- end
- arg
- })
- end
-
- it "no longer mutate the object after it was passed to the proc" do
- string = Marshal.load(Marshal.dump("foo"), :freeze.to_proc)
- string.should.frozen?
- end
+ it "does not call freeze method" do
+ object = MarshalSpec::ObjectWithFreezeRaisingException.new
+ object = Marshal.send(@method, Marshal.dump(object), freeze: true)
+ object.should.frozen?
end
- ruby_bug "#19427", ""..."3.3" do
- it "call the proc with extended objects" do
- objs = []
- obj = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", Proc.new { |o| objs << o; o })
- objs.should == [obj]
- end
+ it "returns frozen object even if object does not respond to freeze method" do
+ object = MarshalSpec::ObjectWithoutFreeze.new
+ object = Marshal.send(@method, Marshal.dump(object), freeze: true)
+ object.should.frozen?
end
- it "returns the value of the proc" do
- Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4]
- end
+ it "returns a frozen object when is an instance of String/Array/Regexp/Hash subclass and has instance variables" do
+ source_object = UserString.new
+ source_object.instance_variable_set(:@foo, "bar")
- ruby_bug "#18141", ""..."3.1" do
- it "calls the proc for recursively visited data" do
- a = [1]
- a << a
- ret = []
- Marshal.send(@method, Marshal.dump(a), proc { |arg| ret << arg.inspect; arg })
- ret[0].should == 1.inspect
- ret[1].should == a.inspect
- ret.size.should == 2
- end
+ object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ object.should.frozen?
+ end
- it "loads an Array with proc" do
+ describe "when called with a proc" do
+ it "call the proc with frozen objects" do
arr = []
s = +'hi'
s.instance_variable_set(:@foo, 5)
@@ -279,16 +193,96 @@ describe :marshal_load, shared: true do
a.instance_variable_set(:@two, 2)
obj = [s, 10, s, s, st, a]
obj.instance_variable_set(:@zoo, 'ant')
- proc = Proc.new { |o| arr << o.dup; o}
+ proc = Proc.new { |o| arr << o; o}
- Marshal.send(@method, "\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F", proc)
+ Marshal.send(
+ @method,
+ "\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F",
+ proc,
+ freeze: true,
+ )
arr.should == [
false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st,
:b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]],
]
+
+ arr.each do |v|
+ v.should.frozen?
+ end
+
Struct.send(:remove_const, :Brittle)
end
+
+ it "does not freeze the object returned by the proc" do
+ string = Marshal.send(@method, Marshal.dump("foo"), proc { |o| o.upcase }, freeze: true)
+ string.should == "FOO"
+ string.should_not.frozen?
+ end
+ end
+ end
+
+ describe "when called with a proc" do
+ it "call the proc with fully initialized strings" do
+ utf8_string = "foo".encode(Encoding::UTF_8)
+ Marshal.send(@method, Marshal.dump(utf8_string), proc { |arg|
+ if arg.is_a?(String)
+ arg.should == utf8_string
+ arg.encoding.should == Encoding::UTF_8
+ end
+ arg
+ })
+ end
+
+ it "no longer mutate the object after it was passed to the proc" do
+ string = Marshal.load(Marshal.dump("foo"), :freeze.to_proc)
+ string.should.frozen?
+ end
+
+ ruby_bug "#19427", ""..."3.3" do
+ it "call the proc with extended objects" do
+ objs = []
+ obj = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", Proc.new { |o| objs << o; o })
+ objs.should == [obj]
+ end
+ end
+
+ it "returns the value of the proc" do
+ Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4]
+ end
+
+ it "calls the proc for recursively visited data" do
+ a = [1]
+ a << a
+ ret = []
+ Marshal.send(@method, Marshal.dump(a), proc { |arg| ret << arg.inspect; arg })
+ ret[0].should == 1.inspect
+ ret[1].should == a.inspect
+ ret.size.should == 2
+ end
+
+ it "loads an Array with proc" do
+ arr = []
+ s = +'hi'
+ s.instance_variable_set(:@foo, 5)
+ st = Struct.new("Brittle", :a).new
+ st.instance_variable_set(:@clue, 'none')
+ st.a = 0.0
+ h = Hash.new('def')
+ h['nine'] = 9
+ a = [:a, :b, :c]
+ a.instance_variable_set(:@two, 2)
+ obj = [s, 10, s, s, st, a]
+ obj.instance_variable_set(:@zoo, 'ant')
+ proc = Proc.new { |o| arr << o.dup; o}
+
+ Marshal.send(@method, "\x04\bI[\vI\"\ahi\a:\x06EF:\t@fooi\ni\x0F@\x06@\x06IS:\x14Struct::Brittle\x06:\x06af\x060\x06:\n@clueI\"\tnone\x06;\x00FI[\b;\b:\x06b:\x06c\x06:\t@twoi\a\x06:\t@zooI\"\bant\x06;\x00F", proc)
+
+ arr.should == [
+ false, 5, "hi", 10, "hi", "hi", 0.0, false, "none", st,
+ :b, :c, 2, a, false, "ant", ["hi", 10, "hi", "hi", st, [:a, :b, :c]],
+ ]
+ Struct.send(:remove_const, :Brittle)
end
end
@@ -364,39 +358,37 @@ describe :marshal_load, shared: true do
end
end
- ruby_bug "#18141", ""..."3.1" do
- it "loads an array containing objects having _dump method, and with proc" do
- arr = []
- myproc = Proc.new { |o| arr << o.dup; o }
- o1 = UserDefined.new;
- o2 = UserDefinedWithIvar.new
- obj = [o1, o2, o1, o2]
+ it "loads an array containing objects having _dump method, and with proc" do
+ arr = []
+ myproc = Proc.new { |o| arr << o.dup; o }
+ o1 = UserDefined.new;
+ o2 = UserDefinedWithIvar.new
+ obj = [o1, o2, o1, o2]
- Marshal.send(@method, "\x04\b[\tu:\x10UserDefined\x18\x04\b[\aI\"\nstuff\x06:\x06EF@\x06u:\x18UserDefinedWithIvar>\x04\b[\bI\"\nstuff\a:\x06EF:\t@foo:\x18UserDefinedWithIvarI\"\tmore\x06;\x00F@\a@\x06@\a", myproc)
+ Marshal.send(@method, "\x04\b[\tu:\x10UserDefined\x18\x04\b[\aI\"\nstuff\x06:\x06EF@\x06u:\x18UserDefinedWithIvar>\x04\b[\bI\"\nstuff\a:\x06EF:\t@foo:\x18UserDefinedWithIvarI\"\tmore\x06;\x00F@\a@\x06@\a", myproc)
- arr[0].should == o1
- arr[1].should == o2
- arr[2].should == obj
- arr.size.should == 3
- end
+ arr[0].should == o1
+ arr[1].should == o2
+ arr[2].should == obj
+ arr.size.should == 3
+ end
- it "loads an array containing objects having marshal_dump method, and with proc" do
- arr = []
- proc = Proc.new { |o| arr << o.dup; o }
- o1 = UserMarshal.new
- o2 = UserMarshalWithIvar.new
+ it "loads an array containing objects having marshal_dump method, and with proc" do
+ arr = []
+ proc = Proc.new { |o| arr << o.dup; o }
+ o1 = UserMarshal.new
+ o2 = UserMarshalWithIvar.new
- Marshal.send(@method, "\004\b[\tU:\020UserMarshal\"\nstuffU:\030UserMarshalWithIvar[\006\"\fmy data@\006@\b", proc)
+ Marshal.send(@method, "\004\b[\tU:\020UserMarshal\"\nstuffU:\030UserMarshalWithIvar[\006\"\fmy data@\006@\b", proc)
- arr[0].should == 'stuff'
- arr[1].should == o1
- arr[2].should == 'my data'
- arr[3].should == ['my data']
- arr[4].should == o2
- arr[5].should == [o1, o2, o1, o2]
+ arr[0].should == 'stuff'
+ arr[1].should == o1
+ arr[2].should == 'my data'
+ arr[3].should == ['my data']
+ arr[4].should == o2
+ arr[5].should == [o1, o2, o1, o2]
- arr.size.should == 6
- end
+ arr.size.should == 6
end
it "assigns classes to nested subclasses of Array correctly" do
@@ -526,28 +518,26 @@ describe :marshal_load, shared: true do
unmarshalled[:key].instance_variable_get(:@string_ivar).should == 'string ivar'
end
- ruby_version_is "3.1" do
- it "preserves compare_by_identity behaviour" do
- h = { a: 1 }
- h.compare_by_identity
- unmarshalled = Marshal.send(@method, Marshal.dump(h))
- unmarshalled.should.compare_by_identity?
+ it "preserves compare_by_identity behaviour" do
+ h = { a: 1 }
+ h.compare_by_identity
+ unmarshalled = Marshal.send(@method, Marshal.dump(h))
+ unmarshalled.should.compare_by_identity?
- h = { a: 1 }
- unmarshalled = Marshal.send(@method, Marshal.dump(h))
- unmarshalled.should_not.compare_by_identity?
- end
+ h = { a: 1 }
+ unmarshalled = Marshal.send(@method, Marshal.dump(h))
+ unmarshalled.should_not.compare_by_identity?
+ end
- it "preserves compare_by_identity behaviour for a Hash subclass" do
- h = UserHash.new({ a: 1 })
- h.compare_by_identity
- unmarshalled = Marshal.send(@method, Marshal.dump(h))
- unmarshalled.should.compare_by_identity?
+ it "preserves compare_by_identity behaviour for a Hash subclass" do
+ h = UserHash.new({ a: 1 })
+ h.compare_by_identity
+ unmarshalled = Marshal.send(@method, Marshal.dump(h))
+ unmarshalled.should.compare_by_identity?
- h = UserHash.new({ a: 1 })
- unmarshalled = Marshal.send(@method, Marshal.dump(h))
- unmarshalled.should_not.compare_by_identity?
- end
+ h = UserHash.new({ a: 1 })
+ unmarshalled = Marshal.send(@method, Marshal.dump(h))
+ unmarshalled.should_not.compare_by_identity?
end
it "allocates an instance of the proper class when Hash subclass with compare_by_identity behaviour" do
@@ -749,31 +739,29 @@ describe :marshal_load, shared: true do
end
end
- ruby_version_is "3.2" do
- describe "for a Data" do
- it "loads a Data" do
- obj = MarshalSpec::DataSpec::Measure.new(100, 'km')
- dumped = "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
- Marshal.dump(obj).should == dumped
+ describe "for a Data" do
+ it "loads a Data" do
+ obj = MarshalSpec::DataSpec::Measure.new(100, 'km')
+ dumped = "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
+ Marshal.dump(obj).should == dumped
- Marshal.send(@method, dumped).should == obj
- end
+ Marshal.send(@method, dumped).should == obj
+ end
- it "loads an extended Data" do
- obj = MarshalSpec::DataSpec::MeasureExtended.new(100, "km")
- dumped = "\x04\bS:+MarshalSpec::DataSpec::MeasureExtended\a:\vamountii:\tunit\"\akm"
- Marshal.dump(obj).should == dumped
+ it "loads an extended Data" do
+ obj = MarshalSpec::DataSpec::MeasureExtended.new(100, "km")
+ dumped = "\x04\bS:+MarshalSpec::DataSpec::MeasureExtended\a:\vamountii:\tunit\"\akm"
+ Marshal.dump(obj).should == dumped
- Marshal.send(@method, dumped).should == obj
- end
+ Marshal.send(@method, dumped).should == obj
+ end
- it "returns a frozen object" do
- obj = MarshalSpec::DataSpec::Measure.new(100, 'km')
- dumped = "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
- Marshal.dump(obj).should == dumped
+ it "returns a frozen object" do
+ obj = MarshalSpec::DataSpec::Measure.new(100, 'km')
+ dumped = "\x04\bS:#MarshalSpec::DataSpec::Measure\a:\vamountii:\tunit\"\akm"
+ Marshal.dump(obj).should == dumped
- Marshal.send(@method, dumped).should.frozen?
- end
+ Marshal.send(@method, dumped).should.frozen?
end
end
diff --git a/spec/ruby/core/matchdata/bytebegin_spec.rb b/spec/ruby/core/matchdata/bytebegin_spec.rb
new file mode 100644
index 0000000000..08c1fd6d1e
--- /dev/null
+++ b/spec/ruby/core/matchdata/bytebegin_spec.rb
@@ -0,0 +1,132 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.4" do
+ describe "MatchData#bytebegin" do
+ context "when passed an integer argument" do
+ it "returns the byte-based offset of the start of the nth element" do
+ match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(0).should == 1
+ match_data.bytebegin(2).should == 2
+ end
+
+ it "returns nil when the nth match isn't found" do
+ match_data = /something is( not)? (right)/.match("something is right")
+ match_data.bytebegin(1).should be_nil
+ end
+
+ it "returns the byte-based offset for multi-byte strings" do
+ match_data = /(.)(.)(\d+)(\d)/.match("TñX1138.")
+ match_data.bytebegin(0).should == 1
+ match_data.bytebegin(2).should == 3
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi-byte strings with unicode regexp" do
+ match_data = /(.)(.)(\d+)(\d)/u.match("TñX1138.")
+ match_data.bytebegin(0).should == 1
+ match_data.bytebegin(2).should == 3
+ end
+ end
+
+ it "tries to convert the passed argument to an Integer using #to_int" do
+ obj = mock('to_int')
+ obj.should_receive(:to_int).and_return(2)
+
+ match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(obj).should == 2
+ end
+
+ it "raises IndexError if index is out of bounds" do
+ match_data = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ match_data.bytebegin(-1)
+ }.should raise_error(IndexError, "index -1 out of matches")
+
+ -> {
+ match_data.bytebegin(3)
+ }.should raise_error(IndexError, "index 3 out of matches")
+ end
+ end
+
+ context "when passed a String argument" do
+ it "return the byte-based offset of the start of the named capture" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin("a").should == 1
+ match_data.bytebegin("b").should == 3
+ end
+
+ it "returns the byte-based offset for multi byte strings" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("TñX1138.")
+ match_data.bytebegin("a").should == 1
+ match_data.bytebegin("b").should == 4
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi byte strings with unicode regexp" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/u.match("TñX1138.")
+ match_data.bytebegin("a").should == 1
+ match_data.bytebegin("b").should == 4
+ end
+ end
+
+ it "returns the byte-based offset for the farthest match when multiple named captures use the same name" do
+ match_data = /(?<a>.)(.)(?<a>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin("a").should == 3
+ end
+
+ it "returns the byte-based offset for multi-byte names" do
+ match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin("æ").should == 1
+ end
+
+ it "raises IndexError if there is no group with the provided name" do
+ match_data = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ match_data.bytebegin("y")
+ }.should raise_error(IndexError, "undefined group name reference: y")
+ end
+ end
+
+ context "when passed a Symbol argument" do
+ it "return the byte-based offset of the start of the named capture" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(:a).should == 1
+ match_data.bytebegin(:b).should == 3
+ end
+
+ it "returns the byte-based offset for multi byte strings" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("TñX1138.")
+ match_data.bytebegin(:a).should == 1
+ match_data.bytebegin(:b).should == 4
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi byte strings with unicode regexp" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/u.match("TñX1138.")
+ match_data.bytebegin(:a).should == 1
+ match_data.bytebegin(:b).should == 4
+ end
+ end
+
+ it "returns the byte-based offset for the farthest match when multiple named captures use the same name" do
+ match_data = /(?<a>.)(.)(?<a>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(:a).should == 3
+ end
+
+ it "returns the byte-based offset for multi-byte names" do
+ match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.bytebegin(:æ).should == 1
+ end
+
+ it "raises IndexError if there is no group with the provided name" do
+ match_data = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ match_data.bytebegin(:y)
+ }.should raise_error(IndexError, "undefined group name reference: y")
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/matchdata/byteend_spec.rb b/spec/ruby/core/matchdata/byteend_spec.rb
new file mode 100644
index 0000000000..98015e287d
--- /dev/null
+++ b/spec/ruby/core/matchdata/byteend_spec.rb
@@ -0,0 +1,104 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.4" do
+ describe "MatchData#byteend" do
+ context "when passed an integer argument" do
+ it "returns the byte-based offset of the end of the nth element" do
+ match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ match_data.byteend(0).should == 7
+ match_data.byteend(2).should == 3
+ end
+
+ it "returns nil when the nth match isn't found" do
+ match_data = /something is( not)? (right)/.match("something is right")
+ match_data.byteend(1).should be_nil
+ end
+
+ it "returns the byte-based offset for multi-byte strings" do
+ match_data = /(.)(.)(\d+)(\d)/.match("TñX1138.")
+ match_data.byteend(0).should == 8
+ match_data.byteend(2).should == 4
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi-byte strings with unicode regexp" do
+ match_data = /(.)(.)(\d+)(\d)/u.match("TñX1138.")
+ match_data.byteend(0).should == 8
+ match_data.byteend(2).should == 4
+ end
+ end
+
+ it "tries to convert the passed argument to an Integer using #to_int" do
+ obj = mock('to_int')
+ obj.should_receive(:to_int).and_return(2)
+
+ match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ match_data.byteend(obj).should == 3
+ end
+ end
+
+ context "when passed a String argument" do
+ it "return the byte-based offset of the start of the named capture" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.byteend("a").should == 2
+ match_data.byteend("b").should == 6
+ end
+
+ it "returns the byte-based offset for multi byte strings" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("TñX1138.")
+ match_data.byteend("a").should == 3
+ match_data.byteend("b").should == 7
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi byte strings with unicode regexp" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/u.match("TñX1138.")
+ match_data.byteend("a").should == 3
+ match_data.byteend("b").should == 7
+ end
+ end
+
+ it "returns the byte-based offset for the farthest match when multiple named captures use the same name" do
+ match_data = /(?<a>.)(.)(?<a>\d+)(\d)/.match("THX1138.")
+ match_data.byteend("a").should == 6
+ end
+
+ it "returns the byte-based offset for multi-byte names" do
+ match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.byteend("æ").should == 2
+ end
+ end
+
+ context "when passed a Symbol argument" do
+ it "return the byte-based offset of the start of the named capture" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.byteend(:a).should == 2
+ match_data.byteend(:b).should == 6
+ end
+
+ it "returns the byte-based offset for multi byte strings" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/.match("TñX1138.")
+ match_data.byteend(:a).should == 3
+ match_data.byteend(:b).should == 7
+ end
+
+ not_supported_on :opal do
+ it "returns the byte-based offset for multi byte strings with unicode regexp" do
+ match_data = /(?<a>.)(.)(?<b>\d+)(\d)/u.match("TñX1138.")
+ match_data.byteend(:a).should == 3
+ match_data.byteend(:b).should == 7
+ end
+ end
+
+ it "returns the byte-based offset for the farthest match when multiple named captures use the same name" do
+ match_data = /(?<a>.)(.)(?<a>\d+)(\d)/.match("THX1138.")
+ match_data.byteend(:a).should == 6
+ end
+
+ it "returns the byte-based offset for multi-byte names" do
+ match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
+ match_data.byteend(:æ).should == 2
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/matchdata/byteoffset_spec.rb b/spec/ruby/core/matchdata/byteoffset_spec.rb
index b27267fd0e..fb8f5fb67d 100644
--- a/spec/ruby/core/matchdata/byteoffset_spec.rb
+++ b/spec/ruby/core/matchdata/byteoffset_spec.rb
@@ -1,95 +1,93 @@
require_relative '../../spec_helper'
describe "MatchData#byteoffset" do
- ruby_version_is "3.2" do
- it "returns beginning and ending byte-based offset of whole matched substring for 0 element" do
- m = /(.)(.)(\d+)(\d)/.match("THX1138.")
- m.byteoffset(0).should == [1, 7]
- end
+ it "returns beginning and ending byte-based offset of whole matched substring for 0 element" do
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ m.byteoffset(0).should == [1, 7]
+ end
- it "returns beginning and ending byte-based offset of n-th match, all the subsequent elements are capturing groups" do
- m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ it "returns beginning and ending byte-based offset of n-th match, all the subsequent elements are capturing groups" do
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
- m.byteoffset(2).should == [2, 3]
- m.byteoffset(3).should == [3, 6]
- m.byteoffset(4).should == [6, 7]
- end
+ m.byteoffset(2).should == [2, 3]
+ m.byteoffset(3).should == [3, 6]
+ m.byteoffset(4).should == [6, 7]
+ end
- it "accepts String as a reference to a named capture" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "accepts String as a reference to a named capture" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- m.byteoffset("f").should == [0, 3]
- m.byteoffset("b").should == [3, 6]
- end
+ m.byteoffset("f").should == [0, 3]
+ m.byteoffset("b").should == [3, 6]
+ end
- it "accepts Symbol as a reference to a named capture" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "accepts Symbol as a reference to a named capture" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- m.byteoffset(:f).should == [0, 3]
- m.byteoffset(:b).should == [3, 6]
- end
+ m.byteoffset(:f).should == [0, 3]
+ m.byteoffset(:b).should == [3, 6]
+ end
- it "returns [nil, nil] if a capturing group is optional and doesn't match" do
- m = /(?<x>q..)?/.match("foobarbaz")
+ it "returns [nil, nil] if a capturing group is optional and doesn't match" do
+ m = /(?<x>q..)?/.match("foobarbaz")
- m.byteoffset("x").should == [nil, nil]
- m.byteoffset(1).should == [nil, nil]
- end
+ m.byteoffset("x").should == [nil, nil]
+ m.byteoffset(1).should == [nil, nil]
+ end
- it "returns correct beginning and ending byte-based offset for multi-byte strings" do
- m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+ it "returns correct beginning and ending byte-based offset for multi-byte strings" do
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
- m.byteoffset(1).should == [3, 6]
- m.byteoffset(3).should == [6, 9]
- end
+ m.byteoffset(1).should == [3, 6]
+ m.byteoffset(3).should == [6, 9]
+ end
- it "returns [nil, nil] if a capturing group is optional and doesn't match for multi-byte string" do
- m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+ it "returns [nil, nil] if a capturing group is optional and doesn't match for multi-byte string" do
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
- m.byteoffset(2).should == [nil, nil]
- end
+ m.byteoffset(2).should == [nil, nil]
+ end
- it "converts argument into integer if is not String nor Symbol" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "converts argument into integer if is not String nor Symbol" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- obj = Object.new
- def obj.to_int; 2; end
+ obj = Object.new
+ def obj.to_int; 2; end
- m.byteoffset(1r).should == [0, 3]
- m.byteoffset(1.1).should == [0, 3]
- m.byteoffset(obj).should == [3, 6]
- end
+ m.byteoffset(1r).should == [0, 3]
+ m.byteoffset(1.1).should == [0, 3]
+ m.byteoffset(obj).should == [3, 6]
+ end
- it "raises IndexError if there is no group with the provided name" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "raises IndexError if there is no group with the provided name" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- -> {
- m.byteoffset("y")
- }.should raise_error(IndexError, "undefined group name reference: y")
+ -> {
+ m.byteoffset("y")
+ }.should raise_error(IndexError, "undefined group name reference: y")
- -> {
- m.byteoffset(:y)
- }.should raise_error(IndexError, "undefined group name reference: y")
- end
+ -> {
+ m.byteoffset(:y)
+ }.should raise_error(IndexError, "undefined group name reference: y")
+ end
- it "raises IndexError if index is out of bounds" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "raises IndexError if index is out of bounds" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- -> {
- m.byteoffset(-1)
- }.should raise_error(IndexError, "index -1 out of matches")
+ -> {
+ m.byteoffset(-1)
+ }.should raise_error(IndexError, "index -1 out of matches")
- -> {
- m.byteoffset(3)
- }.should raise_error(IndexError, "index 3 out of matches")
- end
+ -> {
+ m.byteoffset(3)
+ }.should raise_error(IndexError, "index 3 out of matches")
+ end
- it "raises TypeError if can't convert argument into Integer" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "raises TypeError if can't convert argument into Integer" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- -> {
- m.byteoffset([])
- }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
- end
+ -> {
+ m.byteoffset([])
+ }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
end
end
diff --git a/spec/ruby/core/matchdata/deconstruct_keys_spec.rb b/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
index 5b68f886c7..bf22bc33ff 100644
--- a/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
@@ -1,65 +1,63 @@
require_relative '../../spec_helper'
describe "MatchData#deconstruct_keys" do
- ruby_version_is "3.2" do
- it "returns whole hash for nil as an argument" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "returns whole hash for nil as an argument" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- m.deconstruct_keys(nil).should == { f: "foo", b: "bar" }
- end
+ m.deconstruct_keys(nil).should == { f: "foo", b: "bar" }
+ end
- it "returns only specified keys" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "returns only specified keys" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- m.deconstruct_keys([:f]).should == { f: "foo" }
- end
+ m.deconstruct_keys([:f]).should == { f: "foo" }
+ end
- it "requires one argument" do
- m = /l/.match("l")
+ it "requires one argument" do
+ m = /l/.match("l")
- -> {
- m.deconstruct_keys
- }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1)")
- end
+ -> {
+ m.deconstruct_keys
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1)")
+ end
- it "it raises error when argument is neither nil nor array" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "it raises error when argument is neither nil nor array" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- -> { m.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array)")
- -> { m.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array)")
- -> { m.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array)")
- -> { m.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array)")
- end
+ -> { m.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array)")
+ -> { m.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array)")
+ -> { m.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array)")
+ -> { m.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array)")
+ end
- it "returns {} when passed []" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "returns {} when passed []" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- m.deconstruct_keys([]).should == {}
- end
+ m.deconstruct_keys([]).should == {}
+ end
- it "does not accept non-Symbol keys" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ it "does not accept non-Symbol keys" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
- -> {
- m.deconstruct_keys(['year', :foo])
- }.should raise_error(TypeError, "wrong argument type String (expected Symbol)")
- end
+ -> {
+ m.deconstruct_keys(['year', :foo])
+ }.should raise_error(TypeError, "wrong argument type String (expected Symbol)")
+ end
- it "process keys till the first non-existing one" do
- m = /(?<f>foo)(?<b>bar)(?<c>baz)/.match("foobarbaz")
+ it "process keys till the first non-existing one" do
+ m = /(?<f>foo)(?<b>bar)(?<c>baz)/.match("foobarbaz")
- m.deconstruct_keys([:f, :a, :b]).should == { f: "foo" }
- end
+ m.deconstruct_keys([:f, :a, :b]).should == { f: "foo" }
+ end
- it "returns {} when there are no named captured groups at all" do
- m = /foo.+/.match("foobar")
+ it "returns {} when there are no named captured groups at all" do
+ m = /foo.+/.match("foobar")
- m.deconstruct_keys(nil).should == {}
- end
+ m.deconstruct_keys(nil).should == {}
+ end
- it "returns {} when passed more keys than named captured groups" do
- m = /(?<f>foo)(?<b>bar)/.match("foobar")
- m.deconstruct_keys([:f, :b, :c]).should == {}
- end
+ it "returns {} when passed more keys than named captured groups" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ m.deconstruct_keys([:f, :b, :c]).should == {}
end
end
diff --git a/spec/ruby/core/matchdata/deconstruct_spec.rb b/spec/ruby/core/matchdata/deconstruct_spec.rb
index 6af55113b6..c55095665d 100644
--- a/spec/ruby/core/matchdata/deconstruct_spec.rb
+++ b/spec/ruby/core/matchdata/deconstruct_spec.rb
@@ -2,7 +2,5 @@ require_relative '../../spec_helper'
require_relative 'shared/captures'
describe "MatchData#deconstruct" do
- ruby_version_is "3.2" do
- it_behaves_like :matchdata_captures, :deconstruct
- end
+ it_behaves_like :matchdata_captures, :deconstruct
end
diff --git a/spec/ruby/core/matchdata/match_length_spec.rb b/spec/ruby/core/matchdata/match_length_spec.rb
index f7785ab1a0..824f94a397 100644
--- a/spec/ruby/core/matchdata/match_length_spec.rb
+++ b/spec/ruby/core/matchdata/match_length_spec.rb
@@ -2,33 +2,31 @@
require_relative '../../spec_helper'
-ruby_version_is "3.1" do
- describe "MatchData#match_length" do
- it "returns the length of the corresponding match when given an Integer" do
- md = /(.)(.)(\d+)(\d)/.match("THX1138.")
+describe "MatchData#match_length" do
+ it "returns the length of the corresponding match when given an Integer" do
+ md = /(.)(.)(\d+)(\d)/.match("THX1138.")
- md.match_length(0).should == 6
- md.match_length(1).should == 1
- md.match_length(2).should == 1
- md.match_length(3).should == 3
- md.match_length(4).should == 1
- end
+ md.match_length(0).should == 6
+ md.match_length(1).should == 1
+ md.match_length(2).should == 1
+ md.match_length(3).should == 3
+ md.match_length(4).should == 1
+ end
- it "returns nil on non-matching index matches" do
- md = /\d+(\w)?/.match("THX1138.")
- md.match_length(1).should == nil
- end
+ it "returns nil on non-matching index matches" do
+ md = /\d+(\w)?/.match("THX1138.")
+ md.match_length(1).should == nil
+ end
- it "returns the length of the corresponding named match when given a Symbol" do
- md = 'haystack'.match(/(?<t>t(?<a>ack))/)
- md.match_length(:a).should == 3
- md.match_length(:t).should == 4
- end
+ it "returns the length of the corresponding named match when given a Symbol" do
+ md = 'haystack'.match(/(?<t>t(?<a>ack))/)
+ md.match_length(:a).should == 3
+ md.match_length(:t).should == 4
+ end
- it "returns nil on non-matching index matches" do
- md = 'haystack'.match(/(?<t>t)(?<a>all)?/)
- md.match_length(:t).should == 1
- md.match_length(:a).should == nil
- end
+ it "returns nil on non-matching index matches" do
+ md = 'haystack'.match(/(?<t>t)(?<a>all)?/)
+ md.match_length(:t).should == 1
+ md.match_length(:a).should == nil
end
end
diff --git a/spec/ruby/core/matchdata/match_spec.rb b/spec/ruby/core/matchdata/match_spec.rb
index 545de6f93f..a16914ea15 100644
--- a/spec/ruby/core/matchdata/match_spec.rb
+++ b/spec/ruby/core/matchdata/match_spec.rb
@@ -2,33 +2,31 @@
require_relative '../../spec_helper'
-ruby_version_is "3.1" do
- describe "MatchData#match" do
- it "returns the corresponding match when given an Integer" do
- md = /(.)(.)(\d+)(\d)/.match("THX1138.")
+describe "MatchData#match" do
+ it "returns the corresponding match when given an Integer" do
+ md = /(.)(.)(\d+)(\d)/.match("THX1138.")
- md.match(0).should == 'HX1138'
- md.match(1).should == 'H'
- md.match(2).should == 'X'
- md.match(3).should == '113'
- md.match(4).should == '8'
- end
+ md.match(0).should == 'HX1138'
+ md.match(1).should == 'H'
+ md.match(2).should == 'X'
+ md.match(3).should == '113'
+ md.match(4).should == '8'
+ end
- it "returns nil on non-matching index matches" do
- md = /\d+(\w)?/.match("THX1138.")
- md.match(1).should == nil
- end
+ it "returns nil on non-matching index matches" do
+ md = /\d+(\w)?/.match("THX1138.")
+ md.match(1).should == nil
+ end
- it "returns the corresponding named match when given a Symbol" do
- md = 'haystack'.match(/(?<t>t(?<a>ack))/)
- md.match(:a).should == 'ack'
- md.match(:t).should == 'tack'
- end
+ it "returns the corresponding named match when given a Symbol" do
+ md = 'haystack'.match(/(?<t>t(?<a>ack))/)
+ md.match(:a).should == 'ack'
+ md.match(:t).should == 'tack'
+ end
- it "returns nil on non-matching index matches" do
- md = 'haystack'.match(/(?<t>t)(?<a>all)?/)
- md.match(:t).should == 't'
- md.match(:a).should == nil
- end
+ it "returns nil on non-matching index matches" do
+ md = 'haystack'.match(/(?<t>t)(?<a>all)?/)
+ md.match(:t).should == 't'
+ md.match(:a).should == nil
end
end
diff --git a/spec/ruby/core/matchdata/offset_spec.rb b/spec/ruby/core/matchdata/offset_spec.rb
index 1ccb54b7a7..a03d58aad1 100644
--- a/spec/ruby/core/matchdata/offset_spec.rb
+++ b/spec/ruby/core/matchdata/offset_spec.rb
@@ -1,30 +1,102 @@
-# -*- encoding: utf-8 -*-
-
require_relative '../../spec_helper'
describe "MatchData#offset" do
- it "returns a two element array with the begin and end of the nth match" do
- match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
- match_data.offset(0).should == [1, 7]
- match_data.offset(4).should == [6, 7]
+ it "returns beginning and ending character offset of whole matched substring for 0 element" do
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ m.offset(0).should == [1, 7]
+ end
+
+ it "returns beginning and ending character offset of n-th match, all the subsequent elements are capturing groups" do
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+
+ m.offset(2).should == [2, 3]
+ m.offset(3).should == [3, 6]
+ m.offset(4).should == [6, 7]
+ end
+
+ it "accepts String as a reference to a named capture" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.offset("f").should == [0, 3]
+ m.offset("b").should == [3, 6]
+ end
+
+ it "accepts Symbol as a reference to a named capture" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.offset(:f).should == [0, 3]
+ m.offset(:b).should == [3, 6]
end
- it "returns [nil, nil] when the nth match isn't found" do
- match_data = /something is( not)? (right)/.match("something is right")
- match_data.offset(1).should == [nil, nil]
+ it "returns [nil, nil] if a capturing group is optional and doesn't match" do
+ m = /(?<x>q..)?/.match("foobarbaz")
+
+ m.offset("x").should == [nil, nil]
+ m.offset(1).should == [nil, nil]
end
- it "returns the offset for multi byte strings" do
- match_data = /(.)(.)(\d+)(\d)/.match("TñX1138.")
- match_data.offset(0).should == [1, 7]
- match_data.offset(4).should == [6, 7]
+ it "returns correct beginning and ending character offset for multi-byte strings" do
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+
+ m.offset(1).should == [1, 2]
+ m.offset(3).should == [2, 3]
end
not_supported_on :opal do
- it "returns the offset for multi byte strings with unicode regexp" do
- match_data = /(.)(.)(\d+)(\d)/u.match("TñX1138.")
- match_data.offset(0).should == [1, 7]
- match_data.offset(4).should == [6, 7]
+ it "returns correct character offset for multi-byte strings with unicode regexp" do
+ m = /\A\u3042(.)(.)?(.)\z/u.match("\u3042\u3043\u3044")
+
+ m.offset(1).should == [1, 2]
+ m.offset(3).should == [2, 3]
end
end
+
+ it "returns [nil, nil] if a capturing group is optional and doesn't match for multi-byte string" do
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+
+ m.offset(2).should == [nil, nil]
+ end
+
+ it "converts argument into integer if is not String nor Symbol" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ obj = Object.new
+ def obj.to_int; 2; end
+
+ m.offset(1r).should == [0, 3]
+ m.offset(1.1).should == [0, 3]
+ m.offset(obj).should == [3, 6]
+ end
+
+ it "raises IndexError if there is no group with the provided name" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ m.offset("y")
+ }.should raise_error(IndexError, "undefined group name reference: y")
+
+ -> {
+ m.offset(:y)
+ }.should raise_error(IndexError, "undefined group name reference: y")
+ end
+
+ it "raises IndexError if index is out of bounds" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ m.offset(-1)
+ }.should raise_error(IndexError, "index -1 out of matches")
+
+ -> {
+ m.offset(3)
+ }.should raise_error(IndexError, "index 3 out of matches")
+ end
+
+ it "raises TypeError if can't convert argument into Integer" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ m.offset([])
+ }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
+ end
end
diff --git a/spec/ruby/core/math/atanh_spec.rb b/spec/ruby/core/math/atanh_spec.rb
index 21fb209941..edcb8f2e52 100644
--- a/spec/ruby/core/math/atanh_spec.rb
+++ b/spec/ruby/core/math/atanh_spec.rb
@@ -1,6 +1,6 @@
require_relative '../../spec_helper'
-require_relative '../../fixtures/math/common'
-require_relative '../../shared/math/atanh'
+require_relative 'fixtures/common'
+require_relative 'shared/atanh'
describe "Math.atanh" do
it_behaves_like :math_atanh_base, :atanh, Math
diff --git a/spec/ruby/core/math/expm1_spec.rb b/spec/ruby/core/math/expm1_spec.rb
new file mode 100644
index 0000000000..5725319abb
--- /dev/null
+++ b/spec/ruby/core/math/expm1_spec.rb
@@ -0,0 +1,37 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is "4.0" do
+ describe "Math.expm1" do
+ it "calculates Math.exp(arg) - 1" do
+ Math.expm1(3).should == Math.exp(3) - 1
+ end
+
+ it "preserves precision that can be lost otherwise" do
+ Math.expm1(1.0e-16).should be_close(1.0e-16, TOLERANCE)
+ Math.expm1(1.0e-16).should != 0.0
+ end
+
+ it "raises a TypeError if the argument cannot be coerced with Float()" do
+ -> { Math.expm1("test") }.should raise_error(TypeError, "can't convert String into Float")
+ end
+
+ it "returns NaN given NaN" do
+ Math.expm1(nan_value).nan?.should be_true
+ end
+
+ it "raises a TypeError if the argument is nil" do
+ -> { Math.expm1(nil) }.should raise_error(TypeError, "can't convert nil into Float")
+ end
+
+ it "accepts any argument that can be coerced with Float()" do
+ Math.expm1(MathSpecs::Float.new).should be_close(Math::E - 1, TOLERANCE)
+ end
+ end
+
+ describe "Math#expm1" do
+ it "is accessible as a private instance method" do
+ IncludesMath.new.send(:expm1, 23.1415).should be_close(11226018483.0012, TOLERANCE)
+ end
+ end
+end
diff --git a/spec/ruby/core/math/fixtures/common.rb b/spec/ruby/core/math/fixtures/common.rb
new file mode 100644
index 0000000000..024732fa7a
--- /dev/null
+++ b/spec/ruby/core/math/fixtures/common.rb
@@ -0,0 +1,3 @@
+class IncludesMath
+ include Math
+end
diff --git a/spec/ruby/core/math/lgamma_spec.rb b/spec/ruby/core/math/lgamma_spec.rb
index 33e7836448..2bf350993e 100644
--- a/spec/ruby/core/math/lgamma_spec.rb
+++ b/spec/ruby/core/math/lgamma_spec.rb
@@ -5,10 +5,8 @@ describe "Math.lgamma" do
Math.lgamma(0).should == [infinity_value, 1]
end
- platform_is_not :windows do
- it "returns [Infinity, 1] when passed -1" do
- Math.lgamma(-1).should == [infinity_value, 1]
- end
+ it "returns [Infinity, ...] when passed -1" do
+ Math.lgamma(-1)[0].should == infinity_value
end
it "returns [Infinity, -1] when passed -0.0" do
@@ -47,8 +45,7 @@ describe "Math.lgamma" do
Math.lgamma(infinity_value).should == [infinity_value, 1]
end
- it "returns [NaN, 1] when passed NaN" do
- Math.lgamma(nan_value)[0].nan?.should be_true
- Math.lgamma(nan_value)[1].should == 1
+ it "returns [NaN, ...] when passed NaN" do
+ Math.lgamma(nan_value)[0].should.nan?
end
end
diff --git a/spec/ruby/core/math/log1p_spec.rb b/spec/ruby/core/math/log1p_spec.rb
new file mode 100644
index 0000000000..216358a3c4
--- /dev/null
+++ b/spec/ruby/core/math/log1p_spec.rb
@@ -0,0 +1,49 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is "4.0" do
+ describe "Math.log1p" do
+ it "calculates Math.log(1 + arg)" do
+ Math.log1p(3).should == Math.log(1 + 3)
+ end
+
+ it "preserves precision that can be lost otherwise" do
+ Math.log1p(1e-16).should be_close(1.0e-16, TOLERANCE)
+ Math.log1p(1e-16).should != 0.0
+ end
+
+ it "raises an Math::DomainError if the argument is less than 1" do
+ -> { Math.log1p(-1-1e-15) }.should raise_error(Math::DomainError, "Numerical argument is out of domain - log1p")
+ end
+
+ it "raises a TypeError if the argument cannot be coerced with Float()" do
+ -> { Math.log1p("test") }.should raise_error(TypeError, "can't convert String into Float")
+ end
+
+ it "raises a TypeError for numerical values passed as string" do
+ -> { Math.log1p("10") }.should raise_error(TypeError, "can't convert String into Float")
+ end
+
+ it "does not accept a second argument for the base" do
+ -> { Math.log1p(9, 3) }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 1)")
+ end
+
+ it "returns NaN given NaN" do
+ Math.log1p(nan_value).nan?.should be_true
+ end
+
+ it "raises a TypeError if the argument is nil" do
+ -> { Math.log1p(nil) }.should raise_error(TypeError, "can't convert nil into Float")
+ end
+
+ it "accepts any argument that can be coerced with Float()" do
+ Math.log1p(MathSpecs::Float.new).should be_close(0.6931471805599453, TOLERANCE)
+ end
+ end
+
+ describe "Math#log1p" do
+ it "is accessible as a private instance method" do
+ IncludesMath.new.send(:log1p, 4.21).should be_close(1.65057985576528, TOLERANCE)
+ end
+ end
+end
diff --git a/spec/ruby/core/math/shared/atanh.rb b/spec/ruby/core/math/shared/atanh.rb
new file mode 100644
index 0000000000..3fb64153a0
--- /dev/null
+++ b/spec/ruby/core/math/shared/atanh.rb
@@ -0,0 +1,44 @@
+describe :math_atanh_base, shared: true do
+ it "returns a float" do
+ @object.send(@method, 0.5).should be_an_instance_of(Float)
+ end
+
+ it "returns the inverse hyperbolic tangent of the argument" do
+ @object.send(@method, 0.0).should == 0.0
+ @object.send(@method, -0.0).should == -0.0
+ @object.send(@method, 0.5).should be_close(0.549306144334055, TOLERANCE)
+ @object.send(@method, -0.2).should be_close(-0.202732554054082, TOLERANCE)
+ end
+
+ it "raises a TypeError if the argument is nil" do
+ -> { @object.send(@method, nil) }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError if the argument is not a Numeric" do
+ -> { @object.send(@method, "test") }.should raise_error(TypeError)
+ end
+
+ it "returns Infinity if x == 1.0" do
+ @object.send(@method, 1.0).should == Float::INFINITY
+ end
+
+ it "return -Infinity if x == -1.0" do
+ @object.send(@method, -1.0).should == -Float::INFINITY
+ end
+end
+
+describe :math_atanh_private, shared: true do
+ it "is a private instance method" do
+ Math.should have_private_instance_method(@method)
+ end
+end
+
+describe :math_atanh_no_complex, shared: true do
+ it "raises a Math::DomainError for arguments greater than 1.0" do
+ -> { @object.send(@method, 1.0 + Float::EPSILON) }.should raise_error(Math::DomainError)
+ end
+
+ it "raises a Math::DomainError for arguments less than -1.0" do
+ -> { @object.send(@method, -1.0 - Float::EPSILON) }.should raise_error(Math::DomainError)
+ end
+end
diff --git a/spec/ruby/core/method/owner_spec.rb b/spec/ruby/core/method/owner_spec.rb
index 05422f1697..1cdc4edfa7 100644
--- a/spec/ruby/core/method/owner_spec.rb
+++ b/spec/ruby/core/method/owner_spec.rb
@@ -24,9 +24,7 @@ describe "Method#owner" do
end
end
- ruby_version_is "3.2" do
- it "returns the class on which public was called for a private method in ancestor" do
- MethodSpecs::InheritedMethods::C.new.method(:derp).owner.should == MethodSpecs::InheritedMethods::C
- end
+ it "returns the class on which public was called for a private method in ancestor" do
+ MethodSpecs::InheritedMethods::C.new.method(:derp).owner.should == MethodSpecs::InheritedMethods::C
end
end
diff --git a/spec/ruby/core/method/parameters_spec.rb b/spec/ruby/core/method/parameters_spec.rb
index 8495aef4d2..f1c2523cf0 100644
--- a/spec/ruby/core/method/parameters_spec.rb
+++ b/spec/ruby/core/method/parameters_spec.rb
@@ -233,54 +233,27 @@ describe "Method#parameters" do
m.method(:handled_via_method_missing).parameters.should == [[:rest]]
end
- ruby_version_is '3.2' do
- it "adds rest arg with name * for \"star\" argument" do
- m = MethodSpecs::Methods.new
- m.method(:one_unnamed_splat).parameters.should == [[:rest, :*]]
- end
-
- it "adds keyrest arg with ** as a name for \"double star\" argument" do
- m = MethodSpecs::Methods.new
- m.method(:one_unnamed_keyrest).parameters.should == [[:keyrest, :**]]
- end
+ it "adds rest arg with name * for \"star\" argument" do
+ m = MethodSpecs::Methods.new
+ m.method(:one_unnamed_splat).parameters.should == [[:rest, :*]]
end
- ruby_version_is ''...'3.2' do
- it "adds nameless rest arg for \"star\" argument" do
- m = MethodSpecs::Methods.new
- m.method(:one_unnamed_splat).parameters.should == [[:rest]]
- end
-
- it "adds nameless keyrest arg for \"double star\" argument" do
- m = MethodSpecs::Methods.new
- m.method(:one_unnamed_keyrest).parameters.should == [[:keyrest]]
- end
+ it "adds keyrest arg with ** as a name for \"double star\" argument" do
+ m = MethodSpecs::Methods.new
+ m.method(:one_unnamed_keyrest).parameters.should == [[:keyrest, :**]]
end
- ruby_version_is '3.1' do
- it "adds block arg with name & for anonymous block argument" do
- object = Object.new
-
- eval(<<~RUBY).should == [[:block, :&]]
- def object.foo(&)
- end
- object.method(:foo).parameters
- RUBY
+ it "adds block arg with name & for anonymous block argument" do
+ object = Object.new
+ def object.foo(&)
end
- end
- ruby_version_is ""..."3.1" do
- it "returns [:rest, :*], [:block, :&] for forward parameters operator" do
- m = MethodSpecs::Methods.new
- m.method(:forward_parameters).parameters.should == [[:rest, :*], [:block, :&]]
- end
+ object.method(:foo).parameters.should == [[:block, :&]]
end
- ruby_version_is "3.1" do
- it "returns [:rest, :*], [:keyrest, :**], [:block, :&] for forward parameters operator" do
- m = MethodSpecs::Methods.new
- m.method(:forward_parameters).parameters.should == [[:rest, :*], [:keyrest, :**], [:block, :&]]
- end
+ it "returns [:rest, :*], [:keyrest, :**], [:block, :&] for forward parameters operator" do
+ m = MethodSpecs::Methods.new
+ m.method(:forward_parameters).parameters.should == [[:rest, :*], [:keyrest, :**], [:block, :&]]
end
it "returns the args and block for a splat and block argument" do
diff --git a/spec/ruby/core/method/private_spec.rb b/spec/ruby/core/method/private_spec.rb
index fd550036a3..e708542b2e 100644
--- a/spec/ruby/core/method/private_spec.rb
+++ b/spec/ruby/core/method/private_spec.rb
@@ -2,27 +2,8 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Method#private?" do
- ruby_version_is "3.1"..."3.2" do
- it "returns false when the method is public" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_public_method).private?.should == false
- end
-
- it "returns false when the method is protected" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_protected_method).private?.should == false
- end
-
- it "returns true when the method is private" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_private_method).private?.should == true
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_private_method).should_not.respond_to?(:private?)
- end
+ it "has been removed" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_private_method).should_not.respond_to?(:private?)
end
end
diff --git a/spec/ruby/core/method/protected_spec.rb b/spec/ruby/core/method/protected_spec.rb
index 8423e8c64c..f9e422ae3d 100644
--- a/spec/ruby/core/method/protected_spec.rb
+++ b/spec/ruby/core/method/protected_spec.rb
@@ -2,27 +2,8 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Method#protected?" do
- ruby_version_is "3.1"..."3.2" do
- it "returns false when the method is public" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_public_method).protected?.should == false
- end
-
- it "returns true when the method is protected" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_protected_method).protected?.should == true
- end
-
- it "returns false when the method is private" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_private_method).protected?.should == false
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_protected_method).should_not.respond_to?(:protected?)
- end
+ it "has been removed" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_protected_method).should_not.respond_to?(:protected?)
end
end
diff --git a/spec/ruby/core/method/public_spec.rb b/spec/ruby/core/method/public_spec.rb
index 20d0081a27..4cb23f4cf1 100644
--- a/spec/ruby/core/method/public_spec.rb
+++ b/spec/ruby/core/method/public_spec.rb
@@ -2,27 +2,8 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Method#public?" do
- ruby_version_is "3.1"..."3.2" do
- it "returns true when the method is public" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_public_method).public?.should == true
- end
-
- it "returns false when the method is protected" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_protected_method).public?.should == false
- end
-
- it "returns false when the method is private" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_private_method).public?.should == false
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = MethodSpecs::Methods.new
- obj.method(:my_public_method).should_not.respond_to?(:public?)
- end
+ it "has been removed" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_public_method).should_not.respond_to?(:public?)
end
end
diff --git a/spec/ruby/core/method/shared/dup.rb b/spec/ruby/core/method/shared/dup.rb
index 1a10b90689..c74847083f 100644
--- a/spec/ruby/core/method/shared/dup.rb
+++ b/spec/ruby/core/method/shared/dup.rb
@@ -16,7 +16,7 @@ describe :method_dup, shared: true do
end
it "copies the finalizer" do
- code = <<-RUBY
+ code = <<-'RUBY'
obj = Object.new.method(:method)
ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" })
diff --git a/spec/ruby/core/method/source_location_spec.rb b/spec/ruby/core/method/source_location_spec.rb
index c5b296f6e2..87413a2ab6 100644
--- a/spec/ruby/core/method/source_location_spec.rb
+++ b/spec/ruby/core/method/source_location_spec.rb
@@ -11,23 +11,23 @@ describe "Method#source_location" do
end
it "sets the first value to the path of the file in which the method was defined" do
- file = @method.source_location.first
+ file = @method.source_location[0]
file.should be_an_instance_of(String)
file.should == File.realpath('fixtures/classes.rb', __dir__)
end
it "sets the last value to an Integer representing the line on which the method was defined" do
- line = @method.source_location.last
+ line = @method.source_location[1]
line.should be_an_instance_of(Integer)
line.should == 5
end
it "returns the last place the method was defined" do
- MethodSpecs::SourceLocation.method(:redefined).source_location.last.should == 13
+ MethodSpecs::SourceLocation.method(:redefined).source_location[1].should == 13
end
it "returns the location of the original method even if it was aliased" do
- MethodSpecs::SourceLocation.new.method(:aka).source_location.last.should == 17
+ MethodSpecs::SourceLocation.new.method(:aka).source_location[1].should == 17
end
it "works for methods defined with a block" do
@@ -108,7 +108,13 @@ describe "Method#source_location" do
c = Class.new do
eval('def self.m; end', nil, "foo", 100)
end
- c.method(:m).source_location.should == ["foo", 100]
+ location = c.method(:m).source_location
+ ruby_version_is(""..."4.1") do
+ location.should == ["foo", 100]
+ end
+ ruby_version_is("4.1") do
+ location.should == ["foo", 100, 0, 100, 15]
+ end
end
describe "for a Method generated by respond_to_missing?" do
diff --git a/spec/ruby/core/method/unbind_spec.rb b/spec/ruby/core/method/unbind_spec.rb
index bdedd513ce..0b630e4d88 100644
--- a/spec/ruby/core/method/unbind_spec.rb
+++ b/spec/ruby/core/method/unbind_spec.rb
@@ -27,16 +27,8 @@ describe "Method#unbind" do
@string.should =~ /MethodSpecs::MyMod/
end
- ruby_version_is ""..."3.2" do
- it "returns a String containing the Module the method is referenced from" do
- @string.should =~ /MethodSpecs::MySub/
- end
- end
-
- ruby_version_is "3.2" do
- it "returns a String containing the Module the method is referenced from" do
- @string.should =~ /MethodSpecs::MyMod/
- end
+ it "returns a String containing the Module the method is referenced from" do
+ @string.should =~ /MethodSpecs::MyMod/
end
end
diff --git a/spec/ruby/core/module/ancestors_spec.rb b/spec/ruby/core/module/ancestors_spec.rb
index 43ebdb864f..90c26941d1 100644
--- a/spec/ruby/core/module/ancestors_spec.rb
+++ b/spec/ruby/core/module/ancestors_spec.rb
@@ -7,10 +7,17 @@ describe "Module#ancestors" do
ModuleSpecs.ancestors.should == [ModuleSpecs]
ModuleSpecs::Basic.ancestors.should == [ModuleSpecs::Basic]
ModuleSpecs::Super.ancestors.should == [ModuleSpecs::Super, ModuleSpecs::Basic]
- ModuleSpecs.without_test_modules(ModuleSpecs::Parent.ancestors).should ==
- [ModuleSpecs::Parent, Object, Kernel, BasicObject]
- ModuleSpecs.without_test_modules(ModuleSpecs::Child.ancestors).should ==
- [ModuleSpecs::Child, ModuleSpecs::Super, ModuleSpecs::Basic, ModuleSpecs::Parent, Object, Kernel, BasicObject]
+ if defined?(Ruby::Box) && Ruby::Box.enabled?
+ ModuleSpecs.without_test_modules(ModuleSpecs::Parent.ancestors).should ==
+ [ModuleSpecs::Parent, Object, Ruby::Box::Loader, Kernel, BasicObject]
+ ModuleSpecs.without_test_modules(ModuleSpecs::Child.ancestors).should ==
+ [ModuleSpecs::Child, ModuleSpecs::Super, ModuleSpecs::Basic, ModuleSpecs::Parent, Object, Ruby::Box::Loader, Kernel, BasicObject]
+ else
+ ModuleSpecs.without_test_modules(ModuleSpecs::Parent.ancestors).should ==
+ [ModuleSpecs::Parent, Object, Kernel, BasicObject]
+ ModuleSpecs.without_test_modules(ModuleSpecs::Child.ancestors).should ==
+ [ModuleSpecs::Child, ModuleSpecs::Super, ModuleSpecs::Basic, ModuleSpecs::Parent, Object, Kernel, BasicObject]
+ end
end
it "returns only modules and classes" do
diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb
index 45d18b8608..625d945686 100644
--- a/spec/ruby/core/module/autoload_spec.rb
+++ b/spec/ruby/core/module/autoload_spec.rb
@@ -486,42 +486,21 @@ describe "Module#autoload" do
ScratchPad.recorded.should == [:raise, :raise]
end
- ruby_version_is "3.1" do
- it "removes the constant from Module#constants if the loaded file does not define it" do
- path = fixture(__FILE__, "autoload_o.rb")
- ScratchPad.record []
- ModuleSpecs::Autoload.autoload :O, path
-
- ModuleSpecs::Autoload.const_defined?(:O).should == true
- ModuleSpecs::Autoload.should have_constant(:O)
- ModuleSpecs::Autoload.autoload?(:O).should == path
-
- -> { ModuleSpecs::Autoload::O }.should raise_error(NameError)
-
- ModuleSpecs::Autoload.const_defined?(:O).should == false
- ModuleSpecs::Autoload.should_not have_constant(:O)
- ModuleSpecs::Autoload.autoload?(:O).should == nil
- -> { ModuleSpecs::Autoload.const_get(:O) }.should raise_error(NameError)
- end
- end
-
- ruby_version_is ""..."3.1" do
- it "does not remove the constant from Module#constants if the loaded file does not define it, but leaves it as 'undefined'" do
- path = fixture(__FILE__, "autoload_o.rb")
- ScratchPad.record []
- ModuleSpecs::Autoload.autoload :O, path
+ it "removes the constant from Module#constants if the loaded file does not define it" do
+ path = fixture(__FILE__, "autoload_o.rb")
+ ScratchPad.record []
+ ModuleSpecs::Autoload.autoload :O, path
- ModuleSpecs::Autoload.const_defined?(:O).should == true
- ModuleSpecs::Autoload.should have_constant(:O)
- ModuleSpecs::Autoload.autoload?(:O).should == path
+ ModuleSpecs::Autoload.const_defined?(:O).should == true
+ ModuleSpecs::Autoload.should have_constant(:O)
+ ModuleSpecs::Autoload.autoload?(:O).should == path
- -> { ModuleSpecs::Autoload::O }.should raise_error(NameError)
+ -> { ModuleSpecs::Autoload::O }.should raise_error(NameError)
- ModuleSpecs::Autoload.const_defined?(:O).should == false
- ModuleSpecs::Autoload.should have_constant(:O)
- ModuleSpecs::Autoload.autoload?(:O).should == nil
- -> { ModuleSpecs::Autoload.const_get(:O) }.should raise_error(NameError)
- end
+ ModuleSpecs::Autoload.const_defined?(:O).should == false
+ ModuleSpecs::Autoload.should_not have_constant(:O)
+ ModuleSpecs::Autoload.autoload?(:O).should == nil
+ -> { ModuleSpecs::Autoload.const_get(:O) }.should raise_error(NameError)
end
it "does not try to load the file again if the loaded file did not define the constant" do
@@ -624,78 +603,51 @@ describe "Module#autoload" do
end
end
- ruby_version_is "3.2" do
- it "warns once in verbose mode if the constant was defined in a parent scope" do
- ScratchPad.record -> {
- ModuleSpecs::DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
- }
+ it "warns once in verbose mode if the constant was defined in a parent scope" do
+ ScratchPad.record -> {
+ ModuleSpecs::DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
+ }
- module ModuleSpecs
- module Autoload
- autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
- self.autoload?(:DeclaredInCurrentDefinedInParent).should == fixture(__FILE__, "autoload_callback.rb")
- const_defined?(:DeclaredInCurrentDefinedInParent).should == true
-
- -> {
- DeclaredInCurrentDefinedInParent
- }.should complain(
- /Expected .*autoload_callback.rb to define ModuleSpecs::Autoload::DeclaredInCurrentDefinedInParent but it didn't/,
- verbose: true,
- )
-
- -> {
- DeclaredInCurrentDefinedInParent
- }.should_not complain(/.*/, verbose: true)
- self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
- const_defined?(:DeclaredInCurrentDefinedInParent).should == false
- ModuleSpecs.const_defined?(:DeclaredInCurrentDefinedInParent).should == true
- end
+ module ModuleSpecs
+ module Autoload
+ autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
+ self.autoload?(:DeclaredInCurrentDefinedInParent).should == fixture(__FILE__, "autoload_callback.rb")
+ const_defined?(:DeclaredInCurrentDefinedInParent).should == true
+
+ -> {
+ DeclaredInCurrentDefinedInParent
+ }.should complain(
+ /Expected .*autoload_callback.rb to define ModuleSpecs::Autoload::DeclaredInCurrentDefinedInParent but it didn't/,
+ verbose: true,
+ )
+
+ -> {
+ DeclaredInCurrentDefinedInParent
+ }.should_not complain(/.*/, verbose: true)
+ self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
+ const_defined?(:DeclaredInCurrentDefinedInParent).should == false
+ ModuleSpecs.const_defined?(:DeclaredInCurrentDefinedInParent).should == true
end
end
end
- ruby_version_is "3.1" do
- it "looks up in parent scope after failed autoload" do
- @remove << :DeclaredInCurrentDefinedInParent
- module ModuleSpecs::Autoload
- ScratchPad.record -> {
- DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
- }
-
- class LexicalScope
- autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
- -> { DeclaredInCurrentDefinedInParent }.should_not raise_error(NameError)
- # Basically, the autoload constant remains in a "undefined" state
- self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
- const_defined?(:DeclaredInCurrentDefinedInParent).should == false
- -> { const_get(:DeclaredInCurrentDefinedInParent) }.should raise_error(NameError)
- end
+ it "looks up in parent scope after failed autoload" do
+ @remove << :DeclaredInCurrentDefinedInParent
+ module ModuleSpecs::Autoload
+ ScratchPad.record -> {
+ DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
+ }
- DeclaredInCurrentDefinedInParent.should == :declared_in_current_defined_in_parent
+ class LexicalScope
+ autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
+ -> { DeclaredInCurrentDefinedInParent }.should_not raise_error(NameError)
+ # Basically, the autoload constant remains in a "undefined" state
+ self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
+ const_defined?(:DeclaredInCurrentDefinedInParent).should == false
+ -> { const_get(:DeclaredInCurrentDefinedInParent) }.should raise_error(NameError)
end
- end
- end
-
- ruby_version_is ""..."3.1" do
- it "and fails when finding the undefined autoload constant in the current scope when declared in current and defined in parent" do
- @remove << :DeclaredInCurrentDefinedInParent
- module ModuleSpecs::Autoload
- ScratchPad.record -> {
- DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
- }
- class LexicalScope
- autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
- -> { DeclaredInCurrentDefinedInParent }.should raise_error(NameError)
- # Basically, the autoload constant remains in a "undefined" state
- self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
- const_defined?(:DeclaredInCurrentDefinedInParent).should == false
- self.should have_constant(:DeclaredInCurrentDefinedInParent)
- -> { const_get(:DeclaredInCurrentDefinedInParent) }.should raise_error(NameError)
- end
-
- DeclaredInCurrentDefinedInParent.should == :declared_in_current_defined_in_parent
- end
+ DeclaredInCurrentDefinedInParent.should == :declared_in_current_defined_in_parent
end
end
@@ -766,6 +718,21 @@ describe "Module#autoload" do
end
end
+ it "should trigger the autoload when using `private_constant`" do
+ @remove << :DynClass
+ module ModuleSpecs::Autoload
+ autoload :DynClass, fixture(__FILE__, "autoload_c.rb")
+ private_constant :DynClass
+
+ ScratchPad.recorded.should be_nil
+
+ DynClass::C.new.loaded.should == :dynclass_c
+ ScratchPad.recorded.should == :loaded
+ end
+
+ -> { ModuleSpecs::Autoload::DynClass }.should raise_error(NameError, /private constant/)
+ end
+
# [ruby-core:19127] [ruby-core:29941]
it "does NOT raise a NameError when the autoload file did not define the constant and a module is opened with the same name" do
module ModuleSpecs::Autoload
diff --git a/spec/ruby/core/module/const_added_spec.rb b/spec/ruby/core/module/const_added_spec.rb
index 4b10dd5963..90cd36551a 100644
--- a/spec/ruby/core/module/const_added_spec.rb
+++ b/spec/ruby/core/module/const_added_spec.rb
@@ -3,201 +3,236 @@ require_relative 'fixtures/classes'
require_relative 'fixtures/const_added'
describe "Module#const_added" do
- ruby_version_is "3.2" do
- it "is a private instance method" do
- Module.should have_private_instance_method(:const_added)
+ it "is a private instance method" do
+ Module.should have_private_instance_method(:const_added)
+ end
+
+ it "returns nil in the default implementation" do
+ Module.new do
+ const_added(:TEST).should == nil
end
+ end
+
+ it "for a class defined with the `class` keyword, const_added runs before inherited" do
+ ScratchPad.record []
- it "returns nil in the default implementation" do
- Module.new do
- const_added(:TEST).should == nil
+ mod = Module.new do
+ def self.const_added(_)
+ ScratchPad << :const_added
end
end
- it "is called when a new constant is assigned on self" do
- ScratchPad.record []
-
- mod = Module.new do
- def self.const_added(name)
- ScratchPad << name
- end
+ parent = Class.new do
+ def self.inherited(_)
+ ScratchPad << :inherited
end
+ end
- mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
- TEST = 1
- RUBY
+ class mod::C < parent; end
- ScratchPad.recorded.should == [:TEST]
- end
+ ScratchPad.recorded.should == [:const_added, :inherited]
+ end
- it "is called when a new constant is assigned on self through const_set" do
- ScratchPad.record []
+ it "the superclass of a class assigned to a constant is set before const_added is called" do
+ ScratchPad.record []
- mod = Module.new do
- def self.const_added(name)
- ScratchPad << name
- end
+ parent = Class.new do
+ def self.const_added(name)
+ ScratchPad << name
+ ScratchPad << const_get(name).superclass
end
+ end
- mod.const_set(:TEST, 1)
+ class parent::C < parent; end
- ScratchPad.recorded.should == [:TEST]
- end
+ ScratchPad.recorded.should == [:C, parent]
+ end
- it "is called when a new module is defined under self" do
- ScratchPad.record []
+ it "is called when a new constant is assigned on self" do
+ ScratchPad.record []
- mod = Module.new do
- def self.const_added(name)
- ScratchPad << name
- end
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad << name
end
+ end
- mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
- module SubModule
- end
+ mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
+ TEST = 1
+ RUBY
- module SubModule
- end
- RUBY
+ ScratchPad.recorded.should == [:TEST]
+ end
- ScratchPad.recorded.should == [:SubModule]
+ it "is called when a new constant is assigned on self through const_set" do
+ ScratchPad.record []
+
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad << name
+ end
end
- it "is called when a new module is defined under a named module (assigned to a constant)" do
- ScratchPad.record []
+ mod.const_set(:TEST, 1)
- ModuleSpecs::ConstAddedSpecs::NamedModule = Module.new do
- def self.const_added(name)
- ScratchPad << name
- end
+ ScratchPad.recorded.should == [:TEST]
+ end
- module self::A
- def self.const_added(name)
- ScratchPad << name
- end
+ it "is called when a new module is defined under self" do
+ ScratchPad.record []
- module self::B
- end
- end
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad << name
end
-
- ScratchPad.recorded.should == [:A, :B]
end
- it "is called when a new class is defined under self" do
- ScratchPad.record []
-
- mod = Module.new do
- def self.const_added(name)
- ScratchPad << name
- end
+ mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
+ module SubModule
end
- mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
- class SubClass
- end
+ module SubModule
+ end
+ RUBY
- class SubClass
- end
- RUBY
+ ScratchPad.recorded.should == [:SubModule]
+ end
- ScratchPad.recorded.should == [:SubClass]
- end
+ it "is called when a new module is defined under a named module (assigned to a constant)" do
+ ScratchPad.record []
- it "is called when a new class is defined under a named module (assigned to a constant)" do
- ScratchPad.record []
+ ModuleSpecs::ConstAddedSpecs::NamedModule = Module.new do
+ def self.const_added(name)
+ ScratchPad << name
+ end
- ModuleSpecs::ConstAddedSpecs::NamedModuleB = Module.new do
+ module self::A
def self.const_added(name)
ScratchPad << name
end
- class self::A
- def self.const_added(name)
- ScratchPad << name
- end
-
- class self::B
- end
+ module self::B
end
end
+ end
+
+ ScratchPad.recorded.should == [:A, :B]
+ ModuleSpecs::ConstAddedSpecs.send :remove_const, :NamedModule
+ end
- ScratchPad.recorded.should == [:A, :B]
+ it "is called when a new class is defined under self" do
+ ScratchPad.record []
+
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad << name
+ end
end
- it "is called when an autoload is defined" do
- ScratchPad.record []
+ mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
+ class SubClass
+ end
- mod = Module.new do
- def self.const_added(name)
- ScratchPad << name
- end
+ class SubClass
end
+ RUBY
- mod.autoload :Autoload, "foo"
- ScratchPad.recorded.should == [:Autoload]
- end
+ ScratchPad.recorded.should == [:SubClass]
+ end
+
+ it "is called when a new class is defined under a named module (assigned to a constant)" do
+ ScratchPad.record []
- it "is called with a precise caller location with the line of definition" do
- ScratchPad.record []
+ ModuleSpecs::ConstAddedSpecs::NamedModuleB = Module.new do
+ def self.const_added(name)
+ ScratchPad << name
+ end
- mod = Module.new do
+ class self::A
def self.const_added(name)
- location = caller_locations(1, 1)[0]
- ScratchPad << location.lineno
+ ScratchPad << name
+ end
+
+ class self::B
end
end
+ end
- line = __LINE__
- mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
- TEST = 1
+ ScratchPad.recorded.should == [:A, :B]
+ ModuleSpecs::ConstAddedSpecs.send :remove_const, :NamedModuleB
+ end
- module SubModule
- end
+ it "is called when an autoload is defined" do
+ ScratchPad.record []
- class SubClass
- end
- RUBY
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad << name
+ end
+ end
- mod.const_set(:CONST_SET, 1)
+ mod.autoload :Autoload, "foo"
+ ScratchPad.recorded.should == [:Autoload]
+ end
+
+ it "is called with a precise caller location with the line of definition" do
+ ScratchPad.record []
- ScratchPad.recorded.should == [line + 2, line + 4, line + 7, line + 11]
+ mod = Module.new do
+ def self.const_added(name)
+ location = caller_locations(1, 1)[0]
+ ScratchPad << location.lineno
+ end
end
- it "is called when the constant is already assigned a value" do
- ScratchPad.record []
+ line = __LINE__
+ mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
+ TEST = 1
- mod = Module.new do
- def self.const_added(name)
- ScratchPad.record const_get(name)
- end
+ module SubModule
end
- mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
- TEST = 123
- RUBY
+ class SubClass
+ end
+ RUBY
- ScratchPad.recorded.should == 123
- end
+ mod.const_set(:CONST_SET, 1)
- it "records re-definition of existing constants" do
- ScratchPad.record []
+ ScratchPad.recorded.should == [line + 2, line + 4, line + 7, line + 11]
+ end
- mod = Module.new do
- def self.const_added(name)
- ScratchPad << const_get(name)
- end
+ it "is called when the constant is already assigned a value" do
+ ScratchPad.record []
+
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad.record const_get(name)
end
+ end
+
+ mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
+ TEST = 123
+ RUBY
+
+ ScratchPad.recorded.should == 123
+ end
- -> {
- mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
- TEST = 123
- TEST = 456
- RUBY
- }.should complain(/warning: already initialized constant .+::TEST/)
+ it "records re-definition of existing constants" do
+ ScratchPad.record []
- ScratchPad.recorded.should == [123, 456]
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad << const_get(name)
+ end
end
+
+ -> {
+ mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
+ TEST = 123
+ TEST = 456
+ RUBY
+ }.should complain(/warning: already initialized constant .+::TEST/)
+
+ ScratchPad.recorded.should == [123, 456]
end
end
diff --git a/spec/ruby/core/module/const_defined_spec.rb b/spec/ruby/core/module/const_defined_spec.rb
index 027cf5a245..8b137cd134 100644
--- a/spec/ruby/core/module/const_defined_spec.rb
+++ b/spec/ruby/core/module/const_defined_spec.rb
@@ -65,6 +65,8 @@ describe "Module#const_defined?" do
str = "CS_CONSTλ".encode("euc-jp")
ConstantSpecs.const_set str, 1
ConstantSpecs.const_defined?(str).should be_true
+ ensure
+ ConstantSpecs.send(:remove_const, str)
end
it "returns false if the constant is not defined in the receiver, its superclass, or any included modules" do
diff --git a/spec/ruby/core/module/const_get_spec.rb b/spec/ruby/core/module/const_get_spec.rb
index 0233118f4b..4b53cbe7b3 100644
--- a/spec/ruby/core/module/const_get_spec.rb
+++ b/spec/ruby/core/module/const_get_spec.rb
@@ -131,7 +131,7 @@ describe "Module#const_get" do
end
it "does read private constants" do
- ConstantSpecs.const_get(:CS_PRIVATE).should == :cs_private
+ ConstantSpecs.const_get(:CS_PRIVATE).should == :cs_private
end
it 'does autoload a constant' do
@@ -202,40 +202,60 @@ describe "Module#const_get" do
ConstantSpecs::ContainerA::ChildA::CS_CONST301 = :const301_5
ConstantSpecs::ContainerA::ChildA.const_get(:CS_CONST301).should == :const301_5
+ ensure
+ ConstantSpecs::ClassA.send(:remove_const, :CS_CONST301)
+ ConstantSpecs::ModuleA.send(:remove_const, :CS_CONST301)
+ ConstantSpecs::ParentA.send(:remove_const, :CS_CONST301)
+ ConstantSpecs::ContainerA::ChildA.send(:remove_const, :CS_CONST301)
end
it "searches a module included in the immediate class before the superclass" do
ConstantSpecs::ParentB::CS_CONST302 = :const302_1
ConstantSpecs::ModuleF::CS_CONST302 = :const302_2
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST302).should == :const302_2
+ ensure
+ ConstantSpecs::ParentB.send(:remove_const, :CS_CONST302)
+ ConstantSpecs::ModuleF.send(:remove_const, :CS_CONST302)
end
it "searches the superclass before a module included in the superclass" do
ConstantSpecs::ModuleE::CS_CONST303 = :const303_1
ConstantSpecs::ParentB::CS_CONST303 = :const303_2
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST303).should == :const303_2
+ ensure
+ ConstantSpecs::ModuleE.send(:remove_const, :CS_CONST303)
+ ConstantSpecs::ParentB.send(:remove_const, :CS_CONST303)
end
it "searches a module included in the superclass" do
ConstantSpecs::ModuleA::CS_CONST304 = :const304_1
ConstantSpecs::ModuleE::CS_CONST304 = :const304_2
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST304).should == :const304_2
+ ensure
+ ConstantSpecs::ModuleA.send(:remove_const, :CS_CONST304)
+ ConstantSpecs::ModuleE.send(:remove_const, :CS_CONST304)
end
it "searches the superclass chain" do
ConstantSpecs::ModuleA::CS_CONST305 = :const305
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST305).should == :const305
+ ensure
+ ConstantSpecs::ModuleA.send(:remove_const, :CS_CONST305)
end
it "returns a toplevel constant when the receiver is a Class" do
Object::CS_CONST306 = :const306
ConstantSpecs::ContainerB::ChildB.const_get(:CS_CONST306).should == :const306
+ ensure
+ Object.send(:remove_const, :CS_CONST306)
end
it "returns a toplevel constant when the receiver is a Module" do
Object::CS_CONST308 = :const308
ConstantSpecs.const_get(:CS_CONST308).should == :const308
ConstantSpecs::ModuleA.const_get(:CS_CONST308).should == :const308
+ ensure
+ Object.send(:remove_const, :CS_CONST308)
end
it "returns the updated value of a constant" do
@@ -246,6 +266,8 @@ describe "Module#const_get" do
ConstantSpecs::ClassB::CS_CONST309 = :const309_2
}.should complain(/already initialized constant/)
ConstantSpecs::ClassB.const_get(:CS_CONST309).should == :const309_2
+ ensure
+ ConstantSpecs::ClassB.send(:remove_const, :CS_CONST309)
end
end
end
diff --git a/spec/ruby/core/module/const_set_spec.rb b/spec/ruby/core/module/const_set_spec.rb
index 5bdfd7b68f..823768b882 100644
--- a/spec/ruby/core/module/const_set_spec.rb
+++ b/spec/ruby/core/module/const_set_spec.rb
@@ -8,16 +8,23 @@ describe "Module#const_set" do
ConstantSpecs.const_set "CS_CONST402", :const402
ConstantSpecs.const_get(:CS_CONST402).should == :const402
+ ensure
+ ConstantSpecs.send(:remove_const, :CS_CONST401)
+ ConstantSpecs.send(:remove_const, :CS_CONST402)
end
it "returns the value set" do
ConstantSpecs.const_set(:CS_CONST403, :const403).should == :const403
+ ensure
+ ConstantSpecs.send(:remove_const, :CS_CONST403)
end
it "sets the name of an anonymous module" do
m = Module.new
ConstantSpecs.const_set(:CS_CONST1000, m)
m.name.should == "ConstantSpecs::CS_CONST1000"
+ ensure
+ ConstantSpecs.send(:remove_const, :CS_CONST1000)
end
it "sets the name of a module scoped by an anonymous module" do
@@ -38,6 +45,8 @@ describe "Module#const_set" do
b.name.should == "ModuleSpecs_CS3::B"
c.name.should == "ModuleSpecs_CS3::B::C"
d.name.should == "ModuleSpecs_CS3::D"
+ ensure
+ Object.send(:remove_const, :ModuleSpecs_CS3)
end
it "raises a NameError if the name does not start with a capital letter" do
@@ -55,6 +64,8 @@ describe "Module#const_set" do
ConstantSpecs.const_set("CS_CONST404", :const404).should == :const404
-> { ConstantSpecs.const_set "Name=", 1 }.should raise_error(NameError)
-> { ConstantSpecs.const_set "Name?", 1 }.should raise_error(NameError)
+ ensure
+ ConstantSpecs.send(:remove_const, :CS_CONST404)
end
it "calls #to_str to convert the given name to a String" do
@@ -62,6 +73,8 @@ describe "Module#const_set" do
name.should_receive(:to_str).and_return("CS_CONST405")
ConstantSpecs.const_set(name, :const405).should == :const405
ConstantSpecs::CS_CONST405.should == :const405
+ ensure
+ ConstantSpecs.send(:remove_const, :CS_CONST405)
end
it "raises a TypeError if conversion to a String by calling #to_str fails" do
diff --git a/spec/ruby/core/module/const_source_location_spec.rb b/spec/ruby/core/module/const_source_location_spec.rb
index c194c9113f..96649ea10b 100644
--- a/spec/ruby/core/module/const_source_location_spec.rb
+++ b/spec/ruby/core/module/const_source_location_spec.rb
@@ -19,40 +19,60 @@ describe "Module#const_source_location" do
ConstantSpecs::ContainerA::ChildA::CSL_CONST301 = :const301_5
ConstantSpecs::ContainerA::ChildA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
+ ensure
+ ConstantSpecs::ClassA.send(:remove_const, :CSL_CONST301)
+ ConstantSpecs::ModuleA.send(:remove_const, :CSL_CONST301)
+ ConstantSpecs::ParentA.send(:remove_const, :CSL_CONST301)
+ ConstantSpecs::ContainerA::ChildA.send(:remove_const, :CSL_CONST301)
end
it "searches a path in a module included in the immediate class before the superclass" do
ConstantSpecs::ParentB::CSL_CONST302 = :const302_1
ConstantSpecs::ModuleF::CSL_CONST302 = :const302_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST302).should == [__FILE__, __LINE__ - 1]
+ ensure
+ ConstantSpecs::ParentB.send(:remove_const, :CSL_CONST302)
+ ConstantSpecs::ModuleF.send(:remove_const, :CSL_CONST302)
end
it "searches a path in the superclass before a module included in the superclass" do
ConstantSpecs::ModuleE::CSL_CONST303 = :const303_1
ConstantSpecs::ParentB::CSL_CONST303 = :const303_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST303).should == [__FILE__, __LINE__ - 1]
+ ensure
+ ConstantSpecs::ModuleE.send(:remove_const, :CSL_CONST303)
+ ConstantSpecs::ParentB.send(:remove_const, :CSL_CONST303)
end
it "searches a path in a module included in the superclass" do
ConstantSpecs::ModuleA::CSL_CONST304 = :const304_1
ConstantSpecs::ModuleE::CSL_CONST304 = :const304_2
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST304).should == [__FILE__, __LINE__ - 1]
+ ensure
+ ConstantSpecs::ModuleA.send(:remove_const, :CSL_CONST304)
+ ConstantSpecs::ModuleE.send(:remove_const, :CSL_CONST304)
end
it "searches a path in the superclass chain" do
ConstantSpecs::ModuleA::CSL_CONST305 = :const305
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST305).should == [__FILE__, __LINE__ - 1]
+ ensure
+ ConstantSpecs::ModuleA.send(:remove_const, :CSL_CONST305)
end
it "returns path to a toplevel constant when the receiver is a Class" do
Object::CSL_CONST306 = :const306
ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST306).should == [__FILE__, __LINE__ - 1]
+ ensure
+ Object.send(:remove_const, :CSL_CONST306)
end
it "returns path to a toplevel constant when the receiver is a Module" do
Object::CSL_CONST308 = :const308
ConstantSpecs.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 1]
ConstantSpecs::ModuleA.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 2]
+ ensure
+ Object.send(:remove_const, :CSL_CONST308)
end
it "returns path to the updated value of a constant" do
@@ -63,6 +83,8 @@ describe "Module#const_source_location" do
ConstantSpecs::ClassB::CSL_CONST309 = :const309_2
}.should complain(/already initialized constant/)
ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 2]
+ ensure
+ ConstantSpecs::ClassB.send(:remove_const, :CSL_CONST309)
end
end
@@ -207,7 +229,7 @@ describe "Module#const_source_location" do
end
it "does search private constants path" do
- ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE]
+ ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE]
end
it "works for eval with a given line" do
@@ -223,6 +245,14 @@ describe "Module#const_source_location" do
@line = __LINE__ - 1
end
+ before :each do
+ @loaded_features = $".dup
+ end
+
+ after :each do
+ $".replace @loaded_features
+ end
+
it 'returns the autoload location while not resolved' do
ConstantSpecs.const_source_location('CSL_CONST1').should == [__FILE__, @line]
end
@@ -243,6 +273,8 @@ describe "Module#const_source_location" do
ConstantSpecs.const_source_location(:ConstSource).should == autoload_location
ConstantSpecs::ConstSource::LOCATION.should == ConstantSpecs.const_source_location(:ConstSource)
ConstantSpecs::BEFORE_DEFINE_LOCATION.should == autoload_location
+ ConstantSpecs.send :remove_const, :ConstSource
+ ConstantSpecs.send :remove_const, :BEFORE_DEFINE_LOCATION
end
end
end
diff --git a/spec/ruby/core/module/define_method_spec.rb b/spec/ruby/core/module/define_method_spec.rb
index e04bb87ceb..c5dfc53764 100644
--- a/spec/ruby/core/module/define_method_spec.rb
+++ b/spec/ruby/core/module/define_method_spec.rb
@@ -476,6 +476,9 @@ describe "Module#define_method" do
ChildClass = Class.new(ParentClass) { define_method(:foo) { :baz } }
ParentClass.send :define_method, :foo, ChildClass.instance_method(:foo)
}.should raise_error(TypeError, /bind argument must be a subclass of ChildClass/)
+ ensure
+ Object.send(:remove_const, :ParentClass)
+ Object.send(:remove_const, :ChildClass)
end
it "raises a TypeError when an UnboundMethod from one class is defined on an unrelated class" do
diff --git a/spec/ruby/core/module/fixtures/classes.rb b/spec/ruby/core/module/fixtures/classes.rb
index a434e7b0b8..964f64c593 100644
--- a/spec/ruby/core/module/fixtures/classes.rb
+++ b/spec/ruby/core/module/fixtures/classes.rb
@@ -1,6 +1,6 @@
module ModuleSpecs
def self.without_test_modules(modules)
- ignore = %w[MSpecRSpecAdapter PP::ObjectMixin ModuleSpecs::IncludedInObject MainSpecs::Module ConstantSpecs::ModuleA]
+ ignore = %w[MSpecRSpecAdapter PP::ObjectMixin MainSpecs::Module ConstantSpecs::ModuleA]
modules.reject { |k| ignore.include?(k.name) }
end
diff --git a/spec/ruby/core/module/fixtures/set_temporary_name.rb b/spec/ruby/core/module/fixtures/set_temporary_name.rb
new file mode 100644
index 0000000000..901b3b94d1
--- /dev/null
+++ b/spec/ruby/core/module/fixtures/set_temporary_name.rb
@@ -0,0 +1,4 @@
+module ModuleSpecs
+ module SetTemporaryNameSpec
+ end
+end
diff --git a/spec/ruby/core/module/include_spec.rb b/spec/ruby/core/module/include_spec.rb
index 862c6976e1..210918b2e7 100644
--- a/spec/ruby/core/module/include_spec.rb
+++ b/spec/ruby/core/module/include_spec.rb
@@ -44,35 +44,23 @@ describe "Module#include" do
end
it "does not raise a TypeError when the argument is an instance of a subclass of Module" 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")
+ class ModuleSpecs::SubclassSpec::AClass
end
+ -> { ModuleSpecs::SubclassSpec::AClass.include(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
+ ensure
+ ModuleSpecs::SubclassSpec.send(:remove_const, :AClass)
end
- ruby_version_is "3.2" do
- it "raises a TypeError when the argument is a refinement" do
- refinement = nil
+ it "raises a TypeError when the argument is a refinement" do
+ refinement = nil
- Module.new do
- refine String do
- refinement = self
- end
+ Module.new do
+ refine String do
+ refinement = self
end
-
- -> { ModuleSpecs::Basic.include(refinement) }.should raise_error(TypeError, "Cannot include refinement")
end
+
+ -> { ModuleSpecs::Basic.include(refinement) }.should raise_error(TypeError, "Cannot include refinement")
end
it "imports constants to modules and classes" do
@@ -427,6 +415,8 @@ describe "Module#include" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
+ ensure
+ ModuleSpecs.send(:remove_const, :ConstUpdated)
end
it "updates the constant when a module included after a call is later updated" do
@@ -453,6 +443,8 @@ describe "Module#include" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
+ ensure
+ ModuleSpecs.send(:remove_const, :ConstLaterUpdated)
end
it "updates the constant when a module included in another module after a call is later updated" do
@@ -479,6 +471,8 @@ describe "Module#include" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
+ ensure
+ ModuleSpecs.send(:remove_const, :ConstModuleLaterUpdated)
end
it "updates the constant when a nested included module is updated" do
@@ -507,6 +501,8 @@ describe "Module#include" do
N.const_set(:FOO, 'n')
B.foo.should == 'n'
end
+ ensure
+ ModuleSpecs.send(:remove_const, :ConstUpdatedNestedIncludeUpdated)
end
it "updates the constant when a new module is included" do
@@ -531,6 +527,8 @@ describe "Module#include" do
B.include(M)
B.foo.should == 'm'
end
+ ensure
+ ModuleSpecs.send(:remove_const, :ConstUpdatedNewInclude)
end
it "updates the constant when a new module with nested module is included" do
@@ -559,6 +557,8 @@ describe "Module#include" do
B.include M
B.foo.should == 'n'
end
+ ensure
+ ModuleSpecs.send(:remove_const, :ConstUpdatedNestedIncluded)
end
it "overrides a previous super method call" do
diff --git a/spec/ruby/core/module/instance_method_spec.rb b/spec/ruby/core/module/instance_method_spec.rb
index 8d006e647e..182cdf5c54 100644
--- a/spec/ruby/core/module/instance_method_spec.rb
+++ b/spec/ruby/core/module/instance_method_spec.rb
@@ -48,11 +48,6 @@ describe "Module#instance_method" do
@mod_um.inspect.should =~ /\bbar\b/
@mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethMod\b/
-
- ruby_version_is ""..."3.2" do
- @child_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/
- @mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/
- end
end
it "raises a TypeError if the given name is not a String/Symbol" do
diff --git a/spec/ruby/core/module/module_function_spec.rb b/spec/ruby/core/module/module_function_spec.rb
index 1c3ec5471b..51f647142e 100644
--- a/spec/ruby/core/module/module_function_spec.rb
+++ b/spec/ruby/core/module/module_function_spec.rb
@@ -38,22 +38,11 @@ describe "Module#module_function with specific method names" do
m.respond_to?(:test3).should == false
end
- ruby_version_is ""..."3.1" do
- it "returns self" do
- Module.new do
- def foo; end
- module_function(:foo).should equal(self)
- end
- end
- end
-
- ruby_version_is "3.1" do
- it "returns argument or arguments if given" do
- Module.new do
- def foo; end
- module_function(:foo).should equal(:foo)
- module_function(:foo, :foo).should == [:foo, :foo]
- end
+ it "returns argument or arguments if given" do
+ Module.new do
+ def foo; end
+ module_function(:foo).should equal(:foo)
+ module_function(:foo, :foo).should == [:foo, :foo]
end
end
@@ -216,19 +205,9 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do
m.respond_to?(:test2).should == true
end
- ruby_version_is ""..."3.1" do
- it "returns self" do
- Module.new do
- module_function.should equal(self)
- end
- end
- end
-
- ruby_version_is "3.1" do
- it "returns nil" do
- Module.new do
- module_function.should equal(nil)
- end
+ it "returns nil" do
+ Module.new do
+ module_function.should equal(nil)
end
end
diff --git a/spec/ruby/core/module/name_spec.rb b/spec/ruby/core/module/name_spec.rb
index 33e8400e88..d3318e1645 100644
--- a/spec/ruby/core/module/name_spec.rb
+++ b/spec/ruby/core/module/name_spec.rb
@@ -30,6 +30,8 @@ describe "Module#name" do
m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
ModuleSpecs::Anonymous::WasAnnon = m::N
m::N.name.should == "ModuleSpecs::Anonymous::WasAnnon"
+ ensure
+ ModuleSpecs::Anonymous.send(:remove_const, :WasAnnon)
end
it "may be the repeated in different module objects" do
@@ -76,12 +78,16 @@ describe "Module#name" do
m = Module.new
ModuleSpecs::Anonymous::A = m
m.name.should == "ModuleSpecs::Anonymous::A"
+ ensure
+ ModuleSpecs::Anonymous.send(:remove_const, :A)
end
it "is set when assigning to a constant (constant path does not match outer module name)" do
m = Module.new
ModuleSpecs::Anonymous::SameChild::A = m
m.name.should == "ModuleSpecs::Anonymous::Child::A"
+ ensure
+ ModuleSpecs::Anonymous::SameChild.send(:remove_const, :A)
end
it "is not modified when assigning to a new constant after it has been accessed" do
@@ -90,6 +96,9 @@ describe "Module#name" do
m.name.should == "ModuleSpecs::Anonymous::B"
ModuleSpecs::Anonymous::C = m
m.name.should == "ModuleSpecs::Anonymous::B"
+ ensure
+ ModuleSpecs::Anonymous.send(:remove_const, :B)
+ ModuleSpecs::Anonymous.send(:remove_const, :C)
end
it "is not modified when assigned to a different anonymous module" do
@@ -125,6 +134,8 @@ describe "Module#name" do
m::N = Module.new
ModuleSpecs::Anonymous::E = m
m::N.name.should == "ModuleSpecs::Anonymous::E::N"
+ ensure
+ ModuleSpecs::Anonymous.send(:remove_const, :E)
end
# https://bugs.ruby-lang.org/issues/19681
@@ -138,47 +149,48 @@ describe "Module#name" do
"ModuleSpecs::Anonymous::StoredInMultiplePlaces::O"
]
valid_names.should include(m::N.name) # You get one of the two, but you don't know which one.
+ ensure
+ ModuleSpecs::Anonymous.send(:remove_const, :StoredInMultiplePlaces)
end
- ruby_version_is "3.2" do
- it "is set in #const_added callback when a module defined in the top-level scope" do
- ruby_exe(<<~RUBY, args: "2>&1").chomp.should == "TEST1\nTEST2"
- class Module
- def const_added(name)
- puts const_get(name).name
- end
+ it "is set in #const_added callback when a module defined in the top-level scope" do
+ ruby_exe(<<~RUBY, args: "2>&1").chomp.should == "TEST1\nTEST2"
+ class Module
+ def const_added(name)
+ puts const_get(name).name
end
+ end
- # module with name
- module TEST1
- end
+ # module with name
+ module TEST1
+ end
- # anonymous module
- TEST2 = Module.new
- RUBY
- end
+ # anonymous module
+ TEST2 = Module.new
+ RUBY
+ end
- it "is set in #const_added callback for a nested module when an outer module defined in the top-level scope" do
- ScratchPad.record []
+ it "is set in #const_added callback for a nested module when an outer module defined in the top-level scope" do
+ ScratchPad.record []
- ModuleSpecs::NameSpecs::NamedModule = Module.new do
+ ModuleSpecs::NameSpecs::NamedModule = Module.new do
+ def self.const_added(name)
+ ScratchPad << const_get(name).name
+ end
+
+ module self::A
def self.const_added(name)
ScratchPad << const_get(name).name
end
- module self::A
- def self.const_added(name)
- ScratchPad << const_get(name).name
- end
-
- module self::B
- end
+ module self::B
end
end
-
- ScratchPad.recorded.should.one?(/#<Module.+>::A$/)
- ScratchPad.recorded.should.one?(/#<Module.+>::A::B$/)
end
+
+ ScratchPad.recorded.should.one?(/#<Module.+>::A$/)
+ ScratchPad.recorded.should.one?(/#<Module.+>::A::B$/)
+ ModuleSpecs::NameSpecs.send :remove_const, :NamedModule
end
it "returns a frozen String" do
diff --git a/spec/ruby/core/module/prepend_spec.rb b/spec/ruby/core/module/prepend_spec.rb
index b40d12f0de..71e82c513e 100644
--- a/spec/ruby/core/module/prepend_spec.rb
+++ b/spec/ruby/core/module/prepend_spec.rb
@@ -261,6 +261,8 @@ describe "Module#prepend" do
B.prepend M
B.foo.should == 'm'
end
+ ensure
+ ModuleSpecs.send(:remove_const, :ConstUpdatePrepended)
end
it "updates the constant when a prepended module is updated" do
@@ -281,6 +283,8 @@ describe "Module#prepend" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
+ ensure
+ ModuleSpecs.send(:remove_const, :ConstPrependedUpdated)
end
it "updates the constant when there is a base included constant and the prepended module overrides it" do
@@ -302,6 +306,8 @@ describe "Module#prepend" do
A.prepend M
A.foo.should == 'm'
end
+ ensure
+ ModuleSpecs.send(:remove_const, :ConstIncludedPrependedOverride)
end
it "updates the constant when there is a base included constant and the prepended module is later updated" do
@@ -325,6 +331,8 @@ describe "Module#prepend" do
M.const_set(:FOO, 'm')
A.foo.should == 'm'
end
+ ensure
+ ModuleSpecs.send(:remove_const, :ConstIncludedPrependedLaterUpdated)
end
it "updates the constant when a module prepended after a constant is later updated" do
@@ -348,6 +356,8 @@ describe "Module#prepend" do
M.const_set(:FOO, 'm')
B.foo.should == 'm'
end
+ ensure
+ ModuleSpecs.send(:remove_const, :ConstUpdatedPrependedAfterLaterUpdated)
end
it "updates the constant when a module is prepended after another and the constant is defined later on that module" do
@@ -372,6 +382,8 @@ describe "Module#prepend" do
N.const_set(:FOO, 'n')
A.foo.should == 'n'
end
+ ensure
+ ModuleSpecs.send(:remove_const, :ConstUpdatedPrependedAfterConstDefined)
end
it "updates the constant when a module is included in a prepended module and the constant is defined later" do
@@ -399,6 +411,8 @@ describe "Module#prepend" do
N.const_set(:FOO, 'n')
A.foo.should == 'n'
end
+ ensure
+ ModuleSpecs.send(:remove_const, :ConstUpdatedIncludedInPrependedConstDefinedLater)
end
it "updates the constant when a new module with an included module is prepended" do
@@ -425,6 +439,8 @@ describe "Module#prepend" do
B.prepend M
B.foo.should == 'n'
end
+ ensure
+ ModuleSpecs.send(:remove_const, :ConstUpdatedNewModuleIncludedPrepended)
end
it "raises a TypeError when the argument is not a Module" do
@@ -432,35 +448,23 @@ describe "Module#prepend" do
end
it "does not raise a TypeError when the argument is an instance of a subclass of Module" 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")
+ class ModuleSpecs::SubclassSpec::AClass
end
+ -> { ModuleSpecs::SubclassSpec::AClass.prepend(ModuleSpecs::Subclass.new) }.should_not raise_error(TypeError)
+ ensure
+ ModuleSpecs::SubclassSpec.send(:remove_const, :AClass)
end
- ruby_version_is "3.2" do
- it "raises a TypeError when the argument is a refinement" do
- refinement = nil
+ it "raises a TypeError when the argument is a refinement" do
+ refinement = nil
- Module.new do
- refine String do
- refinement = self
- end
+ Module.new do
+ refine String do
+ refinement = self
end
-
- -> { ModuleSpecs::Basic.prepend(refinement) }.should raise_error(TypeError, "Cannot prepend refinement")
end
+
+ -> { ModuleSpecs::Basic.prepend(refinement) }.should raise_error(TypeError, "Cannot prepend refinement")
end
it "imports constants" do
@@ -787,34 +791,17 @@ describe "Module#prepend" do
# https://bugs.ruby-lang.org/issues/17423
describe "when module already exists in ancestor chain" do
- ruby_version_is ""..."3.1" do
- it "does not modify the ancestor chain" do
- m = Module.new do; end
- a = Module.new do; end
- b = Class.new do; end
-
- b.include(a)
- a.prepend(m)
- b.ancestors.take(4).should == [b, m, a, Object]
-
- b.prepend(m)
- b.ancestors.take(4).should == [b, m, a, Object]
- end
- end
+ it "modifies the ancestor chain" do
+ m = Module.new do; end
+ a = Module.new do; end
+ b = Class.new do; end
- ruby_version_is "3.1" do
- it "modifies the ancestor chain" do
- m = Module.new do; end
- a = Module.new do; end
- b = Class.new do; end
+ b.include(a)
+ a.prepend(m)
+ b.ancestors.take(4).should == [b, m, a, Object]
- b.include(a)
- a.prepend(m)
- b.ancestors.take(4).should == [b, m, a, Object]
-
- b.prepend(m)
- b.ancestors.take(5).should == [m, b, m, a, Object]
- end
+ b.prepend(m)
+ b.ancestors.take(5).should == [m, b, m, a, Object]
end
end
diff --git a/spec/ruby/core/module/private_spec.rb b/spec/ruby/core/module/private_spec.rb
index ead806637c..9e1a297eea 100644
--- a/spec/ruby/core/module/private_spec.rb
+++ b/spec/ruby/core/module/private_spec.rb
@@ -38,25 +38,13 @@ describe "Module#private" do
:module_specs_public_method_on_object_for_kernel_private)
end
- ruby_version_is ""..."3.1" do
- it "returns self" do
- (class << Object.new; self; end).class_eval do
- def foo; end
- private(:foo).should equal(self)
- private.should equal(self)
- end
- end
- end
-
- ruby_version_is "3.1" do
- it "returns argument or arguments if given" do
- (class << Object.new; self; end).class_eval do
- def foo; end
- private(:foo).should equal(:foo)
- private([:foo, :foo]).should == [:foo, :foo]
- private(:foo, :foo).should == [:foo, :foo]
- private.should equal(nil)
- end
+ it "returns argument or arguments if given" do
+ (class << Object.new; self; end).class_eval do
+ def foo; end
+ private(:foo).should equal(:foo)
+ private([:foo, :foo]).should == [:foo, :foo]
+ private(:foo, :foo).should == [:foo, :foo]
+ private.should equal(nil)
end
end
diff --git a/spec/ruby/core/module/protected_spec.rb b/spec/ruby/core/module/protected_spec.rb
index 058d49d751..9e37223e18 100644
--- a/spec/ruby/core/module/protected_spec.rb
+++ b/spec/ruby/core/module/protected_spec.rb
@@ -39,25 +39,13 @@ describe "Module#protected" do
:module_specs_public_method_on_object_for_kernel_protected)
end
- ruby_version_is ""..."3.1" do
- it "returns self" do
- (class << Object.new; self; end).class_eval do
- def foo; end
- protected(:foo).should equal(self)
- protected.should equal(self)
- end
- end
- end
-
- ruby_version_is "3.1" do
- it "returns argument or arguments if given" do
- (class << Object.new; self; end).class_eval do
- def foo; end
- protected(:foo).should equal(:foo)
- protected([:foo, :foo]).should == [:foo, :foo]
- protected(:foo, :foo).should == [:foo, :foo]
- protected.should equal(nil)
- end
+ it "returns argument or arguments if given" do
+ (class << Object.new; self; end).class_eval do
+ def foo; end
+ protected(:foo).should equal(:foo)
+ protected([:foo, :foo]).should == [:foo, :foo]
+ protected(:foo, :foo).should == [:foo, :foo]
+ protected.should equal(nil)
end
end
diff --git a/spec/ruby/core/module/public_spec.rb b/spec/ruby/core/module/public_spec.rb
index e3b183f228..ce31eb5d0e 100644
--- a/spec/ruby/core/module/public_spec.rb
+++ b/spec/ruby/core/module/public_spec.rb
@@ -27,25 +27,13 @@ describe "Module#public" do
:module_specs_private_method_on_object_for_kernel_public)
end
- ruby_version_is ""..."3.1" do
- it "returns self" do
- (class << Object.new; self; end).class_eval do
- def foo; end
- public(:foo).should equal(self)
- public.should equal(self)
- end
- end
- end
-
- ruby_version_is "3.1" do
- it "returns argument or arguments if given" do
- (class << Object.new; self; end).class_eval do
- def foo; end
- public(:foo).should equal(:foo)
- public([:foo, :foo]).should == [:foo, :foo]
- public(:foo, :foo).should == [:foo, :foo]
- public.should equal(nil)
- end
+ it "returns argument or arguments if given" do
+ (class << Object.new; self; end).class_eval do
+ def foo; end
+ public(:foo).should equal(:foo)
+ public([:foo, :foo]).should == [:foo, :foo]
+ public(:foo, :foo).should == [:foo, :foo]
+ public.should equal(nil)
end
end
diff --git a/spec/ruby/core/module/refine_spec.rb b/spec/ruby/core/module/refine_spec.rb
index 8b9ea5eca8..d219b98825 100644
--- a/spec/ruby/core/module/refine_spec.rb
+++ b/spec/ruby/core/module/refine_spec.rb
@@ -243,36 +243,10 @@ describe "Module#refine" do
result.should == "foo from singleton class"
end
- ruby_version_is ""..."3.2" do
- it "looks in the included modules for builtin methods" do
- result = ruby_exe(<<-RUBY)
- a = Module.new do
- def /(other) quo(other) end
- end
-
- refinement = Module.new do
- refine Integer do
- include a
- end
- end
-
- result = nil
- Module.new do
- using refinement
- result = 1 / 2
- end
-
- print result.class
- RUBY
-
- result.should == 'Rational'
- end
- end
-
it "looks in later included modules of the refined module first" do
a = Module.new do
def foo
- "foo from A"
+ "foo from A"
end
end
@@ -300,67 +274,6 @@ describe "Module#refine" do
result.should == "foo from IncludeMeLater"
end
- ruby_version_is ""..."3.1" do
- it "looks in prepended modules from the refinement first" do
- refined_class = ModuleSpecs.build_refined_class
-
- refinement = Module.new do
- refine refined_class do
- include ModuleSpecs::IncludedModule
- prepend ModuleSpecs::PrependedModule
-
- def foo; "foo from refinement"; end
- end
- end
-
- result = nil
- Module.new do
- using refinement
- result = refined_class.new.foo
- end
-
- result.should == "foo from prepended module"
- end
-
- it "looks in refinement then" do
- refined_class = ModuleSpecs.build_refined_class
-
- refinement = Module.new do
- refine(refined_class) do
- include ModuleSpecs::IncludedModule
-
- def foo; "foo from refinement"; end
- end
- end
-
- result = nil
- Module.new do
- using refinement
- result = refined_class.new.foo
- end
-
- result.should == "foo from refinement"
- end
-
- it "looks in included modules from the refinement then" do
- refined_class = ModuleSpecs.build_refined_class
-
- refinement = Module.new do
- refine refined_class do
- include ModuleSpecs::IncludedModule
- end
- end
-
- result = nil
- Module.new do
- using refinement
- result = refined_class.new.foo
- end
-
- result.should == "foo from included module"
- end
- end
-
it "looks in the class then" do
refined_class = ModuleSpecs.build_refined_class
@@ -606,30 +519,6 @@ describe "Module#refine" do
end
context "when super is called in a refinement" do
- ruby_version_is ""..."3.1" do
- it "looks in the included to refinery module" do
- refined_class = ModuleSpecs.build_refined_class
-
- refinement = Module.new do
- refine refined_class do
- include ModuleSpecs::IncludedModule
-
- def foo
- super
- end
- end
- end
-
- result = nil
- Module.new do
- using refinement
- result = refined_class.new.foo
- end
-
- result.should == "foo from included module"
- end
- end
-
it "looks in the refined class" do
refined_class = ModuleSpecs.build_refined_class
@@ -650,59 +539,6 @@ describe "Module#refine" do
result.should == "foo"
end
- ruby_version_is ""..."3.1" do
- it "looks in the refined class from included module" do
- refined_class = ModuleSpecs.build_refined_class(for_super: true)
-
- a = Module.new do
- def foo
- [:A] + super
- end
- end
-
- refinement = Module.new do
- refine refined_class do
- include a
- end
- end
-
- result = nil
- Module.new do
- using refinement
-
- result = refined_class.new.foo
- end
-
- result.should == [:A, :C]
- end
-
- it "looks in the refined ancestors from included module" do
- refined_class = ModuleSpecs.build_refined_class(for_super: true)
- subclass = Class.new(refined_class)
-
- a = Module.new do
- def foo
- [:A] + super
- end
- end
-
- refinement = Module.new do
- refine refined_class do
- include a
- end
- end
-
- result = nil
- Module.new do
- using refinement
-
- result = subclass.new.foo
- end
-
- result.should == [:A, :C]
- end
- end
-
# super in a method of a refinement invokes the method in the refined
# class even if there is another refinement which has been activated
# in the same context.
@@ -763,179 +599,6 @@ describe "Module#refine" do
}.should raise_error(NoMethodError)
end
end
-
- ruby_version_is ""..."3.1" do
- it "does't have access to active refinements for C from included module" do
- refined_class = ModuleSpecs.build_refined_class
-
- a = Module.new do
- def foo
- super + bar
- end
- end
-
- refinement = Module.new do
- refine refined_class do
- include a
-
- def bar
- "bar is not seen from A methods"
- end
- end
- end
-
- Module.new do
- using refinement
- -> {
- refined_class.new.foo
- }.should raise_error(NameError) { |e| e.name.should == :bar }
- end
- end
-
- it "does't have access to other active refinements from included module" do
- refined_class = ModuleSpecs.build_refined_class
-
- refinement_integer = Module.new do
- refine Integer do
- def bar
- "bar is not seen from A methods"
- end
- end
- end
-
- a = Module.new do
- def foo
- super + 1.bar
- end
- end
-
- refinement = Module.new do
- refine refined_class do
- include a
- end
- end
-
- Module.new do
- using refinement
- using refinement_integer
- -> {
- refined_class.new.foo
- }.should raise_error(NameError) { |e| e.name.should == :bar }
- end
- end
-
- # https://bugs.ruby-lang.org/issues/16977
- it "looks in the another active refinement if super called from included modules" do
- refined_class = ModuleSpecs.build_refined_class(for_super: true)
-
- a = Module.new do
- def foo
- [:A] + super
- end
- end
-
- b = Module.new do
- def foo
- [:B] + super
- end
- end
-
- refinement_a = Module.new do
- refine refined_class do
- include a
- end
- end
-
- refinement_b = Module.new do
- refine refined_class do
- include b
- end
- end
-
- result = nil
- Module.new do
- using refinement_a
- using refinement_b
- result = refined_class.new.foo
- end
-
- result.should == [:B, :A, :C]
- end
-
- it "looks in the current active refinement from included modules" do
- refined_class = ModuleSpecs.build_refined_class(for_super: true)
-
- a = Module.new do
- def foo
- [:A] + super
- end
- end
-
- b = Module.new do
- def foo
- [:B] + super
- end
- end
-
- refinement = Module.new do
- refine refined_class do
- def foo
- [:LAST] + super
- end
- end
- end
-
- refinement_a_b = Module.new do
- refine refined_class do
- include a
- include b
- end
- end
-
- result = nil
- Module.new do
- using refinement
- using refinement_a_b
- result = refined_class.new.foo
- end
-
- result.should == [:B, :A, :LAST, :C]
- end
-
- it "looks in the lexical scope refinements before other active refinements" do
- refined_class = ModuleSpecs.build_refined_class(for_super: true)
-
- refinement_local = Module.new do
- refine refined_class do
- def foo
- [:LOCAL] + super
- end
- end
- end
-
- a = Module.new do
- using refinement_local
-
- def foo
- [:A] + super
- end
- end
-
- refinement = Module.new do
- refine refined_class do
- include a
- end
- end
-
- result = nil
- Module.new do
- using refinement
- result = refined_class.new.foo
- end
-
- result.should == [:A, :LOCAL, :C]
- end
- end
end
it 'and alias aliases a method within a refinement module, but not outside it' do
diff --git a/spec/ruby/core/module/refinements_spec.rb b/spec/ruby/core/module/refinements_spec.rb
index 5648fcbd6f..05658a8b0e 100644
--- a/spec/ruby/core/module/refinements_spec.rb
+++ b/spec/ruby/core/module/refinements_spec.rb
@@ -1,45 +1,43 @@
require_relative '../../spec_helper'
describe "Module#refinements" do
- ruby_version_is "3.2" do
- it "returns refinements defined in a module" do
- ScratchPad.record []
-
- m = Module.new do
- refine String do
- ScratchPad << self
- end
-
- refine Array do
- ScratchPad << self
- end
+ it "returns refinements defined in a module" do
+ ScratchPad.record []
+
+ m = Module.new do
+ refine String do
+ ScratchPad << self
end
- m.refinements.sort_by(&:object_id).should == ScratchPad.recorded.sort_by(&:object_id)
+ refine Array do
+ ScratchPad << self
+ end
end
- it "does not return refinements defined in the included module" do
- ScratchPad.record []
+ m.refinements.sort_by(&:object_id).should == ScratchPad.recorded.sort_by(&:object_id)
+ end
- m1 = Module.new do
- refine Integer do
- nil
- end
+ it "does not return refinements defined in the included module" do
+ ScratchPad.record []
+
+ m1 = Module.new do
+ refine Integer do
+ nil
end
+ end
- m2 = Module.new do
- include m1
+ m2 = Module.new do
+ include m1
- refine String do
- ScratchPad << self
- end
+ refine String do
+ ScratchPad << self
end
-
- m2.refinements.should == ScratchPad.recorded
end
- it "returns an empty array if no refinements defined in a module" do
- Module.new.refinements.should == []
- end
+ m2.refinements.should == ScratchPad.recorded
+ end
+
+ it "returns an empty array if no refinements defined in a module" do
+ Module.new.refinements.should == []
end
end
diff --git a/spec/ruby/core/module/remove_const_spec.rb b/spec/ruby/core/module/remove_const_spec.rb
index 0ac23f05a5..35a9d65105 100644
--- a/spec/ruby/core/module/remove_const_spec.rb
+++ b/spec/ruby/core/module/remove_const_spec.rb
@@ -101,5 +101,7 @@ describe "Module#remove_const" do
A.send(:remove_const,:FOO)
A.foo.should == 'm'
end
+ ensure
+ ConstantSpecs.send(:remove_const, :RemovedConstantUpdate)
end
end
diff --git a/spec/ruby/core/module/ruby2_keywords_spec.rb b/spec/ruby/core/module/ruby2_keywords_spec.rb
index aca419f522..652f9f7083 100644
--- a/spec/ruby/core/module/ruby2_keywords_spec.rb
+++ b/spec/ruby/core/module/ruby2_keywords_spec.rb
@@ -76,122 +76,60 @@ describe "Module#ruby2_keywords" do
Hash.ruby2_keywords_hash?(marked).should == true
end
- ruby_version_is "3.2" do
- it "makes a copy and unmark the Hash when calling a method taking (*args)" do
- obj = Object.new
- obj.singleton_class.class_exec do
- def splat(*args)
- args.last
- end
-
- def splat1(arg, *args)
- args.last
- end
+ it "makes a copy and unmark the Hash when calling a method taking (*args)" do
+ obj = Object.new
+ obj.singleton_class.class_exec do
+ def splat(*args)
+ args.last
+ end
- def proc_call(*args)
- -> *a { a.last }.call(*args)
- end
+ def splat1(arg, *args)
+ args.last
end
- h = { a: 1 }
- args = mark(**h)
- marked = args.last
- Hash.ruby2_keywords_hash?(marked).should == true
-
- after_usage = obj.splat(*args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- after_usage.should_not.equal?(marked)
- Hash.ruby2_keywords_hash?(after_usage).should == false
- Hash.ruby2_keywords_hash?(marked).should == true
-
- args = mark(1, **h)
- marked = args.last
- after_usage = obj.splat1(*args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- after_usage.should_not.equal?(marked)
- Hash.ruby2_keywords_hash?(after_usage).should == false
- Hash.ruby2_keywords_hash?(marked).should == true
-
- args = mark(**h)
- marked = args.last
- after_usage = obj.proc_call(*args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- after_usage.should_not.equal?(marked)
- Hash.ruby2_keywords_hash?(after_usage).should == false
- Hash.ruby2_keywords_hash?(marked).should == true
-
- args = mark(**h)
- marked = args.last
- after_usage = obj.send(:splat, *args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- after_usage.should_not.equal?(marked)
- Hash.ruby2_keywords_hash?(after_usage).should == false
- Hash.ruby2_keywords_hash?(marked).should == true
+ def proc_call(*args)
+ -> *a { a.last }.call(*args)
+ end
end
- end
- ruby_version_is ""..."3.2" do
- # https://bugs.ruby-lang.org/issues/18625
- it "does NOT copy the Hash when calling a method taking (*args)" do
- obj = Object.new
- obj.singleton_class.class_exec do
- def splat(*args)
- args.last
- end
+ h = { a: 1 }
+ args = mark(**h)
+ marked = args.last
+ Hash.ruby2_keywords_hash?(marked).should == true
- def splat1(arg, *args)
- args.last
- end
+ after_usage = obj.splat(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
- def proc_call(*args)
- -> *a { a.last }.call(*args)
- end
- end
+ args = mark(1, **h)
+ marked = args.last
+ after_usage = obj.splat1(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
- h = { a: 1 }
- args = mark(**h)
- marked = args.last
- Hash.ruby2_keywords_hash?(marked).should == true
-
- after_usage = obj.splat(*args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625
- Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625
- Hash.ruby2_keywords_hash?(marked).should == true
-
- args = mark(1, **h)
- marked = args.last
- after_usage = obj.splat1(*args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625
- Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625
- Hash.ruby2_keywords_hash?(marked).should == true
-
- args = mark(**h)
- marked = args.last
- after_usage = obj.proc_call(*args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625
- Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625
- Hash.ruby2_keywords_hash?(marked).should == true
-
- args = mark(**h)
- marked = args.last
- after_usage = obj.send(:splat, *args)
- after_usage.should == h
- after_usage.should_not.equal?(h)
- send_copies = RUBY_ENGINE == "ruby" # inconsistent with Proc#call above for CRuby
- after_usage.equal?(marked).should == !send_copies
- Hash.ruby2_keywords_hash?(after_usage).should == !send_copies
- Hash.ruby2_keywords_hash?(marked).should == true
- end
+ args = mark(**h)
+ marked = args.last
+ after_usage = obj.proc_call(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
+
+ args = mark(**h)
+ marked = args.last
+ after_usage = obj.send(:splat, *args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
end
it "applies to the underlying method and applies across aliasing" do
@@ -275,7 +213,7 @@ describe "Module#ruby2_keywords" do
it "prints warning when a method accepts keywords" do
obj = Object.new
- def obj.foo(a:, b:) end
+ def obj.foo(*a, b:) end
-> {
obj.singleton_class.class_exec do
@@ -286,7 +224,7 @@ describe "Module#ruby2_keywords" do
it "prints warning when a method accepts keyword splat" do
obj = Object.new
- def obj.foo(**a) end
+ def obj.foo(*a, **b) end
-> {
obj.singleton_class.class_exec do
@@ -294,4 +232,17 @@ describe "Module#ruby2_keywords" do
end
}.should complain(/Skipping set of ruby2_keywords flag for/)
end
+
+ ruby_version_is "4.0" do
+ it "prints warning when a method accepts post arguments" do
+ obj = Object.new
+ def obj.foo(*a, b) end
+
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords :foo
+ end
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
+ end
end
diff --git a/spec/ruby/core/module/set_temporary_name_spec.rb b/spec/ruby/core/module/set_temporary_name_spec.rb
index f5886a3398..46605ed675 100644
--- a/spec/ruby/core/module/set_temporary_name_spec.rb
+++ b/spec/ruby/core/module/set_temporary_name_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/set_temporary_name'
ruby_version_is "3.3" do
describe "Module#set_temporary_name" do
@@ -13,13 +14,34 @@ ruby_version_is "3.3" do
m.name.should be_nil
end
+ it "returns self" do
+ m = Module.new
+ m.set_temporary_name("fake_name").should.equal? m
+ end
+
it "can assign a temporary name which is not a valid constant path" do
m = Module.new
- m.set_temporary_name("a::B")
- m.name.should == "a::B"
+
+ m.set_temporary_name("name")
+ m.name.should == "name"
m.set_temporary_name("Template['foo.rb']")
m.name.should == "Template['foo.rb']"
+
+ m.set_temporary_name("a::B")
+ m.name.should == "a::B"
+
+ m.set_temporary_name("A::b")
+ m.name.should == "A::b"
+
+ m.set_temporary_name("A::B::")
+ m.name.should == "A::B::"
+
+ m.set_temporary_name("A::::B")
+ m.name.should == "A::::B"
+
+ m.set_temporary_name("A=")
+ m.name.should == "A="
end
it "can't assign empty string as name" do
@@ -43,7 +65,7 @@ ruby_version_is "3.3" do
-> { Object.set_temporary_name("fake_name") }.should raise_error(RuntimeError, "can't change permanent name")
end
- it "can assign a temporary name to a nested module" do
+ it "can assign a temporary name to a module nested into an anonymous module" do
m = Module.new
module m::N; end
m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
@@ -55,6 +77,18 @@ ruby_version_is "3.3" do
m::N.name.should be_nil
end
+ it "discards a temporary name when an outer anonymous module gets a permanent name" do
+ m = Module.new
+ module m::N; end
+
+ m::N.set_temporary_name("fake_name")
+ m::N.name.should == "fake_name"
+
+ ModuleSpecs::SetTemporaryNameSpec::M = m
+ m::N.name.should == "ModuleSpecs::SetTemporaryNameSpec::M::N"
+ ModuleSpecs::SetTemporaryNameSpec.send :remove_const, :M
+ end
+
it "can update the name when assigned to a constant" do
m = Module.new
m::N = Module.new
@@ -64,5 +98,50 @@ ruby_version_is "3.3" do
m::M = m::N
m::M.name.should =~ /\A#<Module:0x\h+>::M\z/m
end
+
+ it "can reassign a temporary name repeatedly" do
+ m = Module.new
+
+ m.set_temporary_name("fake_name")
+ m.name.should == "fake_name"
+
+ m.set_temporary_name("fake_name_2")
+ m.name.should == "fake_name_2"
+ end
+
+ ruby_bug "#21094", ""..."4.0" do
+ it "also updates a name of a nested module" do
+ m = Module.new
+ m::N = Module.new
+ m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
+
+ m.set_temporary_name "m"
+ m::N.name.should == "m::N"
+
+ m.set_temporary_name nil
+ m::N.name.should == nil
+ end
+ end
+
+ it "keeps temporary name when assigned in an anonymous module" do
+ outer = Module.new
+ m = Module.new
+ m.set_temporary_name "m"
+ m.name.should == "m"
+ outer::M = m
+ m.name.should == "m"
+ m.inspect.should == "m"
+ end
+
+ it "keeps temporary name when assigned in an anonymous module and nested before" do
+ outer = Module.new
+ m = Module.new
+ outer::A = m
+ m.set_temporary_name "m"
+ m.name.should == "m"
+ outer::M = m
+ m.name.should == "m"
+ m.inspect.should == "m"
+ end
end
end
diff --git a/spec/ruby/core/module/to_s_spec.rb b/spec/ruby/core/module/to_s_spec.rb
index 6b1a615ef9..83c0ae0825 100644
--- a/spec/ruby/core/module/to_s_spec.rb
+++ b/spec/ruby/core/module/to_s_spec.rb
@@ -51,6 +51,8 @@ describe "Module#to_s" do
ModuleSpecs::RefinementInspect::R.name.should == 'ModuleSpecs::RefinementInspect::R'
ModuleSpecs::RefinementInspect::R.to_s.should == '#<refinement:String@ModuleSpecs::RefinementInspect>'
+ ensure
+ ModuleSpecs.send(:remove_const, :RefinementInspect)
end
it 'does not call #inspect or #to_s for singleton classes' do
diff --git a/spec/ruby/core/module/undefined_instance_methods_spec.rb b/spec/ruby/core/module/undefined_instance_methods_spec.rb
index 3be860d053..d33ee93fc1 100644
--- a/spec/ruby/core/module/undefined_instance_methods_spec.rb
+++ b/spec/ruby/core/module/undefined_instance_methods_spec.rb
@@ -2,25 +2,23 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Module#undefined_instance_methods" do
- ruby_version_is "3.2" do
- it "returns methods undefined in the class" do
- methods = ModuleSpecs::UndefinedInstanceMethods::Parent.undefined_instance_methods
- methods.should == [:undefed_method]
- end
+ it "returns methods undefined in the class" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Parent.undefined_instance_methods
+ methods.should == [:undefed_method]
+ end
- it "returns inherited methods undefined in the class" do
- methods = ModuleSpecs::UndefinedInstanceMethods::Child.undefined_instance_methods
- methods.should include(:parent_method, :another_parent_method)
- end
+ it "returns inherited methods undefined in the class" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Child.undefined_instance_methods
+ methods.should include(:parent_method, :another_parent_method)
+ end
- it "returns methods from an included module that are undefined in the class" do
- methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods
- methods.should include(:super_included_method)
- end
+ it "returns methods from an included module that are undefined in the class" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods
+ methods.should include(:super_included_method)
+ end
- it "does not returns ancestors undefined methods" do
- methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods
- methods.should_not include(:parent_method, :another_parent_method)
- end
+ it "does not returns ancestors undefined methods" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods
+ methods.should_not include(:parent_method, :another_parent_method)
end
end
diff --git a/spec/ruby/core/module/used_refinements_spec.rb b/spec/ruby/core/module/used_refinements_spec.rb
index c16cab0e3c..40dd4a444e 100644
--- a/spec/ruby/core/module/used_refinements_spec.rb
+++ b/spec/ruby/core/module/used_refinements_spec.rb
@@ -1,87 +1,85 @@
require_relative '../../spec_helper'
describe "Module.used_refinements" do
- ruby_version_is "3.2" do
- it "returns list of all refinements imported in the current scope" do
- refinement_int = nil
- refinement_str = nil
- ScratchPad.record []
-
- m1 = Module.new do
- refine Integer do
- refinement_int = self
- end
+ it "returns list of all refinements imported in the current scope" do
+ refinement_int = nil
+ refinement_str = nil
+ ScratchPad.record []
+
+ m1 = Module.new do
+ refine Integer do
+ refinement_int = self
end
+ end
- m2 = Module.new do
- refine String do
- refinement_str = self
- end
+ m2 = Module.new do
+ refine String do
+ refinement_str = self
end
+ end
- Module.new do
- using m1
- using m2
+ Module.new do
+ using m1
+ using m2
- Module.used_refinements.each { |r| ScratchPad << r }
- end
-
- ScratchPad.recorded.sort_by(&:object_id).should == [refinement_int, refinement_str].sort_by(&:object_id)
+ Module.used_refinements.each { |r| ScratchPad << r }
end
- it "returns empty array if does not have any refinements imported" do
- used_refinements = nil
+ ScratchPad.recorded.sort_by(&:object_id).should == [refinement_int, refinement_str].sort_by(&:object_id)
+ end
- Module.new do
- used_refinements = Module.used_refinements
- end
+ it "returns empty array if does not have any refinements imported" do
+ used_refinements = nil
- used_refinements.should == []
+ Module.new do
+ used_refinements = Module.used_refinements
end
- it "ignores refinements imported in a module that is included into the current one" do
- used_refinements = nil
+ used_refinements.should == []
+ end
- m1 = Module.new do
- refine Integer do
- nil
- end
- end
+ it "ignores refinements imported in a module that is included into the current one" do
+ used_refinements = nil
- m2 = Module.new do
- using m1
+ m1 = Module.new do
+ refine Integer do
+ nil
end
+ end
- Module.new do
- include m2
+ m2 = Module.new do
+ using m1
+ end
- used_refinements = Module.used_refinements
- end
+ Module.new do
+ include m2
- used_refinements.should == []
+ used_refinements = Module.used_refinements
end
- it "returns refinements even not defined directly in a module refinements are imported from" do
- used_refinements = nil
- ScratchPad.record []
+ used_refinements.should == []
+ end
- m1 = Module.new do
- refine Integer do
- ScratchPad << self
- end
- end
+ it "returns refinements even not defined directly in a module refinements are imported from" do
+ used_refinements = nil
+ ScratchPad.record []
- m2 = Module.new do
- include m1
+ m1 = Module.new do
+ refine Integer do
+ ScratchPad << self
end
+ end
- Module.new do
- using m2
+ m2 = Module.new do
+ include m1
+ end
- used_refinements = Module.used_refinements
- end
+ Module.new do
+ using m2
- used_refinements.should == ScratchPad.recorded
+ used_refinements = Module.used_refinements
end
+
+ used_refinements.should == ScratchPad.recorded
end
end
diff --git a/spec/ruby/core/numeric/shared/imag.rb b/spec/ruby/core/numeric/shared/imag.rb
index ac2da40a3b..4f117e243a 100644
--- a/spec/ruby/core/numeric/shared/imag.rb
+++ b/spec/ruby/core/numeric/shared/imag.rb
@@ -19,8 +19,8 @@ describe :numeric_imag, shared: true do
end
it "raises an ArgumentError if given any arguments" do
- @numbers.each do |number|
- -> { number.send(@method, number) }.should raise_error(ArgumentError)
- end
+ @numbers.each do |number|
+ -> { number.send(@method, number) }.should raise_error(ArgumentError)
+ end
end
end
diff --git a/spec/ruby/core/numeric/shared/rect.rb b/spec/ruby/core/numeric/shared/rect.rb
index 9cde19a398..120a69b1c4 100644
--- a/spec/ruby/core/numeric/shared/rect.rb
+++ b/spec/ruby/core/numeric/shared/rect.rb
@@ -25,24 +25,24 @@ describe :numeric_rect, shared: true do
end
it "returns self as the first element" do
- @numbers.each do |number|
- if Float === number and number.nan?
- number.send(@method).first.nan?.should be_true
- else
- number.send(@method).first.should == number
- end
- end
+ @numbers.each do |number|
+ if Float === number and number.nan?
+ number.send(@method).first.nan?.should be_true
+ else
+ number.send(@method).first.should == number
+ end
+ end
end
it "returns 0 as the last element" do
- @numbers.each do |number|
- number.send(@method).last.should == 0
- end
+ @numbers.each do |number|
+ number.send(@method).last.should == 0
+ end
end
it "raises an ArgumentError if given any arguments" do
- @numbers.each do |number|
- -> { number.send(@method, number) }.should raise_error(ArgumentError)
- end
+ @numbers.each do |number|
+ -> { number.send(@method, number) }.should raise_error(ArgumentError)
+ end
end
end
diff --git a/spec/ruby/core/objectspace/_id2ref_spec.rb b/spec/ruby/core/objectspace/_id2ref_spec.rb
index c088ae2743..1ae3230bdf 100644
--- a/spec/ruby/core/objectspace/_id2ref_spec.rb
+++ b/spec/ruby/core/objectspace/_id2ref_spec.rb
@@ -1,52 +1,65 @@
require_relative '../../spec_helper'
-describe "ObjectSpace._id2ref" do
- it "converts an object id to a reference to the object" do
- s = "I am a string"
- r = ObjectSpace._id2ref(s.object_id)
- r.should == s
+ruby_version_is "4.0" do
+ describe "ObjectSpace._id2ref" do
+ it "is deprecated" do
+ id = nil.object_id
+ -> {
+ ObjectSpace._id2ref(id)
+ }.should complain(/warning: ObjectSpace\._id2ref is deprecated/)
+ end
end
+end
- it "retrieves true by object_id" do
- ObjectSpace._id2ref(true.object_id).should == true
- end
+ruby_version_is ""..."4.0" do
+ describe "ObjectSpace._id2ref" do
+ it "converts an object id to a reference to the object" do
+ s = "I am a string"
+ r = ObjectSpace._id2ref(s.object_id)
+ r.should == s
+ end
- it "retrieves false by object_id" do
- ObjectSpace._id2ref(false.object_id).should == false
- end
+ it "retrieves true by object_id" do
+ ObjectSpace._id2ref(true.object_id).should == true
+ end
- it "retrieves nil by object_id" do
- ObjectSpace._id2ref(nil.object_id).should == nil
- end
+ it "retrieves false by object_id" do
+ ObjectSpace._id2ref(false.object_id).should == false
+ end
- it "retrieves a small Integer by object_id" do
- ObjectSpace._id2ref(1.object_id).should == 1
- ObjectSpace._id2ref((-42).object_id).should == -42
- end
+ it "retrieves nil by object_id" do
+ ObjectSpace._id2ref(nil.object_id).should == nil
+ end
- it "retrieves a large Integer by object_id" do
- obj = 1 << 88
- ObjectSpace._id2ref(obj.object_id).should.equal?(obj)
- end
+ it "retrieves a small Integer by object_id" do
+ ObjectSpace._id2ref(1.object_id).should == 1
+ ObjectSpace._id2ref((-42).object_id).should == -42
+ end
- it "retrieves a Symbol by object_id" do
- ObjectSpace._id2ref(:sym.object_id).should.equal?(:sym)
- end
+ it "retrieves a large Integer by object_id" do
+ obj = 1 << 88
+ ObjectSpace._id2ref(obj.object_id).should.equal?(obj)
+ end
- it "retrieves a String by object_id" do
- obj = "str"
- ObjectSpace._id2ref(obj.object_id).should.equal?(obj)
- end
+ it "retrieves a Symbol by object_id" do
+ ObjectSpace._id2ref(:sym.object_id).should.equal?(:sym)
+ end
- it "retrieves a frozen literal String by object_id" do
- ObjectSpace._id2ref("frozen string literal _id2ref".freeze.object_id).should.equal?("frozen string literal _id2ref".freeze)
- end
+ it "retrieves a String by object_id" do
+ obj = "str"
+ ObjectSpace._id2ref(obj.object_id).should.equal?(obj)
+ end
- it "retrieves an Encoding by object_id" do
- ObjectSpace._id2ref(Encoding::UTF_8.object_id).should.equal?(Encoding::UTF_8)
- end
+ it "retrieves a frozen literal String by object_id" do
+ ObjectSpace._id2ref("frozen string literal _id2ref".freeze.object_id).should.equal?("frozen string literal _id2ref".freeze)
+ end
+
+ it "retrieves an Encoding by object_id" do
+ ObjectSpace._id2ref(Encoding::UTF_8.object_id).should.equal?(Encoding::UTF_8)
+ end
- it 'raises RangeError when an object could not be found' do
- proc { ObjectSpace._id2ref(1 << 60) }.should raise_error(RangeError)
+ it 'raises RangeError when an object could not be found' do
+ proc { ObjectSpace._id2ref(1 << 60) }.should raise_error(RangeError)
+ end
end
end
diff --git a/spec/ruby/core/objectspace/define_finalizer_spec.rb b/spec/ruby/core/objectspace/define_finalizer_spec.rb
index 4d4cfa9270..0f4b54c345 100644
--- a/spec/ruby/core/objectspace/define_finalizer_spec.rb
+++ b/spec/ruby/core/objectspace/define_finalizer_spec.rb
@@ -156,7 +156,7 @@ describe "ObjectSpace.define_finalizer" do
end
it "allows multiple finalizers with different 'callables' to be defined" do
- code = <<-RUBY
+ code = <<-'RUBY'
obj = Object.new
ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized1\n" })
@@ -193,25 +193,23 @@ describe "ObjectSpace.define_finalizer" do
ret[1].should.equal?(p)
end
- ruby_version_is "3.1" do
- describe "when $VERBOSE is not nil" do
- it "warns if an exception is raised in finalizer" do
- code = <<-RUBY
- ObjectSpace.define_finalizer(Object.new) { raise "finalizing" }
- RUBY
+ describe "when $VERBOSE is not nil" do
+ it "warns if an exception is raised in finalizer" do
+ code = <<-RUBY
+ ObjectSpace.define_finalizer(Object.new) { raise "finalizing" }
+ RUBY
- ruby_exe(code, args: "2>&1").should include("warning: Exception in finalizer", "finalizing")
- end
+ ruby_exe(code, args: "2>&1").should include("warning: Exception in finalizer", "finalizing")
end
+ end
- describe "when $VERBOSE is nil" do
- it "does not warn even if an exception is raised in finalizer" do
- code = <<-RUBY
- ObjectSpace.define_finalizer(Object.new) { raise "finalizing" }
- RUBY
+ describe "when $VERBOSE is nil" do
+ it "does not warn even if an exception is raised in finalizer" do
+ code = <<-RUBY
+ ObjectSpace.define_finalizer(Object.new) { raise "finalizing" }
+ RUBY
- ruby_exe(code, args: "2>&1", options: "-W0").should == ""
- end
+ ruby_exe(code, args: "2>&1", options: "-W0").should == ""
end
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb b/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb
new file mode 100644
index 0000000000..8050e2c307
--- /dev/null
+++ b/spec/ruby/core/objectspace/weakkeymap/clear_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is '3.3' do
+ describe "ObjectSpace::WeakKeyMap#clear" do
+ it "removes all the entries" do
+ m = ObjectSpace::WeakKeyMap.new
+
+ key = Object.new
+ value = Object.new
+ m[key] = value
+
+ key2 = Object.new
+ value2 = Object.new
+ m[key2] = value2
+
+ m.clear
+
+ m.key?(key).should == false
+ m.key?(key2).should == false
+ end
+
+ it "returns self" do
+ m = ObjectSpace::WeakKeyMap.new
+ m.clear.should.equal?(m)
+ end
+ end
+end
diff --git a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
index 6e534b8ea8..3cd61355d6 100644
--- a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
@@ -33,8 +33,19 @@ ruby_version_is '3.3' do
end
it "returns nil if the key is not found when no block is given" do
- m = ObjectSpace::WeakMap.new
+ m = ObjectSpace::WeakKeyMap.new
m.delete(Object.new).should == nil
end
+
+ it "returns nil when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
+
+ map.delete(1).should == nil
+ map.delete(1.0).should == nil
+ map.delete(:a).should == nil
+ map.delete(true).should == nil
+ map.delete(false).should == nil
+ map.delete(nil).should == nil
+ end
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
index 862480cd02..51368e8d3b 100644
--- a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../../spec_helper'
+require_relative 'fixtures/classes'
ruby_version_is "3.3" do
describe "ObjectSpace::WeakKeyMap#[]" do
@@ -15,12 +16,92 @@ ruby_version_is "3.3" do
map[key2].should == ref2
end
- it "matches using equality semantics" do
+ it "compares keys with #eql? semantics" do
+ map = ObjectSpace::WeakKeyMap.new
+ key = [1.0]
+ map[key] = "x"
+ map[[1]].should == nil
+ map[[1.0]].should == "x"
+ key.should == [1.0] # keep the key alive until here to keep the map entry
+
+ map = ObjectSpace::WeakKeyMap.new
+ key = [1]
+ map[key] = "x"
+ map[[1.0]].should == nil
+ map[[1]].should == "x"
+ key.should == [1] # keep the key alive until here to keep the map entry
+
map = ObjectSpace::WeakKeyMap.new
key1, key2 = %w[a a].map(&:upcase)
ref = "x"
map[key1] = ref
map[key2].should == ref
end
+
+ it "compares key via #hash first" do
+ x = mock('0')
+ x.should_receive(:hash).and_return(0)
+
+ map = ObjectSpace::WeakKeyMap.new
+ key = 'foo'
+ map[key] = :bar
+ map[x].should == nil
+ end
+
+ it "does not compare keys with different #hash values via #eql?" do
+ x = mock('x')
+ x.should_not_receive(:eql?)
+ x.stub!(:hash).and_return(0)
+
+ y = mock('y')
+ y.should_not_receive(:eql?)
+ y.stub!(:hash).and_return(1)
+
+ map = ObjectSpace::WeakKeyMap.new
+ map[y] = 1
+ map[x].should == nil
+ end
+
+ it "compares keys with the same #hash value via #eql?" do
+ x = mock('x')
+ x.should_receive(:eql?).and_return(true)
+ x.stub!(:hash).and_return(42)
+
+ y = mock('y')
+ y.should_not_receive(:eql?)
+ y.stub!(:hash).and_return(42)
+
+ map = ObjectSpace::WeakKeyMap.new
+ map[y] = 1
+ map[x].should == 1
+ end
+
+ it "finds a value via an identical key even when its #eql? isn't reflexive" do
+ x = mock('x')
+ x.should_receive(:hash).at_least(1).and_return(42)
+ x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
+
+ map = ObjectSpace::WeakKeyMap.new
+ map[x] = :x
+ map[x].should == :x
+ end
+
+ it "supports keys with private #hash method" do
+ key = WeakKeyMapSpecs::KeyWithPrivateHash.new
+ map = ObjectSpace::WeakKeyMap.new
+ map[key] = 42
+ map[key].should == 42
+ end
+
+ it "returns nil and does not raise error when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
+
+ map[1].should == nil
+ map[1.0].should == nil
+ map[:a].should == nil
+ map[true].should == nil
+ map[false].should == nil
+ map[nil].should == nil
+ end
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
index c427e01ca5..8db8d780c7 100644
--- a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
@@ -8,10 +8,6 @@ ruby_version_is "3.3" do
map[key].should == value
end
- def should_not_accept(map, key, value)
- -> { map[key] = value }.should raise_error(ArgumentError)
- end
-
it "is correct" do
map = ObjectSpace::WeakKeyMap.new
key1, key2 = %w[a b].map(&:upcase)
@@ -40,32 +36,47 @@ ruby_version_is "3.3" do
should_accept(map, y, x)
end
- it "rejects symbols as keys" do
+ it "does not duplicate and freeze String keys (like Hash#[]= does)" do
map = ObjectSpace::WeakKeyMap.new
- should_not_accept(map, :foo, true)
- should_not_accept(map, rand.to_s.to_sym, true)
- end
+ key = +"a"
+ map[key] = 1
- it "rejects integers as keys" do
- map = ObjectSpace::WeakKeyMap.new
- should_not_accept(map, 42, true)
- should_not_accept(map, 2 ** 68, true)
- end
+ map.getkey("a").should.equal? key
+ map.getkey("a").should_not.frozen?
- it "rejects floats as keys" do
- map = ObjectSpace::WeakKeyMap.new
- should_not_accept(map, 4.2, true)
+ key.should == "a" # keep the key alive until here to keep the map entry
end
- it "rejects booleans as keys" do
- map = ObjectSpace::WeakKeyMap.new
- should_not_accept(map, true, true)
- should_not_accept(map, false, true)
- end
+ context "a key cannot be garbage collected" do
+ it "raises ArgumentError when Integer is used as a key" do
+ map = ObjectSpace::WeakKeyMap.new
+ -> { map[1] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
+ end
- it "rejects nil as keys" do
- map = ObjectSpace::WeakKeyMap.new
- should_not_accept(map, nil, true)
+ it "raises ArgumentError when Float is used as a key" do
+ map = ObjectSpace::WeakKeyMap.new
+ -> { map[1.0] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
+ end
+
+ it "raises ArgumentError when Symbol is used as a key" do
+ map = ObjectSpace::WeakKeyMap.new
+ -> { map[:a] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
+ end
+
+ it "raises ArgumentError when true is used as a key" do
+ map = ObjectSpace::WeakKeyMap.new
+ -> { map[true] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
+ end
+
+ it "raises ArgumentError when false is used as a key" do
+ map = ObjectSpace::WeakKeyMap.new
+ -> { map[false] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
+ end
+
+ it "raises ArgumentError when nil is used as a key" do
+ map = ObjectSpace::WeakKeyMap.new
+ -> { map[nil] = "x" }.should raise_error(ArgumentError, /WeakKeyMap (keys )?must be garbage collectable/)
+ end
end
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/fixtures/classes.rb b/spec/ruby/core/objectspace/weakkeymap/fixtures/classes.rb
new file mode 100644
index 0000000000..0fd04551b5
--- /dev/null
+++ b/spec/ruby/core/objectspace/weakkeymap/fixtures/classes.rb
@@ -0,0 +1,5 @@
+module WeakKeyMapSpecs
+ class KeyWithPrivateHash
+ private :hash
+ end
+end
diff --git a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
index 3af0186f27..8a2dbf809d 100644
--- a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
@@ -9,6 +9,20 @@ ruby_version_is "3.3" do
map[key1] = true
map.getkey(key2).should equal(key1)
map.getkey("X").should == nil
+
+ key1.should == "A" # keep the key alive until here to keep the map entry
+ key2.should == "A" # keep the key alive until here to keep the map entry
+ end
+
+ it "returns nil when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
+
+ map.getkey(1).should == nil
+ map.getkey(1.0).should == nil
+ map.getkey(:a).should == nil
+ map.getkey(true).should == nil
+ map.getkey(false).should == nil
+ map.getkey(nil).should == nil
end
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
index 557fbc8733..319f050970 100644
--- a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
@@ -12,6 +12,10 @@ ruby_version_is "3.3" do
map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
map[key3] = 3
map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
+
+ key1.should == "foo" # keep the key alive until here to keep the map entry
+ key2.should == "bar" # keep the key alive until here to keep the map entry
+ key3.should == "bar" # keep the key alive until here to keep the map entry
end
end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
index 2af9c2b8e7..a9a2e12432 100644
--- a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
+++ b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
@@ -29,5 +29,16 @@ ruby_version_is "3.3" do
map[key] = nil
map.key?(key).should == true
end
+
+ it "returns false when a key cannot be garbage collected" do
+ map = ObjectSpace::WeakKeyMap.new
+
+ map.key?(1).should == false
+ map.key?(1.0).should == false
+ map.key?(:a).should == false
+ map.key?(true).should == false
+ map.key?(false).should == false
+ map.key?(nil).should == false
+ end
end
end
diff --git a/spec/ruby/core/proc/clone_spec.rb b/spec/ruby/core/proc/clone_spec.rb
index 7eca9c561e..730dc421a8 100644
--- a/spec/ruby/core/proc/clone_spec.rb
+++ b/spec/ruby/core/proc/clone_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/common'
require_relative 'shared/dup'
describe "Proc#clone" do
@@ -12,4 +13,18 @@ describe "Proc#clone" do
proc.clone.frozen?.should == true
end
end
+
+ ruby_version_is "3.3" do
+ it "calls #initialize_clone on subclass" do
+ obj = ProcSpecs::MyProc2.new(:a, 2) { }
+ dup = obj.clone
+
+ dup.should_not equal(obj)
+ dup.class.should == ProcSpecs::MyProc2
+
+ dup.first.should == :a
+ dup.second.should == 2
+ dup.initializer.should == :clone
+ end
+ end
end
diff --git a/spec/ruby/core/proc/dup_spec.rb b/spec/ruby/core/proc/dup_spec.rb
index dd19b3c1e9..716357d1f0 100644
--- a/spec/ruby/core/proc/dup_spec.rb
+++ b/spec/ruby/core/proc/dup_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/common'
require_relative 'shared/dup'
describe "Proc#dup" do
@@ -10,4 +11,18 @@ describe "Proc#dup" do
proc.frozen?.should == true
proc.dup.frozen?.should == false
end
+
+ ruby_version_is "3.3" do
+ it "calls #initialize_dup on subclass" do
+ obj = ProcSpecs::MyProc2.new(:a, 2) { }
+ dup = obj.dup
+
+ dup.should_not equal(obj)
+ dup.class.should == ProcSpecs::MyProc2
+
+ dup.first.should == :a
+ dup.second.should == 2
+ dup.initializer.should == :dup
+ end
+ end
end
diff --git a/spec/ruby/core/proc/element_reference_spec.rb b/spec/ruby/core/proc/element_reference_spec.rb
index 9077e44c34..81ceb91af5 100644
--- a/spec/ruby/core/proc/element_reference_spec.rb
+++ b/spec/ruby/core/proc/element_reference_spec.rb
@@ -17,7 +17,7 @@ describe "Proc#call on a Proc created with Kernel#lambda or Kernel#proc" do
it_behaves_like :proc_call_on_proc_or_lambda, :call
end
-describe "Proc#[] with frozen_string_literals" do
+describe "Proc#[] with frozen_string_literal: true/false" do
it "doesn't duplicate frozen strings" do
ProcArefSpecs.aref.frozen?.should be_false
ProcArefSpecs.aref_freeze.frozen?.should be_true
diff --git a/spec/ruby/core/proc/fixtures/common.rb b/spec/ruby/core/proc/fixtures/common.rb
index 6e27a2dee7..dfe67d7ba8 100644
--- a/spec/ruby/core/proc/fixtures/common.rb
+++ b/spec/ruby/core/proc/fixtures/common.rb
@@ -32,7 +32,28 @@ module ProcSpecs
@second = b
end
- attr_reader :first, :second
+ attr_reader :first, :second, :initializer
+
+ def initialize_copy(other)
+ super
+ @initializer = :copy
+ @first = other.first
+ @second = other.second
+ end
+
+ def initialize_dup(other)
+ super
+ @initializer = :dup
+ @first = other.first
+ @second = other.second
+ end
+
+ def initialize_clone(other, **options)
+ super
+ @initializer = :clone
+ @first = other.first
+ @second = other.second
+ end
end
class Arity
diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb
index 972596d2ea..cf8a8f5b12 100644
--- a/spec/ruby/core/proc/parameters_spec.rb
+++ b/spec/ruby/core/proc/parameters_spec.rb
@@ -20,29 +20,27 @@ describe "Proc#parameters" do
proc {|x| }.parameters.first.first.should == :opt
end
- ruby_version_is "3.2" do
- it "sets the first element of each sub-Array to :req for required argument if lambda keyword used" do
- proc {|x| }.parameters(lambda: true).first.first.should == :req
- proc {|y,*x| }.parameters(lambda: true).first.first.should == :req
- end
+ it "sets the first element of each sub-Array to :req for required argument if lambda keyword used" do
+ proc {|x| }.parameters(lambda: true).first.first.should == :req
+ proc {|y,*x| }.parameters(lambda: true).first.first.should == :req
+ end
- it "regards named parameters in procs as required if lambda keyword used" do
- proc {|x| }.parameters(lambda: true).first.first.should == :req
- end
+ it "regards named parameters in procs as required if lambda keyword used" do
+ proc {|x| }.parameters(lambda: true).first.first.should == :req
+ end
- it "regards named parameters in lambda as optional if lambda: false keyword used" do
- -> x { }.parameters(lambda: false).first.first.should == :opt
- end
+ it "regards named parameters in lambda as optional if lambda: false keyword used" do
+ -> x { }.parameters(lambda: false).first.first.should == :opt
+ end
- it "regards named parameters in procs and lambdas as required if lambda keyword is truthy" do
- proc {|x| }.parameters(lambda: 123).first.first.should == :req
- -> x { }.parameters(lambda: 123).first.first.should == :req
- end
+ it "regards named parameters in procs and lambdas as required if lambda keyword is truthy" do
+ proc {|x| }.parameters(lambda: 123).first.first.should == :req
+ -> x { }.parameters(lambda: 123).first.first.should == :req
+ end
- it "ignores the lambda keyword if it is nil" do
- proc {|x|}.parameters(lambda: nil).first.first.should == :opt
- -> x { }.parameters(lambda: nil).first.first.should == :req
- end
+ it "ignores the lambda keyword if it is nil" do
+ proc {|x|}.parameters(lambda: nil).first.first.should == :opt
+ -> x { }.parameters(lambda: nil).first.first.should == :req
end
it "regards optional keyword parameters in procs as optional" do
@@ -64,7 +62,7 @@ describe "Proc#parameters" do
end
it "regards keyword parameters in lambdas as required" do
- eval("lambda {|x:| }").parameters.first.first.should == :keyreq
+ -> x: { }.parameters.first.first.should == :keyreq
end
it "sets the first element of each sub-Array to :rest for parameters prefixed with asterisks" do
@@ -110,30 +108,16 @@ describe "Proc#parameters" do
-> x { }.parameters.should == [[:req, :x]]
end
- ruby_version_is '3.2' do
- it "adds rest arg with name * for \"star\" argument" do
- -> * {}.parameters.should == [[:rest, :*]]
- end
-
- it "adds keyrest arg with ** as a name for \"double star\" argument" do
- -> ** {}.parameters.should == [[:keyrest, :**]]
- end
+ it "adds rest arg with name * for \"star\" argument" do
+ -> * {}.parameters.should == [[:rest, :*]]
end
- ruby_version_is ''...'3.2' do
- it "adds nameless rest arg for \"star\" argument" do
- -> * {}.parameters.should == [[:rest]]
- end
-
- it "adds nameless keyrest arg for \"double star\" argument" do
- -> ** {}.parameters.should == [[:keyrest]]
- end
+ it "adds keyrest arg with ** as a name for \"double star\" argument" do
+ -> ** {}.parameters.should == [[:keyrest, :**]]
end
- ruby_version_is '3.1' do
- it "adds block arg with name & for anonymous block argument" do
- eval('-> & {}.parameters').should == [[:block, :&]]
- end
+ it "adds block arg with name & for anonymous block argument" do
+ -> & {}.parameters.should == [[:block, :&]]
end
it "does not add locals as block options with a block and splat" do
@@ -174,4 +158,18 @@ describe "Proc#parameters" do
it "returns :nokey for **nil parameter" do
proc { |**nil| }.parameters.should == [[:nokey]]
end
+
+ ruby_version_is "3.4"..."4.0" do
+ it "handles the usage of `it` as a parameter" do
+ eval("proc { it }").parameters.should == [[:opt, nil]]
+ eval("lambda { it }").parameters.should == [[:req]]
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "handles the usage of `it` as a parameter" do
+ eval("proc { it }").parameters.should == [[:opt]]
+ eval("lambda { it }").parameters.should == [[:req]]
+ end
+ end
end
diff --git a/spec/ruby/core/proc/ruby2_keywords_spec.rb b/spec/ruby/core/proc/ruby2_keywords_spec.rb
index ab67302231..d7f8f592e1 100644
--- a/spec/ruby/core/proc/ruby2_keywords_spec.rb
+++ b/spec/ruby/core/proc/ruby2_keywords_spec.rb
@@ -39,7 +39,7 @@ describe "Proc#ruby2_keywords" do
end
it "prints warning when a proc accepts keywords" do
- f = -> a:, b: { }
+ f = -> *a, b: { }
-> {
f.ruby2_keywords
@@ -47,10 +47,20 @@ describe "Proc#ruby2_keywords" do
end
it "prints warning when a proc accepts keyword splat" do
- f = -> **a { }
+ f = -> *a, **b { }
-> {
f.ruby2_keywords
}.should complain(/Skipping set of ruby2_keywords flag for/)
end
+
+ ruby_version_is "4.0" do
+ it "prints warning when a proc accepts post arguments" do
+ f = -> *a, b { }
+
+ -> {
+ f.ruby2_keywords
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
+ end
end
diff --git a/spec/ruby/core/proc/shared/dup.rb b/spec/ruby/core/proc/shared/dup.rb
index c419a4078a..1266337f94 100644
--- a/spec/ruby/core/proc/shared/dup.rb
+++ b/spec/ruby/core/proc/shared/dup.rb
@@ -8,12 +8,10 @@ describe :proc_dup, shared: true do
a.call.should == b.call
end
- ruby_version_is "3.2" do
- it "returns an instance of subclass" do
- cl = Class.new(Proc)
+ it "returns an instance of subclass" do
+ cl = Class.new(Proc)
- cl.new{}.send(@method).class.should == cl
- end
+ cl.new{}.send(@method).class.should == cl
end
ruby_version_is "3.4" do
@@ -25,7 +23,7 @@ describe :proc_dup, shared: true do
end
it "copies the finalizer" do
- code = <<-RUBY
+ code = <<-'RUBY'
obj = Proc.new { }
ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" })
diff --git a/spec/ruby/core/proc/source_location_spec.rb b/spec/ruby/core/proc/source_location_spec.rb
index a8b99287d5..fd33f21a26 100644
--- a/spec/ruby/core/proc/source_location_spec.rb
+++ b/spec/ruby/core/proc/source_location_spec.rb
@@ -17,57 +17,64 @@ describe "Proc#source_location" do
end
it "sets the first value to the path of the file in which the proc was defined" do
- file = @proc.source_location.first
+ file = @proc.source_location[0]
file.should be_an_instance_of(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)
- file = @proc_new.source_location.first
+ file = @proc_new.source_location[0]
file.should be_an_instance_of(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)
- file = @lambda.source_location.first
+ file = @lambda.source_location[0]
file.should be_an_instance_of(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)
- file = @method.source_location.first
+ file = @method.source_location[0]
file.should be_an_instance_of(String)
file.should == File.realpath('fixtures/source_location.rb', __dir__)
end
- it "sets the last value to an Integer representing the line on which the proc was defined" do
- line = @proc.source_location.last
+ it "sets the second value to an Integer representing the line on which the proc was defined" do
+ line = @proc.source_location[1]
line.should be_an_instance_of(Integer)
line.should == 4
- line = @proc_new.source_location.last
+ line = @proc_new.source_location[1]
line.should be_an_instance_of(Integer)
line.should == 12
- line = @lambda.source_location.last
+ line = @lambda.source_location[1]
line.should be_an_instance_of(Integer)
line.should == 8
- line = @method.source_location.last
+ line = @method.source_location[1]
line.should be_an_instance_of(Integer)
line.should == 15
end
it "works even if the proc was created on the same line" do
- proc { true }.source_location.should == [__FILE__, __LINE__]
- Proc.new { true }.source_location.should == [__FILE__, __LINE__]
- -> { true }.source_location.should == [__FILE__, __LINE__]
+ ruby_version_is(""..."4.1") do
+ proc { true }.source_location.should == [__FILE__, __LINE__]
+ Proc.new { true }.source_location.should == [__FILE__, __LINE__]
+ -> { true }.source_location.should == [__FILE__, __LINE__]
+ end
+ ruby_version_is("4.1") do
+ proc { true }.source_location.should == [__FILE__, __LINE__, 11, __LINE__, 19]
+ Proc.new { true }.source_location.should == [__FILE__, __LINE__, 15, __LINE__, 23]
+ -> { true }.source_location.should == [__FILE__, __LINE__, 6, __LINE__, 17]
+ end
end
it "returns the first line of a multi-line proc (i.e. the line containing 'proc do')" do
- ProcSpecs::SourceLocation.my_multiline_proc.source_location.last.should == 20
- ProcSpecs::SourceLocation.my_multiline_proc_new.source_location.last.should == 34
- ProcSpecs::SourceLocation.my_multiline_lambda.source_location.last.should == 27
+ ProcSpecs::SourceLocation.my_multiline_proc.source_location[1].should == 20
+ ProcSpecs::SourceLocation.my_multiline_proc_new.source_location[1].should == 34
+ ProcSpecs::SourceLocation.my_multiline_lambda.source_location[1].should == 27
end
it "returns the location of the proc's body; not necessarily the proc itself" do
- ProcSpecs::SourceLocation.my_detached_proc.source_location.last.should == 41
- ProcSpecs::SourceLocation.my_detached_proc_new.source_location.last.should == 51
- ProcSpecs::SourceLocation.my_detached_lambda.source_location.last.should == 46
+ ProcSpecs::SourceLocation.my_detached_proc.source_location[1].should == 41
+ ProcSpecs::SourceLocation.my_detached_proc_new.source_location[1].should == 51
+ ProcSpecs::SourceLocation.my_detached_lambda.source_location[1].should == 46
end
it "returns the same value for a proc-ified method as the method reports" do
@@ -86,6 +93,12 @@ describe "Proc#source_location" do
it "works for eval with a given line" do
proc = eval('-> {}', nil, "foo", 100)
- proc.source_location.should == ["foo", 100]
+ location = proc.source_location
+ ruby_version_is(""..."4.1") do
+ location.should == ["foo", 100]
+ end
+ ruby_version_is("4.1") do
+ location.should == ["foo", 100, 0, 100, 5]
+ end
end
end
diff --git a/spec/ruby/core/process/_fork_spec.rb b/spec/ruby/core/process/_fork_spec.rb
index 6f711ad2dd..e1f45e2656 100644
--- a/spec/ruby/core/process/_fork_spec.rb
+++ b/spec/ruby/core/process/_fork_spec.rb
@@ -1,24 +1,24 @@
require_relative '../../spec_helper'
-ruby_version_is "3.1" do
- describe "Process._fork" do
- it "for #respond_to? returns the same as Process.respond_to?(:fork)" do
- Process.respond_to?(:_fork).should == Process.respond_to?(:fork)
- end
+describe "Process._fork" do
+ it "for #respond_to? returns the same as Process.respond_to?(:fork)" do
+ Process.respond_to?(:_fork).should == Process.respond_to?(:fork)
+ end
- guard_not -> { Process.respond_to?(:fork) } do
- it "raises a NotImplementedError when called" do
- -> { Process._fork }.should raise_error(NotImplementedError)
- end
+ # Using respond_to? in a guard here is OK because the correct semantics
+ # are that _fork is implemented if and only if fork is (see above).
+ guard_not -> { Process.respond_to?(:fork) } do
+ it "raises a NotImplementedError when called" do
+ -> { Process._fork }.should raise_error(NotImplementedError)
end
+ end
- guard -> { Process.respond_to?(:fork) } do
- it "is called by Process#fork" do
- Process.should_receive(:_fork).once.and_return(42)
+ guard -> { Process.respond_to?(:fork) } do
+ it "is called by Process#fork" do
+ Process.should_receive(:_fork).once.and_return(42)
- pid = Process.fork {}
- pid.should equal(42)
- end
+ pid = Process.fork {}
+ pid.should equal(42)
end
end
end
diff --git a/spec/ruby/core/process/fixtures/clocks.rb b/spec/ruby/core/process/fixtures/clocks.rb
index f043f6ac1f..5757e280be 100644
--- a/spec/ruby/core/process/fixtures/clocks.rb
+++ b/spec/ruby/core/process/fixtures/clocks.rb
@@ -2,7 +2,7 @@ module ProcessSpecs
def self.clock_constants
clocks = []
- platform_is_not :windows, :solaris do
+ platform_is_not :windows do
clocks += Process.constants.select { |c| c.to_s.start_with?('CLOCK_') }
# These require CAP_WAKE_ALARM and are not documented in
diff --git a/spec/ruby/core/process/gid_spec.rb b/spec/ruby/core/process/gid_spec.rb
index 07221da420..ca935ed520 100644
--- a/spec/ruby/core/process/gid_spec.rb
+++ b/spec/ruby/core/process/gid_spec.rb
@@ -3,8 +3,8 @@ require_relative '../../spec_helper'
describe "Process.gid" do
platform_is_not :windows do
it "returns the correct gid for the user executing this process" do
- current_gid_according_to_unix = `id -gr`.to_i
- Process.gid.should == current_gid_according_to_unix
+ current_gid_according_to_unix = `id -gr`.to_i
+ Process.gid.should == current_gid_according_to_unix
end
end
diff --git a/spec/ruby/core/process/setrlimit_spec.rb b/spec/ruby/core/process/setrlimit_spec.rb
index b92f98fd40..ba8d1e04ca 100644
--- a/spec/ruby/core/process/setrlimit_spec.rb
+++ b/spec/ruby/core/process/setrlimit_spec.rb
@@ -73,20 +73,18 @@ describe "Process.setrlimit" do
Process.setrlimit(:STACK, *Process.getrlimit(Process::RLIMIT_STACK)).should be_nil
end
- platform_is_not :solaris, :aix do
+ platform_is_not :aix do
it "coerces :MEMLOCK into RLIMIT_MEMLOCK" do
Process.setrlimit(:MEMLOCK, *Process.getrlimit(Process::RLIMIT_MEMLOCK)).should be_nil
end
end
- platform_is_not :solaris do
- it "coerces :NPROC into RLIMIT_NPROC" do
- Process.setrlimit(:NPROC, *Process.getrlimit(Process::RLIMIT_NPROC)).should be_nil
- end
+ it "coerces :NPROC into RLIMIT_NPROC" do
+ Process.setrlimit(:NPROC, *Process.getrlimit(Process::RLIMIT_NPROC)).should be_nil
+ end
- it "coerces :RSS into RLIMIT_RSS" do
- Process.setrlimit(:RSS, *Process.getrlimit(Process::RLIMIT_RSS)).should be_nil
- end
+ it "coerces :RSS into RLIMIT_RSS" do
+ Process.setrlimit(:RSS, *Process.getrlimit(Process::RLIMIT_RSS)).should be_nil
end
platform_is :netbsd, :freebsd do
@@ -155,20 +153,18 @@ describe "Process.setrlimit" do
Process.setrlimit("STACK", *Process.getrlimit(Process::RLIMIT_STACK)).should be_nil
end
- platform_is_not :solaris, :aix do
+ platform_is_not :aix do
it "coerces 'MEMLOCK' into RLIMIT_MEMLOCK" do
Process.setrlimit("MEMLOCK", *Process.getrlimit(Process::RLIMIT_MEMLOCK)).should be_nil
end
end
- platform_is_not :solaris do
- it "coerces 'NPROC' into RLIMIT_NPROC" do
- Process.setrlimit("NPROC", *Process.getrlimit(Process::RLIMIT_NPROC)).should be_nil
- end
+ it "coerces 'NPROC' into RLIMIT_NPROC" do
+ Process.setrlimit("NPROC", *Process.getrlimit(Process::RLIMIT_NPROC)).should be_nil
+ end
- it "coerces 'RSS' into RLIMIT_RSS" do
- Process.setrlimit("RSS", *Process.getrlimit(Process::RLIMIT_RSS)).should be_nil
- end
+ it "coerces 'RSS' into RLIMIT_RSS" do
+ Process.setrlimit("RSS", *Process.getrlimit(Process::RLIMIT_RSS)).should be_nil
end
platform_is :netbsd, :freebsd do
diff --git a/spec/ruby/core/process/status/bit_and_spec.rb b/spec/ruby/core/process/status/bit_and_spec.rb
index f4a4328907..a805364629 100644
--- a/spec/ruby/core/process/status/bit_and_spec.rb
+++ b/spec/ruby/core/process/status/bit_and_spec.rb
@@ -1,35 +1,38 @@
require_relative '../../../spec_helper'
-describe "Process::Status#&" do
- it "returns a bitwise and of the integer status of an exited child" do
- suppress_warning do
- ruby_exe("exit(29)", exit_status: 29)
- ($? & 0).should == 0
- ($? & $?.to_i).should == $?.to_i
+ruby_version_is ""..."4.0" do
- # Actual value is implementation specific
- platform_is :linux do
- # 29 == 0b11101
- ($? & 0b1011100000000).should == 0b1010100000000
+ describe "Process::Status#&" do
+ it "returns a bitwise and of the integer status of an exited child" do
+ suppress_warning do
+ ruby_exe("exit(29)", exit_status: 29)
+ ($? & 0).should == 0
+ ($? & $?.to_i).should == $?.to_i
+
+ # Actual value is implementation specific
+ platform_is :linux do
+ # 29 == 0b11101
+ ($? & 0b1011100000000).should == 0b1010100000000
+ end
end
end
- end
- ruby_version_is "3.3" do
- it "raises an ArgumentError if mask is negative" do
- suppress_warning do
+ ruby_version_is "3.3"..."4.0" do
+ it "raises an ArgumentError if mask is negative" do
+ suppress_warning do
+ ruby_exe("exit(0)")
+ -> {
+ $? & -1
+ }.should raise_error(ArgumentError, 'negative mask value: -1')
+ end
+ end
+
+ it "shows a deprecation warning" do
ruby_exe("exit(0)")
-> {
- $? & -1
- }.should raise_error(ArgumentError, 'negative mask value: -1')
+ $? & 0
+ }.should complain(/warning: Process::Status#& is deprecated and will be removed .*use other Process::Status predicates instead/)
end
end
-
- it "shows a deprecation warning" do
- ruby_exe("exit(0)")
- -> {
- $? & 0
- }.should complain(/warning: Process::Status#& is deprecated and will be removed .*use other Process::Status predicates instead/)
- end
end
end
diff --git a/spec/ruby/core/process/status/right_shift_spec.rb b/spec/ruby/core/process/status/right_shift_spec.rb
index 034ce348cb..355aaf4c95 100644
--- a/spec/ruby/core/process/status/right_shift_spec.rb
+++ b/spec/ruby/core/process/status/right_shift_spec.rb
@@ -1,34 +1,37 @@
require_relative '../../../spec_helper'
-describe "Process::Status#>>" do
- it "returns a right shift of the integer status of an exited child" do
- suppress_warning do
- ruby_exe("exit(29)", exit_status: 29)
- ($? >> 0).should == $?.to_i
- ($? >> 1).should == $?.to_i >> 1
+ruby_version_is ""..."4.0" do
- # Actual value is implementation specific
- platform_is :linux do
- ($? >> 8).should == 29
+ describe "Process::Status#>>" do
+ it "returns a right shift of the integer status of an exited child" do
+ suppress_warning do
+ ruby_exe("exit(29)", exit_status: 29)
+ ($? >> 0).should == $?.to_i
+ ($? >> 1).should == $?.to_i >> 1
+
+ # Actual value is implementation specific
+ platform_is :linux do
+ ($? >> 8).should == 29
+ end
end
end
- end
- ruby_version_is "3.3" do
- it "raises an ArgumentError if shift value is negative" do
- suppress_warning do
+ ruby_version_is "3.3"..."4.0" do
+ it "raises an ArgumentError if shift value is negative" do
+ suppress_warning do
+ ruby_exe("exit(0)")
+ -> {
+ $? >> -1
+ }.should raise_error(ArgumentError, 'negative shift value: -1')
+ end
+ end
+
+ it "shows a deprecation warning" do
ruby_exe("exit(0)")
-> {
- $? >> -1
- }.should raise_error(ArgumentError, 'negative shift value: -1')
+ $? >> 0
+ }.should complain(/warning: Process::Status#>> is deprecated and will be removed .*use other Process::Status attributes instead/)
end
end
-
- it "shows a deprecation warning" do
- ruby_exe("exit(0)")
- -> {
- $? >> 0
- }.should complain(/warning: Process::Status#>> is deprecated and will be removed .*use other Process::Status attributes instead/)
- end
end
end
diff --git a/spec/ruby/core/process/tms/cstime_spec.rb b/spec/ruby/core/process/tms/cstime_spec.rb
new file mode 100644
index 0000000000..9c2d9e8632
--- /dev/null
+++ b/spec/ruby/core/process/tms/cstime_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+
+describe "Process::Tms#cstime" do
+ it "returns cstime attribute" do
+ cstime = Object.new
+ Process::Tms.new(nil, nil, nil, cstime).cstime.should == cstime
+ end
+end
+
+describe "Process::Tms#cstime=" do
+ it "assigns a value to the cstime attribute" do
+ cstime = Object.new
+ tms = Process::Tms.new
+ tms.cstime = cstime
+ tms.cstime.should == cstime
+ end
+end
diff --git a/spec/ruby/core/process/tms/cutime_spec.rb b/spec/ruby/core/process/tms/cutime_spec.rb
new file mode 100644
index 0000000000..0ac3ff1964
--- /dev/null
+++ b/spec/ruby/core/process/tms/cutime_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+
+describe "Process::Tms#cutime" do
+ it "returns cutime attribute" do
+ cutime = Object.new
+ Process::Tms.new(nil, nil, cutime, nil).cutime.should == cutime
+ end
+end
+
+describe "Process::Tms#cutime=" do
+ it "assigns a value to the cutime attribute" do
+ cutime = Object.new
+ tms = Process::Tms.new
+ tms.cutime = cutime
+ tms.cutime.should == cutime
+ end
+end
diff --git a/spec/ruby/core/process/tms/stime_spec.rb b/spec/ruby/core/process/tms/stime_spec.rb
new file mode 100644
index 0000000000..1e8371475f
--- /dev/null
+++ b/spec/ruby/core/process/tms/stime_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+
+describe "Process::Tms#stime" do
+ it "returns stime attribute" do
+ stime = Object.new
+ Process::Tms.new(nil, stime, nil, nil).stime.should == stime
+ end
+end
+
+describe "Process::Tms#stime=" do
+ it "assigns a value to the stime attribute" do
+ stime = Object.new
+ tms = Process::Tms.new
+ tms.stime = stime
+ tms.stime.should == stime
+ end
+end
diff --git a/spec/ruby/core/process/tms/utime_spec.rb b/spec/ruby/core/process/tms/utime_spec.rb
new file mode 100644
index 0000000000..403a31e2e6
--- /dev/null
+++ b/spec/ruby/core/process/tms/utime_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+
+describe "Process::Tms#utime" do
+ it "returns utime attribute" do
+ utime = Object.new
+ Process::Tms.new(utime, nil, nil, nil).utime.should == utime
+ end
+end
+
+describe "Process::Tms#utime=" do
+ it "assigns a value to the ctime attribute" do
+ utime = Object.new
+ tms = Process::Tms.new
+ tms.utime = utime
+ tms.utime.should == utime
+ end
+end
diff --git a/spec/ruby/core/queue/deq_spec.rb b/spec/ruby/core/queue/deq_spec.rb
index f84d4220ea..a2784e6a63 100644
--- a/spec/ruby/core/queue/deq_spec.rb
+++ b/spec/ruby/core/queue/deq_spec.rb
@@ -7,7 +7,5 @@ describe "Queue#deq" do
end
describe "Queue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.deq(timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.deq(timeout: v) }
end
diff --git a/spec/ruby/core/queue/initialize_spec.rb b/spec/ruby/core/queue/initialize_spec.rb
index c6c1ae63c5..592fbe2487 100644
--- a/spec/ruby/core/queue/initialize_spec.rb
+++ b/spec/ruby/core/queue/initialize_spec.rb
@@ -11,9 +11,21 @@ describe "Queue#initialize" do
Queue.private_instance_methods.include?(:initialize).should == true
end
- ruby_version_is '3.1' do
- it "adds all elements of the passed Enumerable to self" do
- q = Queue.new([1, 2, 3])
+ it "adds all elements of the passed Enumerable to self" do
+ q = Queue.new([1, 2, 3])
+ q.size.should == 3
+ q.should_not.empty?
+ q.pop.should == 1
+ q.pop.should == 2
+ q.pop.should == 3
+ q.should.empty?
+ end
+
+ describe "converts the given argument to an Array using #to_a" do
+ it "uses #to_a on the provided Enumerable" do
+ enumerable = MockObject.new('mock-enumerable')
+ enumerable.should_receive(:to_a).and_return([1, 2, 3])
+ q = Queue.new(enumerable)
q.size.should == 3
q.should_not.empty?
q.pop.should == 1
@@ -22,41 +34,27 @@ describe "Queue#initialize" do
q.should.empty?
end
- describe "converts the given argument to an Array using #to_a" do
- it "uses #to_a on the provided Enumerable" do
- enumerable = MockObject.new('mock-enumerable')
- enumerable.should_receive(:to_a).and_return([1, 2, 3])
- q = Queue.new(enumerable)
- q.size.should == 3
- q.should_not.empty?
- q.pop.should == 1
- q.pop.should == 2
- q.pop.should == 3
- q.should.empty?
- end
-
- it "raises a TypeError if the given argument can't be converted to an Array" do
- -> { Queue.new(42) }.should raise_error(TypeError)
- -> { Queue.new(:abc) }.should raise_error(TypeError)
- end
-
- it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do
- enumerable = MockObject.new('mock-enumerable')
- enumerable.should_receive(:to_a).and_raise(NoMethodError)
- -> { Queue.new(enumerable) }.should raise_error(NoMethodError)
- end
+ it "raises a TypeError if the given argument can't be converted to an Array" do
+ -> { Queue.new(42) }.should raise_error(TypeError)
+ -> { Queue.new(:abc) }.should raise_error(TypeError)
end
- it "raises TypeError if the provided Enumerable does not respond to #to_a" do
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do
enumerable = MockObject.new('mock-enumerable')
- -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject into Array")
+ enumerable.should_receive(:to_a).and_raise(NoMethodError)
+ -> { Queue.new(enumerable) }.should raise_error(NoMethodError)
end
+ end
- it "raises TypeError if #to_a does not return Array" do
- enumerable = MockObject.new('mock-enumerable')
- enumerable.should_receive(:to_a).and_return("string")
+ it "raises TypeError if the provided Enumerable does not respond to #to_a" do
+ enumerable = MockObject.new('mock-enumerable')
+ -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject into Array")
+ end
- -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_a gives String)")
- end
+ it "raises TypeError if #to_a does not return Array" do
+ enumerable = MockObject.new('mock-enumerable')
+ enumerable.should_receive(:to_a).and_return("string")
+
+ -> { Queue.new(enumerable) }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_a gives String)")
end
end
diff --git a/spec/ruby/core/queue/pop_spec.rb b/spec/ruby/core/queue/pop_spec.rb
index d344740834..3dff7db242 100644
--- a/spec/ruby/core/queue/pop_spec.rb
+++ b/spec/ruby/core/queue/pop_spec.rb
@@ -7,7 +7,5 @@ describe "Queue#pop" do
end
describe "Queue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.pop(timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.pop(timeout: v) }
end
diff --git a/spec/ruby/core/queue/shift_spec.rb b/spec/ruby/core/queue/shift_spec.rb
index 64165e0b61..c105da74b2 100644
--- a/spec/ruby/core/queue/shift_spec.rb
+++ b/spec/ruby/core/queue/shift_spec.rb
@@ -7,7 +7,5 @@ describe "Queue#shift" do
end
describe "Queue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.shift(timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.shift(timeout: v) }
end
diff --git a/spec/ruby/core/random/bytes_spec.rb b/spec/ruby/core/random/bytes_spec.rb
index b42dc61234..c9be07cd3f 100644
--- a/spec/ruby/core/random/bytes_spec.rb
+++ b/spec/ruby/core/random/bytes_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'shared/bytes'
diff --git a/spec/ruby/core/random/default_spec.rb b/spec/ruby/core/random/default_spec.rb
index 01d7430df8..9e4845986d 100644
--- a/spec/ruby/core/random/default_spec.rb
+++ b/spec/ruby/core/random/default_spec.rb
@@ -1,35 +1,7 @@
require_relative '../../spec_helper'
describe "Random::DEFAULT" do
- ruby_version_is ''...'3.2' do
- it "returns a random number generator" do
- suppress_warning do
- Random::DEFAULT.should respond_to(:rand)
- end
- end
-
- it "changes seed on reboot" do
- seed1 = ruby_exe('p Random::DEFAULT.seed', options: '--disable-gems')
- seed2 = ruby_exe('p Random::DEFAULT.seed', options: '--disable-gems')
- seed1.should != seed2
- end
-
- it "refers to the Random class" do
- suppress_warning do
- Random::DEFAULT.should.equal?(Random)
- end
- end
-
- it "is deprecated" do
- -> {
- Random::DEFAULT.should.equal?(Random)
- }.should complain(/constant Random::DEFAULT is deprecated/)
- end
- end
-
- ruby_version_is '3.2' do
- it "is no longer defined" do
- Random.should_not.const_defined?(:DEFAULT)
- end
+ it "is no longer defined" do
+ Random.should_not.const_defined?(:DEFAULT)
end
end
diff --git a/spec/ruby/core/random/new_spec.rb b/spec/ruby/core/random/new_spec.rb
index 90e2a9d6f2..69210cef03 100644
--- a/spec/ruby/core/random/new_spec.rb
+++ b/spec/ruby/core/random/new_spec.rb
@@ -11,7 +11,7 @@ describe "Random.new" do
it "returns Random instances initialized with different seeds" do
first = Random.new
second = Random.new
- (0..20).map { first.rand } .should_not == (0..20).map { second.rand }
+ (0..20).map { first.rand }.should_not == (0..20).map { second.rand }
end
it "accepts an Integer seed value as an argument" do
diff --git a/spec/ruby/core/range/case_compare_spec.rb b/spec/ruby/core/range/case_compare_spec.rb
index 65878aaabe..c9b253f0a5 100644
--- a/spec/ruby/core/range/case_compare_spec.rb
+++ b/spec/ruby/core/range/case_compare_spec.rb
@@ -11,7 +11,7 @@ describe "Range#===" do
it_behaves_like :range_cover_and_include, :===
it_behaves_like :range_cover, :===
- ruby_bug "#19533", "3.2"..."3.3" do
+ ruby_bug "#19533", ""..."3.3" do
it "returns true on any value if begin and end are both nil" do
(nil..nil).should === 1
end
diff --git a/spec/ruby/core/range/cover_spec.rb b/spec/ruby/core/range/cover_spec.rb
index eb7cddc967..c05bb50614 100644
--- a/spec/ruby/core/range/cover_spec.rb
+++ b/spec/ruby/core/range/cover_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'shared/cover_and_include'
require_relative 'shared/cover'
diff --git a/spec/ruby/core/range/each_spec.rb b/spec/ruby/core/range/each_spec.rb
index ecae17c881..f10330d61d 100644
--- a/spec/ruby/core/range/each_spec.rb
+++ b/spec/ruby/core/range/each_spec.rb
@@ -40,21 +40,21 @@ describe "Range#each" do
it "works with endless ranges" do
a = []
- eval("(-2..)").each { |x| break if x > 2; a << x }
+ (-2..).each { |x| break if x > 2; a << x }
a.should == [-2, -1, 0, 1, 2]
a = []
- eval("(-2...)").each { |x| break if x > 2; a << x }
+ (-2...).each { |x| break if x > 2; a << x }
a.should == [-2, -1, 0, 1, 2]
end
it "works with String endless ranges" do
a = []
- eval("('A'..)").each { |x| break if x > "D"; a << x }
+ ('A'..).each { |x| break if x > "D"; a << x }
a.should == ["A", "B", "C", "D"]
a = []
- eval("('A'...)").each { |x| break if x > "D"; a << x }
+ ('A'...).each { |x| break if x > "D"; a << x }
a.should == ["A", "B", "C", "D"]
end
@@ -82,27 +82,14 @@ describe "Range#each" do
enum.to_a.should == [1, 2, 3]
end
- ruby_version_is "3.1" do
- it "supports Time objects that respond to #succ" do
- t = Time.utc(1970)
- def t.succ; self + 1 end
- t_succ = t.succ
- def t_succ.succ; self + 1; end
+ it "supports Time objects that respond to #succ" do
+ t = Time.utc(1970)
+ def t.succ; self + 1 end
+ t_succ = t.succ
+ def t_succ.succ; self + 1; end
- (t..t_succ).to_a.should == [Time.utc(1970), Time.utc(1970, nil, nil, nil, nil, 1)]
- (t...t_succ).to_a.should == [Time.utc(1970)]
- end
- end
-
- ruby_version_is ""..."3.1" do
- it "raises a TypeError if the first element is a Time object even if it responds to #succ" do
- t = Time.utc(1970)
- def t.succ; self + 1 end
- t_succ = t.succ
- def t_succ.succ; self + 1; end
-
- -> { (t..t_succ).each { |i| i } }.should raise_error(TypeError)
- end
+ (t..t_succ).to_a.should == [Time.utc(1970), Time.utc(1970, nil, nil, nil, nil, 1)]
+ (t...t_succ).to_a.should == [Time.utc(1970)]
end
it "passes each Symbol element by using #succ" do
diff --git a/spec/ruby/core/range/include_spec.rb b/spec/ruby/core/range/include_spec.rb
index 277de205d1..449e18985b 100644
--- a/spec/ruby/core/range/include_spec.rb
+++ b/spec/ruby/core/range/include_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'shared/cover_and_include'
require_relative 'shared/include'
diff --git a/spec/ruby/core/range/last_spec.rb b/spec/ruby/core/range/last_spec.rb
index 6698686dd5..82b3e2ff53 100644
--- a/spec/ruby/core/range/last_spec.rb
+++ b/spec/ruby/core/range/last_spec.rb
@@ -8,10 +8,8 @@ describe "Range#last" do
(1..5).last(3).should == [3, 4, 5]
end
- ruby_bug '#18994', '2.7'...'3.2' do
- it "returns the specified number if elements for single element inclusive range" do
- (1..1).last(1).should == [1]
- end
+ it "returns the specified number if elements for single element inclusive range" do
+ (1..1).last(1).should == [1]
end
it "returns an empty array for an empty Range" do
diff --git a/spec/ruby/core/range/max_spec.rb b/spec/ruby/core/range/max_spec.rb
index a3bbc31e7d..09371f5298 100644
--- a/spec/ruby/core/range/max_spec.rb
+++ b/spec/ruby/core/range/max_spec.rb
@@ -55,10 +55,24 @@ describe "Range#max" do
(..1.0).max.should == 1.0
end
- it "raises for an exclusive beginless range" do
+ ruby_version_is ""..."4.0" do
+ it "raises for an exclusive beginless Integer range" do
+ -> {
+ (...1).max
+ }.should raise_error(TypeError, 'cannot exclude end value with non Integer begin value')
+ end
+ end
+
+ ruby_version_is "4.0" do
+ it "returns the end point for exclusive beginless Integer ranges" do
+ (...1).max.should == 0
+ end
+ end
+
+ it "raises for an exclusive beginless non Integer range" do
-> {
- (...1).max
- }.should raise_error(TypeError, 'cannot exclude end value with non Integer begin value')
+ (...1.0).max
+ }.should raise_error(TypeError, 'cannot exclude non Integer end value')
end
end
diff --git a/spec/ruby/core/range/member_spec.rb b/spec/ruby/core/range/member_spec.rb
index ab61f92951..78299ae9e5 100644
--- a/spec/ruby/core/range/member_spec.rb
+++ b/spec/ruby/core/range/member_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'shared/cover_and_include'
require_relative 'shared/include'
diff --git a/spec/ruby/core/range/overlap_spec.rb b/spec/ruby/core/range/overlap_spec.rb
new file mode 100644
index 0000000000..9b6fc13493
--- /dev/null
+++ b/spec/ruby/core/range/overlap_spec.rb
@@ -0,0 +1,89 @@
+require_relative '../../spec_helper'
+
+ruby_version_is '3.3' do
+ describe "Range#overlap?" do
+ it "returns true if other Range overlaps self" do
+ (0..2).overlap?(1..3).should == true
+ (1..3).overlap?(0..2).should == true
+ (0..2).overlap?(0..2).should == true
+ (0..3).overlap?(1..2).should == true
+ (1..2).overlap?(0..3).should == true
+
+ ('a'..'c').overlap?('b'..'d').should == true
+ end
+
+ it "returns false if other Range does not overlap self" do
+ (0..2).overlap?(3..4).should == false
+ (0..2).overlap?(-4..-1).should == false
+
+ ('a'..'c').overlap?('d'..'f').should == false
+ end
+
+ it "raises TypeError when called with non-Range argument" do
+ -> {
+ (0..2).overlap?(1)
+ }.should raise_error(TypeError, "wrong argument type Integer (expected Range)")
+ end
+
+ it "returns true when beginningless and endless Ranges overlap" do
+ (0..2).overlap?(..3).should == true
+ (0..2).overlap?(..1).should == true
+ (0..2).overlap?(..0).should == true
+
+ (..3).overlap?(0..2).should == true
+ (..1).overlap?(0..2).should == true
+ (..0).overlap?(0..2).should == true
+
+ (0..2).overlap?(-1..).should == true
+ (0..2).overlap?(1..).should == true
+ (0..2).overlap?(2..).should == true
+
+ (-1..).overlap?(0..2).should == true
+ (1..).overlap?(0..2).should == true
+ (2..).overlap?(0..2).should == true
+
+ (0..).overlap?(2..).should == true
+ (..0).overlap?(..2).should == true
+ end
+
+ it "returns false when beginningless and endless Ranges do not overlap" do
+ (0..2).overlap?(..-1).should == false
+ (0..2).overlap?(3..).should == false
+
+ (..-1).overlap?(0..2).should == false
+ (3..).overlap?(0..2).should == false
+ end
+
+ it "returns false when Ranges are not compatible" do
+ (0..2).overlap?('a'..'d').should == false
+ end
+
+ it "return false when self is empty" do
+ (2..0).overlap?(1..3).should == false
+ (2...2).overlap?(1..3).should == false
+ (1...1).overlap?(1...1).should == false
+ (2..0).overlap?(2..0).should == false
+
+ ('c'..'a').overlap?('b'..'d').should == false
+ ('a'...'a').overlap?('b'..'d').should == false
+ ('b'...'b').overlap?('b'...'b').should == false
+ ('c'...'a').overlap?('c'...'a').should == false
+ end
+
+ it "return false when other Range is empty" do
+ (1..3).overlap?(2..0).should == false
+ (1..3).overlap?(2...2).should == false
+
+ ('b'..'d').overlap?('c'..'a').should == false
+ ('b'..'d').overlap?('c'...'c').should == false
+ end
+
+ it "takes into account exclusive end" do
+ (0...2).overlap?(2..4).should == false
+ (2..4).overlap?(0...2).should == false
+
+ ('a'...'c').overlap?('c'..'e').should == false
+ ('c'..'e').overlap?('a'...'c').should == false
+ end
+ end
+end
diff --git a/spec/ruby/core/range/reverse_each_spec.rb b/spec/ruby/core/range/reverse_each_spec.rb
index b51e04c3ff..56390cc0da 100644
--- a/spec/ruby/core/range/reverse_each_spec.rb
+++ b/spec/ruby/core/range/reverse_each_spec.rb
@@ -88,7 +88,7 @@ ruby_version_is "3.3" do
(1..3).reverse_each.size.should == 3
end
- ruby_bug "#20936", "3.4"..."3.5" do
+ ruby_bug "#20936", "3.4"..."4.0" do
it "returns Infinity when Range size is infinite" do
(..3).reverse_each.size.should == Float::INFINITY
end
diff --git a/spec/ruby/core/range/shared/cover.rb b/spec/ruby/core/range/shared/cover.rb
index 0b41a26455..eaefb45942 100644
--- a/spec/ruby/core/range/shared/cover.rb
+++ b/spec/ruby/core/range/shared/cover.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
diff --git a/spec/ruby/core/range/shared/cover_and_include.rb b/spec/ruby/core/range/shared/cover_and_include.rb
index f36a2cef8b..13fc5e1790 100644
--- a/spec/ruby/core/range/shared/cover_and_include.rb
+++ b/spec/ruby/core/range/shared/cover_and_include.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
describe :range_cover_and_include, shared: true do
@@ -20,8 +20,8 @@ describe :range_cover_and_include, shared: true do
end
it "returns true if other is an element of self for endless ranges" do
- eval("(1..)").send(@method, 2.4).should == true
- eval("(0.5...)").send(@method, 2.4).should == true
+ (1..).send(@method, 2.4).should == true
+ (0.5...).send(@method, 2.4).should == true
end
it "returns true if other is an element of self for beginless ranges" do
@@ -29,6 +29,17 @@ describe :range_cover_and_include, shared: true do
(...10.5).send(@method, 2.4).should == true
end
+ it "returns false if values are not comparable" do
+ (1..10).send(@method, nil).should == false
+ (1...10).send(@method, nil).should == false
+
+ (..10).send(@method, nil).should == false
+ (...10).send(@method, nil).should == false
+
+ (1..).send(@method, nil).should == false
+ (1...).send(@method, nil).should == false
+ end
+
it "compares values using <=>" do
rng = (1..5)
m = mock("int")
diff --git a/spec/ruby/core/range/shared/include.rb b/spec/ruby/core/range/shared/include.rb
index c6c5c2becf..15a0e5fb9f 100644
--- a/spec/ruby/core/range/shared/include.rb
+++ b/spec/ruby/core/range/shared/include.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
diff --git a/spec/ruby/core/range/size_spec.rb b/spec/ruby/core/range/size_spec.rb
index a1fe3ce17d..1a3ddd197e 100644
--- a/spec/ruby/core/range/size_spec.rb
+++ b/spec/ruby/core/range/size_spec.rb
@@ -22,16 +22,7 @@ describe "Range#size" do
eval("('z'..)").size.should == nil
end
- ruby_version_is ""..."3.2" do
- it 'returns Float::INFINITY for all beginless ranges' do
- (..1).size.should == Float::INFINITY
- (...0.5).size.should == Float::INFINITY
- (..nil).size.should == Float::INFINITY
- (...'o').size.should == Float::INFINITY
- end
- end
-
- ruby_version_is "3.2"..."3.4" do
+ ruby_version_is ""..."3.4" do
it 'returns Float::INFINITY for all beginless ranges if the end is numeric' do
(..1).size.should == Float::INFINITY
(...0.5).size.should == Float::INFINITY
diff --git a/spec/ruby/core/range/step_spec.rb b/spec/ruby/core/range/step_spec.rb
index 31cfd400cc..0d0caf746d 100644
--- a/spec/ruby/core/range/step_spec.rb
+++ b/spec/ruby/core/range/step_spec.rb
@@ -322,13 +322,11 @@ describe "Range#step" do
ScratchPad.recorded.should eql([1.0, 2.8, 4.6])
end
- ruby_version_is '3.1' do
- it "correctly handles values near the upper limit" do # https://bugs.ruby-lang.org/issues/16612
- (1.0...55.6).step(18.2) { |x| ScratchPad << x }
- ScratchPad.recorded.should eql([1.0, 19.2, 37.4, 55.599999999999994])
+ it "correctly handles values near the upper limit" do # https://bugs.ruby-lang.org/issues/16612
+ (1.0...55.6).step(18.2) { |x| ScratchPad << x }
+ ScratchPad.recorded.should eql([1.0, 19.2, 37.4, 55.599999999999994])
- (1.0...55.6).step(18.2).size.should == 4
- end
+ (1.0...55.6).step(18.2).size.should == 4
end
it "handles infinite values at either end" do
@@ -408,108 +406,108 @@ describe "Range#step" do
describe "with an endless range" do
describe "and Integer values" do
it "yield Integer values incremented by 1 when not passed a step" do
- eval("(-2..)").step { |x| break if x > 2; ScratchPad << x }
+ (-2..).step { |x| break if x > 2; ScratchPad << x }
ScratchPad.recorded.should eql([-2, -1, 0, 1, 2])
ScratchPad.record []
- eval("(-2...)").step { |x| break if x > 2; ScratchPad << x }
+ (-2...).step { |x| break if x > 2; ScratchPad << x }
ScratchPad.recorded.should eql([-2, -1, 0, 1, 2])
end
it "yields Integer values incremented by an Integer step" do
- eval("(-5..)").step(2) { |x| break if x > 3; ScratchPad << x }
+ (-5..).step(2) { |x| break if x > 3; ScratchPad << x }
ScratchPad.recorded.should eql([-5, -3, -1, 1, 3])
ScratchPad.record []
- eval("(-5...)").step(2) { |x| break if x > 3; ScratchPad << x }
+ (-5...).step(2) { |x| break if x > 3; ScratchPad << x }
ScratchPad.recorded.should eql([-5, -3, -1, 1, 3])
end
it "yields Float values incremented by a Float step" do
- eval("(-2..)").step(1.5) { |x| break if x > 1.0; ScratchPad << x }
+ (-2..).step(1.5) { |x| break if x > 1.0; ScratchPad << x }
ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])
ScratchPad.record []
- eval("(-2..)").step(1.5) { |x| break if x > 1.0; ScratchPad << x }
+ (-2..).step(1.5) { |x| break if x > 1.0; ScratchPad << x }
ScratchPad.recorded.should eql([-2.0, -0.5, 1.0])
end
end
describe "and Float values" do
it "yields Float values incremented by 1 and less than end when not passed a step" do
- eval("(-2.0..)").step { |x| break if x > 1.5; ScratchPad << x }
+ (-2.0..).step { |x| break if x > 1.5; ScratchPad << x }
ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
ScratchPad.record []
- eval("(-2.0...)").step { |x| break if x > 1.5; ScratchPad << x }
+ (-2.0...).step { |x| break if x > 1.5; ScratchPad << x }
ScratchPad.recorded.should eql([-2.0, -1.0, 0.0, 1.0])
end
it "yields Float values incremented by an Integer step" do
- eval("(-5.0..)").step(2) { |x| break if x > 3.5; ScratchPad << x }
+ (-5.0..).step(2) { |x| break if x > 3.5; ScratchPad << x }
ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
ScratchPad.record []
- eval("(-5.0...)").step(2) { |x| break if x > 3.5; ScratchPad << x }
+ (-5.0...).step(2) { |x| break if x > 3.5; ScratchPad << x }
ScratchPad.recorded.should eql([-5.0, -3.0, -1.0, 1.0, 3.0])
end
it "yields Float values incremented by a Float step" do
- eval("(-1.0..)").step(0.5) { |x| break if x > 0.6; ScratchPad << x }
+ (-1.0..).step(0.5) { |x| break if x > 0.6; ScratchPad << x }
ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
ScratchPad.record []
- eval("(-1.0...)").step(0.5) { |x| break if x > 0.6; ScratchPad << x }
+ (-1.0...).step(0.5) { |x| break if x > 0.6; ScratchPad << x }
ScratchPad.recorded.should eql([-1.0, -0.5, 0.0, 0.5])
end
it "handles infinite values at the start" do
- eval("(-Float::INFINITY..)").step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
+ (-Float::INFINITY..).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
ScratchPad.record []
- eval("(-Float::INFINITY...)").step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
+ (-Float::INFINITY...).step(2) { |x| ScratchPad << x; break if ScratchPad.recorded.size == 3 }
ScratchPad.recorded.should eql([-Float::INFINITY, -Float::INFINITY, -Float::INFINITY])
end
end
describe "and String values" do
it "yields String values incremented by #succ and less than or equal to end when not passed a step" do
- eval("('A'..)").step { |x| break if x > "D"; ScratchPad << x }
+ ('A'..).step { |x| break if x > "D"; ScratchPad << x }
ScratchPad.recorded.should == ["A", "B", "C", "D"]
ScratchPad.record []
- eval("('A'...)").step { |x| break if x > "D"; ScratchPad << x }
+ ('A'...).step { |x| break if x > "D"; ScratchPad << x }
ScratchPad.recorded.should == ["A", "B", "C", "D"]
end
it "yields String values incremented by #succ called Integer step times" do
- eval("('A'..)").step(2) { |x| break if x > "F"; ScratchPad << x }
+ ('A'..).step(2) { |x| break if x > "F"; ScratchPad << x }
ScratchPad.recorded.should == ["A", "C", "E"]
ScratchPad.record []
- eval("('A'...)").step(2) { |x| break if x > "F"; ScratchPad << x }
+ ('A'...).step(2) { |x| break if x > "F"; ScratchPad << x }
ScratchPad.recorded.should == ["A", "C", "E"]
end
it "raises a TypeError when passed a Float step" do
- -> { eval("('A'..)").step(2.0) { } }.should raise_error(TypeError)
- -> { eval("('A'...)").step(2.0) { } }.should raise_error(TypeError)
+ -> { ('A'..).step(2.0) { } }.should raise_error(TypeError)
+ -> { ('A'...).step(2.0) { } }.should raise_error(TypeError)
end
ruby_version_is "3.4" do
it "yields String values adjusted by step" do
- eval("('A'..)").step("A") { |x| break if x > "AAA"; ScratchPad << x }
+ ('A'..).step("A") { |x| break if x > "AAA"; ScratchPad << x }
ScratchPad.recorded.should == ["A", "AA", "AAA"]
ScratchPad.record []
- eval("('A'...)").step("A") { |x| break if x > "AAA"; ScratchPad << x }
+ ('A'...).step("A") { |x| break if x > "AAA"; ScratchPad << x }
ScratchPad.recorded.should == ["A", "AA", "AAA"]
end
it "raises a TypeError when passed an incompatible type step" do
- -> { eval("('A'..)").step([]) { } }.should raise_error(TypeError)
- -> { eval("('A'...)").step([]) { } }.should raise_error(TypeError)
+ -> { ('A'..).step([]) { } }.should raise_error(TypeError)
+ -> { ('A'...).step([]) { } }.should raise_error(TypeError)
end
end
end
diff --git a/spec/ruby/core/range/to_set_spec.rb b/spec/ruby/core/range/to_set_spec.rb
new file mode 100644
index 0000000000..589c0e9aed
--- /dev/null
+++ b/spec/ruby/core/range/to_set_spec.rb
@@ -0,0 +1,55 @@
+require_relative '../../spec_helper'
+require_relative '../enumerable/fixtures/classes'
+
+describe "Enumerable#to_set" do
+ it "returns a new Set created from self" do
+ (1..4).to_set.should == Set[1, 2, 3, 4]
+ (1...4).to_set.should == Set[1, 2, 3]
+ end
+
+ it "passes down passed blocks" do
+ (1..3).to_set { |x| x * x }.should == Set[1, 4, 9]
+ end
+
+ ruby_version_is "4.0" do
+ it "raises a RangeError if the range is infinite" do
+ -> { (1..).to_set }.should raise_error(RangeError, "cannot convert endless range to a set")
+ -> { (1...).to_set }.should raise_error(RangeError, "cannot convert endless range to a set")
+ end
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "instantiates an object of provided as the first argument set class" do
+ set = (1..3).to_set(EnumerableSpecs::SetSubclass)
+ set.should be_kind_of(EnumerableSpecs::SetSubclass)
+ set.to_a.sort.should == [1, 2, 3]
+ end
+ end
+
+ ruby_version_is "4.0"..."4.1" do
+ it "instantiates an object of provided as the first argument set class and warns" do
+ set = nil
+ proc {
+ set = (1..3).to_set(EnumerableSpecs::SetSubclass)
+ }.should complain(/Enumerable#to_set/)
+ set.should be_kind_of(EnumerableSpecs::SetSubclass)
+ set.to_a.sort.should == [1, 2, 3]
+ end
+ end
+
+ ruby_version_is "4.1" do
+ it "does not accept any positional argument" do
+ -> {
+ (1..3).to_set(EnumerableSpecs::SetSubclass)
+ }.should raise_error(ArgumentError, 'wrong number of arguments (given 1, expected 0)')
+ end
+ end
+
+ it "does not need explicit `require 'set'`" do
+ output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1')
+ puts (1..3).to_set.to_a.inspect
+ RUBY
+
+ output.chomp.should == "[1, 2, 3]"
+ end
+end
diff --git a/spec/ruby/core/rational/abs_spec.rb b/spec/ruby/core/rational/abs_spec.rb
index 7272ad2422..54099aa14d 100644
--- a/spec/ruby/core/rational/abs_spec.rb
+++ b/spec/ruby/core/rational/abs_spec.rb
@@ -1,5 +1,5 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/abs'
+require_relative 'shared/abs'
describe "Rational#abs" do
it_behaves_like :rational_abs, :abs
diff --git a/spec/ruby/core/rational/ceil_spec.rb b/spec/ruby/core/rational/ceil_spec.rb
index e736351604..d5bdadf3b6 100644
--- a/spec/ruby/core/rational/ceil_spec.rb
+++ b/spec/ruby/core/rational/ceil_spec.rb
@@ -1,6 +1,45 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/ceil'
describe "Rational#ceil" do
- it_behaves_like :rational_ceil, :ceil
+ before do
+ @rational = Rational(2200, 7)
+ end
+
+ describe "with no arguments (precision = 0)" do
+ it "returns an Integer" do
+ @rational.ceil.should be_kind_of(Integer)
+ end
+
+ it "returns the truncated value toward positive infinity" do
+ @rational.ceil.should == 315
+ Rational(1, 2).ceil.should == 1
+ Rational(-1, 2).ceil.should == 0
+ end
+ end
+
+ describe "with a precision < 0" do
+ it "returns an Integer" do
+ @rational.ceil(-2).should be_kind_of(Integer)
+ @rational.ceil(-1).should be_kind_of(Integer)
+ end
+
+ it "moves the truncation point n decimal places left" do
+ @rational.ceil(-3).should == 1000
+ @rational.ceil(-2).should == 400
+ @rational.ceil(-1).should == 320
+ end
+ end
+
+ describe "with precision > 0" do
+ it "returns a Rational" do
+ @rational.ceil(1).should be_kind_of(Rational)
+ @rational.ceil(2).should be_kind_of(Rational)
+ end
+
+ it "moves the truncation point n decimal places right" do
+ @rational.ceil(1).should == Rational(3143, 10)
+ @rational.ceil(2).should == Rational(31429, 100)
+ @rational.ceil(3).should == Rational(157143, 500)
+ end
+ end
end
diff --git a/spec/ruby/core/rational/comparison_spec.rb b/spec/ruby/core/rational/comparison_spec.rb
index 877069fb8f..c9db60d5c7 100644
--- a/spec/ruby/core/rational/comparison_spec.rb
+++ b/spec/ruby/core/rational/comparison_spec.rb
@@ -1,23 +1,93 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/comparison'
+require_relative 'fixtures/rational'
describe "Rational#<=> when passed a Rational object" do
- it_behaves_like :rational_cmp_rat, :<=>
+ it "returns 1 when self is greater than the passed argument" do
+ (Rational(4, 4) <=> Rational(3, 4)).should equal(1)
+ (Rational(-3, 4) <=> Rational(-4, 4)).should equal(1)
+ end
+
+ it "returns 0 when self is equal to the passed argument" do
+ (Rational(4, 4) <=> Rational(4, 4)).should equal(0)
+ (Rational(-3, 4) <=> Rational(-3, 4)).should equal(0)
+ end
+
+ it "returns -1 when self is less than the passed argument" do
+ (Rational(3, 4) <=> Rational(4, 4)).should equal(-1)
+ (Rational(-4, 4) <=> Rational(-3, 4)).should equal(-1)
+ end
end
describe "Rational#<=> when passed an Integer object" do
- it_behaves_like :rational_cmp_int, :<=>
+ it "returns 1 when self is greater than the passed argument" do
+ (Rational(4, 4) <=> 0).should equal(1)
+ (Rational(4, 4) <=> -10).should equal(1)
+ (Rational(-3, 4) <=> -1).should equal(1)
+ end
+
+ it "returns 0 when self is equal to the passed argument" do
+ (Rational(4, 4) <=> 1).should equal(0)
+ (Rational(-8, 4) <=> -2).should equal(0)
+ end
+
+ it "returns -1 when self is less than the passed argument" do
+ (Rational(3, 4) <=> 1).should equal(-1)
+ (Rational(-4, 4) <=> 0).should equal(-1)
+ end
end
describe "Rational#<=> when passed a Float object" do
- it_behaves_like :rational_cmp_float, :<=>
+ it "returns 1 when self is greater than the passed argument" do
+ (Rational(4, 4) <=> 0.5).should equal(1)
+ (Rational(4, 4) <=> -1.5).should equal(1)
+ (Rational(-3, 4) <=> -0.8).should equal(1)
+ end
+
+ it "returns 0 when self is equal to the passed argument" do
+ (Rational(4, 4) <=> 1.0).should equal(0)
+ (Rational(-6, 4) <=> -1.5).should equal(0)
+ end
+
+ it "returns -1 when self is less than the passed argument" do
+ (Rational(3, 4) <=> 1.2).should equal(-1)
+ (Rational(-4, 4) <=> 0.5).should equal(-1)
+ end
end
describe "Rational#<=> when passed an Object that responds to #coerce" do
- it_behaves_like :rational_cmp_coerce, :<=>
- it_behaves_like :rational_cmp_coerce_exception, :<=>
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational <=> obj
+ end
+
+ it "calls #<=> on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:<=>).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ (rational <=> obj).should == :result
+ end
+
+ it "does not rescue exception raised in other#coerce" do
+ b = mock("numeric with failed #coerce")
+ b.should_receive(:coerce).and_raise(RationalSpecs::CoerceError)
+
+ -> { Rational(3, 4) <=> b }.should raise_error(RationalSpecs::CoerceError)
+ end
end
describe "Rational#<=> when passed a non-Numeric Object that doesn't respond to #coerce" do
- it_behaves_like :rational_cmp_other, :<=>
+ it "returns nil" do
+ (Rational <=> mock("Object")).should be_nil
+ end
end
diff --git a/spec/ruby/core/rational/denominator_spec.rb b/spec/ruby/core/rational/denominator_spec.rb
index c2f49b4190..4687244893 100644
--- a/spec/ruby/core/rational/denominator_spec.rb
+++ b/spec/ruby/core/rational/denominator_spec.rb
@@ -1,6 +1,14 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/denominator'
describe "Rational#denominator" do
- it_behaves_like :rational_denominator, :denominator
+ it "returns the denominator" do
+ Rational(3, 4).denominator.should equal(4)
+ Rational(3, -4).denominator.should equal(4)
+
+ Rational(1, bignum_value).denominator.should == bignum_value
+ end
+
+ it "returns 1 if no denominator was given" do
+ Rational(80).denominator.should == 1
+ end
end
diff --git a/spec/ruby/core/rational/div_spec.rb b/spec/ruby/core/rational/div_spec.rb
index bee7d01a67..d3adb9b536 100644
--- a/spec/ruby/core/rational/div_spec.rb
+++ b/spec/ruby/core/rational/div_spec.rb
@@ -1,18 +1,54 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/div'
describe "Rational#div" do
- it_behaves_like :rational_div, :div
+ it "returns an Integer" do
+ Rational(229, 21).div(82).should be_kind_of(Integer)
+ end
+
+ it "raises an ArgumentError if passed more than one argument" do
+ -> { Rational(3, 4).div(2,3) }.should raise_error(ArgumentError)
+ end
+
+ # See http://redmine.ruby-lang.org/issues/show/1648
+ it "raises a TypeError if passed a non-numeric argument" do
+ -> { Rational(3, 4).div([]) }.should raise_error(TypeError)
+ end
end
describe "Rational#div passed a Rational" do
- it_behaves_like :rational_div_rat, :div
+ it "performs integer division and returns the result" do
+ Rational(2, 3).div(Rational(2, 3)).should == 1
+ Rational(-2, 9).div(Rational(-9, 2)).should == 0
+ end
+
+ it "raises a ZeroDivisionError when the argument has a numerator of 0" do
+ -> { Rational(3, 4).div(Rational(0, 3)) }.should raise_error(ZeroDivisionError)
+ end
+
+ it "raises a ZeroDivisionError when the argument has a numerator of 0.0" do
+ -> { Rational(3, 4).div(Rational(0.0, 3)) }.should raise_error(ZeroDivisionError)
+ end
end
describe "Rational#div passed an Integer" do
- it_behaves_like :rational_div_int, :div
+ it "performs integer division and returns the result" do
+ Rational(2, 1).div(1).should == 2
+ Rational(25, 5).div(-50).should == -1
+ end
+
+ it "raises a ZeroDivisionError when the argument is 0" do
+ -> { Rational(3, 4).div(0) }.should raise_error(ZeroDivisionError)
+ end
end
describe "Rational#div passed a Float" do
- it_behaves_like :rational_div_float, :div
+ it "performs integer division and returns the result" do
+ Rational(2, 3).div(30.333).should == 0
+ Rational(2, 9).div(Rational(-8.6)).should == -1
+ Rational(3.12).div(0.5).should == 6
+ end
+
+ it "raises a ZeroDivisionError when the argument is 0.0" do
+ -> { Rational(3, 4).div(0.0) }.should raise_error(ZeroDivisionError)
+ end
end
diff --git a/spec/ruby/core/rational/divide_spec.rb b/spec/ruby/core/rational/divide_spec.rb
index 14e8c4c195..8f5ca1fdec 100644
--- a/spec/ruby/core/rational/divide_spec.rb
+++ b/spec/ruby/core/rational/divide_spec.rb
@@ -1,20 +1,74 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/divide'
-require_relative '../../shared/rational/arithmetic_exception_in_coerce'
+require_relative 'shared/arithmetic_exception_in_coerce'
describe "Rational#/" do
- it_behaves_like :rational_divide, :/
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational / obj
+ end
+
+ it "calls #/ on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:/).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ (rational / obj).should == :result
+ end
+
it_behaves_like :rational_arithmetic_exception_in_coerce, :/
end
describe "Rational#/ when passed an Integer" do
- it_behaves_like :rational_divide_int, :/
+ it "returns self divided by other as a Rational" do
+ (Rational(3, 4) / 2).should eql(Rational(3, 8))
+ (Rational(2, 4) / 2).should eql(Rational(1, 4))
+ (Rational(6, 7) / -2).should eql(Rational(-3, 7))
+ end
+
+ it "raises a ZeroDivisionError when passed 0" do
+ -> { Rational(3, 4) / 0 }.should raise_error(ZeroDivisionError)
+ end
end
describe "Rational#/ when passed a Rational" do
- it_behaves_like :rational_divide_rat, :/
+ it "returns self divided by other as a Rational" do
+ (Rational(3, 4) / Rational(3, 4)).should eql(Rational(1, 1))
+ (Rational(2, 4) / Rational(1, 4)).should eql(Rational(2, 1))
+
+ (Rational(2, 4) / 2).should == Rational(1, 4)
+ (Rational(6, 7) / -2).should == Rational(-3, 7)
+ end
+
+ it "raises a ZeroDivisionError when passed a Rational with a numerator of 0" do
+ -> { Rational(3, 4) / Rational(0, 1) }.should raise_error(ZeroDivisionError)
+ end
end
describe "Rational#/ when passed a Float" do
- it_behaves_like :rational_divide_float, :/
+ it "returns self divided by other as a Float" do
+ (Rational(3, 4) / 0.75).should eql(1.0)
+ (Rational(3, 4) / 0.25).should eql(3.0)
+ (Rational(3, 4) / 0.3).should eql(2.5)
+
+ (Rational(-3, 4) / 0.3).should eql(-2.5)
+ (Rational(3, -4) / 0.3).should eql(-2.5)
+ (Rational(3, 4) / -0.3).should eql(-2.5)
+ end
+
+ it "returns infinity when passed 0" do
+ (Rational(3, 4) / 0.0).infinite?.should eql(1)
+ (Rational(-3, -4) / 0.0).infinite?.should eql(1)
+
+ (Rational(-3, 4) / 0.0).infinite?.should eql(-1)
+ (Rational(3, -4) / 0.0).infinite?.should eql(-1)
+ end
end
diff --git a/spec/ruby/core/rational/divmod_spec.rb b/spec/ruby/core/rational/divmod_spec.rb
index 7ffdde74f4..f0555294a3 100644
--- a/spec/ruby/core/rational/divmod_spec.rb
+++ b/spec/ruby/core/rational/divmod_spec.rb
@@ -1,14 +1,42 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/divmod'
describe "Rational#divmod when passed a Rational" do
- it_behaves_like :rational_divmod_rat, :divmod
+ it "returns the quotient as Integer and the remainder as Rational" do
+ Rational(7, 4).divmod(Rational(1, 2)).should eql([3, Rational(1, 4)])
+ Rational(7, 4).divmod(Rational(-1, 2)).should eql([-4, Rational(-1, 4)])
+ Rational(0, 4).divmod(Rational(4, 3)).should eql([0, Rational(0, 1)])
+
+ Rational(bignum_value, 4).divmod(Rational(4, 3)).should eql([3458764513820540928, Rational(0, 1)])
+ end
+
+ it "raises a ZeroDivisionError when passed a Rational with a numerator of 0" do
+ -> { Rational(7, 4).divmod(Rational(0, 3)) }.should raise_error(ZeroDivisionError)
+ end
end
describe "Rational#divmod when passed an Integer" do
- it_behaves_like :rational_divmod_int, :divmod
+ it "returns the quotient as Integer and the remainder as Rational" do
+ Rational(7, 4).divmod(2).should eql([0, Rational(7, 4)])
+ Rational(7, 4).divmod(-2).should eql([-1, Rational(-1, 4)])
+
+ Rational(bignum_value, 4).divmod(3).should eql([1537228672809129301, Rational(1, 1)])
+ end
+
+ it "raises a ZeroDivisionError when passed 0" do
+ -> { Rational(7, 4).divmod(0) }.should raise_error(ZeroDivisionError)
+ end
end
describe "Rational#divmod when passed a Float" do
- it_behaves_like :rational_divmod_float, :divmod
+ it "returns the quotient as Integer and the remainder as Float" do
+ Rational(7, 4).divmod(0.5).should eql([3, 0.25])
+ end
+
+ it "returns the quotient as Integer and the remainder as Float" do
+ Rational(7, 4).divmod(-0.5).should eql([-4, -0.25])
+ end
+
+ it "raises a ZeroDivisionError when passed 0" do
+ -> { Rational(7, 4).divmod(0.0) }.should raise_error(ZeroDivisionError)
+ end
end
diff --git a/spec/ruby/core/rational/equal_value_spec.rb b/spec/ruby/core/rational/equal_value_spec.rb
index c6f7f4c6a2..ba40d29c3b 100644
--- a/spec/ruby/core/rational/equal_value_spec.rb
+++ b/spec/ruby/core/rational/equal_value_spec.rb
@@ -1,18 +1,39 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/equal_value'
describe "Rational#==" do
- it_behaves_like :rational_equal_value, :==
+ it "returns the result of calling #== with self on the passed argument" do
+ obj = mock("Object")
+ obj.should_receive(:==).and_return(:result)
+
+ (Rational(3, 4) == obj).should_not be_false
+ end
end
describe "Rational#== when passed a Rational" do
- it_behaves_like :rational_equal_value_rat, :==
+ it "returns true if self has the same numerator and denominator as the passed argument" do
+ (Rational(3, 4) == Rational(3, 4)).should be_true
+ (Rational(-3, -4) == Rational(3, 4)).should be_true
+ (Rational(-4, 5) == Rational(4, -5)).should be_true
+
+ (Rational(bignum_value, 3) == Rational(bignum_value, 3)).should be_true
+ (Rational(-bignum_value, 3) == Rational(bignum_value, -3)).should be_true
+ end
end
describe "Rational#== when passed a Float" do
- it_behaves_like :rational_equal_value_float, :==
+ it "converts self to a Float and compares it with the passed argument" do
+ (Rational(3, 4) == 0.75).should be_true
+ (Rational(4, 2) == 2.0).should be_true
+ (Rational(-4, 2) == -2.0).should be_true
+ (Rational(4, -2) == -2.0).should be_true
+ end
end
describe "Rational#== when passed an Integer" do
- it_behaves_like :rational_equal_value_int, :==
+ it "returns true if self has the passed argument as numerator and a denominator of 1" do
+ # Rational(x, y) reduces x and y automatically
+ (Rational(4, 2) == 2).should be_true
+ (Rational(-4, 2) == -2).should be_true
+ (Rational(4, -2) == -2).should be_true
+ end
end
diff --git a/spec/ruby/core/rational/exponent_spec.rb b/spec/ruby/core/rational/exponent_spec.rb
index 7e35b4ebc1..65fbf2ed1c 100644
--- a/spec/ruby/core/rational/exponent_spec.rb
+++ b/spec/ruby/core/rational/exponent_spec.rb
@@ -1,6 +1,236 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/exponent'
describe "Rational#**" do
- it_behaves_like :rational_exponent, :**
+ describe "when passed Rational" do
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ it "returns Rational(1) if the exponent is Rational(0)" do
+ (Rational(0) ** Rational(0)).should eql(Rational(1))
+ (Rational(1) ** Rational(0)).should eql(Rational(1))
+ (Rational(3, 4) ** Rational(0)).should eql(Rational(1))
+ (Rational(-1) ** Rational(0)).should eql(Rational(1))
+ (Rational(-3, 4) ** Rational(0)).should eql(Rational(1))
+ (Rational(bignum_value) ** Rational(0)).should eql(Rational(1))
+ (Rational(-bignum_value) ** Rational(0)).should eql(Rational(1))
+ end
+
+ it "returns self raised to the argument as a Rational if the exponent's denominator is 1" do
+ (Rational(3, 4) ** Rational(1, 1)).should eql(Rational(3, 4))
+ (Rational(3, 4) ** Rational(2, 1)).should eql(Rational(9, 16))
+ (Rational(3, 4) ** Rational(-1, 1)).should eql(Rational(4, 3))
+ (Rational(3, 4) ** Rational(-2, 1)).should eql(Rational(16, 9))
+ end
+
+ it "returns self raised to the argument as a Float if the exponent's denominator is not 1" do
+ (Rational(3, 4) ** Rational(4, 3)).should be_close(0.681420222312052, TOLERANCE)
+ (Rational(3, 4) ** Rational(-4, 3)).should be_close(1.46752322173095, TOLERANCE)
+ (Rational(3, 4) ** Rational(4, -3)).should be_close(1.46752322173095, TOLERANCE)
+ end
+
+ it "returns a complex number when self is negative and the passed argument is not 0" do
+ (Rational(-3, 4) ** Rational(-4, 3)).should be_close(Complex(-0.7337616108654732, 1.2709123906625817), TOLERANCE)
+ end
+ end
+ end
+
+ describe "when passed Integer" do
+ it "returns the Rational value of self raised to the passed argument" do
+ (Rational(3, 4) ** 4).should == Rational(81, 256)
+ (Rational(3, 4) ** -4).should == Rational(256, 81)
+ (Rational(-3, 4) ** -4).should == Rational(256, 81)
+ (Rational(3, -4) ** -4).should == Rational(256, 81)
+
+ (Rational(bignum_value, 4) ** 4).should == Rational(452312848583266388373324160190187140051835877600158453279131187530910662656, 1)
+ (Rational(3, bignum_value) ** -4).should == Rational(115792089237316195423570985008687907853269984665640564039457584007913129639936, 81)
+ (Rational(-bignum_value, 4) ** -4).should == Rational(1, 452312848583266388373324160190187140051835877600158453279131187530910662656)
+ (Rational(3, -bignum_value) ** -4).should == Rational(115792089237316195423570985008687907853269984665640564039457584007913129639936, 81)
+ end
+
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ it "returns Rational(1, 1) when the passed argument is 0" do
+ (Rational(3, 4) ** 0).should eql(Rational(1, 1))
+ (Rational(-3, 4) ** 0).should eql(Rational(1, 1))
+ (Rational(3, -4) ** 0).should eql(Rational(1, 1))
+
+ (Rational(bignum_value, 4) ** 0).should eql(Rational(1, 1))
+ (Rational(3, -bignum_value) ** 0).should eql(Rational(1, 1))
+ end
+ end
+ end
+
+ describe "when passed Bignum" do
+ # #5713
+ it "returns Rational(0) when self is Rational(0) and the exponent is positive" do
+ (Rational(0) ** bignum_value).should eql(Rational(0))
+ end
+
+ it "raises ZeroDivisionError when self is Rational(0) and the exponent is negative" do
+ -> { Rational(0) ** -bignum_value }.should raise_error(ZeroDivisionError)
+ end
+
+ it "returns Rational(1) when self is Rational(1)" do
+ (Rational(1) ** bignum_value).should eql(Rational(1))
+ (Rational(1) ** -bignum_value).should eql(Rational(1))
+ end
+
+ it "returns Rational(1) when self is Rational(-1) and the exponent is positive and even" do
+ (Rational(-1) ** bignum_value(0)).should eql(Rational(1))
+ (Rational(-1) ** bignum_value(2)).should eql(Rational(1))
+ end
+
+ it "returns Rational(-1) when self is Rational(-1) and the exponent is positive and odd" do
+ (Rational(-1) ** bignum_value(1)).should eql(Rational(-1))
+ (Rational(-1) ** bignum_value(3)).should eql(Rational(-1))
+ end
+
+ ruby_version_is ""..."3.4" do
+ it "returns positive Infinity when self is > 1" do
+ -> {
+ (Rational(2) ** bignum_value).infinite?.should == 1
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ -> {
+ (Rational(fixnum_max) ** bignum_value).infinite?.should == 1
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ end
+
+ it "returns 0.0 when self is > 1 and the exponent is negative" do
+ -> {
+ (Rational(2) ** -bignum_value).should eql(0.0)
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ -> {
+ (Rational(fixnum_max) ** -bignum_value).should eql(0.0)
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "raises an ArgumentError when self is > 1" do
+ -> {
+ (Rational(2) ** bignum_value)
+ }.should raise_error(ArgumentError)
+ -> {
+ (Rational(fixnum_max) ** bignum_value)
+ }.should raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError when self is > 1 and the exponent is negative" do
+ -> {
+ (Rational(2) ** -bignum_value)
+ }.should raise_error(ArgumentError)
+ -> {
+ (Rational(fixnum_max) ** -bignum_value)
+ }.should raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError when self is < -1" do
+ -> {
+ (Rational(-2) ** bignum_value)
+ }.should raise_error(ArgumentError)
+ -> {
+ (Rational(fixnum_min) ** bignum_value)
+ }.should raise_error(ArgumentError)
+ end
+
+ it "raises an ArgumentError when self is < -1 and the exponent is negative" do
+ -> {
+ (Rational(-2) ** -bignum_value)
+ }.should raise_error(ArgumentError)
+ -> {
+ (Rational(fixnum_min) ** -bignum_value)
+ }.should raise_error(ArgumentError)
+ end
+ end
+
+ # Fails on linux due to pow() bugs in glibc: http://sources.redhat.com/bugzilla/show_bug.cgi?id=3866
+ platform_is_not :linux do
+ ruby_version_is ""..."3.4" do
+ it "returns positive Infinity when self < -1" do
+ -> {
+ (Rational(-2) ** bignum_value).infinite?.should == 1
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ -> {
+ (Rational(-2) ** (bignum_value + 1)).infinite?.should == 1
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ -> {
+ (Rational(fixnum_min) ** bignum_value).infinite?.should == 1
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ end
+
+ it "returns 0.0 when self is < -1 and the exponent is negative" do
+ -> {
+ (Rational(-2) ** -bignum_value).should eql(0.0)
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ -> {
+ (Rational(fixnum_min) ** -bignum_value).should eql(0.0)
+ }.should complain(/warning: in a\*\*b, b may be too big/)
+ end
+ end
+ end
+ end
+
+ describe "when passed Float" do
+ it "returns self converted to Float and raised to the passed argument" do
+ (Rational(3, 1) ** 3.0).should eql(27.0)
+ (Rational(3, 1) ** 1.5).should be_close(5.19615242270663, TOLERANCE)
+ (Rational(3, 1) ** -1.5).should be_close(0.192450089729875, TOLERANCE)
+ end
+
+ it "returns a complex number if self is negative and the passed argument is not 0" do
+ (Rational(-3, 2) ** 1.5).should be_close(Complex(0.0, -1.8371173070873836), TOLERANCE)
+ (Rational(3, -2) ** 1.5).should be_close(Complex(0.0, -1.8371173070873836), TOLERANCE)
+ (Rational(3, -2) ** -1.5).should be_close(Complex(0.0, 0.5443310539518174), TOLERANCE)
+ end
+
+ it "returns Complex(1.0) when the passed argument is 0.0" do
+ (Rational(3, 4) ** 0.0).should == Complex(1.0)
+ (Rational(-3, 4) ** 0.0).should == Complex(1.0)
+ (Rational(-3, 4) ** 0.0).should == Complex(1.0)
+ end
+ end
+
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational ** obj
+ end
+
+ it "calls #** on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:**).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ (rational ** obj).should == :result
+ end
+
+ it "raises ZeroDivisionError for Rational(0, 1) passed a negative Integer" do
+ [-1, -4, -9999].each do |exponent|
+ -> { Rational(0, 1) ** exponent }.should raise_error(ZeroDivisionError, "divided by 0")
+ end
+ end
+
+ it "raises ZeroDivisionError for Rational(0, 1) passed a negative Rational with denominator 1" do
+ [Rational(-1, 1), Rational(-3, 1)].each do |exponent|
+ -> { Rational(0, 1) ** exponent }.should raise_error(ZeroDivisionError, "divided by 0")
+ end
+ end
+
+ # #7513
+ it "raises ZeroDivisionError for Rational(0, 1) passed a negative Rational" do
+ -> { Rational(0, 1) ** Rational(-3, 2) }.should raise_error(ZeroDivisionError, "divided by 0")
+ end
+
+ it "returns Infinity for Rational(0, 1) passed a negative Float" do
+ [-1.0, -3.0, -3.14].each do |exponent|
+ (Rational(0, 1) ** exponent).infinite?.should == 1
+ end
+ end
end
diff --git a/spec/ruby/core/rational/fdiv_spec.rb b/spec/ruby/core/rational/fdiv_spec.rb
index b75f39abd5..118d93dbe7 100644
--- a/spec/ruby/core/rational/fdiv_spec.rb
+++ b/spec/ruby/core/rational/fdiv_spec.rb
@@ -1,6 +1,5 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/fdiv'
describe "Rational#fdiv" do
- it_behaves_like :rational_fdiv, :fdiv
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/core/rational/fixtures/rational.rb b/spec/ruby/core/rational/fixtures/rational.rb
new file mode 100644
index 0000000000..844d7f9820
--- /dev/null
+++ b/spec/ruby/core/rational/fixtures/rational.rb
@@ -0,0 +1,14 @@
+module RationalSpecs
+ class SubNumeric < Numeric
+ def initialize(value)
+ @value = Rational(value)
+ end
+
+ def to_r
+ @value
+ end
+ end
+
+ class CoerceError < StandardError
+ end
+end
diff --git a/spec/ruby/core/rational/floor_spec.rb b/spec/ruby/core/rational/floor_spec.rb
index 70db0499d0..8068aaf119 100644
--- a/spec/ruby/core/rational/floor_spec.rb
+++ b/spec/ruby/core/rational/floor_spec.rb
@@ -1,6 +1,45 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/floor'
describe "Rational#floor" do
- it_behaves_like :rational_floor, :floor
+ before do
+ @rational = Rational(2200, 7)
+ end
+
+ describe "with no arguments (precision = 0)" do
+ it "returns an integer" do
+ @rational.floor.should be_kind_of(Integer)
+ end
+
+ it "returns the truncated value toward negative infinity" do
+ @rational.floor.should == 314
+ Rational(1, 2).floor.should == 0
+ Rational(-1, 2).floor.should == -1
+ end
+ end
+
+ describe "with a precision < 0" do
+ it "returns an integer" do
+ @rational.floor(-2).should be_kind_of(Integer)
+ @rational.floor(-1).should be_kind_of(Integer)
+ end
+
+ it "moves the truncation point n decimal places left" do
+ @rational.floor(-3).should == 0
+ @rational.floor(-2).should == 300
+ @rational.floor(-1).should == 310
+ end
+ end
+
+ describe "with a precision > 0" do
+ it "returns a Rational" do
+ @rational.floor(1).should be_kind_of(Rational)
+ @rational.floor(2).should be_kind_of(Rational)
+ end
+
+ it "moves the truncation point n decimal places right" do
+ @rational.floor(1).should == Rational(1571, 5)
+ @rational.floor(2).should == Rational(7857, 25)
+ @rational.floor(3).should == Rational(62857, 200)
+ end
+ end
end
diff --git a/spec/ruby/core/rational/hash_spec.rb b/spec/ruby/core/rational/hash_spec.rb
index 7e8d30049b..528638056a 100644
--- a/spec/ruby/core/rational/hash_spec.rb
+++ b/spec/ruby/core/rational/hash_spec.rb
@@ -1,6 +1,9 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/hash'
describe "Rational#hash" do
- it_behaves_like :rational_hash, :hash
+ # BUG: Rational(2, 3).hash == Rational(3, 2).hash
+ it "is static" do
+ Rational(2, 3).hash.should == Rational(2, 3).hash
+ Rational(2, 4).hash.should_not == Rational(2, 3).hash
+ end
end
diff --git a/spec/ruby/core/rational/inspect_spec.rb b/spec/ruby/core/rational/inspect_spec.rb
index 2cbf6cadc1..edc5cffee9 100644
--- a/spec/ruby/core/rational/inspect_spec.rb
+++ b/spec/ruby/core/rational/inspect_spec.rb
@@ -1,6 +1,14 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/inspect'
describe "Rational#inspect" do
- it_behaves_like :rational_inspect, :inspect
+ it "returns a string representation of self" do
+ Rational(3, 4).inspect.should == "(3/4)"
+ Rational(-5, 8).inspect.should == "(-5/8)"
+ Rational(-1, -2).inspect.should == "(1/2)"
+
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ Rational(bignum_value, 1).inspect.should == "(#{bignum_value}/1)"
+ end
+ end
end
diff --git a/spec/ruby/core/rational/magnitude_spec.rb b/spec/ruby/core/rational/magnitude_spec.rb
index 27d9af6a81..f5f667edb1 100644
--- a/spec/ruby/core/rational/magnitude_spec.rb
+++ b/spec/ruby/core/rational/magnitude_spec.rb
@@ -1,5 +1,5 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/abs'
+require_relative 'shared/abs'
describe "Rational#abs" do
it_behaves_like :rational_abs, :magnitude
diff --git a/spec/ruby/core/rational/minus_spec.rb b/spec/ruby/core/rational/minus_spec.rb
index a61b62ebe6..8aee85f9dd 100644
--- a/spec/ruby/core/rational/minus_spec.rb
+++ b/spec/ruby/core/rational/minus_spec.rb
@@ -1,5 +1,5 @@
require_relative '../../spec_helper'
-require_relative '../../shared/rational/arithmetic_exception_in_coerce'
+require_relative 'shared/arithmetic_exception_in_coerce'
describe "Rational#-" do
it_behaves_like :rational_arithmetic_exception_in_coerce, :-
diff --git a/spec/ruby/core/rational/modulo_spec.rb b/spec/ruby/core/rational/modulo_spec.rb
index 7a60c176ac..23ed93e118 100644
--- a/spec/ruby/core/rational/modulo_spec.rb
+++ b/spec/ruby/core/rational/modulo_spec.rb
@@ -1,6 +1,43 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/modulo'
describe "Rational#%" do
- it_behaves_like :rational_modulo, :%
+ it "returns the remainder when this value is divided by other" do
+ (Rational(2, 3) % Rational(2, 3)).should == Rational(0, 1)
+ (Rational(4, 3) % Rational(2, 3)).should == Rational(0, 1)
+ (Rational(2, -3) % Rational(-2, 3)).should == Rational(0, 1)
+ (Rational(0, -1) % -1).should == Rational(0, 1)
+
+ (Rational(7, 4) % Rational(1, 2)).should == Rational(1, 4)
+ (Rational(7, 4) % 1).should == Rational(3, 4)
+ (Rational(7, 4) % Rational(1, 7)).should == Rational(1, 28)
+
+ (Rational(3, 4) % -1).should == Rational(-1, 4)
+ (Rational(1, -5) % -1).should == Rational(-1, 5)
+ end
+
+ it "returns a Float value when the argument is Float" do
+ (Rational(7, 4) % 1.0).should be_kind_of(Float)
+ (Rational(7, 4) % 1.0).should == 0.75
+ (Rational(7, 4) % 0.26).should be_close(0.19, 0.0001)
+ end
+
+ it "raises ZeroDivisionError on zero denominator" do
+ -> {
+ Rational(3, 5) % Rational(0, 1)
+ }.should raise_error(ZeroDivisionError)
+
+ -> {
+ Rational(0, 1) % Rational(0, 1)
+ }.should raise_error(ZeroDivisionError)
+
+ -> {
+ Rational(3, 5) % 0
+ }.should raise_error(ZeroDivisionError)
+ end
+
+ it "raises a ZeroDivisionError when the argument is 0.0" do
+ -> {
+ Rational(3, 5) % 0.0
+ }.should raise_error(ZeroDivisionError)
+ end
end
diff --git a/spec/ruby/core/rational/multiply_spec.rb b/spec/ruby/core/rational/multiply_spec.rb
index 7413376bb1..87fb4de2b4 100644
--- a/spec/ruby/core/rational/multiply_spec.rb
+++ b/spec/ruby/core/rational/multiply_spec.rb
@@ -1,20 +1,65 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/multiply'
-require_relative '../../shared/rational/arithmetic_exception_in_coerce'
+require_relative 'shared/arithmetic_exception_in_coerce'
describe "Rational#*" do
- it_behaves_like :rational_multiply, :*
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational * obj
+ end
+
+ it "calls #* on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:*).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ (rational * obj).should == :result
+ end
+
it_behaves_like :rational_arithmetic_exception_in_coerce, :*
end
describe "Rational#* passed a Rational" do
- it_behaves_like :rational_multiply_rat, :*
+ it "returns self divided by other as a Rational" do
+ (Rational(3, 4) * Rational(3, 4)).should eql(Rational(9, 16))
+ (Rational(2, 4) * Rational(1, 4)).should eql(Rational(1, 8))
+
+ (Rational(3, 4) * Rational(0, 1)).should eql(Rational(0, 4))
+ end
end
describe "Rational#* passed a Float" do
- it_behaves_like :rational_multiply_float, :*
+ it "returns self divided by other as a Float" do
+ (Rational(3, 4) * 0.75).should eql(0.5625)
+ (Rational(3, 4) * 0.25).should eql(0.1875)
+ (Rational(3, 4) * 0.3).should be_close(0.225, TOLERANCE)
+
+ (Rational(-3, 4) * 0.3).should be_close(-0.225, TOLERANCE)
+ (Rational(3, -4) * 0.3).should be_close(-0.225, TOLERANCE)
+ (Rational(3, 4) * -0.3).should be_close(-0.225, TOLERANCE)
+
+ (Rational(3, 4) * 0.0).should eql(0.0)
+ (Rational(-3, -4) * 0.0).should eql(0.0)
+
+ (Rational(-3, 4) * 0.0).should eql(0.0)
+ (Rational(3, -4) * 0.0).should eql(0.0)
+ end
end
describe "Rational#* passed an Integer" do
- it_behaves_like :rational_multiply_int, :*
+ it "returns self divided by other as a Rational" do
+ (Rational(3, 4) * 2).should eql(Rational(3, 2))
+ (Rational(2, 4) * 2).should eql(Rational(1, 1))
+ (Rational(6, 7) * -2).should eql(Rational(-12, 7))
+
+ (Rational(3, 4) * 0).should eql(Rational(0, 4))
+ end
end
diff --git a/spec/ruby/core/rational/numerator_spec.rb b/spec/ruby/core/rational/numerator_spec.rb
index 6f9a9c0e3b..2b9fe2ff5c 100644
--- a/spec/ruby/core/rational/numerator_spec.rb
+++ b/spec/ruby/core/rational/numerator_spec.rb
@@ -1,6 +1,10 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/numerator'
describe "Rational#numerator" do
- it_behaves_like :rational_numerator, :numerator
+ it "returns the numerator" do
+ Rational(3, 4).numerator.should equal(3)
+ Rational(3, -4).numerator.should equal(-3)
+
+ Rational(bignum_value, 1).numerator.should == bignum_value
+ end
end
diff --git a/spec/ruby/core/rational/plus_spec.rb b/spec/ruby/core/rational/plus_spec.rb
index 67c0ff63d2..01df5f6719 100644
--- a/spec/ruby/core/rational/plus_spec.rb
+++ b/spec/ruby/core/rational/plus_spec.rb
@@ -1,19 +1,50 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/plus'
-require_relative '../../shared/rational/arithmetic_exception_in_coerce'
+require_relative 'shared/arithmetic_exception_in_coerce'
describe "Rational#+" do
- it_behaves_like :rational_plus, :+
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational + obj
+ end
+
+ it "calls #+ on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:+).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ (rational + obj).should == :result
+ end
+
it_behaves_like :rational_arithmetic_exception_in_coerce, :+
end
describe "Rational#+ with a Rational" do
- it_behaves_like :rational_plus_rat, :+
+ it "returns the result of subtracting other from self as a Rational" do
+ (Rational(3, 4) + Rational(0, 1)).should eql(Rational(3, 4))
+ (Rational(3, 4) + Rational(1, 4)).should eql(Rational(1, 1))
+
+ (Rational(3, 4) + Rational(2, 1)).should eql(Rational(11, 4))
+ end
end
describe "Rational#+ with a Float" do
- it_behaves_like :rational_plus_float, :+
+ it "returns the result of subtracting other from self as a Float" do
+ (Rational(3, 4) + 0.2).should eql(0.95)
+ (Rational(3, 4) + 2.5).should eql(3.25)
+ end
end
describe "Rational#+ with an Integer" do
- it_behaves_like :rational_plus_int, :+
+ it "returns the result of subtracting other from self as a Rational" do
+ (Rational(3, 4) + 1).should eql(Rational(7, 4))
+ (Rational(3, 4) + 2).should eql(Rational(11, 4))
+ end
end
diff --git a/spec/ruby/core/rational/quo_spec.rb b/spec/ruby/core/rational/quo_spec.rb
index 181f091f7c..907898ad34 100644
--- a/spec/ruby/core/rational/quo_spec.rb
+++ b/spec/ruby/core/rational/quo_spec.rb
@@ -1,6 +1,25 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/divide'
describe "Rational#quo" do
- it_behaves_like :rational_divide, :quo
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational.quo(obj)
+ end
+
+ it "calls #/ on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:/).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ rational.quo(obj).should == :result
+ end
end
diff --git a/spec/ruby/core/rational/remainder_spec.rb b/spec/ruby/core/rational/remainder_spec.rb
index 1c0035e5f4..86ba4674e6 100644
--- a/spec/ruby/core/rational/remainder_spec.rb
+++ b/spec/ruby/core/rational/remainder_spec.rb
@@ -1,6 +1,5 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/remainder'
describe "Rational#remainder" do
- it_behaves_like :rational_remainder, :remainder
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/core/rational/round_spec.rb b/spec/ruby/core/rational/round_spec.rb
index 36614a552d..ac3dcafe7b 100644
--- a/spec/ruby/core/rational/round_spec.rb
+++ b/spec/ruby/core/rational/round_spec.rb
@@ -1,6 +1,106 @@
require_relative '../../spec_helper'
-require_relative '../../shared/rational/round'
describe "Rational#round" do
- it_behaves_like :rational_round, :round
+ before do
+ @rational = Rational(2200, 7)
+ end
+
+ describe "with no arguments (precision = 0)" do
+ it "returns an integer" do
+ @rational.round.should be_kind_of(Integer)
+ Rational(0, 1).round(0).should be_kind_of(Integer)
+ Rational(124, 1).round(0).should be_kind_of(Integer)
+ end
+
+ it "returns the truncated value toward the nearest integer" do
+ @rational.round.should == 314
+ Rational(0, 1).round(0).should == 0
+ Rational(2, 1).round(0).should == 2
+ end
+
+ it "returns the rounded value toward the nearest integer" do
+ Rational(1, 2).round.should == 1
+ Rational(-1, 2).round.should == -1
+ Rational(3, 2).round.should == 2
+ Rational(-3, 2).round.should == -2
+ Rational(5, 2).round.should == 3
+ Rational(-5, 2).round.should == -3
+ end
+ end
+
+ describe "with a precision < 0" do
+ it "returns an integer" do
+ @rational.round(-2).should be_kind_of(Integer)
+ @rational.round(-1).should be_kind_of(Integer)
+ Rational(0, 1).round(-1).should be_kind_of(Integer)
+ Rational(2, 1).round(-1).should be_kind_of(Integer)
+ end
+
+ it "moves the truncation point n decimal places left" do
+ @rational.round(-3).should == 0
+ @rational.round(-2).should == 300
+ @rational.round(-1).should == 310
+ end
+ end
+
+ describe "with a precision > 0" do
+ it "returns a Rational" do
+ @rational.round(1).should be_kind_of(Rational)
+ @rational.round(2).should be_kind_of(Rational)
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ Rational(0, 1).round(1).should be_kind_of(Rational)
+ Rational(2, 1).round(1).should be_kind_of(Rational)
+ end
+ end
+
+ it "moves the truncation point n decimal places right" do
+ @rational.round(1).should == Rational(3143, 10)
+ @rational.round(2).should == Rational(31429, 100)
+ @rational.round(3).should == Rational(157143, 500)
+ Rational(0, 1).round(1).should == Rational(0, 1)
+ Rational(2, 1).round(1).should == Rational(2, 1)
+ end
+
+ it "doesn't alter the value if the precision is too great" do
+ Rational(3, 2).round(10).should == Rational(3, 2).round(20)
+ end
+
+ # #6605
+ it "doesn't fail when rounding to an absurdly large positive precision" do
+ Rational(3, 2).round(2_097_171).should == Rational(3, 2)
+ end
+ end
+
+ describe "with half option" do
+ it "returns an Integer when precision is not passed" do
+ Rational(10, 4).round(half: nil).should == 3
+ Rational(10, 4).round(half: :up).should == 3
+ Rational(10, 4).round(half: :down).should == 2
+ Rational(10, 4).round(half: :even).should == 2
+ Rational(-10, 4).round(half: nil).should == -3
+ Rational(-10, 4).round(half: :up).should == -3
+ Rational(-10, 4).round(half: :down).should == -2
+ Rational(-10, 4).round(half: :even).should == -2
+ end
+
+ it "returns a Rational when the precision is greater than 0" do
+ Rational(25, 100).round(1, half: nil).should == Rational(3, 10)
+ Rational(25, 100).round(1, half: :up).should == Rational(3, 10)
+ Rational(25, 100).round(1, half: :down).should == Rational(1, 5)
+ Rational(25, 100).round(1, half: :even).should == Rational(1, 5)
+ Rational(35, 100).round(1, half: nil).should == Rational(2, 5)
+ Rational(35, 100).round(1, half: :up).should == Rational(2, 5)
+ Rational(35, 100).round(1, half: :down).should == Rational(3, 10)
+ Rational(35, 100).round(1, half: :even).should == Rational(2, 5)
+ Rational(-25, 100).round(1, half: nil).should == Rational(-3, 10)
+ Rational(-25, 100).round(1, half: :up).should == Rational(-3, 10)
+ Rational(-25, 100).round(1, half: :down).should == Rational(-1, 5)
+ Rational(-25, 100).round(1, half: :even).should == Rational(-1, 5)
+ end
+
+ it "raise for a non-existent round mode" do
+ -> { Rational(10, 4).round(half: :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode: nonsense")
+ end
+ end
end
diff --git a/spec/ruby/core/rational/shared/abs.rb b/spec/ruby/core/rational/shared/abs.rb
new file mode 100644
index 0000000000..3d64bcc1a0
--- /dev/null
+++ b/spec/ruby/core/rational/shared/abs.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+
+describe :rational_abs, shared: true do
+ it "returns self's absolute value" do
+ Rational(3, 4).send(@method).should == Rational(3, 4)
+ Rational(-3, 4).send(@method).should == Rational(3, 4)
+ Rational(3, -4).send(@method).should == Rational(3, 4)
+
+ Rational(bignum_value, -bignum_value).send(@method).should == Rational(bignum_value, bignum_value)
+ end
+end
diff --git a/spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb b/spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb
new file mode 100644
index 0000000000..f4cf70d147
--- /dev/null
+++ b/spec/ruby/core/rational/shared/arithmetic_exception_in_coerce.rb
@@ -0,0 +1,11 @@
+require_relative '../fixtures/rational'
+
+describe :rational_arithmetic_exception_in_coerce, shared: true do
+ it "does not rescue exception raised in other#coerce" do
+ b = mock("numeric with failed #coerce")
+ b.should_receive(:coerce).and_raise(RationalSpecs::CoerceError)
+
+ # e.g. Rational(3, 4) + b
+ -> { Rational(3, 4).send(@method, b) }.should raise_error(RationalSpecs::CoerceError)
+ end
+end
diff --git a/spec/ruby/core/rational/to_f_spec.rb b/spec/ruby/core/rational/to_f_spec.rb
index a9cd1be3b5..d0da49d377 100644
--- a/spec/ruby/core/rational/to_f_spec.rb
+++ b/spec/ruby/core/rational/to_f_spec.rb
@@ -1,6 +1,16 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/to_f'
describe "Rational#to_f" do
- it_behaves_like :rational_to_f, :to_f
+ it "returns self converted to a Float" do
+ Rational(3, 4).to_f.should eql(0.75)
+ Rational(3, -4).to_f.should eql(-0.75)
+ Rational(-1, 4).to_f.should eql(-0.25)
+ Rational(-1, -4).to_f.should eql(0.25)
+ end
+
+ it "converts to a Float for large numerator and denominator" do
+ num = 1000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146010000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146010000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146009
+ den = 2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ Rational(num, den).to_f.should == 500.0
+ end
end
diff --git a/spec/ruby/core/rational/to_i_spec.rb b/spec/ruby/core/rational/to_i_spec.rb
index 22cf02b4da..520a380b2a 100644
--- a/spec/ruby/core/rational/to_i_spec.rb
+++ b/spec/ruby/core/rational/to_i_spec.rb
@@ -1,6 +1,12 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/to_i'
describe "Rational#to_i" do
- it_behaves_like :rational_to_i, :to_i
+ it "converts self to an Integer by truncation" do
+ Rational(7, 4).to_i.should eql(1)
+ Rational(11, 4).to_i.should eql(2)
+ end
+
+ it "converts self to an Integer by truncation" do
+ Rational(-7, 4).to_i.should eql(-1)
+ end
end
diff --git a/spec/ruby/core/rational/to_r_spec.rb b/spec/ruby/core/rational/to_r_spec.rb
index 03f204daf1..34f16d7890 100644
--- a/spec/ruby/core/rational/to_r_spec.rb
+++ b/spec/ruby/core/rational/to_r_spec.rb
@@ -1,8 +1,13 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/to_r'
describe "Rational#to_r" do
- it_behaves_like :rational_to_r, :to_r
+ it "returns self" do
+ a = Rational(3, 4)
+ a.to_r.should equal(a)
+
+ a = Rational(bignum_value, 4)
+ a.to_r.should equal(a)
+ end
it "raises TypeError trying to convert BasicObject" do
obj = BasicObject.new
diff --git a/spec/ruby/core/rational/to_s_spec.rb b/spec/ruby/core/rational/to_s_spec.rb
index 5d90c7d80b..24e30778e5 100644
--- a/spec/ruby/core/rational/to_s_spec.rb
+++ b/spec/ruby/core/rational/to_s_spec.rb
@@ -1,6 +1,14 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/to_s'
describe "Rational#to_s" do
- it_behaves_like :rational_to_s, :to_s
+ it "returns a string representation of self" do
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ Rational(1, 1).to_s.should == "1/1"
+ Rational(2, 1).to_s.should == "2/1"
+ end
+ Rational(1, 2).to_s.should == "1/2"
+ Rational(-1, 3).to_s.should == "-1/3"
+ Rational(1, -3).to_s.should == "-1/3"
+ end
end
diff --git a/spec/ruby/core/rational/truncate_spec.rb b/spec/ruby/core/rational/truncate_spec.rb
index 47a7cdf17c..728fca34ea 100644
--- a/spec/ruby/core/rational/truncate_spec.rb
+++ b/spec/ruby/core/rational/truncate_spec.rb
@@ -1,6 +1,71 @@
require_relative "../../spec_helper"
-require_relative '../../shared/rational/truncate'
describe "Rational#truncate" do
- it_behaves_like :rational_truncate, :truncate
+ before do
+ @rational = Rational(2200, 7)
+ end
+
+ describe "with no arguments (precision = 0)" do
+ it "returns an integer" do
+ @rational.truncate.should be_kind_of(Integer)
+ end
+
+ it "returns the truncated value toward 0" do
+ @rational.truncate.should == 314
+ Rational(1, 2).truncate.should == 0
+ Rational(-1, 2).truncate.should == 0
+ end
+ end
+
+ describe "with an explicit precision = 0" do
+ it "returns an integer" do
+ @rational.truncate(0).should be_kind_of(Integer)
+ end
+
+ it "returns the truncated value toward 0" do
+ @rational.truncate(0).should == 314
+ Rational(1, 2).truncate(0).should == 0
+ Rational(-1, 2).truncate(0).should == 0
+ end
+ end
+
+ describe "with a precision < 0" do
+ it "returns an integer" do
+ @rational.truncate(-2).should be_kind_of(Integer)
+ @rational.truncate(-1).should be_kind_of(Integer)
+ end
+
+ it "moves the truncation point n decimal places left" do
+ @rational.truncate(-3).should == 0
+ @rational.truncate(-2).should == 300
+ @rational.truncate(-1).should == 310
+ end
+ end
+
+ describe "with a precision > 0" do
+ it "returns a Rational" do
+ @rational.truncate(1).should be_kind_of(Rational)
+ @rational.truncate(2).should be_kind_of(Rational)
+ end
+
+ it "moves the truncation point n decimal places right" do
+ @rational.truncate(1).should == Rational(1571, 5)
+ @rational.truncate(2).should == Rational(7857, 25)
+ @rational.truncate(3).should == Rational(62857, 200)
+ end
+ end
+
+ describe "with an invalid value for precision" do
+ it "raises a TypeError" do
+ -> { @rational.truncate(nil) }.should raise_error(TypeError, "not an integer")
+ -> { @rational.truncate(1.0) }.should raise_error(TypeError, "not an integer")
+ -> { @rational.truncate('') }.should raise_error(TypeError, "not an integer")
+ end
+
+ it "does not call to_int on the argument" do
+ object = Object.new
+ object.should_not_receive(:to_int)
+ -> { @rational.truncate(object) }.should raise_error(TypeError, "not an integer")
+ end
+ end
end
diff --git a/spec/ruby/core/refinement/append_features_spec.rb b/spec/ruby/core/refinement/append_features_spec.rb
index fb84f245bd..f7e5f32bc1 100644
--- a/spec/ruby/core/refinement/append_features_spec.rb
+++ b/spec/ruby/core/refinement/append_features_spec.rb
@@ -1,20 +1,18 @@
require_relative '../../spec_helper'
describe "Refinement#append_features" do
- ruby_version_is "3.2" do
- it "is not defined" do
- Refinement.should_not have_private_instance_method(:append_features)
- end
+ it "is not defined" do
+ Refinement.should_not have_private_instance_method(:append_features)
+ end
- it "is not called by Module#include" do
- c = Class.new
- Module.new do
- refine c do
- called = false
- define_method(:append_features){called = true}
- proc{c.include(self)}.should raise_error(TypeError)
- called.should == false
- end
+ it "is not called by Module#include" do
+ c = Class.new
+ Module.new do
+ refine c do
+ called = false
+ define_method(:append_features){called = true}
+ proc{c.include(self)}.should raise_error(TypeError)
+ called.should == false
end
end
end
diff --git a/spec/ruby/core/refinement/extend_object_spec.rb b/spec/ruby/core/refinement/extend_object_spec.rb
index 6c2a0af4f3..4da8b359cc 100644
--- a/spec/ruby/core/refinement/extend_object_spec.rb
+++ b/spec/ruby/core/refinement/extend_object_spec.rb
@@ -1,22 +1,20 @@
require_relative '../../spec_helper'
describe "Refinement#extend_object" do
- ruby_version_is "3.2" do
- it "is not defined" do
- Refinement.should_not have_private_instance_method(:extend_object)
- end
+ it "is not defined" do
+ Refinement.should_not have_private_instance_method(:extend_object)
+ end
- it "is not called by Object#extend" do
- c = Class.new
- Module.new do
- refine c do
- called = false
- define_method(:extend_object) { called = true }
- -> {
- c.extend(self)
- }.should raise_error(TypeError)
- called.should == false
- end
+ it "is not called by Object#extend" do
+ c = Class.new
+ Module.new do
+ refine c do
+ called = false
+ define_method(:extend_object) { called = true }
+ -> {
+ c.extend(self)
+ }.should raise_error(TypeError)
+ called.should == false
end
end
end
diff --git a/spec/ruby/core/refinement/import_methods_spec.rb b/spec/ruby/core/refinement/import_methods_spec.rb
index 614c54dff8..13c0b1004c 100644
--- a/spec/ruby/core/refinement/import_methods_spec.rb
+++ b/spec/ruby/core/refinement/import_methods_spec.rb
@@ -2,137 +2,76 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Refinement#import_methods" do
- ruby_version_is "3.1" do
- context "when methods are defined in Ruby code" do
- it "imports methods" do
- str_utils = Module.new do
- def indent(level)
- " " * level + self
- end
- end
-
- Module.new do
- refine String do
- import_methods str_utils
- "foo".indent(3).should == " foo"
- end
+ context "when methods are defined in Ruby code" do
+ it "imports methods" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
end
end
- it "throws an exception when argument is not a module" do
- Module.new do
- refine String do
- -> {
- import_methods Integer
- }.should raise_error(TypeError, "wrong argument type Class (expected Module)")
- end
+ Module.new do
+ refine String do
+ import_methods str_utils
+ "foo".indent(3).should == " foo"
end
end
+ end
- it "imports methods from multiple modules" do
- str_utils = Module.new do
- def indent(level)
- " " * level + self
- end
- end
-
- str_utils_fancy = Module.new do
- def indent_star(level)
- "*" * level + self
- end
- end
-
- Module.new do
- refine String do
- import_methods str_utils, str_utils_fancy
- "foo".indent(3).should == " foo"
- "foo".indent_star(3).should == "***foo"
- end
+ it "throws an exception when argument is not a module" do
+ Module.new do
+ refine String do
+ -> {
+ import_methods Integer
+ }.should raise_error(TypeError, "wrong argument type Class (expected Module)")
end
end
+ end
- it "imports a method defined in the last module if method with same name is defined in multiple modules" do
- str_utils = Module.new do
- def indent(level)
- " " * level + self
- end
- end
-
- str_utils_fancy = Module.new do
- def indent(level)
- "*" * level + self
- end
- end
-
- Module.new do
- refine String do
- import_methods str_utils, str_utils_fancy
- "foo".indent(3).should == "***foo"
- end
+ it "imports methods from multiple modules" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
end
end
- it "still imports methods of modules listed before a module that contains method not defined in Ruby" do
- str_utils = Module.new do
- def indent(level)
- " " * level + self
- end
- end
-
- string_refined = Module.new do
- refine String do
- -> {
- import_methods str_utils, Kernel
- }.should raise_error(ArgumentError)
- end
+ str_utils_fancy = Module.new do
+ def indent_star(level)
+ "*" * level + self
end
+ end
- Module.new do
- using string_refined
+ Module.new do
+ refine String do
+ import_methods str_utils, str_utils_fancy
"foo".indent(3).should == " foo"
+ "foo".indent_star(3).should == "***foo"
end
end
end
- it "warns if a module includes/prepends some other module" do
- module1 = Module.new do
- end
-
- module2 = Module.new do
- include module1
- end
-
- Module.new do
- refine String do
- -> {
- import_methods module2
- }.should complain(/warning: #<Module:\w*> has ancestors, but Refinement#import_methods doesn't import their methods/)
+ it "imports a method defined in the last module if method with same name is defined in multiple modules" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
end
end
- Module.new do
- refine String do
- -> {
- import_methods RefinementSpec::ModuleWithAncestors
- }.should complain(/warning: RefinementSpec::ModuleWithAncestors has ancestors, but Refinement#import_methods doesn't import their methods/)
+ str_utils_fancy = Module.new do
+ def indent(level)
+ "*" * level + self
end
end
- end
- it "doesn't import methods from included/prepended modules" do
Module.new do
refine String do
- suppress_warning { import_methods RefinementSpec::ModuleWithAncestors }
+ import_methods str_utils, str_utils_fancy
+ "foo".indent(3).should == "***foo"
end
-
- using self
- -> {
- "foo".indent(3)
- }.should raise_error(NoMethodError, /undefined method [`']indent' for ("foo":String|an instance of String)/)
end
end
- it "doesn't import any methods if one of the arguments is not a module" do
+ it "still imports methods of modules listed before a module that contains method not defined in Ruby" do
str_utils = Module.new do
def indent(level)
" " * level + self
@@ -142,126 +81,185 @@ describe "Refinement#import_methods" do
string_refined = Module.new do
refine String do
-> {
- import_methods str_utils, Integer
- }.should raise_error(TypeError)
+ import_methods str_utils, Kernel
+ }.should raise_error(ArgumentError)
end
end
Module.new do
using string_refined
+ "foo".indent(3).should == " foo"
+ end
+ end
+ end
+
+ it "warns if a module includes/prepends some other module" do
+ module1 = Module.new do
+ end
+
+ module2 = Module.new do
+ include module1
+ end
+
+ Module.new do
+ refine String do
-> {
- "foo".indent(3)
- }.should raise_error(NoMethodError)
+ import_methods module2
+ }.should complain(/warning: #<Module:\w*> has ancestors, but Refinement#import_methods doesn't import their methods/)
end
end
- it "imports methods from multiple modules so that methods see other's module's methods" do
- str_utils = Module.new do
- def indent(level)
- " " * level + self
- end
+ Module.new do
+ refine String do
+ -> {
+ import_methods RefinementSpec::ModuleWithAncestors
+ }.should complain(/warning: RefinementSpec::ModuleWithAncestors has ancestors, but Refinement#import_methods doesn't import their methods/)
+ end
+ end
+ end
+
+ it "doesn't import methods from included/prepended modules" do
+ Module.new do
+ refine String do
+ suppress_warning { import_methods RefinementSpec::ModuleWithAncestors }
end
- str_utils_normal = Module.new do
- def indent_normal(level)
- self.indent(level)
- end
+ using self
+ -> {
+ "foo".indent(3)
+ }.should raise_error(NoMethodError, /undefined method [`']indent' for ("foo":String|an instance of String)/)
+ end
+ end
+
+ it "doesn't import any methods if one of the arguments is not a module" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
end
+ end
- Module.new do
- refine String do
- import_methods str_utils, str_utils_normal
- end
+ string_refined = Module.new do
+ refine String do
+ -> {
+ import_methods str_utils, Integer
+ }.should raise_error(TypeError)
+ end
+ end
- using self
- "foo".indent_normal(3).should == " foo"
+ Module.new do
+ using string_refined
+ -> {
+ "foo".indent(3)
+ }.should raise_error(NoMethodError)
+ end
+ end
+
+ it "imports methods from multiple modules so that methods see other's module's methods" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
end
end
- it "imports methods from module so that methods can see each other" do
- str_utils = Module.new do
- def indent(level)
- " " * level + self
- end
+ str_utils_normal = Module.new do
+ def indent_normal(level)
+ self.indent(level)
+ end
+ end
- def indent_with_dot(level)
- self.indent(level) + "."
- end
+ Module.new do
+ refine String do
+ import_methods str_utils, str_utils_normal
end
- Module.new do
- refine String do
- import_methods str_utils
- end
+ using self
+ "foo".indent_normal(3).should == " foo"
+ end
+ end
- using self
- "foo".indent_with_dot(3).should == " foo."
+ it "imports methods from module so that methods can see each other" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+
+ def indent_with_dot(level)
+ self.indent(level) + "."
end
end
- it "doesn't import module's class methods" do
- str_utils = Module.new do
- def self.indent(level)
- " " * level + self
- end
+ Module.new do
+ refine String do
+ import_methods str_utils
end
- Module.new do
- refine String do
- import_methods str_utils
- end
+ using self
+ "foo".indent_with_dot(3).should == " foo."
+ end
+ end
- using self
- -> {
- String.indent(3)
- }.should raise_error(NoMethodError, /undefined method [`']indent' for (String:Class|class String)/)
+ it "doesn't import module's class methods" do
+ str_utils = Module.new do
+ def self.indent(level)
+ " " * level + self
end
end
- it "imports module methods with super" do
- class_to_refine = Class.new do
- def foo(number)
- 2 * number
- end
+ Module.new do
+ refine String do
+ import_methods str_utils
end
- extension = Module.new do
- def foo(number)
- super * 2
- end
+ using self
+ -> {
+ String.indent(3)
+ }.should raise_error(NoMethodError, /undefined method [`']indent' for (String:Class|class String)/)
+ end
+ end
+
+ it "imports module methods with super" do
+ class_to_refine = Class.new do
+ def foo(number)
+ 2 * number
end
+ end
- refinement = Module.new do
- refine class_to_refine do
- import_methods extension
- end
+ extension = Module.new do
+ def foo(number)
+ super * 2
end
+ end
- Module.new do
- using refinement
- class_to_refine.new.foo(2).should == 8
+ refinement = Module.new do
+ refine class_to_refine do
+ import_methods extension
end
end
- context "when methods are not defined in Ruby code" do
- it "raises ArgumentError" do
- Module.new do
- refine String do
- -> {
- import_methods Kernel
- }.should raise_error(ArgumentError)
- end
+ Module.new do
+ using refinement
+ class_to_refine.new.foo(2).should == 8
+ end
+ end
+
+ context "when methods are not defined in Ruby code" do
+ it "raises ArgumentError" do
+ Module.new do
+ refine String do
+ -> {
+ import_methods Kernel
+ }.should raise_error(ArgumentError)
end
end
+ end
- it "raises ArgumentError when importing methods from C extension" do
- require 'zlib'
- Module.new do
- refine String do
- -> {
- import_methods Zlib
- }.should raise_error(ArgumentError, /Can't import method which is not defined with Ruby code: Zlib#*/)
- end
+ it "raises ArgumentError when importing methods from C extension" do
+ require 'zlib'
+ Module.new do
+ refine String do
+ -> {
+ import_methods Zlib
+ }.should raise_error(ArgumentError, /Can't import method which is not defined with Ruby code: Zlib#*/)
end
end
end
diff --git a/spec/ruby/core/refinement/include_spec.rb b/spec/ruby/core/refinement/include_spec.rb
index 25a53f0ec7..57451bd9bc 100644
--- a/spec/ruby/core/refinement/include_spec.rb
+++ b/spec/ruby/core/refinement/include_spec.rb
@@ -1,26 +1,12 @@
require_relative '../../spec_helper'
describe "Refinement#include" do
- ruby_version_is "3.1"..."3.2" do
- it "warns about deprecation" do
- Module.new do
- refine String do
- -> {
- include Module.new
- }.should complain(/warning: Refinement#include is deprecated and will be removed in Ruby 3.2/)
- end
- end
- end
- end
-
- ruby_version_is "3.2" do
- it "raises a TypeError" do
- Module.new do
- refine String do
- -> {
- include Module.new
- }.should raise_error(TypeError, "Refinement#include has been removed")
- end
+ it "raises a TypeError" do
+ Module.new do
+ refine String do
+ -> {
+ include Module.new
+ }.should raise_error(TypeError, "Refinement#include has been removed")
end
end
end
diff --git a/spec/ruby/core/refinement/prepend_features_spec.rb b/spec/ruby/core/refinement/prepend_features_spec.rb
index 9fdea199a2..fbc431bbd2 100644
--- a/spec/ruby/core/refinement/prepend_features_spec.rb
+++ b/spec/ruby/core/refinement/prepend_features_spec.rb
@@ -1,20 +1,18 @@
require_relative '../../spec_helper'
describe "Refinement#prepend_features" do
- ruby_version_is "3.2" do
- it "is not defined" do
- Refinement.should_not have_private_instance_method(:prepend_features)
- end
+ it "is not defined" do
+ Refinement.should_not have_private_instance_method(:prepend_features)
+ end
- it "is not called by Module#prepend" do
- c = Class.new
- Module.new do
- refine c do
- called = false
- define_method(:prepend_features){called = true}
- proc{c.prepend(self)}.should raise_error(TypeError)
- called.should == false
- end
+ it "is not called by Module#prepend" do
+ c = Class.new
+ Module.new do
+ refine c do
+ called = false
+ define_method(:prepend_features){called = true}
+ proc{c.prepend(self)}.should raise_error(TypeError)
+ called.should == false
end
end
end
diff --git a/spec/ruby/core/refinement/prepend_spec.rb b/spec/ruby/core/refinement/prepend_spec.rb
index 27b70d392a..64cf7cd17f 100644
--- a/spec/ruby/core/refinement/prepend_spec.rb
+++ b/spec/ruby/core/refinement/prepend_spec.rb
@@ -1,26 +1,12 @@
require_relative '../../spec_helper'
describe "Refinement#prepend" do
- ruby_version_is "3.1"..."3.2" do
- it "warns about deprecation" do
- Module.new do
- refine String do
- -> {
- prepend Module.new
- }.should complain(/warning: Refinement#prepend is deprecated and will be removed in Ruby 3.2/)
- end
- end
- end
- end
-
- ruby_version_is "3.2" do
- it "raises a TypeError" do
- Module.new do
- refine String do
- -> {
- prepend Module.new
- }.should raise_error(TypeError, "Refinement#prepend has been removed")
- end
+ it "raises a TypeError" do
+ Module.new do
+ refine String do
+ -> {
+ prepend Module.new
+ }.should raise_error(TypeError, "Refinement#prepend has been removed")
end
end
end
diff --git a/spec/ruby/core/refinement/refined_class_spec.rb b/spec/ruby/core/refinement/refined_class_spec.rb
index acc6e2cb2b..60a58380cc 100644
--- a/spec/ruby/core/refinement/refined_class_spec.rb
+++ b/spec/ruby/core/refinement/refined_class_spec.rb
@@ -2,7 +2,7 @@ require_relative "../../spec_helper"
require_relative 'shared/target'
describe "Refinement#refined_class" do
- ruby_version_is "3.2"..."3.3" do
+ ruby_version_is ""..."3.3" do
it_behaves_like :refinement_target, :refined_class
end
diff --git a/spec/ruby/core/regexp/compile_spec.rb b/spec/ruby/core/regexp/compile_spec.rb
index c41399cfbb..887c8d77dc 100644
--- a/spec/ruby/core/regexp/compile_spec.rb
+++ b/spec/ruby/core/regexp/compile_spec.rb
@@ -14,6 +14,6 @@ describe "Regexp.compile given a Regexp" do
it_behaves_like :regexp_new_regexp, :compile
end
-describe "Regexp.new given a non-String/Regexp" do
+describe "Regexp.compile given a non-String/Regexp" do
it_behaves_like :regexp_new_non_string_or_regexp, :compile
end
diff --git a/spec/ruby/core/regexp/linear_time_spec.rb b/spec/ruby/core/regexp/linear_time_spec.rb
index 4dc436264f..cf9e73c37c 100644
--- a/spec/ruby/core/regexp/linear_time_spec.rb
+++ b/spec/ruby/core/regexp/linear_time_spec.rb
@@ -1,25 +1,33 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "Regexp.linear_time?" do
- it "returns true if matching can be done in linear time" do
- Regexp.linear_time?(/a/).should == true
- Regexp.linear_time?('a').should == true
- end
+describe "Regexp.linear_time?" do
+ it "returns true if matching can be done in linear time" do
+ Regexp.linear_time?(/a/).should == true
+ Regexp.linear_time?('a').should == true
+ end
- it "return false if matching can't be done in linear time" do
- Regexp.linear_time?(/(a)\1/).should == false
- Regexp.linear_time?("(a)\\1").should == false
- end
+ it "returns true if matching can be done in linear time for a binary Regexp" do
+ Regexp.linear_time?(/[\x80-\xff]/n).should == true
+ end
- it "accepts flags for string argument" do
- Regexp.linear_time?('a', Regexp::IGNORECASE).should == true
- end
+ it "return false if matching can't be done in linear time" do
+ Regexp.linear_time?(/(a)\1/).should == false
+ Regexp.linear_time?("(a)\\1").should == false
+ end
+
+ it "accepts flags for string argument" do
+ Regexp.linear_time?('a', Regexp::IGNORECASE).should == true
+ end
+
+ it "warns about flags being ignored for regexp arguments" do
+ -> {
+ Regexp.linear_time?(/a/, Regexp::IGNORECASE)
+ }.should complain(/warning: flags ignored/)
+ end
- it "warns about flags being ignored for regexp arguments" do
- -> {
- Regexp.linear_time?(/a/, Regexp::IGNORECASE)
- }.should complain(/warning: flags ignored/)
+ ruby_version_is "3.3" do
+ it "returns true for positive lookarounds" do
+ Regexp.linear_time?(/(?:(?=a*)a)*/).should == true
end
end
end
diff --git a/spec/ruby/core/regexp/new_spec.rb b/spec/ruby/core/regexp/new_spec.rb
index 65f612df55..79210e9a23 100644
--- a/spec/ruby/core/regexp/new_spec.rb
+++ b/spec/ruby/core/regexp/new_spec.rb
@@ -7,11 +7,11 @@ end
describe "Regexp.new given a String" do
it_behaves_like :regexp_new_string, :new
+ it_behaves_like :regexp_new_string_binary, :new
end
describe "Regexp.new given a Regexp" do
it_behaves_like :regexp_new_regexp, :new
- it_behaves_like :regexp_new_string_binary, :new
end
describe "Regexp.new given a non-String/Regexp" do
diff --git a/spec/ruby/core/regexp/shared/new.rb b/spec/ruby/core/regexp/shared/new.rb
index 3ca50d5a47..12c3d7c9c2 100644
--- a/spec/ruby/core/regexp/shared/new.rb
+++ b/spec/ruby/core/regexp/shared/new.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :regexp_new, shared: true do
it "requires one argument and creates a new regular expression object" do
@@ -123,140 +123,67 @@ describe :regexp_new_string, shared: true do
(r.options & Regexp::EXTENDED).should_not == 0
end
- ruby_version_is ""..."3.2" do
- it "does not try to convert the second argument to Integer with #to_int method call" do
- ScratchPad.clear
- obj = Object.new
- def obj.to_int() ScratchPad.record(:called) end
+ it "does not try to convert the second argument to Integer with #to_int method call" do
+ ScratchPad.clear
+ obj = Object.new
+ def obj.to_int() ScratchPad.record(:called) end
+ -> {
Regexp.send(@method, "Hi", obj)
+ }.should complain(/expected true or false as ignorecase/, {verbose: true})
- ScratchPad.recorded.should == nil
- end
- end
-
- ruby_version_is "3.2" do
- it "does not try to convert the second argument to Integer with #to_int method call" do
- ScratchPad.clear
- obj = Object.new
- def obj.to_int() ScratchPad.record(:called) end
-
- -> {
- Regexp.send(@method, "Hi", obj)
- }.should complain(/expected true or false as ignorecase/, {verbose: true})
-
- ScratchPad.recorded.should == nil
- end
+ ScratchPad.recorded.should == nil
end
- ruby_version_is ""..."3.2" do
- it "treats any non-Integer, non-nil, non-false second argument as IGNORECASE" do
+ it "warns any non-Integer, non-nil, non-false second argument" do
+ r = nil
+ -> {
r = Regexp.send(@method, 'Hi', Object.new)
- (r.options & Regexp::IGNORECASE).should_not == 0
- (r.options & Regexp::MULTILINE).should == 0
- not_supported_on :opal do
- (r.options & Regexp::EXTENDED).should == 0
- end
- end
- end
-
- ruby_version_is "3.2" do
- it "warns any non-Integer, non-nil, non-false second argument" do
- r = nil
- -> {
- r = Regexp.send(@method, 'Hi', Object.new)
- }.should complain(/expected true or false as ignorecase/, {verbose: true})
- (r.options & Regexp::IGNORECASE).should_not == 0
- (r.options & Regexp::MULTILINE).should == 0
- not_supported_on :opal do
- (r.options & Regexp::EXTENDED).should == 0
- end
- end
-
- it "accepts a String of supported flags as the second argument" do
- r = Regexp.send(@method, 'Hi', 'i')
- (r.options & Regexp::IGNORECASE).should_not == 0
- (r.options & Regexp::MULTILINE).should == 0
- not_supported_on :opal do
- (r.options & Regexp::EXTENDED).should == 0
- end
-
- r = Regexp.send(@method, 'Hi', 'imx')
- (r.options & Regexp::IGNORECASE).should_not == 0
- (r.options & Regexp::MULTILINE).should_not == 0
- not_supported_on :opal do
- (r.options & Regexp::EXTENDED).should_not == 0
- end
-
- r = Regexp.send(@method, 'Hi', 'mimi')
- (r.options & Regexp::IGNORECASE).should_not == 0
- (r.options & Regexp::MULTILINE).should_not == 0
- not_supported_on :opal do
- (r.options & Regexp::EXTENDED).should == 0
- end
-
- r = Regexp.send(@method, 'Hi', '')
- (r.options & Regexp::IGNORECASE).should == 0
- (r.options & Regexp::MULTILINE).should == 0
- not_supported_on :opal do
- (r.options & Regexp::EXTENDED).should == 0
- end
- end
-
- it "raises an Argument error if the second argument contains unsupported chars" do
- -> { Regexp.send(@method, 'Hi', 'e') }.should raise_error(ArgumentError, "unknown regexp option: e")
- -> { Regexp.send(@method, 'Hi', 'n') }.should raise_error(ArgumentError, "unknown regexp option: n")
- -> { Regexp.send(@method, 'Hi', 's') }.should raise_error(ArgumentError, "unknown regexp option: s")
- -> { Regexp.send(@method, 'Hi', 'u') }.should raise_error(ArgumentError, "unknown regexp option: u")
- -> { Regexp.send(@method, 'Hi', 'j') }.should raise_error(ArgumentError, "unknown regexp option: j")
- -> { Regexp.send(@method, 'Hi', 'mjx') }.should raise_error(ArgumentError, /unknown regexp option: mjx\b/)
+ }.should complain(/expected true or false as ignorecase/, {verbose: true})
+ (r.options & Regexp::IGNORECASE).should_not == 0
+ (r.options & Regexp::MULTILINE).should == 0
+ not_supported_on :opal do
+ (r.options & Regexp::EXTENDED).should == 0
end
end
- ruby_version_is ""..."3.2" do
- it "ignores the third argument if it is 'e' or 'euc' (case-insensitive)" do
- -> {
- Regexp.send(@method, 'Hi', nil, 'e').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'euc').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'E').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'EUC').encoding.should == Encoding::US_ASCII
- }.should complain(/encoding option is ignored/)
+ it "accepts a String of supported flags as the second argument" do
+ r = Regexp.send(@method, 'Hi', 'i')
+ (r.options & Regexp::IGNORECASE).should_not == 0
+ (r.options & Regexp::MULTILINE).should == 0
+ not_supported_on :opal do
+ (r.options & Regexp::EXTENDED).should == 0
end
- it "ignores the third argument if it is 's' or 'sjis' (case-insensitive)" do
- -> {
- Regexp.send(@method, 'Hi', nil, 's').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'sjis').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'S').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'SJIS').encoding.should == Encoding::US_ASCII
- }.should complain(/encoding option is ignored/)
+ r = Regexp.send(@method, 'Hi', 'imx')
+ (r.options & Regexp::IGNORECASE).should_not == 0
+ (r.options & Regexp::MULTILINE).should_not == 0
+ not_supported_on :opal do
+ (r.options & Regexp::EXTENDED).should_not == 0
end
- it "ignores the third argument if it is 'u' or 'utf8' (case-insensitive)" do
- -> {
- Regexp.send(@method, 'Hi', nil, 'u').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'utf8').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'U').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'UTF8').encoding.should == Encoding::US_ASCII
- }.should complain(/encoding option is ignored/)
+ r = Regexp.send(@method, 'Hi', 'mimi')
+ (r.options & Regexp::IGNORECASE).should_not == 0
+ (r.options & Regexp::MULTILINE).should_not == 0
+ not_supported_on :opal do
+ (r.options & Regexp::EXTENDED).should == 0
end
- it "uses US_ASCII encoding if third argument is 'n' or 'none' (case insensitive) and only ascii characters" do
- Regexp.send(@method, 'Hi', nil, 'n').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'none').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'N').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'NONE').encoding.should == Encoding::US_ASCII
+ r = Regexp.send(@method, 'Hi', '')
+ (r.options & Regexp::IGNORECASE).should == 0
+ (r.options & Regexp::MULTILINE).should == 0
+ not_supported_on :opal do
+ (r.options & Regexp::EXTENDED).should == 0
end
+ end
- it "uses ASCII_8BIT encoding if third argument is 'n' or 'none' (case insensitive) and non-ascii characters" do
- a = "(?:[\x8E\xA1-\xFE])"
- str = "\A(?:#{a}|x*)\z"
-
- Regexp.send(@method, str, nil, 'N').encoding.should == Encoding::BINARY
- Regexp.send(@method, str, nil, 'n').encoding.should == Encoding::BINARY
- Regexp.send(@method, str, nil, 'none').encoding.should == Encoding::BINARY
- Regexp.send(@method, str, nil, 'NONE').encoding.should == Encoding::BINARY
- end
+ it "raises an Argument error if the second argument contains unsupported chars" do
+ -> { Regexp.send(@method, 'Hi', 'e') }.should raise_error(ArgumentError, "unknown regexp option: e")
+ -> { Regexp.send(@method, 'Hi', 'n') }.should raise_error(ArgumentError, "unknown regexp option: n")
+ -> { Regexp.send(@method, 'Hi', 's') }.should raise_error(ArgumentError, "unknown regexp option: s")
+ -> { Regexp.send(@method, 'Hi', 'u') }.should raise_error(ArgumentError, "unknown regexp option: u")
+ -> { Regexp.send(@method, 'Hi', 'j') }.should raise_error(ArgumentError, "unknown regexp option: j")
+ -> { Regexp.send(@method, 'Hi', 'mjx') }.should raise_error(ArgumentError, /unknown regexp option: mjx\b/)
end
describe "with escaped characters" do
@@ -268,190 +195,14 @@ describe :regexp_new_string, shared: true do
-> { Regexp.send(@method, "\\\\") }.should_not raise_error(RegexpError)
end
- it "accepts a backspace followed by a character" do
+ it "accepts a backspace followed by a non-special character" do
Regexp.send(@method, "\\N").should == /#{"\x5c"+"N"}/
end
- it "accepts a one-digit octal value" do
- Regexp.send(@method, "\0").should == /#{"\x00"}/
- end
-
- it "accepts a two-digit octal value" do
- Regexp.send(@method, "\11").should == /#{"\x09"}/
- end
-
- it "accepts a one-digit hexadecimal value" do
- Regexp.send(@method, "\x9n").should == /#{"\x09n"}/
- end
-
- it "accepts a two-digit hexadecimal value" do
- Regexp.send(@method, "\x23").should == /#{"\x23"}/
- end
-
- it "interprets a digit following a two-digit hexadecimal value as a character" do
- Regexp.send(@method, "\x420").should == /#{"\x420"}/
- end
-
it "raises a RegexpError if \\x is not followed by any hexadecimal digits" do
-> { Regexp.send(@method, "\\" + "xn") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid hex escape: /\\xn/")))
end
- it "accepts an escaped string interpolation" do
- Regexp.send(@method, "\#{abc}").should == /#{"\#{abc}"}/
- end
-
- it "accepts '\\n'" do
- Regexp.send(@method, "\n").should == /#{"\x0a"}/
- end
-
- it "accepts '\\t'" do
- Regexp.send(@method, "\t").should == /#{"\x09"}/
- end
-
- it "accepts '\\r'" do
- Regexp.send(@method, "\r").should == /#{"\x0d"}/
- end
-
- it "accepts '\\f'" do
- Regexp.send(@method, "\f").should == /#{"\x0c"}/
- end
-
- it "accepts '\\v'" do
- Regexp.send(@method, "\v").should == /#{"\x0b"}/
- end
-
- it "accepts '\\a'" do
- Regexp.send(@method, "\a").should == /#{"\x07"}/
- end
-
- it "accepts '\\e'" do
- Regexp.send(@method, "\e").should == /#{"\x1b"}/
- end
-
- it "accepts '\\C-\\n'" do
- Regexp.send(@method, "\C-\n").should == /#{"\x0a"}/
- end
-
- it "accepts '\\C-\\t'" do
- Regexp.send(@method, "\C-\t").should == /#{"\x09"}/
- end
-
- it "accepts '\\C-\\r'" do
- Regexp.send(@method, "\C-\r").should == /#{"\x0d"}/
- end
-
- it "accepts '\\C-\\f'" do
- Regexp.send(@method, "\C-\f").should == /#{"\x0c"}/
- end
-
- it "accepts '\\C-\\v'" do
- Regexp.send(@method, "\C-\v").should == /#{"\x0b"}/
- end
-
- it "accepts '\\C-\\a'" do
- Regexp.send(@method, "\C-\a").should == /#{"\x07"}/
- end
-
- it "accepts '\\C-\\e'" do
- Regexp.send(@method, "\C-\e").should == /#{"\x1b"}/
- end
-
- it "accepts multiple consecutive '\\' characters" do
- Regexp.send(@method, "\\\\\\N").should == /#{"\\\\\\"+"N"}/
- end
-
- it "accepts characters and escaped octal digits" do
- Regexp.send(@method, "abc\076").should == /#{"abc\x3e"}/
- end
-
- it "accepts escaped octal digits and characters" do
- Regexp.send(@method, "\076abc").should == /#{"\x3eabc"}/
- end
-
- it "accepts characters and escaped hexadecimal digits" do
- Regexp.send(@method, "abc\x42").should == /#{"abc\x42"}/
- end
-
- it "accepts escaped hexadecimal digits and characters" do
- Regexp.send(@method, "\x3eabc").should == /#{"\x3eabc"}/
- end
-
- it "accepts escaped hexadecimal and octal digits" do
- Regexp.send(@method, "\061\x42").should == /#{"\x31\x42"}/
- end
-
- it "accepts \\u{H} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{f}").should == /#{"\x0f"}/
- end
-
- it "accepts \\u{HH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{7f}").should == /#{"\x7f"}/
- end
-
- it "accepts \\u{HHH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{07f}").should == /#{"\x7f"}/
- end
-
- it "accepts \\u{HHHH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{0000}").should == /#{"\x00"}/
- end
-
- it "accepts \\u{HHHHH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{00001}").should == /#{"\x01"}/
- end
-
- it "accepts \\u{HHHHHH} for a single Unicode codepoint" do
- Regexp.send(@method, "\u{000000}").should == /#{"\x00"}/
- end
-
- it "accepts characters followed by \\u{HHHH}" do
- Regexp.send(@method, "abc\u{3042}").should == /#{"abc\u3042"}/
- end
-
- it "accepts \\u{HHHH} followed by characters" do
- Regexp.send(@method, "\u{3042}abc").should == /#{"\u3042abc"}/
- end
-
- it "accepts escaped hexadecimal digits followed by \\u{HHHH}" do
- Regexp.send(@method, "\x42\u{3042}").should == /#{"\x42\u3042"}/
- end
-
- it "accepts escaped octal digits followed by \\u{HHHH}" do
- Regexp.send(@method, "\056\u{3042}").should == /#{"\x2e\u3042"}/
- end
-
- it "accepts a combination of escaped octal and hexadecimal digits and \\u{HHHH}" do
- Regexp.send(@method, "\056\x42\u{3042}\x52\076").should == /#{"\x2e\x42\u3042\x52\x3e"}/
- end
-
- it "accepts \\uHHHH for a single Unicode codepoint" do
- Regexp.send(@method, "\u3042").should == /#{"\u3042"}/
- end
-
- it "accepts characters followed by \\uHHHH" do
- Regexp.send(@method, "abc\u3042").should == /#{"abc\u3042"}/
- end
-
- it "accepts \\uHHHH followed by characters" do
- Regexp.send(@method, "\u3042abc").should == /#{"\u3042abc"}/
- end
-
- it "accepts escaped hexadecimal digits followed by \\uHHHH" do
- Regexp.send(@method, "\x42\u3042").should == /#{"\x42\u3042"}/
- end
-
- it "accepts escaped octal digits followed by \\uHHHH" do
- Regexp.send(@method, "\056\u3042").should == /#{"\x2e\u3042"}/
- end
-
- it "accepts a combination of escaped octal and hexadecimal digits and \\uHHHH" do
- Regexp.send(@method, "\056\x42\u3042\x52\076").should == /#{"\x2e\x42\u3042\x52\x3e"}/
- end
-
- it "accepts a multiple byte character which need not be escaped" do
- Regexp.send(@method, "\§").should == /#{"§"}/
- end
-
it "raises a RegexpError if less than four digits are given for \\uHHHH" do
-> { Regexp.send(@method, "\\" + "u304") }.should raise_error(RegexpError, Regexp.new(Regexp.escape("invalid Unicode escape: /\\u304/")))
end
@@ -506,69 +257,6 @@ end
describe :regexp_new_string_binary, shared: true do
describe "with escaped characters" do
- it "accepts a three-digit octal value" do
- Regexp.send(@method, "\315").should == /#{"\xcd"}/
- end
-
- it "interprets a digit following a three-digit octal value as a character" do
- Regexp.send(@method, "\3762").should == /#{"\xfe2"}/
- end
-
- it "accepts '\\M-\\n'" do
- Regexp.send(@method, "\M-\n").should == /#{"\x8a"}/
- end
-
- it "accepts '\\M-\\t'" do
- Regexp.send(@method, "\M-\t").should == /#{"\x89"}/
- end
-
- it "accepts '\\M-\\r'" do
- Regexp.send(@method, "\M-\r").should == /#{"\x8d"}/
- end
-
- it "accepts '\\M-\\f'" do
- Regexp.send(@method, "\M-\f").should == /#{"\x8c"}/
- end
-
- it "accepts '\\M-\\v'" do
- Regexp.send(@method, "\M-\v").should == /#{"\x8b"}/
- end
-
- it "accepts '\\M-\\a'" do
- Regexp.send(@method, "\M-\a").should == /#{"\x87"}/
- end
-
- it "accepts '\\M-\\e'" do
- Regexp.send(@method, "\M-\e").should == /#{"\x9b"}/
- end
-
- it "accepts '\\M-\\C-\\n'" do
- Regexp.send(@method, "\M-\C-\n").should == /#{"\x8a"}/
- end
-
- it "accepts '\\M-\\C-\\t'" do
- Regexp.send(@method, "\M-\C-\t").should == /#{"\x89"}/
- end
-
- it "accepts '\\M-\\C-\\r'" do
- Regexp.send(@method, "\M-\C-\r").should == /#{"\x8d"}/
- end
-
- it "accepts '\\M-\\C-\\f'" do
- Regexp.send(@method, "\M-\C-\f").should == /#{"\x8c"}/
- end
-
- it "accepts '\\M-\\C-\\v'" do
- Regexp.send(@method, "\M-\C-\v").should == /#{"\x8b"}/
- end
-
- it "accepts '\\M-\\C-\\a'" do
- Regexp.send(@method, "\M-\C-\a").should == /#{"\x87"}/
- end
-
- it "accepts '\\M-\\C-\\e'" do
- Regexp.send(@method, "\M-\C-\e").should == /#{"\x9b"}/
- end
end
end
@@ -623,11 +311,5 @@ describe :regexp_new_regexp, shared: true do
it "sets the encoding to US-ASCII if the Regexp literal has the 'n' option and the source String is ASCII only" do
Regexp.send(@method, /Hi/n).encoding.should == Encoding::US_ASCII
end
-
- ruby_version_is ''...'3.2' do
- it "sets the encoding to source String's encoding if the Regexp literal has the 'n' option and the source String is not ASCII only" do
- Regexp.send(@method, Regexp.new("\\xff", nil, 'n')).encoding.should == Encoding::BINARY
- end
- end
end
end
diff --git a/spec/ruby/core/regexp/shared/quote.rb b/spec/ruby/core/regexp/shared/quote.rb
index 48179444f0..3f46a18b5b 100644
--- a/spec/ruby/core/regexp/shared/quote.rb
+++ b/spec/ruby/core/regexp/shared/quote.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :regexp_quote, shared: true do
it "escapes any characters with special meaning in a regular expression" do
diff --git a/spec/ruby/core/regexp/timeout_spec.rb b/spec/ruby/core/regexp/timeout_spec.rb
index 6fce261814..c64103c82c 100644
--- a/spec/ruby/core/regexp/timeout_spec.rb
+++ b/spec/ruby/core/regexp/timeout_spec.rb
@@ -1,35 +1,33 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "Regexp.timeout" do
- after :each do
- Regexp.timeout = nil
- end
+describe "Regexp.timeout" do
+ after :each do
+ Regexp.timeout = nil
+ end
- it "returns global timeout" do
- Regexp.timeout = 3
- Regexp.timeout.should == 3
- end
+ it "returns global timeout" do
+ Regexp.timeout = 3
+ Regexp.timeout.should == 3
+ end
- it "raises Regexp::TimeoutError after global timeout elapsed" do
- Regexp.timeout = 0.001
- Regexp.timeout.should == 0.001
+ it "raises Regexp::TimeoutError after global timeout elapsed" do
+ Regexp.timeout = 0.001
+ Regexp.timeout.should == 0.001
- -> {
- # A typical ReDoS case
- /^(a*)*$/ =~ "a" * 1000000 + "x"
- }.should raise_error(Regexp::TimeoutError, "regexp match timeout")
- end
+ -> {
+ # A typical ReDoS case
+ /^(a*)*$/ =~ "a" * 1000000 + "x"
+ }.should raise_error(Regexp::TimeoutError, "regexp match timeout")
+ end
- it "raises Regexp::TimeoutError after timeout keyword value elapsed" do
- Regexp.timeout = 3 # This should be ignored
- Regexp.timeout.should == 3
+ it "raises Regexp::TimeoutError after timeout keyword value elapsed" do
+ Regexp.timeout = 3 # This should be ignored
+ Regexp.timeout.should == 3
- re = Regexp.new("^a*b?a*$", timeout: 0.001)
+ re = Regexp.new("^a*b?a*$", timeout: 0.001)
- -> {
- re =~ "a" * 1000000 + "x"
- }.should raise_error(Regexp::TimeoutError, "regexp match timeout")
- end
+ -> {
+ re =~ "a" * 1000000 + "x"
+ }.should raise_error(Regexp::TimeoutError, "regexp match timeout")
end
end
diff --git a/spec/ruby/core/set/add_spec.rb b/spec/ruby/core/set/add_spec.rb
new file mode 100644
index 0000000000..0fe1a0926c
--- /dev/null
+++ b/spec/ruby/core/set/add_spec.rb
@@ -0,0 +1,34 @@
+require_relative '../../spec_helper'
+require_relative 'shared/add'
+
+describe "Set#add" do
+ it_behaves_like :set_add, :add
+end
+
+describe "Set#add?" do
+ before :each do
+ @set = Set.new
+ end
+
+ it "adds the passed Object to self" do
+ @set.add?("cat")
+ @set.should include("cat")
+ end
+
+ it "returns self when the Object has not yet been added to self" do
+ @set.add?("cat").should equal(@set)
+ end
+
+ it "returns nil when the Object has already been added to self" do
+ @set.add?("cat")
+ @set.add?("cat").should be_nil
+ end
+
+ it "raises RuntimeError when called during iteration" do
+ set = Set[:a, :b, :c, :d, :e, :f]
+ set.each do |_m|
+ -> { set << 1 }.should raise_error(RuntimeError, /iteration/)
+ end
+ set.should == Set[:a, :b, :c, :d, :e, :f]
+ end
+end
diff --git a/spec/ruby/core/set/append_spec.rb b/spec/ruby/core/set/append_spec.rb
new file mode 100644
index 0000000000..82d34d9130
--- /dev/null
+++ b/spec/ruby/core/set/append_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/add'
+
+describe "Set#<<" do
+ it_behaves_like :set_add, :<<
+end
diff --git a/spec/ruby/core/set/case_compare_spec.rb b/spec/ruby/core/set/case_compare_spec.rb
new file mode 100644
index 0000000000..3781b1b963
--- /dev/null
+++ b/spec/ruby/core/set/case_compare_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../spec_helper'
+require_relative 'shared/include'
+
+describe "Set#===" do
+ it_behaves_like :set_include, :===
+
+ it "is an alias for include?" do
+ set = Set.new
+ set.method(:===).should == set.method(:include?)
+ end
+end
diff --git a/spec/ruby/core/set/case_equality_spec.rb b/spec/ruby/core/set/case_equality_spec.rb
new file mode 100644
index 0000000000..19c1fb6b9c
--- /dev/null
+++ b/spec/ruby/core/set/case_equality_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/include'
+
+describe "Set#===" do
+ it_behaves_like :set_include, :===
+end
diff --git a/spec/ruby/core/set/classify_spec.rb b/spec/ruby/core/set/classify_spec.rb
new file mode 100644
index 0000000000..d86ea2722d
--- /dev/null
+++ b/spec/ruby/core/set/classify_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../spec_helper'
+
+describe "Set#classify" do
+ before :each do
+ @set = Set["one", "two", "three", "four"]
+ end
+
+ it "yields each Object in self" do
+ res = []
+ @set.classify { |x| res << x }
+ res.sort.should == ["one", "two", "three", "four"].sort
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.classify
+ enum.should be_an_instance_of(Enumerator)
+
+ classified = enum.each { |x| x.length }
+ classified.should == { 3 => Set["one", "two"], 4 => Set["four"], 5 => Set["three"] }
+ end
+
+ it "classifies the Objects in self based on the block's return value" do
+ classified = @set.classify { |x| x.length }
+ classified.should == { 3 => Set["one", "two"], 4 => Set["four"], 5 => Set["three"] }
+ end
+end
diff --git a/spec/ruby/core/set/clear_spec.rb b/spec/ruby/core/set/clear_spec.rb
new file mode 100644
index 0000000000..ebeac211d3
--- /dev/null
+++ b/spec/ruby/core/set/clear_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../spec_helper'
+
+describe "Set#clear" do
+ before :each do
+ @set = Set["one", "two", "three", "four"]
+ end
+
+ it "removes all elements from self" do
+ @set.clear
+ @set.should be_empty
+ end
+
+ it "returns self" do
+ @set.clear.should equal(@set)
+ end
+end
diff --git a/spec/ruby/core/set/collect_spec.rb b/spec/ruby/core/set/collect_spec.rb
new file mode 100644
index 0000000000..d186f1a0d9
--- /dev/null
+++ b/spec/ruby/core/set/collect_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/collect'
+
+describe "Set#collect!" do
+ it_behaves_like :set_collect_bang, :collect!
+end
diff --git a/spec/ruby/core/set/compare_by_identity_spec.rb b/spec/ruby/core/set/compare_by_identity_spec.rb
new file mode 100644
index 0000000000..238dc117a6
--- /dev/null
+++ b/spec/ruby/core/set/compare_by_identity_spec.rb
@@ -0,0 +1,153 @@
+require_relative '../../spec_helper'
+
+describe "Set#compare_by_identity" do
+ it "compares its members by identity" do
+ a = "a"
+ b1 = "b"
+ b2 = b1.dup
+
+ set = Set.new
+ set.compare_by_identity
+ set.merge([a, a, b1, b2])
+ set.to_a.sort.should == [a, b1, b2].sort
+ end
+
+ it "causes future comparisons on the receiver to be made by identity" do
+ elt = [1]
+ set = Set.new
+ set << elt
+ set.member?(elt.dup).should be_true
+ set.compare_by_identity
+ set.member?(elt.dup).should be_false
+ end
+
+ it "rehashes internally so that old members can be looked up" do
+ set = Set.new
+ (1..10).each { |k| set << k }
+ o = Object.new
+ def o.hash; 123; end
+ set << o
+ set.compare_by_identity
+ set.member?(o).should be_true
+ end
+
+ it "returns self" do
+ set = Set.new
+ result = set.compare_by_identity
+ result.should equal(set)
+ end
+
+ it "is idempotent and has no effect on an already compare_by_identity set" do
+ set = Set.new.compare_by_identity
+ set << :foo
+ set.compare_by_identity.should equal(set)
+ set.should.compare_by_identity?
+ set.to_a.should == [:foo]
+ end
+
+ it "uses the semantics of BasicObject#equal? to determine members identity" do
+ :a.equal?(:a).should == true
+ Set.new.compare_by_identity.merge([:a, :a]).to_a.should == [:a]
+
+ ary1 = [1]
+ ary2 = [1]
+ ary1.equal?(ary2).should == false
+ Set.new.compare_by_identity.merge([ary1, ary2]).to_a.sort.should == [ary1, ary2].sort
+ end
+
+ it "uses #equal? semantics, but doesn't actually call #equal? to determine identity" do
+ set = Set.new.compare_by_identity
+ obj = mock("equal")
+ obj.should_not_receive(:equal?)
+ set << :foo
+ set << obj
+ set.to_a.should == [:foo, obj]
+ end
+
+ it "does not call #hash on members" do
+ elt = mock("element")
+ elt.should_not_receive(:hash)
+ set = Set.new.compare_by_identity
+ set << elt
+ set.member?(elt).should be_true
+ end
+
+ it "regards #dup'd objects as having different identities" do
+ a1 = "a"
+ a2 = a1.dup
+
+ set = Set.new.compare_by_identity
+ set.merge([a1, a2])
+ set.to_a.sort.should == [a1, a2].sort
+ end
+
+ it "regards #clone'd objects as having different identities" do
+ a1 = "a"
+ a2 = a1.clone
+
+ set = Set.new.compare_by_identity
+ set.merge([a1, a2])
+ set.to_a.sort.should == [a1, a2].sort
+ end
+
+ ruby_version_is "4.0" do
+ it "raises a FrozenError on frozen sets" do
+ set = Set.new.freeze
+ -> {
+ set.compare_by_identity
+ }.should raise_error(FrozenError, /can't modify frozen Set: (#<)?Set(\[|: {)[\]}]>?/)
+ end
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "raises a FrozenError on frozen sets" do
+ set = Set.new.freeze
+ -> {
+ set.compare_by_identity
+ }.should raise_error(FrozenError, /frozen Hash/)
+ end
+ end
+
+ it "persists over #dups" do
+ set = Set.new.compare_by_identity
+ set << :a
+ set_dup = set.dup
+ set_dup.should == set
+ set_dup << :a
+ set_dup.to_a.should == [:a]
+ end
+
+ it "persists over #clones" do
+ set = Set.new.compare_by_identity
+ set << :a
+ set_clone = set.clone
+ set_clone.should == set
+ set_clone << :a
+ set_clone.to_a.should == [:a]
+ end
+
+ it "is not equal to set what does not compare by identity" do
+ Set.new([1, 2]).should == Set.new([1, 2])
+ Set.new([1, 2]).should_not == Set.new([1, 2]).compare_by_identity
+ end
+end
+
+describe "Set#compare_by_identity?" do
+ it "returns false by default" do
+ Set.new.should_not.compare_by_identity?
+ end
+
+ it "returns true once #compare_by_identity has been invoked on self" do
+ set = Set.new
+ set.compare_by_identity
+ set.should.compare_by_identity?
+ end
+
+ it "returns true when called multiple times on the same set" do
+ set = Set.new
+ set.compare_by_identity
+ set.should.compare_by_identity?
+ set.should.compare_by_identity?
+ set.should.compare_by_identity?
+ end
+end
diff --git a/spec/ruby/core/set/comparison_spec.rb b/spec/ruby/core/set/comparison_spec.rb
new file mode 100644
index 0000000000..62059b70b3
--- /dev/null
+++ b/spec/ruby/core/set/comparison_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../spec_helper'
+
+describe "Set#<=>" do
+ it "returns 0 if the sets are equal" do
+ (Set[] <=> Set[]).should == 0
+ (Set[:a, :b, :c] <=> Set[:a, :b, :c]).should == 0
+ end
+
+ it "returns -1 if the set is a proper subset of the other set" do
+ (Set[] <=> Set[1]).should == -1
+ (Set[1, 2] <=> Set[1, 2, 3]).should == -1
+ end
+
+ it "returns +1 if the set is a proper superset of other set" do
+ (Set[1] <=> Set[]).should == +1
+ (Set[1, 2, 3] <=> Set[1, 2]).should == +1
+ end
+
+ it "returns nil if the set has unique elements" do
+ (Set[1, 2, 3] <=> Set[:a, :b, :c]).should be_nil
+ end
+
+ it "returns nil when the argument is not set-like" do
+ (Set[] <=> false).should be_nil
+ end
+end
diff --git a/spec/ruby/core/set/constructor_spec.rb b/spec/ruby/core/set/constructor_spec.rb
new file mode 100644
index 0000000000..365081ad39
--- /dev/null
+++ b/spec/ruby/core/set/constructor_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../spec_helper'
+
+describe "Set[]" do
+ it "returns a new Set populated with the passed Objects" do
+ set = Set[1, 2, 3]
+
+ set.instance_of?(Set).should be_true
+ set.size.should eql(3)
+
+ set.should include(1)
+ set.should include(2)
+ set.should include(3)
+ end
+end
diff --git a/spec/ruby/core/set/delete_if_spec.rb b/spec/ruby/core/set/delete_if_spec.rb
new file mode 100644
index 0000000000..beda73a5e5
--- /dev/null
+++ b/spec/ruby/core/set/delete_if_spec.rb
@@ -0,0 +1,37 @@
+require_relative '../../spec_helper'
+
+describe "Set#delete_if" do
+ before :each do
+ @set = Set["one", "two", "three"]
+ end
+
+ it "yields every element of self" do
+ ret = []
+ @set.delete_if { |x| ret << x }
+ ret.sort.should == ["one", "two", "three"].sort
+ end
+
+ it "deletes every element from self for which the passed block returns true" do
+ @set.delete_if { |x| x.size == 3 }
+ @set.size.should eql(1)
+
+ @set.should_not include("one")
+ @set.should_not include("two")
+ @set.should include("three")
+ end
+
+ it "returns self" do
+ @set.delete_if { |x| x }.should equal(@set)
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.delete_if
+ enum.should be_an_instance_of(Enumerator)
+
+ enum.each { |x| x.size == 3 }
+
+ @set.should_not include("one")
+ @set.should_not include("two")
+ @set.should include("three")
+ end
+end
diff --git a/spec/ruby/core/set/delete_spec.rb b/spec/ruby/core/set/delete_spec.rb
new file mode 100644
index 0000000000..a2543ecbee
--- /dev/null
+++ b/spec/ruby/core/set/delete_spec.rb
@@ -0,0 +1,36 @@
+require_relative '../../spec_helper'
+
+describe "Set#delete" do
+ before :each do
+ @set = Set["a", "b", "c"]
+ end
+
+ it "deletes the passed Object from self" do
+ @set.delete("a")
+ @set.should_not include("a")
+ end
+
+ it "returns self" do
+ @set.delete("a").should equal(@set)
+ @set.delete("x").should equal(@set)
+ end
+end
+
+describe "Set#delete?" do
+ before :each do
+ @set = Set["a", "b", "c"]
+ end
+
+ it "deletes the passed Object from self" do
+ @set.delete?("a")
+ @set.should_not include("a")
+ end
+
+ it "returns self when the passed Object is in self" do
+ @set.delete?("a").should equal(@set)
+ end
+
+ it "returns nil when the passed Object is not in self" do
+ @set.delete?("x").should be_nil
+ end
+end
diff --git a/spec/ruby/core/set/difference_spec.rb b/spec/ruby/core/set/difference_spec.rb
new file mode 100644
index 0000000000..149f946592
--- /dev/null
+++ b/spec/ruby/core/set/difference_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/difference'
+
+describe "Set#difference" do
+ it_behaves_like :set_difference, :difference
+end
diff --git a/spec/ruby/core/set/disjoint_spec.rb b/spec/ruby/core/set/disjoint_spec.rb
new file mode 100644
index 0000000000..89a3c4b157
--- /dev/null
+++ b/spec/ruby/core/set/disjoint_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+
+describe "Set#disjoint?" do
+ it "returns false when two Sets have at least one element in common" do
+ Set[1, 2].disjoint?(Set[2, 3]).should == false
+ end
+
+ it "returns true when two Sets have no element in common" do
+ Set[1, 2].disjoint?(Set[3, 4]).should == true
+ end
+
+ context "when comparing to a Set-like object" do
+ it "returns false when a Set has at least one element in common with a Set-like object" do
+ Set[1, 2].disjoint?(SetSpecs::SetLike.new([2, 3])).should be_false
+ end
+
+ it "returns true when a Set has no element in common with a Set-like object" do
+ Set[1, 2].disjoint?(SetSpecs::SetLike.new([3, 4])).should be_true
+ end
+ end
+end
diff --git a/spec/ruby/core/set/divide_spec.rb b/spec/ruby/core/set/divide_spec.rb
new file mode 100644
index 0000000000..c6c6003e99
--- /dev/null
+++ b/spec/ruby/core/set/divide_spec.rb
@@ -0,0 +1,68 @@
+require_relative '../../spec_helper'
+
+describe "Set#divide" do
+ it "divides self into a set of subsets based on the blocks return values" do
+ set = Set["one", "two", "three", "four", "five"].divide { |x| x.length }
+ set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]]
+ end
+
+ it "yields each Object to the block" do
+ ret = []
+ Set["one", "two", "three", "four", "five"].divide { |x| ret << x }
+ ret.sort.should == ["five", "four", "one", "three", "two"]
+ end
+
+ it "returns an enumerator when not passed a block" do
+ ret = Set[1, 2, 3, 4].divide
+ ret.should be_kind_of(Enumerator)
+ ret.each(&:even?).should == Set[Set[1, 3], Set[2, 4]]
+ end
+end
+
+describe "Set#divide when passed a block with an arity of 2" do
+ it "divides self into a set of subsets based on the blocks return values" do
+ set = Set[1, 3, 4, 6, 9, 10, 11].divide { |x, y| (x - y).abs == 1 }
+ set.map{ |x| x.to_a.sort }.sort.should == [[1], [3, 4], [6], [9, 10, 11]]
+ end
+
+ ruby_version_is "4.0" do
+ it "yields each two Object to the block" do
+ ret = []
+ Set[1, 2].divide { |x, y| ret << [x, y] }
+ ret.sort.should == [[1, 2], [2, 1]]
+ end
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "yields each two Object to the block" do
+ ret = []
+ Set[1, 2].divide { |x, y| ret << [x, y] }
+ ret.sort.should == [[1, 1], [1, 2], [2, 1], [2, 2]]
+ end
+ end
+
+ it "returns an enumerator when not passed a block" do
+ ret = Set[1, 2, 3, 4].divide
+ ret.should be_kind_of(Enumerator)
+ ret.each { |a, b| (a + b).even? }.should == Set[Set[1, 3], Set[2, 4]]
+ end
+end
+
+describe "Set#divide when passed a block with an arity of > 2" do
+ it "only uses the first element if the arity > 2" do
+ set = Set["one", "two", "three", "four", "five"].divide do |x, y, z|
+ y.should be_nil
+ z.should be_nil
+ x.length
+ end
+ set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]]
+ end
+
+ it "only uses the first element if the arity = -1" do
+ set = Set["one", "two", "three", "four", "five"].divide do |*xs|
+ xs.size.should == 1
+ xs.first.length
+ end
+ set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]]
+ end
+end
diff --git a/spec/ruby/core/set/each_spec.rb b/spec/ruby/core/set/each_spec.rb
new file mode 100644
index 0000000000..3d9cdc2d46
--- /dev/null
+++ b/spec/ruby/core/set/each_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../spec_helper'
+
+describe "Set#each" do
+ before :each do
+ @set = Set[1, 2, 3]
+ end
+
+ it "yields each Object in self" do
+ ret = []
+ @set.each { |x| ret << x }
+ ret.sort.should == [1, 2, 3]
+ end
+
+ it "returns self" do
+ @set.each { |x| x }.should equal(@set)
+ end
+
+ it "returns an Enumerator when not passed a block" do
+ enum = @set.each
+ enum.should be_an_instance_of(Enumerator)
+
+ ret = []
+ enum.each { |x| ret << x }
+ ret.sort.should == [1, 2, 3]
+ end
+end
diff --git a/spec/ruby/core/set/empty_spec.rb b/spec/ruby/core/set/empty_spec.rb
new file mode 100644
index 0000000000..4b55658e20
--- /dev/null
+++ b/spec/ruby/core/set/empty_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../spec_helper'
+
+describe "Set#empty?" do
+ it "returns true if self is empty" do
+ Set[].empty?.should be_true
+ Set[1].empty?.should be_false
+ Set[1,2,3].empty?.should be_false
+ end
+end
diff --git a/spec/ruby/core/set/enumerable/to_set_spec.rb b/spec/ruby/core/set/enumerable/to_set_spec.rb
new file mode 100644
index 0000000000..f139e1c025
--- /dev/null
+++ b/spec/ruby/core/set/enumerable/to_set_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../spec_helper'
+
+describe "Enumerable#to_set" do
+ it "returns a new Set created from self" do
+ [1, 2, 3].to_set.should == Set[1, 2, 3]
+ {a: 1, b: 2}.to_set.should == Set[[:b, 2], [:a, 1]]
+ end
+
+ it "passes down passed blocks" do
+ [1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9]
+ end
+end
diff --git a/spec/ruby/core/set/eql_spec.rb b/spec/ruby/core/set/eql_spec.rb
new file mode 100644
index 0000000000..4ad5c3aa5a
--- /dev/null
+++ b/spec/ruby/core/set/eql_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../spec_helper'
+
+describe "Set#eql?" do
+ it "returns true when the passed argument is a Set and contains the same elements" do
+ Set[].should eql(Set[])
+ Set[1, 2, 3].should eql(Set[1, 2, 3])
+ Set[1, 2, 3].should eql(Set[3, 2, 1])
+ Set["a", :b, ?c].should eql(Set[?c, :b, "a"])
+
+ Set[1, 2, 3].should_not eql(Set[1.0, 2, 3])
+ Set[1, 2, 3].should_not eql(Set[2, 3])
+ Set[1, 2, 3].should_not eql(Set[])
+ end
+end
diff --git a/spec/ruby/core/set/equal_value_spec.rb b/spec/ruby/core/set/equal_value_spec.rb
new file mode 100644
index 0000000000..721a79a3f1
--- /dev/null
+++ b/spec/ruby/core/set/equal_value_spec.rb
@@ -0,0 +1,34 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+
+describe "Set#==" do
+ it "returns true when the passed Object is a Set and self and the Object contain the same elements" do
+ Set[].should == Set[]
+ Set[1, 2, 3].should == Set[1, 2, 3]
+ Set["1", "2", "3"].should == Set["1", "2", "3"]
+
+ Set[1, 2, 3].should_not == Set[1.0, 2, 3]
+ Set[1, 2, 3].should_not == [1, 2, 3]
+ end
+
+ it "does not depend on the order of the elements" do
+ Set[1, 2, 3].should == Set[3, 2, 1]
+ Set[:a, "b", ?c].should == Set[?c, "b", :a]
+ end
+
+ it "does not depend on the order of nested Sets" do
+ Set[Set[1], Set[2], Set[3]].should == Set[Set[3], Set[2], Set[1]]
+
+ set1 = Set[Set["a", "b"], Set["c", "d"], Set["e", "f"]]
+ set2 = Set[Set["c", "d"], Set["a", "b"], Set["e", "f"]]
+ set1.should == set2
+ end
+
+ ruby_version_is ""..."4.0" do
+ context "when comparing to a Set-like object" do
+ it "returns true when a Set and a Set-like object contain the same elements" do
+ Set[1, 2, 3].should == SetSpecs::SetLike.new([1, 2, 3])
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/set/exclusion_spec.rb b/spec/ruby/core/set/exclusion_spec.rb
new file mode 100644
index 0000000000..bbc29afa95
--- /dev/null
+++ b/spec/ruby/core/set/exclusion_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../spec_helper'
+
+describe "Set#^" do
+ before :each do
+ @set = Set[1, 2, 3, 4]
+ end
+
+ it "returns a new Set containing elements that are not in both self and the passed Enumerable" do
+ (@set ^ Set[3, 4, 5]).should == Set[1, 2, 5]
+ (@set ^ [3, 4, 5]).should == Set[1, 2, 5]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set ^ 3 }.should raise_error(ArgumentError)
+ -> { @set ^ Object.new }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/ruby/core/set/filter_spec.rb b/spec/ruby/core/set/filter_spec.rb
new file mode 100644
index 0000000000..779254ad68
--- /dev/null
+++ b/spec/ruby/core/set/filter_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/select'
+
+describe "Set#filter!" do
+ it_behaves_like :set_select_bang, :filter!
+end
diff --git a/spec/ruby/core/set/fixtures/set_like.rb b/spec/ruby/core/set/fixtures/set_like.rb
new file mode 100644
index 0000000000..86dec2ed52
--- /dev/null
+++ b/spec/ruby/core/set/fixtures/set_like.rb
@@ -0,0 +1,30 @@
+
+module SetSpecs
+ # This class is used to test the interaction of "Set-like" objects with real Sets
+ #
+ # These "Set-like" objects reply to is_a?(Set) with true and thus real Set objects are able to transparently
+ # interoperate with them in a duck-typing manner.
+ class SetLike
+ include Enumerable
+
+ def is_a?(klass)
+ super || klass == ::Set
+ end
+
+ def initialize(entries)
+ @entries = entries
+ end
+
+ def each(&block)
+ @entries.each(&block)
+ end
+
+ def inspect
+ "#<#{self.class}: {#{map(&:inspect).join(", ")}}>"
+ end
+
+ def size
+ @entries.size
+ end
+ end
+end
diff --git a/spec/ruby/core/set/flatten_merge_spec.rb b/spec/ruby/core/set/flatten_merge_spec.rb
new file mode 100644
index 0000000000..13cedeead9
--- /dev/null
+++ b/spec/ruby/core/set/flatten_merge_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../spec_helper'
+
+describe "Set#flatten_merge" do
+ ruby_version_is ""..."4.0" do
+ it "is protected" do
+ Set.should have_protected_instance_method("flatten_merge")
+ end
+
+ it "flattens the passed Set and merges it into self" do
+ set1 = Set[1, 2]
+ set2 = Set[3, 4, Set[5, 6]]
+
+ set1.send(:flatten_merge, set2).should == Set[1, 2, 3, 4, 5, 6]
+ end
+
+ it "raises an ArgumentError when trying to flatten a recursive Set" do
+ set1 = Set[1, 2, 3]
+ set2 = Set[5, 6, 7]
+ set2 << set2
+
+ -> { set1.send(:flatten_merge, set2) }.should raise_error(ArgumentError)
+ end
+ end
+end
diff --git a/spec/ruby/core/set/flatten_spec.rb b/spec/ruby/core/set/flatten_spec.rb
new file mode 100644
index 0000000000..f2cb3dfa52
--- /dev/null
+++ b/spec/ruby/core/set/flatten_spec.rb
@@ -0,0 +1,59 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
+
+describe "Set#flatten" do
+ it "returns a copy of self with each included Set flattened" do
+ set = Set[1, 2, Set[3, 4, Set[5, 6, Set[7, 8]]], 9, 10]
+ flattened_set = set.flatten
+
+ flattened_set.should_not equal(set)
+ flattened_set.should == Set[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ end
+
+ it "raises an ArgumentError when self is recursive" do
+ (set = Set[]) << set
+ -> { set.flatten }.should raise_error(ArgumentError)
+ end
+
+ ruby_version_is ""..."4.0" do
+ context "when Set contains a Set-like object" do
+ it "returns a copy of self with each included Set-like object flattened" do
+ Set[SetSpecs::SetLike.new([1])].flatten.should == Set[1]
+ end
+ end
+ end
+end
+
+describe "Set#flatten!" do
+ it "flattens self" do
+ set = Set[1, 2, Set[3, 4, Set[5, 6, Set[7, 8]]], 9, 10]
+ set.flatten!
+ set.should == Set[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+ end
+
+ it "returns self when self was modified" do
+ set = Set[1, 2, Set[3, 4]]
+ set.flatten!.should equal(set)
+ end
+
+ it "returns nil when self was not modified" do
+ set = Set[1, 2, 3, 4]
+ set.flatten!.should be_nil
+ end
+
+ it "raises an ArgumentError when self is recursive" do
+ (set = Set[]) << set
+ -> { set.flatten! }.should raise_error(ArgumentError)
+ end
+
+ version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
+ ruby_version_is ""..."4.0" do
+ context "when Set contains a Set-like object" do
+ it "flattens self, including Set-like objects" do
+ Set[SetSpecs::SetLike.new([1])].flatten!.should == Set[1]
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/set/hash_spec.rb b/spec/ruby/core/set/hash_spec.rb
new file mode 100644
index 0000000000..63a0aa66a5
--- /dev/null
+++ b/spec/ruby/core/set/hash_spec.rb
@@ -0,0 +1,19 @@
+require_relative '../../spec_helper'
+
+describe "Set#hash" do
+ it "is static" do
+ Set[].hash.should == Set[].hash
+ Set[1, 2, 3].hash.should == Set[1, 2, 3].hash
+ Set[:a, "b", ?c].hash.should == Set[?c, "b", :a].hash
+
+ Set[].hash.should_not == Set[1, 2, 3].hash
+ Set[1, 2, 3].hash.should_not == Set[:a, "b", ?c].hash
+ end
+
+ ruby_version_is ""..."4.0" do
+ # see https://github.com/jruby/jruby/issues/8393
+ it "is equal to nil.hash for an uninitialized Set" do
+ Set.allocate.hash.should == nil.hash
+ end
+ end
+end
diff --git a/spec/ruby/core/set/include_spec.rb b/spec/ruby/core/set/include_spec.rb
new file mode 100644
index 0000000000..dd33bbc3bd
--- /dev/null
+++ b/spec/ruby/core/set/include_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/include'
+
+describe "Set#include?" do
+ it_behaves_like :set_include, :include?
+end
diff --git a/spec/ruby/core/set/initialize_clone_spec.rb b/spec/ruby/core/set/initialize_clone_spec.rb
new file mode 100644
index 0000000000..13abb7ee4e
--- /dev/null
+++ b/spec/ruby/core/set/initialize_clone_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../spec_helper'
+
+describe "Set#initialize_clone" do
+ # See https://bugs.ruby-lang.org/issues/14266
+ it "does not freeze the new Set when called from clone(freeze: false)" do
+ set1 = Set[1, 2]
+ set1.freeze
+ set2 = set1.clone(freeze: false)
+ set1.frozen?.should == true
+ set2.frozen?.should == false
+ set2.add 3
+ set1.should == Set[1, 2]
+ set2.should == Set[1, 2, 3]
+ end
+end
diff --git a/spec/ruby/core/set/initialize_spec.rb b/spec/ruby/core/set/initialize_spec.rb
new file mode 100644
index 0000000000..ad9e1bd8c9
--- /dev/null
+++ b/spec/ruby/core/set/initialize_spec.rb
@@ -0,0 +1,72 @@
+require_relative '../../spec_helper'
+
+describe "Set#initialize" do
+ it "is private" do
+ Set.should have_private_instance_method(:initialize)
+ end
+
+ it "adds all elements of the passed Enumerable to self" do
+ s = Set.new([1, 2, 3])
+ s.size.should eql(3)
+ s.should include(1)
+ s.should include(2)
+ s.should include(3)
+ end
+
+ it "uses #each_entry on the provided Enumerable" do
+ enumerable = MockObject.new('mock-enumerable')
+ enumerable.should_receive(:each_entry).and_yield(1).and_yield(2).and_yield(3)
+ s = Set.new(enumerable)
+ s.size.should eql(3)
+ s.should include(1)
+ s.should include(2)
+ s.should include(3)
+ end
+
+ it "uses #each on the provided Enumerable if it does not respond to #each_entry" do
+ enumerable = MockObject.new('mock-enumerable')
+ enumerable.should_receive(:each).and_yield(1).and_yield(2).and_yield(3)
+ s = Set.new(enumerable)
+ s.size.should eql(3)
+ s.should include(1)
+ s.should include(2)
+ s.should include(3)
+ end
+
+ it "raises if the provided Enumerable does not respond to #each_entry or #each" do
+ enumerable = MockObject.new('mock-enumerable')
+ -> { Set.new(enumerable) }.should raise_error(ArgumentError, "value must be enumerable")
+ end
+
+ it "should initialize with empty array and set" do
+ s = Set.new([])
+ s.size.should eql(0)
+
+ s = Set.new({})
+ s.size.should eql(0)
+ end
+
+ it "preprocesses all elements by a passed block before adding to self" do
+ s = Set.new([1, 2, 3]) { |x| x * x }
+ s.size.should eql(3)
+ s.should include(1)
+ s.should include(4)
+ s.should include(9)
+ end
+
+ it "should initialize with empty array and block" do
+ s = Set.new([]) { |x| x * x }
+ s.size.should eql(0)
+ end
+
+ it "should initialize with empty set and block" do
+ s = Set.new(Set.new) { |x| x * x }
+ s.size.should eql(0)
+ end
+
+ it "should initialize with just block" do
+ s = Set.new { |x| x * x }
+ s.size.should eql(0)
+ s.should eql(Set.new)
+ end
+end
diff --git a/spec/ruby/core/set/inspect_spec.rb b/spec/ruby/core/set/inspect_spec.rb
new file mode 100644
index 0000000000..0dcce83eb6
--- /dev/null
+++ b/spec/ruby/core/set/inspect_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/inspect'
+
+describe "Set#inspect" do
+ it_behaves_like :set_inspect, :inspect
+end
diff --git a/spec/ruby/core/set/intersect_spec.rb b/spec/ruby/core/set/intersect_spec.rb
new file mode 100644
index 0000000000..0736dea5fd
--- /dev/null
+++ b/spec/ruby/core/set/intersect_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+
+describe "Set#intersect?" do
+ it "returns true when two Sets have at least one element in common" do
+ Set[1, 2].intersect?(Set[2, 3]).should == true
+ end
+
+ it "returns false when two Sets have no element in common" do
+ Set[1, 2].intersect?(Set[3, 4]).should == false
+ end
+
+ context "when comparing to a Set-like object" do
+ it "returns true when a Set has at least one element in common with a Set-like object" do
+ Set[1, 2].intersect?(SetSpecs::SetLike.new([2, 3])).should be_true
+ end
+
+ it "returns false when a Set has no element in common with a Set-like object" do
+ Set[1, 2].intersect?(SetSpecs::SetLike.new([3, 4])).should be_false
+ end
+ end
+end
diff --git a/spec/ruby/core/set/intersection_spec.rb b/spec/ruby/core/set/intersection_spec.rb
new file mode 100644
index 0000000000..136b886775
--- /dev/null
+++ b/spec/ruby/core/set/intersection_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../spec_helper'
+require_relative 'shared/intersection'
+
+describe "Set#intersection" do
+ it_behaves_like :set_intersection, :intersection
+end
+
+describe "Set#&" do
+ it_behaves_like :set_intersection, :&
+end
diff --git a/spec/ruby/core/set/join_spec.rb b/spec/ruby/core/set/join_spec.rb
new file mode 100644
index 0000000000..1c1e8a8af8
--- /dev/null
+++ b/spec/ruby/core/set/join_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../spec_helper'
+
+describe "Set#join" do
+ it "returns an empty string if the Set is empty" do
+ Set[].join.should == ''
+ end
+
+ it "returns a new string formed by joining elements after conversion" do
+ set = Set[:a, :b, :c]
+ set.join.should == "abc"
+ end
+
+ it "does not separate elements when the passed separator is nil" do
+ set = Set[:a, :b, :c]
+ set.join(nil).should == "abc"
+ end
+
+ it "returns a string formed by concatenating each element separated by the separator" do
+ set = Set[:a, :b, :c]
+ set.join(' | ').should == "a | b | c"
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "calls #to_a to convert the Set in to an Array" do
+ set = Set[:a, :b, :c]
+ set.should_receive(:to_a).and_return([:a, :b, :c])
+ set.join.should == "abc"
+ end
+ end
+end
diff --git a/spec/ruby/core/set/keep_if_spec.rb b/spec/ruby/core/set/keep_if_spec.rb
new file mode 100644
index 0000000000..d6abdd6adc
--- /dev/null
+++ b/spec/ruby/core/set/keep_if_spec.rb
@@ -0,0 +1,37 @@
+require_relative '../../spec_helper'
+
+describe "Set#keep_if" do
+ before :each do
+ @set = Set["one", "two", "three"]
+ end
+
+ it "yields every element of self" do
+ ret = []
+ @set.keep_if { |x| ret << x }
+ ret.sort.should == ["one", "two", "three"].sort
+ end
+
+ it "keeps every element from self for which the passed block returns true" do
+ @set.keep_if { |x| x.size != 3 }
+ @set.size.should eql(1)
+
+ @set.should_not include("one")
+ @set.should_not include("two")
+ @set.should include("three")
+ end
+
+ it "returns self" do
+ @set.keep_if {}.should equal(@set)
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.keep_if
+ enum.should be_an_instance_of(Enumerator)
+
+ enum.each { |x| x.size != 3 }
+
+ @set.should_not include("one")
+ @set.should_not include("two")
+ @set.should include("three")
+ end
+end
diff --git a/spec/ruby/core/set/length_spec.rb b/spec/ruby/core/set/length_spec.rb
new file mode 100644
index 0000000000..6bb697b4ca
--- /dev/null
+++ b/spec/ruby/core/set/length_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/length'
+
+describe "Set#length" do
+ it_behaves_like :set_length, :length
+end
diff --git a/spec/ruby/core/set/map_spec.rb b/spec/ruby/core/set/map_spec.rb
new file mode 100644
index 0000000000..996191b0a8
--- /dev/null
+++ b/spec/ruby/core/set/map_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/collect'
+
+describe "Set#map!" do
+ it_behaves_like :set_collect_bang, :map!
+end
diff --git a/spec/ruby/core/set/member_spec.rb b/spec/ruby/core/set/member_spec.rb
new file mode 100644
index 0000000000..5c82e8f826
--- /dev/null
+++ b/spec/ruby/core/set/member_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/include'
+
+describe "Set#member?" do
+ it_behaves_like :set_include, :member?
+end
diff --git a/spec/ruby/core/set/merge_spec.rb b/spec/ruby/core/set/merge_spec.rb
new file mode 100644
index 0000000000..0c6ed27670
--- /dev/null
+++ b/spec/ruby/core/set/merge_spec.rb
@@ -0,0 +1,37 @@
+require_relative '../../spec_helper'
+
+describe "Set#merge" do
+ it "adds the elements of the passed Enumerable to self" do
+ Set[:a, :b].merge(Set[:b, :c, :d]).should == Set[:a, :b, :c, :d]
+ Set[1, 2].merge([3, 4]).should == Set[1, 2, 3, 4]
+ end
+
+ it "returns self" do
+ set = Set[1, 2]
+ set.merge([3, 4]).should equal(set)
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { Set[1, 2].merge(1) }.should raise_error(ArgumentError)
+ -> { Set[1, 2].merge(Object.new) }.should raise_error(ArgumentError)
+ end
+
+ it "raises RuntimeError when called during iteration" do
+ set = Set[:a, :b]
+ set.each do |_m|
+ -> { set.merge([1, 2]) }.should raise_error(RuntimeError, /iteration/)
+ end
+ end
+
+ ruby_version_is ""..."3.3" do
+ it "accepts only a single argument" do
+ -> { Set[].merge([], []) }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 1)")
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "accepts multiple arguments" do
+ Set[:a, :b].merge(Set[:b, :c], [:d]).should == Set[:a, :b, :c, :d]
+ end
+ end
+end
diff --git a/spec/ruby/core/set/minus_spec.rb b/spec/ruby/core/set/minus_spec.rb
new file mode 100644
index 0000000000..72f98f985e
--- /dev/null
+++ b/spec/ruby/core/set/minus_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/difference'
+
+describe "Set#-" do
+ it_behaves_like :set_difference, :-
+end
diff --git a/spec/ruby/core/set/plus_spec.rb b/spec/ruby/core/set/plus_spec.rb
new file mode 100644
index 0000000000..7e44ff0b7e
--- /dev/null
+++ b/spec/ruby/core/set/plus_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/union'
+
+describe "Set#+" do
+ it_behaves_like :set_union, :+
+end
diff --git a/spec/ruby/core/set/pretty_print_cycle_spec.rb b/spec/ruby/core/set/pretty_print_cycle_spec.rb
new file mode 100644
index 0000000000..7e6017c112
--- /dev/null
+++ b/spec/ruby/core/set/pretty_print_cycle_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../spec_helper'
+
+describe "Set#pretty_print_cycle" do
+ it "passes the 'pretty print' representation of a self-referencing Set to the pretty print writer" do
+ pp = mock("PrettyPrint")
+ ruby_version_is(""..."4.0") do
+ pp.should_receive(:text).with("#<Set: {...}>")
+ end
+ ruby_version_is("4.0") do
+ pp.should_receive(:text).with("Set[...]")
+ end
+ Set[1, 2, 3].pretty_print_cycle(pp)
+ end
+end
diff --git a/spec/ruby/core/set/proper_subset_spec.rb b/spec/ruby/core/set/proper_subset_spec.rb
new file mode 100644
index 0000000000..fb7848c001
--- /dev/null
+++ b/spec/ruby/core/set/proper_subset_spec.rb
@@ -0,0 +1,45 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
+
+describe "Set#proper_subset?" do
+ before :each do
+ @set = Set[1, 2, 3, 4]
+ end
+
+ it "returns true if passed a Set that self is a proper subset of" do
+ Set[].proper_subset?(@set).should be_true
+ Set[].proper_subset?(Set[1, 2, 3]).should be_true
+ Set[].proper_subset?(Set["a", :b, ?c]).should be_true
+
+ Set[1, 2, 3].proper_subset?(@set).should be_true
+ Set[1, 3].proper_subset?(@set).should be_true
+ Set[1, 2].proper_subset?(@set).should be_true
+ Set[1].proper_subset?(@set).should be_true
+
+ Set[5].proper_subset?(@set).should be_false
+ Set[1, 5].proper_subset?(@set).should be_false
+ Set[nil].proper_subset?(@set).should be_false
+ Set["test"].proper_subset?(@set).should be_false
+
+ @set.proper_subset?(@set).should be_false
+ Set[].proper_subset?(Set[]).should be_false
+ end
+
+ it "raises an ArgumentError when passed a non-Set" do
+ -> { Set[].proper_subset?([]) }.should raise_error(ArgumentError)
+ -> { Set[].proper_subset?(1) }.should raise_error(ArgumentError)
+ -> { Set[].proper_subset?("test") }.should raise_error(ArgumentError)
+ -> { Set[].proper_subset?(Object.new) }.should raise_error(ArgumentError)
+ end
+
+ version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
+ ruby_version_is ""..."4.0" do
+ context "when comparing to a Set-like object" do
+ it "returns true if passed a Set-like object that self is a proper subset of" do
+ Set[1, 2, 3].proper_subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/set/proper_superset_spec.rb b/spec/ruby/core/set/proper_superset_spec.rb
new file mode 100644
index 0000000000..dc1e87e230
--- /dev/null
+++ b/spec/ruby/core/set/proper_superset_spec.rb
@@ -0,0 +1,42 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+
+describe "Set#proper_superset?" do
+ before :each do
+ @set = Set[1, 2, 3, 4]
+ end
+
+ it "returns true if passed a Set that self is a proper superset of" do
+ @set.proper_superset?(Set[]).should be_true
+ Set[1, 2, 3].proper_superset?(Set[]).should be_true
+ Set["a", :b, ?c].proper_superset?(Set[]).should be_true
+
+ @set.proper_superset?(Set[1, 2, 3]).should be_true
+ @set.proper_superset?(Set[1, 3]).should be_true
+ @set.proper_superset?(Set[1, 2]).should be_true
+ @set.proper_superset?(Set[1]).should be_true
+
+ @set.proper_superset?(Set[5]).should be_false
+ @set.proper_superset?(Set[1, 5]).should be_false
+ @set.proper_superset?(Set[nil]).should be_false
+ @set.proper_superset?(Set["test"]).should be_false
+
+ @set.proper_superset?(@set).should be_false
+ Set[].proper_superset?(Set[]).should be_false
+ end
+
+ it "raises an ArgumentError when passed a non-Set" do
+ -> { Set[].proper_superset?([]) }.should raise_error(ArgumentError)
+ -> { Set[].proper_superset?(1) }.should raise_error(ArgumentError)
+ -> { Set[].proper_superset?("test") }.should raise_error(ArgumentError)
+ -> { Set[].proper_superset?(Object.new) }.should raise_error(ArgumentError)
+ end
+
+ ruby_version_is ""..."4.0" do
+ context "when comparing to a Set-like object" do
+ it "returns true if passed a Set-like object that self is a proper superset of" do
+ Set[1, 2, 3, 4].proper_superset?(SetSpecs::SetLike.new([1, 2, 3])).should be_true
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/set/reject_spec.rb b/spec/ruby/core/set/reject_spec.rb
new file mode 100644
index 0000000000..91d0293415
--- /dev/null
+++ b/spec/ruby/core/set/reject_spec.rb
@@ -0,0 +1,41 @@
+require_relative '../../spec_helper'
+
+describe "Set#reject!" do
+ before :each do
+ @set = Set["one", "two", "three"]
+ end
+
+ it "yields every element of self" do
+ ret = []
+ @set.reject! { |x| ret << x }
+ ret.sort.should == ["one", "two", "three"].sort
+ end
+
+ it "deletes every element from self for which the passed block returns true" do
+ @set.reject! { |x| x.size == 3 }
+ @set.size.should eql(1)
+
+ @set.should_not include("one")
+ @set.should_not include("two")
+ @set.should include("three")
+ end
+
+ it "returns self when self was modified" do
+ @set.reject! { |x| true }.should equal(@set)
+ end
+
+ it "returns nil when self was not modified" do
+ @set.reject! { |x| false }.should be_nil
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.reject!
+ enum.should be_an_instance_of(Enumerator)
+
+ enum.each { |x| x.size == 3 }
+
+ @set.should_not include("one")
+ @set.should_not include("two")
+ @set.should include("three")
+ end
+end
diff --git a/spec/ruby/core/set/replace_spec.rb b/spec/ruby/core/set/replace_spec.rb
new file mode 100644
index 0000000000..c66a2d0ec3
--- /dev/null
+++ b/spec/ruby/core/set/replace_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../spec_helper'
+
+describe "Set#replace" do
+ before :each do
+ @set = Set[:a, :b, :c]
+ end
+
+ it "replaces the contents with other and returns self" do
+ @set.replace(Set[1, 2, 3]).should == @set
+ @set.should == Set[1, 2, 3]
+ end
+
+ it "raises RuntimeError when called during iteration" do
+ set = Set[:a, :b, :c, :d, :e, :f]
+ set.each do |_m|
+ -> { set.replace(Set[1, 2, 3]) }.should raise_error(RuntimeError, /iteration/)
+ end
+ set.should == Set[:a, :b, :c, :d, :e, :f]
+ end
+
+ it "accepts any enumerable as other" do
+ @set.replace([1, 2, 3]).should == Set[1, 2, 3]
+ end
+end
diff --git a/spec/ruby/core/set/select_spec.rb b/spec/ruby/core/set/select_spec.rb
new file mode 100644
index 0000000000..b458ffacaa
--- /dev/null
+++ b/spec/ruby/core/set/select_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/select'
+
+describe "Set#select!" do
+ it_behaves_like :set_select_bang, :select!
+end
diff --git a/spec/ruby/core/set/set_spec.rb b/spec/ruby/core/set/set_spec.rb
new file mode 100644
index 0000000000..fd1d2072e3
--- /dev/null
+++ b/spec/ruby/core/set/set_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../spec_helper'
+
+describe 'Set' do
+ it 'is available without explicit requiring' do
+ output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1')
+ puts Set.new([1, 2, 3]).to_a.inspect
+ RUBY
+ output.chomp.should == "[1, 2, 3]"
+ end
+end
diff --git a/spec/ruby/core/set/shared/add.rb b/spec/ruby/core/set/shared/add.rb
new file mode 100644
index 0000000000..9e797f5df9
--- /dev/null
+++ b/spec/ruby/core/set/shared/add.rb
@@ -0,0 +1,14 @@
+describe :set_add, shared: true do
+ before :each do
+ @set = Set.new
+ end
+
+ it "adds the passed Object to self" do
+ @set.send(@method, "dog")
+ @set.should include("dog")
+ end
+
+ it "returns self" do
+ @set.send(@method, "dog").should equal(@set)
+ end
+end
diff --git a/spec/ruby/core/set/shared/collect.rb b/spec/ruby/core/set/shared/collect.rb
new file mode 100644
index 0000000000..bc58c231be
--- /dev/null
+++ b/spec/ruby/core/set/shared/collect.rb
@@ -0,0 +1,20 @@
+describe :set_collect_bang, shared: true do
+ before :each do
+ @set = Set[1, 2, 3, 4, 5]
+ end
+
+ it "yields each Object in self" do
+ res = []
+ @set.send(@method) { |x| res << x }
+ res.sort.should == [1, 2, 3, 4, 5].sort
+ end
+
+ it "returns self" do
+ @set.send(@method) { |x| x }.should equal(@set)
+ end
+
+ it "replaces self with the return values of the block" do
+ @set.send(@method) { |x| x * 2 }
+ @set.should == Set[2, 4, 6, 8, 10]
+ end
+end
diff --git a/spec/ruby/core/set/shared/difference.rb b/spec/ruby/core/set/shared/difference.rb
new file mode 100644
index 0000000000..f88987ed2a
--- /dev/null
+++ b/spec/ruby/core/set/shared/difference.rb
@@ -0,0 +1,15 @@
+describe :set_difference, shared: true do
+ before :each do
+ @set = Set[:a, :b, :c]
+ end
+
+ it "returns a new Set containing self's elements excluding the elements in the passed Enumerable" do
+ @set.send(@method, Set[:a, :b]).should == Set[:c]
+ @set.send(@method, [:b, :c]).should == Set[:a]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set.send(@method, 1) }.should raise_error(ArgumentError)
+ -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/ruby/core/set/shared/include.rb b/spec/ruby/core/set/shared/include.rb
new file mode 100644
index 0000000000..b4d95cde24
--- /dev/null
+++ b/spec/ruby/core/set/shared/include.rb
@@ -0,0 +1,29 @@
+describe :set_include, shared: true do
+ it "returns true when self contains the passed Object" do
+ set = Set[:a, :b, :c]
+ set.send(@method, :a).should be_true
+ set.send(@method, :e).should be_false
+ end
+
+ describe "member equality" do
+ it "is checked using both #hash and #eql?" do
+ obj = Object.new
+ obj_another = Object.new
+
+ def obj.hash; 42 end
+ def obj_another.hash; 42 end
+ def obj_another.eql?(o) hash == o.hash end
+
+ set = Set["a", "b", "c", obj]
+ set.send(@method, obj_another).should == true
+ end
+
+ it "is not checked using #==" do
+ obj = Object.new
+ set = Set["a", "b", "c"]
+
+ obj.should_not_receive(:==)
+ set.send(@method, obj)
+ end
+ end
+end
diff --git a/spec/ruby/core/set/shared/inspect.rb b/spec/ruby/core/set/shared/inspect.rb
new file mode 100644
index 0000000000..a90af66c98
--- /dev/null
+++ b/spec/ruby/core/set/shared/inspect.rb
@@ -0,0 +1,45 @@
+describe :set_inspect, shared: true do
+ it "returns a String representation of self" do
+ Set[].send(@method).should be_kind_of(String)
+ Set[nil, false, true].send(@method).should be_kind_of(String)
+ Set[1, 2, 3].send(@method).should be_kind_of(String)
+ Set["1", "2", "3"].send(@method).should be_kind_of(String)
+ Set[:a, "b", Set[?c]].send(@method).should be_kind_of(String)
+ end
+
+ ruby_version_is "4.0" do
+ it "does include the elements of the set" do
+ Set["1"].send(@method).should == 'Set["1"]'
+ end
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "does include the elements of the set" do
+ Set["1"].send(@method).should == '#<Set: {"1"}>'
+ end
+ end
+
+ it "puts spaces between the elements" do
+ Set["1", "2"].send(@method).should include('", "')
+ end
+
+ ruby_version_is "4.0" do
+ it "correctly handles cyclic-references" do
+ set1 = Set[]
+ set2 = Set[set1]
+ set1 << set2
+ set1.send(@method).should be_kind_of(String)
+ set1.send(@method).should include("Set[...]")
+ end
+ end
+
+ ruby_version_is ""..."4.0" do
+ it "correctly handles cyclic-references" do
+ set1 = Set[]
+ set2 = Set[set1]
+ set1 << set2
+ set1.send(@method).should be_kind_of(String)
+ set1.send(@method).should include("#<Set: {...}>")
+ end
+ end
+end
diff --git a/spec/ruby/core/set/shared/intersection.rb b/spec/ruby/core/set/shared/intersection.rb
new file mode 100644
index 0000000000..5ae4199c94
--- /dev/null
+++ b/spec/ruby/core/set/shared/intersection.rb
@@ -0,0 +1,15 @@
+describe :set_intersection, shared: true do
+ before :each do
+ @set = Set[:a, :b, :c]
+ end
+
+ it "returns a new Set containing only elements shared by self and the passed Enumerable" do
+ @set.send(@method, Set[:b, :c, :d, :e]).should == Set[:b, :c]
+ @set.send(@method, [:b, :c, :d]).should == Set[:b, :c]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set.send(@method, 1) }.should raise_error(ArgumentError)
+ -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/ruby/core/set/shared/length.rb b/spec/ruby/core/set/shared/length.rb
new file mode 100644
index 0000000000..a8fcee9f39
--- /dev/null
+++ b/spec/ruby/core/set/shared/length.rb
@@ -0,0 +1,6 @@
+describe :set_length, shared: true do
+ it "returns the number of elements in the set" do
+ set = Set[:a, :b, :c]
+ set.send(@method).should == 3
+ end
+end
diff --git a/spec/ruby/core/set/shared/select.rb b/spec/ruby/core/set/shared/select.rb
new file mode 100644
index 0000000000..467b236ed3
--- /dev/null
+++ b/spec/ruby/core/set/shared/select.rb
@@ -0,0 +1,41 @@
+require_relative '../../../spec_helper'
+
+describe :set_select_bang, shared: true do
+ before :each do
+ @set = Set["one", "two", "three"]
+ end
+
+ it "yields every element of self" do
+ ret = []
+ @set.send(@method) { |x| ret << x }
+ ret.sort.should == ["one", "two", "three"].sort
+ end
+
+ it "keeps every element from self for which the passed block returns true" do
+ @set.send(@method) { |x| x.size != 3 }
+ @set.size.should eql(1)
+
+ @set.should_not include("one")
+ @set.should_not include("two")
+ @set.should include("three")
+ end
+
+ it "returns self when self was modified" do
+ @set.send(@method) { false }.should equal(@set)
+ end
+
+ it "returns nil when self was not modified" do
+ @set.send(@method) { true }.should be_nil
+ end
+
+ it "returns an Enumerator when passed no block" do
+ enum = @set.send(@method)
+ enum.should be_an_instance_of(Enumerator)
+
+ enum.each { |x| x.size != 3 }
+
+ @set.should_not include("one")
+ @set.should_not include("two")
+ @set.should include("three")
+ end
+end
diff --git a/spec/ruby/core/set/shared/union.rb b/spec/ruby/core/set/shared/union.rb
new file mode 100644
index 0000000000..314f0e852d
--- /dev/null
+++ b/spec/ruby/core/set/shared/union.rb
@@ -0,0 +1,15 @@
+describe :set_union, shared: true do
+ before :each do
+ @set = Set[:a, :b, :c]
+ end
+
+ it "returns a new Set containing all elements of self and the passed Enumerable" do
+ @set.send(@method, Set[:b, :d, :e]).should == Set[:a, :b, :c, :d, :e]
+ @set.send(@method, [:b, :e]).should == Set[:a, :b, :c, :e]
+ end
+
+ it "raises an ArgumentError when passed a non-Enumerable" do
+ -> { @set.send(@method, 1) }.should raise_error(ArgumentError)
+ -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/ruby/core/set/size_spec.rb b/spec/ruby/core/set/size_spec.rb
new file mode 100644
index 0000000000..4ae22c5f0a
--- /dev/null
+++ b/spec/ruby/core/set/size_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../spec_helper'
+require_relative 'shared/length'
+
+describe "Set#size" do
+ it_behaves_like :set_length, :size
+end
diff --git a/spec/ruby/core/set/sortedset/sortedset_spec.rb b/spec/ruby/core/set/sortedset/sortedset_spec.rb
new file mode 100644
index 0000000000..f3c1ec058d
--- /dev/null
+++ b/spec/ruby/core/set/sortedset/sortedset_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../../spec_helper'
+
+describe "SortedSet" do
+ ruby_version_is ""..."4.0" do
+ it "raises error including message that it has been extracted from the set stdlib" do
+ -> {
+ SortedSet
+ }.should raise_error(RuntimeError) { |e|
+ e.message.should.include?("The `SortedSet` class has been extracted from the `set` library")
+ }
+ end
+ end
+end
diff --git a/spec/ruby/core/set/subset_spec.rb b/spec/ruby/core/set/subset_spec.rb
new file mode 100644
index 0000000000..112bd9b38a
--- /dev/null
+++ b/spec/ruby/core/set/subset_spec.rb
@@ -0,0 +1,45 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
+
+describe "Set#subset?" do
+ before :each do
+ @set = Set[1, 2, 3, 4]
+ end
+
+ it "returns true if passed a Set that is equal to self or self is a subset of" do
+ @set.subset?(@set).should be_true
+ Set[].subset?(Set[]).should be_true
+
+ Set[].subset?(@set).should be_true
+ Set[].subset?(Set[1, 2, 3]).should be_true
+ Set[].subset?(Set["a", :b, ?c]).should be_true
+
+ Set[1, 2, 3].subset?(@set).should be_true
+ Set[1, 3].subset?(@set).should be_true
+ Set[1, 2].subset?(@set).should be_true
+ Set[1].subset?(@set).should be_true
+
+ Set[5].subset?(@set).should be_false
+ Set[1, 5].subset?(@set).should be_false
+ Set[nil].subset?(@set).should be_false
+ Set["test"].subset?(@set).should be_false
+ end
+
+ it "raises an ArgumentError when passed a non-Set" do
+ -> { Set[].subset?([]) }.should raise_error(ArgumentError)
+ -> { Set[].subset?(1) }.should raise_error(ArgumentError)
+ -> { Set[].subset?("test") }.should raise_error(ArgumentError)
+ -> { Set[].subset?(Object.new) }.should raise_error(ArgumentError)
+ end
+
+ version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
+ ruby_version_is ""..."4.0" do
+ context "when comparing to a Set-like object" do
+ it "returns true if passed a Set-like object that self is a subset of" do
+ Set[1, 2, 3].subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/set/subtract_spec.rb b/spec/ruby/core/set/subtract_spec.rb
new file mode 100644
index 0000000000..ae4bc73d41
--- /dev/null
+++ b/spec/ruby/core/set/subtract_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../spec_helper'
+
+describe "Set#subtract" do
+ before :each do
+ @set = Set[:a, :b, :c]
+ end
+
+ it "deletes any elements contained in other and returns self" do
+ @set.subtract(Set[:b, :c]).should == @set
+ @set.should == Set[:a]
+ end
+
+ it "accepts any enumerable as other" do
+ @set.subtract([:c]).should == Set[:a, :b]
+ end
+end
diff --git a/spec/ruby/core/set/superset_spec.rb b/spec/ruby/core/set/superset_spec.rb
new file mode 100644
index 0000000000..9b3df2d047
--- /dev/null
+++ b/spec/ruby/core/set/superset_spec.rb
@@ -0,0 +1,42 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/set_like'
+
+describe "Set#superset?" do
+ before :each do
+ @set = Set[1, 2, 3, 4]
+ end
+
+ it "returns true if passed a Set that equals self or self is a proper superset of" do
+ @set.superset?(@set).should be_true
+ Set[].superset?(Set[]).should be_true
+
+ @set.superset?(Set[]).should be_true
+ Set[1, 2, 3].superset?(Set[]).should be_true
+ Set["a", :b, ?c].superset?(Set[]).should be_true
+
+ @set.superset?(Set[1, 2, 3]).should be_true
+ @set.superset?(Set[1, 3]).should be_true
+ @set.superset?(Set[1, 2]).should be_true
+ @set.superset?(Set[1]).should be_true
+
+ @set.superset?(Set[5]).should be_false
+ @set.superset?(Set[1, 5]).should be_false
+ @set.superset?(Set[nil]).should be_false
+ @set.superset?(Set["test"]).should be_false
+ end
+
+ it "raises an ArgumentError when passed a non-Set" do
+ -> { Set[].superset?([]) }.should raise_error(ArgumentError)
+ -> { Set[].superset?(1) }.should raise_error(ArgumentError)
+ -> { Set[].superset?("test") }.should raise_error(ArgumentError)
+ -> { Set[].superset?(Object.new) }.should raise_error(ArgumentError)
+ end
+
+ ruby_version_is ""..."4.0" do
+ context "when comparing to a Set-like object" do
+ it "returns true if passed a Set-like object that self is a superset of" do
+ Set[1, 2, 3, 4].superset?(SetSpecs::SetLike.new([1, 2, 3])).should be_true
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/set/to_a_spec.rb b/spec/ruby/core/set/to_a_spec.rb
new file mode 100644
index 0000000000..1e9800167a
--- /dev/null
+++ b/spec/ruby/core/set/to_a_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+
+describe "Set#to_a" do
+ it "returns an array containing elements of self" do
+ Set[1, 2, 3].to_a.sort.should == [1, 2, 3]
+ end
+end
diff --git a/spec/ruby/core/set/to_s_spec.rb b/spec/ruby/core/set/to_s_spec.rb
new file mode 100644
index 0000000000..55b8bfd9b2
--- /dev/null
+++ b/spec/ruby/core/set/to_s_spec.rb
@@ -0,0 +1,11 @@
+require_relative "../../spec_helper"
+require_relative 'shared/inspect'
+
+describe "Set#to_s" do
+ it_behaves_like :set_inspect, :to_s
+
+ it "is an alias of inspect" do
+ set = Set.new
+ set.method(:to_s).should == set.method(:inspect)
+ end
+end
diff --git a/spec/ruby/core/set/union_spec.rb b/spec/ruby/core/set/union_spec.rb
new file mode 100644
index 0000000000..3e77022d4b
--- /dev/null
+++ b/spec/ruby/core/set/union_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../spec_helper'
+require_relative 'shared/union'
+
+describe "Set#union" do
+ it_behaves_like :set_union, :union
+end
+
+describe "Set#|" do
+ it_behaves_like :set_union, :|
+end
diff --git a/spec/ruby/core/sizedqueue/append_spec.rb b/spec/ruby/core/sizedqueue/append_spec.rb
index 6fffe2f272..c52baa3802 100644
--- a/spec/ruby/core/sizedqueue/append_spec.rb
+++ b/spec/ruby/core/sizedqueue/append_spec.rb
@@ -12,7 +12,5 @@ describe "SizedQueue#<<" do
end
describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.send(:<<, 1, timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.send(:<<, 1, timeout: v) }
end
diff --git a/spec/ruby/core/sizedqueue/deq_spec.rb b/spec/ruby/core/sizedqueue/deq_spec.rb
index 985d654bb3..2aeb52f8a6 100644
--- a/spec/ruby/core/sizedqueue/deq_spec.rb
+++ b/spec/ruby/core/sizedqueue/deq_spec.rb
@@ -7,7 +7,5 @@ describe "SizedQueue#deq" do
end
describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.deq(timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.deq(timeout: v) }
end
diff --git a/spec/ruby/core/sizedqueue/enq_spec.rb b/spec/ruby/core/sizedqueue/enq_spec.rb
index 619373e46b..b955909475 100644
--- a/spec/ruby/core/sizedqueue/enq_spec.rb
+++ b/spec/ruby/core/sizedqueue/enq_spec.rb
@@ -12,7 +12,5 @@ describe "SizedQueue#enq" do
end
describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.enq(1, timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.enq(1, timeout: v) }
end
diff --git a/spec/ruby/core/sizedqueue/pop_spec.rb b/spec/ruby/core/sizedqueue/pop_spec.rb
index 5e7cfea8fb..6338ddbaa0 100644
--- a/spec/ruby/core/sizedqueue/pop_spec.rb
+++ b/spec/ruby/core/sizedqueue/pop_spec.rb
@@ -7,7 +7,5 @@ describe "SizedQueue#pop" do
end
describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.pop(timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.pop(timeout: v) }
end
diff --git a/spec/ruby/core/sizedqueue/push_spec.rb b/spec/ruby/core/sizedqueue/push_spec.rb
index ce61e89b53..9eaa6beca0 100644
--- a/spec/ruby/core/sizedqueue/push_spec.rb
+++ b/spec/ruby/core/sizedqueue/push_spec.rb
@@ -12,7 +12,5 @@ describe "SizedQueue#push" do
end
describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.push(1, timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.push(1, timeout: v) }
end
diff --git a/spec/ruby/core/sizedqueue/shift_spec.rb b/spec/ruby/core/sizedqueue/shift_spec.rb
index 3220801f3a..52974c1d99 100644
--- a/spec/ruby/core/sizedqueue/shift_spec.rb
+++ b/spec/ruby/core/sizedqueue/shift_spec.rb
@@ -7,7 +7,5 @@ describe "SizedQueue#shift" do
end
describe "SizedQueue operations with timeout" do
- ruby_version_is "3.2" do
- it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.shift(timeout: v) }
- end
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.shift(timeout: v) }
end
diff --git a/spec/ruby/core/string/append_as_bytes_spec.rb b/spec/ruby/core/string/append_as_bytes_spec.rb
index 0e1d09558b..b1703e5f89 100644
--- a/spec/ruby/core/string/append_as_bytes_spec.rb
+++ b/spec/ruby/core/string/append_as_bytes_spec.rb
@@ -34,6 +34,18 @@ describe "String#append_bytes" do
str.should == "hello\xE2\x82\f+\xAC".b
end
+ it "truncates integers to the least significant byte" do
+ str = +""
+ str.append_as_bytes(0x131, 0x232, 0x333, bignum_value, bignum_value(1))
+ str.bytes.should == [0x31, 0x32, 0x33, 0, 1]
+ end
+
+ it "wraps negative integers" do
+ str = "".b
+ str.append_as_bytes(-1, -bignum_value, -bignum_value(1))
+ str.bytes.should == [0xFF, 0, 0xFF]
+ end
+
it "only accepts strings or integers, and doesn't attempt to cast with #to_str or #to_int" do
to_str = mock("to_str")
to_str.should_not_receive(:to_str)
diff --git a/spec/ruby/core/string/byteindex_spec.rb b/spec/ruby/core/string/byteindex_spec.rb
index 47c7be1029..d420f3f683 100644
--- a/spec/ruby/core/string/byteindex_spec.rb
+++ b/spec/ruby/core/string/byteindex_spec.rb
@@ -4,301 +4,295 @@ require_relative 'fixtures/classes'
require_relative 'shared/byte_index_common.rb'
describe "String#byteindex" do
- ruby_version_is "3.2" do
- it "calls #to_str to convert the first argument" do
- char = mock("string index char")
- char.should_receive(:to_str).and_return("b")
- "abc".byteindex(char).should == 1
- end
-
- it "calls #to_int to convert the second argument" do
- offset = mock("string index offset")
- offset.should_receive(:to_int).and_return(1)
- "abc".byteindex("c", offset).should == 2
- end
+ it "calls #to_str to convert the first argument" do
+ char = mock("string index char")
+ char.should_receive(:to_str).and_return("b")
+ "abc".byteindex(char).should == 1
+ end
- it "does not raise IndexError when byte offset is correct or on string boundary" do
- "ã‚".byteindex("").should == 0
- "ã‚".byteindex("", 0).should == 0
- "ã‚".byteindex("", 3).should == 3
- end
+ it "calls #to_int to convert the second argument" do
+ offset = mock("string index offset")
+ offset.should_receive(:to_int).and_return(1)
+ "abc".byteindex("c", offset).should == 2
+ end
- it_behaves_like :byte_index_common, :byteindex
+ it "does not raise IndexError when byte offset is correct or on string boundary" do
+ "ã‚".byteindex("").should == 0
+ "ã‚".byteindex("", 0).should == 0
+ "ã‚".byteindex("", 3).should == 3
end
+
+ it_behaves_like :byte_index_common, :byteindex
end
describe "String#byteindex with String" do
- ruby_version_is "3.2" do
- it "behaves the same as String#byteindex(char) for one-character strings" do
- "blablabla hello cruel world...!".split("").uniq.each do |str|
- chr = str[0]
- str.byteindex(str).should == str.byteindex(chr)
+ it "behaves the same as String#byteindex(char) for one-character strings" do
+ "blablabla hello cruel world...!".split("").uniq.each do |str|
+ chr = str[0]
+ str.byteindex(str).should == str.byteindex(chr)
- 0.upto(str.size + 1) do |start|
- str.byteindex(str, start).should == str.byteindex(chr, start)
- end
+ 0.upto(str.size + 1) do |start|
+ str.byteindex(str, start).should == str.byteindex(chr, start)
+ end
- (-str.size - 1).upto(-1) do |start|
- str.byteindex(str, start).should == str.byteindex(chr, start)
- end
+ (-str.size - 1).upto(-1) do |start|
+ str.byteindex(str, start).should == str.byteindex(chr, start)
end
end
+ end
- it "returns the byteindex of the first occurrence of the given substring" do
- "blablabla".byteindex("").should == 0
- "blablabla".byteindex("b").should == 0
- "blablabla".byteindex("bla").should == 0
- "blablabla".byteindex("blabla").should == 0
- "blablabla".byteindex("blablabla").should == 0
-
- "blablabla".byteindex("l").should == 1
- "blablabla".byteindex("la").should == 1
- "blablabla".byteindex("labla").should == 1
- "blablabla".byteindex("lablabla").should == 1
-
- "blablabla".byteindex("a").should == 2
- "blablabla".byteindex("abla").should == 2
- "blablabla".byteindex("ablabla").should == 2
- end
+ it "returns the byteindex of the first occurrence of the given substring" do
+ "blablabla".byteindex("").should == 0
+ "blablabla".byteindex("b").should == 0
+ "blablabla".byteindex("bla").should == 0
+ "blablabla".byteindex("blabla").should == 0
+ "blablabla".byteindex("blablabla").should == 0
+
+ "blablabla".byteindex("l").should == 1
+ "blablabla".byteindex("la").should == 1
+ "blablabla".byteindex("labla").should == 1
+ "blablabla".byteindex("lablabla").should == 1
+
+ "blablabla".byteindex("a").should == 2
+ "blablabla".byteindex("abla").should == 2
+ "blablabla".byteindex("ablabla").should == 2
+ end
- it "treats the offset as a byteindex" do
- "aaaaa".byteindex("a", 0).should == 0
- "aaaaa".byteindex("a", 2).should == 2
- "aaaaa".byteindex("a", 4).should == 4
- end
+ it "treats the offset as a byteindex" do
+ "aaaaa".byteindex("a", 0).should == 0
+ "aaaaa".byteindex("a", 2).should == 2
+ "aaaaa".byteindex("a", 4).should == 4
+ end
- it "ignores string subclasses" do
- "blablabla".byteindex(StringSpecs::MyString.new("bla")).should == 0
- StringSpecs::MyString.new("blablabla").byteindex("bla").should == 0
- StringSpecs::MyString.new("blablabla").byteindex(StringSpecs::MyString.new("bla")).should == 0
- end
+ it "ignores string subclasses" do
+ "blablabla".byteindex(StringSpecs::MyString.new("bla")).should == 0
+ StringSpecs::MyString.new("blablabla").byteindex("bla").should == 0
+ StringSpecs::MyString.new("blablabla").byteindex(StringSpecs::MyString.new("bla")).should == 0
+ end
- it "starts the search at the given offset" do
- "blablabla".byteindex("bl", 0).should == 0
- "blablabla".byteindex("bl", 1).should == 3
- "blablabla".byteindex("bl", 2).should == 3
- "blablabla".byteindex("bl", 3).should == 3
-
- "blablabla".byteindex("bla", 0).should == 0
- "blablabla".byteindex("bla", 1).should == 3
- "blablabla".byteindex("bla", 2).should == 3
- "blablabla".byteindex("bla", 3).should == 3
-
- "blablabla".byteindex("blab", 0).should == 0
- "blablabla".byteindex("blab", 1).should == 3
- "blablabla".byteindex("blab", 2).should == 3
- "blablabla".byteindex("blab", 3).should == 3
-
- "blablabla".byteindex("la", 1).should == 1
- "blablabla".byteindex("la", 2).should == 4
- "blablabla".byteindex("la", 3).should == 4
- "blablabla".byteindex("la", 4).should == 4
-
- "blablabla".byteindex("lab", 1).should == 1
- "blablabla".byteindex("lab", 2).should == 4
- "blablabla".byteindex("lab", 3).should == 4
- "blablabla".byteindex("lab", 4).should == 4
-
- "blablabla".byteindex("ab", 2).should == 2
- "blablabla".byteindex("ab", 3).should == 5
- "blablabla".byteindex("ab", 4).should == 5
- "blablabla".byteindex("ab", 5).should == 5
-
- "blablabla".byteindex("", 0).should == 0
- "blablabla".byteindex("", 1).should == 1
- "blablabla".byteindex("", 2).should == 2
- "blablabla".byteindex("", 7).should == 7
- "blablabla".byteindex("", 8).should == 8
- "blablabla".byteindex("", 9).should == 9
- end
+ it "starts the search at the given offset" do
+ "blablabla".byteindex("bl", 0).should == 0
+ "blablabla".byteindex("bl", 1).should == 3
+ "blablabla".byteindex("bl", 2).should == 3
+ "blablabla".byteindex("bl", 3).should == 3
+
+ "blablabla".byteindex("bla", 0).should == 0
+ "blablabla".byteindex("bla", 1).should == 3
+ "blablabla".byteindex("bla", 2).should == 3
+ "blablabla".byteindex("bla", 3).should == 3
+
+ "blablabla".byteindex("blab", 0).should == 0
+ "blablabla".byteindex("blab", 1).should == 3
+ "blablabla".byteindex("blab", 2).should == 3
+ "blablabla".byteindex("blab", 3).should == 3
+
+ "blablabla".byteindex("la", 1).should == 1
+ "blablabla".byteindex("la", 2).should == 4
+ "blablabla".byteindex("la", 3).should == 4
+ "blablabla".byteindex("la", 4).should == 4
+
+ "blablabla".byteindex("lab", 1).should == 1
+ "blablabla".byteindex("lab", 2).should == 4
+ "blablabla".byteindex("lab", 3).should == 4
+ "blablabla".byteindex("lab", 4).should == 4
+
+ "blablabla".byteindex("ab", 2).should == 2
+ "blablabla".byteindex("ab", 3).should == 5
+ "blablabla".byteindex("ab", 4).should == 5
+ "blablabla".byteindex("ab", 5).should == 5
+
+ "blablabla".byteindex("", 0).should == 0
+ "blablabla".byteindex("", 1).should == 1
+ "blablabla".byteindex("", 2).should == 2
+ "blablabla".byteindex("", 7).should == 7
+ "blablabla".byteindex("", 8).should == 8
+ "blablabla".byteindex("", 9).should == 9
+ end
- it "starts the search at offset + self.length if offset is negative" do
- str = "blablabla"
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
- ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
- (-str.length .. -1).each do |offset|
- str.byteindex(needle, offset).should ==
- str.byteindex(needle, offset + str.length)
- end
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byteindex(needle, offset).should ==
+ str.byteindex(needle, offset + str.length)
end
end
+ end
- it "returns nil if the substring isn't found" do
- "blablabla".byteindex("B").should == nil
- "blablabla".byteindex("z").should == nil
- "blablabla".byteindex("BLA").should == nil
- "blablabla".byteindex("blablablabla").should == nil
- "blablabla".byteindex("", 10).should == nil
+ it "returns nil if the substring isn't found" do
+ "blablabla".byteindex("B").should == nil
+ "blablabla".byteindex("z").should == nil
+ "blablabla".byteindex("BLA").should == nil
+ "blablabla".byteindex("blablablabla").should == nil
+ "blablabla".byteindex("", 10).should == nil
- "hello".byteindex("he", 1).should == nil
- "hello".byteindex("he", 2).should == nil
- "I’ve got a multibyte character.\n".byteindex("\n\n").should == nil
- end
+ "hello".byteindex("he", 1).should == nil
+ "hello".byteindex("he", 2).should == nil
+ "I’ve got a multibyte character.\n".byteindex("\n\n").should == nil
+ end
- it "returns the character byteindex of a multibyte character" do
- "ã‚りãŒã¨ã†".byteindex("ãŒ").should == 6
- end
+ it "returns the character byteindex of a multibyte character" do
+ "ã‚りãŒã¨ã†".byteindex("ãŒ").should == 6
+ end
- it "returns the character byteindex after offset" do
- "ã‚れã‚れ".byteindex("ã‚", 3).should == 6
- "ã‚りãŒã¨ã†ã‚りãŒã¨ã†".byteindex("ãŒ", 9).should == 21
- end
+ it "returns the character byteindex after offset" do
+ "ã‚れã‚れ".byteindex("ã‚", 3).should == 6
+ "ã‚りãŒã¨ã†ã‚りãŒã¨ã†".byteindex("ãŒ", 9).should == 21
+ end
- it "returns the character byteindex after a partial first match" do
- "</</h".byteindex("</h").should == 2
- end
+ it "returns the character byteindex after a partial first match" do
+ "</</h".byteindex("</h").should == 2
+ end
- it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
- char = "れ".encode Encoding::EUC_JP
- -> do
- "ã‚れ".byteindex(char)
- end.should raise_error(Encoding::CompatibilityError)
- end
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ char = "れ".encode Encoding::EUC_JP
+ -> do
+ "ã‚れ".byteindex(char)
+ end.should raise_error(Encoding::CompatibilityError)
+ end
- it "handles a substring in a superset encoding" do
- 'abc'.dup.force_encoding(Encoding::US_ASCII).byteindex('é').should == nil
- end
+ it "handles a substring in a superset encoding" do
+ 'abc'.dup.force_encoding(Encoding::US_ASCII).byteindex('é').should == nil
+ end
- it "handles a substring in a subset encoding" do
- 'été'.byteindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 2
- end
+ it "handles a substring in a subset encoding" do
+ 'été'.byteindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 2
end
end
describe "String#byteindex with Regexp" do
- ruby_version_is "3.2" do
- it "behaves the same as String#byteindex(string) for escaped string regexps" do
- ["blablabla", "hello cruel world...!"].each do |str|
- ["", "b", "bla", "lab", "o c", "d."].each do |needle|
- regexp = Regexp.new(Regexp.escape(needle))
- str.byteindex(regexp).should == str.byteindex(needle)
-
- 0.upto(str.size + 1) do |start|
- str.byteindex(regexp, start).should == str.byteindex(needle, start)
- end
-
- (-str.size - 1).upto(-1) do |start|
- str.byteindex(regexp, start).should == str.byteindex(needle, start)
- end
+ it "behaves the same as String#byteindex(string) for escaped string regexps" do
+ ["blablabla", "hello cruel world...!"].each do |str|
+ ["", "b", "bla", "lab", "o c", "d."].each do |needle|
+ regexp = Regexp.new(Regexp.escape(needle))
+ str.byteindex(regexp).should == str.byteindex(needle)
+
+ 0.upto(str.size + 1) do |start|
+ str.byteindex(regexp, start).should == str.byteindex(needle, start)
+ end
+
+ (-str.size - 1).upto(-1) do |start|
+ str.byteindex(regexp, start).should == str.byteindex(needle, start)
end
end
end
+ end
- it "returns the byteindex of the first match of regexp" do
- "blablabla".byteindex(/bla/).should == 0
- "blablabla".byteindex(/BLA/i).should == 0
+ it "returns the byteindex of the first match of regexp" do
+ "blablabla".byteindex(/bla/).should == 0
+ "blablabla".byteindex(/BLA/i).should == 0
- "blablabla".byteindex(/.{0}/).should == 0
- "blablabla".byteindex(/.{6}/).should == 0
- "blablabla".byteindex(/.{9}/).should == 0
+ "blablabla".byteindex(/.{0}/).should == 0
+ "blablabla".byteindex(/.{6}/).should == 0
+ "blablabla".byteindex(/.{9}/).should == 0
- "blablabla".byteindex(/.*/).should == 0
- "blablabla".byteindex(/.+/).should == 0
+ "blablabla".byteindex(/.*/).should == 0
+ "blablabla".byteindex(/.+/).should == 0
- "blablabla".byteindex(/lab|b/).should == 0
+ "blablabla".byteindex(/lab|b/).should == 0
- not_supported_on :opal do
- "blablabla".byteindex(/\A/).should == 0
- "blablabla".byteindex(/\Z/).should == 9
- "blablabla".byteindex(/\z/).should == 9
- "blablabla\n".byteindex(/\Z/).should == 9
- "blablabla\n".byteindex(/\z/).should == 10
- end
+ not_supported_on :opal do
+ "blablabla".byteindex(/\A/).should == 0
+ "blablabla".byteindex(/\Z/).should == 9
+ "blablabla".byteindex(/\z/).should == 9
+ "blablabla\n".byteindex(/\Z/).should == 9
+ "blablabla\n".byteindex(/\z/).should == 10
+ end
- "blablabla".byteindex(/^/).should == 0
- "\nblablabla".byteindex(/^/).should == 0
- "b\nablabla".byteindex(/$/).should == 1
- "bl\nablabla".byteindex(/$/).should == 2
+ "blablabla".byteindex(/^/).should == 0
+ "\nblablabla".byteindex(/^/).should == 0
+ "b\nablabla".byteindex(/$/).should == 1
+ "bl\nablabla".byteindex(/$/).should == 2
- "blablabla".byteindex(/.l./).should == 0
- end
+ "blablabla".byteindex(/.l./).should == 0
+ end
- it "starts the search at the given offset" do
- "blablabla".byteindex(/.{0}/, 5).should == 5
- "blablabla".byteindex(/.{1}/, 5).should == 5
- "blablabla".byteindex(/.{2}/, 5).should == 5
- "blablabla".byteindex(/.{3}/, 5).should == 5
- "blablabla".byteindex(/.{4}/, 5).should == 5
-
- "blablabla".byteindex(/.{0}/, 3).should == 3
- "blablabla".byteindex(/.{1}/, 3).should == 3
- "blablabla".byteindex(/.{2}/, 3).should == 3
- "blablabla".byteindex(/.{5}/, 3).should == 3
- "blablabla".byteindex(/.{6}/, 3).should == 3
-
- "blablabla".byteindex(/.l./, 0).should == 0
- "blablabla".byteindex(/.l./, 1).should == 3
- "blablabla".byteindex(/.l./, 2).should == 3
- "blablabla".byteindex(/.l./, 3).should == 3
-
- "xblaxbla".byteindex(/x./, 0).should == 0
- "xblaxbla".byteindex(/x./, 1).should == 4
- "xblaxbla".byteindex(/x./, 2).should == 4
-
- not_supported_on :opal do
- "blablabla\n".byteindex(/\Z/, 9).should == 9
- end
+ it "starts the search at the given offset" do
+ "blablabla".byteindex(/.{0}/, 5).should == 5
+ "blablabla".byteindex(/.{1}/, 5).should == 5
+ "blablabla".byteindex(/.{2}/, 5).should == 5
+ "blablabla".byteindex(/.{3}/, 5).should == 5
+ "blablabla".byteindex(/.{4}/, 5).should == 5
+
+ "blablabla".byteindex(/.{0}/, 3).should == 3
+ "blablabla".byteindex(/.{1}/, 3).should == 3
+ "blablabla".byteindex(/.{2}/, 3).should == 3
+ "blablabla".byteindex(/.{5}/, 3).should == 3
+ "blablabla".byteindex(/.{6}/, 3).should == 3
+
+ "blablabla".byteindex(/.l./, 0).should == 0
+ "blablabla".byteindex(/.l./, 1).should == 3
+ "blablabla".byteindex(/.l./, 2).should == 3
+ "blablabla".byteindex(/.l./, 3).should == 3
+
+ "xblaxbla".byteindex(/x./, 0).should == 0
+ "xblaxbla".byteindex(/x./, 1).should == 4
+ "xblaxbla".byteindex(/x./, 2).should == 4
+
+ not_supported_on :opal do
+ "blablabla\n".byteindex(/\Z/, 9).should == 9
end
+ end
- it "starts the search at offset + self.length if offset is negative" do
- str = "blablabla"
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
- ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
- (-str.length .. -1).each do |offset|
- str.byteindex(needle, offset).should ==
- str.byteindex(needle, offset + str.length)
- end
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byteindex(needle, offset).should ==
+ str.byteindex(needle, offset + str.length)
end
end
+ end
- it "returns nil if the substring isn't found" do
- "blablabla".byteindex(/BLA/).should == nil
+ it "returns nil if the substring isn't found" do
+ "blablabla".byteindex(/BLA/).should == nil
- "blablabla".byteindex(/.{10}/).should == nil
- "blaxbla".byteindex(/.x/, 3).should == nil
- "blaxbla".byteindex(/..x/, 2).should == nil
- end
+ "blablabla".byteindex(/.{10}/).should == nil
+ "blaxbla".byteindex(/.x/, 3).should == nil
+ "blaxbla".byteindex(/..x/, 2).should == nil
+ end
- it "returns nil if the Regexp matches the empty string and the offset is out of range" do
- "ruby".byteindex(//, 12).should be_nil
- end
+ it "returns nil if the Regexp matches the empty string and the offset is out of range" do
+ "ruby".byteindex(//, 12).should be_nil
+ end
- it "supports \\G which matches at the given start offset" do
- "helloYOU.".byteindex(/\GYOU/, 5).should == 5
- "helloYOU.".byteindex(/\GYOU/).should == nil
+ it "supports \\G which matches at the given start offset" do
+ "helloYOU.".byteindex(/\GYOU/, 5).should == 5
+ "helloYOU.".byteindex(/\GYOU/).should == nil
- re = /\G.+YOU/
- # The # marks where \G will match.
- [
- ["#hi!YOUall.", 0],
- ["h#i!YOUall.", 1],
- ["hi#!YOUall.", 2],
- ["hi!#YOUall.", nil]
- ].each do |spec|
+ re = /\G.+YOU/
+ # The # marks where \G will match.
+ [
+ ["#hi!YOUall.", 0],
+ ["h#i!YOUall.", 1],
+ ["hi#!YOUall.", 2],
+ ["hi!#YOUall.", nil]
+ ].each do |spec|
- start = spec[0].byteindex("#")
- str = spec[0].delete("#")
+ start = spec[0].byteindex("#")
+ str = spec[0].delete("#")
- str.byteindex(re, start).should == spec[1]
- end
+ str.byteindex(re, start).should == spec[1]
end
+ end
- it "converts start_offset to an integer via to_int" do
- obj = mock('1')
- obj.should_receive(:to_int).and_return(1)
- "RWOARW".byteindex(/R./, obj).should == 4
- end
+ it "converts start_offset to an integer via to_int" do
+ obj = mock('1')
+ obj.should_receive(:to_int).and_return(1)
+ "RWOARW".byteindex(/R./, obj).should == 4
+ end
- it "returns the character byteindex of a multibyte character" do
- "ã‚りãŒã¨ã†".byteindex(/ãŒ/).should == 6
- end
+ it "returns the character byteindex of a multibyte character" do
+ "ã‚りãŒã¨ã†".byteindex(/ãŒ/).should == 6
+ end
- it "returns the character byteindex after offset" do
- "ã‚れã‚れ".byteindex(/ã‚/, 3).should == 6
- end
+ it "returns the character byteindex after offset" do
+ "ã‚れã‚れ".byteindex(/ã‚/, 3).should == 6
+ end
- it "treats the offset as a byteindex" do
- "ã‚れã‚ã‚れ".byteindex(/ã‚/, 6).should == 6
- end
+ it "treats the offset as a byteindex" do
+ "ã‚れã‚ã‚れ".byteindex(/ã‚/, 6).should == 6
end
end
diff --git a/spec/ruby/core/string/byterindex_spec.rb b/spec/ruby/core/string/byterindex_spec.rb
index 150f709b90..983222e35d 100644
--- a/spec/ruby/core/string/byterindex_spec.rb
+++ b/spec/ruby/core/string/byterindex_spec.rb
@@ -4,356 +4,350 @@ require_relative 'fixtures/classes'
require_relative 'shared/byte_index_common.rb'
describe "String#byterindex with object" do
- ruby_version_is "3.2" do
- it "tries to convert obj to a string via to_str" do
- obj = mock('lo')
- def obj.to_str() "lo" end
- "hello".byterindex(obj).should == "hello".byterindex("lo")
-
- obj = mock('o')
- def obj.respond_to?(arg, *) true end
- def obj.method_missing(*args) "o" end
- "hello".byterindex(obj).should == "hello".byterindex("o")
- end
-
- it "calls #to_int to convert the second argument" do
- offset = mock("string index offset")
- offset.should_receive(:to_int).and_return(3)
- "abc".byterindex("c", offset).should == 2
- end
+ it "tries to convert obj to a string via to_str" do
+ obj = mock('lo')
+ def obj.to_str() "lo" end
+ "hello".byterindex(obj).should == "hello".byterindex("lo")
+
+ obj = mock('o')
+ def obj.respond_to?(arg, *) true end
+ def obj.method_missing(*args) "o" end
+ "hello".byterindex(obj).should == "hello".byterindex("o")
+ end
- it "does not raise IndexError when byte offset is correct or on string boundary" do
- "ã‚".byterindex("", 0).should == 0
- "ã‚".byterindex("", 3).should == 3
- "ã‚".byterindex("").should == 3
- end
+ it "calls #to_int to convert the second argument" do
+ offset = mock("string index offset")
+ offset.should_receive(:to_int).and_return(3)
+ "abc".byterindex("c", offset).should == 2
+ end
- it_behaves_like :byte_index_common, :byterindex
+ it "does not raise IndexError when byte offset is correct or on string boundary" do
+ "ã‚".byterindex("", 0).should == 0
+ "ã‚".byterindex("", 3).should == 3
+ "ã‚".byterindex("").should == 3
end
+
+ it_behaves_like :byte_index_common, :byterindex
end
describe "String#byterindex with String" do
- ruby_version_is "3.2" do
- it "behaves the same as String#byterindex(char) for one-character strings" do
- "blablabla hello cruel world...!".split("").uniq.each do |str|
- chr = str[0]
- str.byterindex(str).should == str.byterindex(chr)
+ it "behaves the same as String#byterindex(char) for one-character strings" do
+ "blablabla hello cruel world...!".split("").uniq.each do |str|
+ chr = str[0]
+ str.byterindex(str).should == str.byterindex(chr)
- 0.upto(str.size + 1) do |start|
- str.byterindex(str, start).should == str.byterindex(chr, start)
- end
+ 0.upto(str.size + 1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
+ end
- (-str.size - 1).upto(-1) do |start|
- str.byterindex(str, start).should == str.byterindex(chr, start)
- end
+ (-str.size - 1).upto(-1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
end
end
+ end
- it "behaves the same as String#byterindex(?char) for one-character strings" do
- "blablabla hello cruel world...!".split("").uniq.each do |str|
- chr = str[0] =~ / / ? str[0] : eval("?#{str[0]}")
- str.byterindex(str).should == str.byterindex(chr)
+ it "behaves the same as String#byterindex(?char) for one-character strings" do
+ "blablabla hello cruel world...!".split("").uniq.each do |str|
+ chr = str[0] =~ / / ? str[0] : eval("?#{str[0]}")
+ str.byterindex(str).should == str.byterindex(chr)
- 0.upto(str.size + 1) do |start|
- str.byterindex(str, start).should == str.byterindex(chr, start)
- end
+ 0.upto(str.size + 1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
+ end
- (-str.size - 1).upto(-1) do |start|
- str.byterindex(str, start).should == str.byterindex(chr, start)
- end
+ (-str.size - 1).upto(-1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
end
end
+ end
- it "returns the index of the last occurrence of the given substring" do
- "blablabla".byterindex("").should == 9
- "blablabla".byterindex("a").should == 8
- "blablabla".byterindex("la").should == 7
- "blablabla".byterindex("bla").should == 6
- "blablabla".byterindex("abla").should == 5
- "blablabla".byterindex("labla").should == 4
- "blablabla".byterindex("blabla").should == 3
- "blablabla".byterindex("ablabla").should == 2
- "blablabla".byterindex("lablabla").should == 1
- "blablabla".byterindex("blablabla").should == 0
-
- "blablabla".byterindex("l").should == 7
- "blablabla".byterindex("bl").should == 6
- "blablabla".byterindex("abl").should == 5
- "blablabla".byterindex("labl").should == 4
- "blablabla".byterindex("blabl").should == 3
- "blablabla".byterindex("ablabl").should == 2
- "blablabla".byterindex("lablabl").should == 1
- "blablabla".byterindex("blablabl").should == 0
-
- "blablabla".byterindex("b").should == 6
- "blablabla".byterindex("ab").should == 5
- "blablabla".byterindex("lab").should == 4
- "blablabla".byterindex("blab").should == 3
- "blablabla".byterindex("ablab").should == 2
- "blablabla".byterindex("lablab").should == 1
- "blablabla".byterindex("blablab").should == 0
- end
+ it "returns the index of the last occurrence of the given substring" do
+ "blablabla".byterindex("").should == 9
+ "blablabla".byterindex("a").should == 8
+ "blablabla".byterindex("la").should == 7
+ "blablabla".byterindex("bla").should == 6
+ "blablabla".byterindex("abla").should == 5
+ "blablabla".byterindex("labla").should == 4
+ "blablabla".byterindex("blabla").should == 3
+ "blablabla".byterindex("ablabla").should == 2
+ "blablabla".byterindex("lablabla").should == 1
+ "blablabla".byterindex("blablabla").should == 0
+
+ "blablabla".byterindex("l").should == 7
+ "blablabla".byterindex("bl").should == 6
+ "blablabla".byterindex("abl").should == 5
+ "blablabla".byterindex("labl").should == 4
+ "blablabla".byterindex("blabl").should == 3
+ "blablabla".byterindex("ablabl").should == 2
+ "blablabla".byterindex("lablabl").should == 1
+ "blablabla".byterindex("blablabl").should == 0
+
+ "blablabla".byterindex("b").should == 6
+ "blablabla".byterindex("ab").should == 5
+ "blablabla".byterindex("lab").should == 4
+ "blablabla".byterindex("blab").should == 3
+ "blablabla".byterindex("ablab").should == 2
+ "blablabla".byterindex("lablab").should == 1
+ "blablabla".byterindex("blablab").should == 0
+ end
- it "ignores string subclasses" do
- "blablabla".byterindex(StringSpecs::MyString.new("bla")).should == 6
- StringSpecs::MyString.new("blablabla").byterindex("bla").should == 6
- StringSpecs::MyString.new("blablabla").byterindex(StringSpecs::MyString.new("bla")).should == 6
- end
+ it "ignores string subclasses" do
+ "blablabla".byterindex(StringSpecs::MyString.new("bla")).should == 6
+ StringSpecs::MyString.new("blablabla").byterindex("bla").should == 6
+ StringSpecs::MyString.new("blablabla").byterindex(StringSpecs::MyString.new("bla")).should == 6
+ end
- it "starts the search at the given offset" do
- "blablabla".byterindex("bl", 0).should == 0
- "blablabla".byterindex("bl", 1).should == 0
- "blablabla".byterindex("bl", 2).should == 0
- "blablabla".byterindex("bl", 3).should == 3
-
- "blablabla".byterindex("bla", 0).should == 0
- "blablabla".byterindex("bla", 1).should == 0
- "blablabla".byterindex("bla", 2).should == 0
- "blablabla".byterindex("bla", 3).should == 3
-
- "blablabla".byterindex("blab", 0).should == 0
- "blablabla".byterindex("blab", 1).should == 0
- "blablabla".byterindex("blab", 2).should == 0
- "blablabla".byterindex("blab", 3).should == 3
- "blablabla".byterindex("blab", 6).should == 3
- "blablablax".byterindex("blab", 6).should == 3
-
- "blablabla".byterindex("la", 1).should == 1
- "blablabla".byterindex("la", 2).should == 1
- "blablabla".byterindex("la", 3).should == 1
- "blablabla".byterindex("la", 4).should == 4
-
- "blablabla".byterindex("lab", 1).should == 1
- "blablabla".byterindex("lab", 2).should == 1
- "blablabla".byterindex("lab", 3).should == 1
- "blablabla".byterindex("lab", 4).should == 4
-
- "blablabla".byterindex("ab", 2).should == 2
- "blablabla".byterindex("ab", 3).should == 2
- "blablabla".byterindex("ab", 4).should == 2
- "blablabla".byterindex("ab", 5).should == 5
-
- "blablabla".byterindex("", 0).should == 0
- "blablabla".byterindex("", 1).should == 1
- "blablabla".byterindex("", 2).should == 2
- "blablabla".byterindex("", 7).should == 7
- "blablabla".byterindex("", 8).should == 8
- "blablabla".byterindex("", 9).should == 9
- "blablabla".byterindex("", 10).should == 9
- end
+ it "starts the search at the given offset" do
+ "blablabla".byterindex("bl", 0).should == 0
+ "blablabla".byterindex("bl", 1).should == 0
+ "blablabla".byterindex("bl", 2).should == 0
+ "blablabla".byterindex("bl", 3).should == 3
+
+ "blablabla".byterindex("bla", 0).should == 0
+ "blablabla".byterindex("bla", 1).should == 0
+ "blablabla".byterindex("bla", 2).should == 0
+ "blablabla".byterindex("bla", 3).should == 3
+
+ "blablabla".byterindex("blab", 0).should == 0
+ "blablabla".byterindex("blab", 1).should == 0
+ "blablabla".byterindex("blab", 2).should == 0
+ "blablabla".byterindex("blab", 3).should == 3
+ "blablabla".byterindex("blab", 6).should == 3
+ "blablablax".byterindex("blab", 6).should == 3
+
+ "blablabla".byterindex("la", 1).should == 1
+ "blablabla".byterindex("la", 2).should == 1
+ "blablabla".byterindex("la", 3).should == 1
+ "blablabla".byterindex("la", 4).should == 4
+
+ "blablabla".byterindex("lab", 1).should == 1
+ "blablabla".byterindex("lab", 2).should == 1
+ "blablabla".byterindex("lab", 3).should == 1
+ "blablabla".byterindex("lab", 4).should == 4
+
+ "blablabla".byterindex("ab", 2).should == 2
+ "blablabla".byterindex("ab", 3).should == 2
+ "blablabla".byterindex("ab", 4).should == 2
+ "blablabla".byterindex("ab", 5).should == 5
+
+ "blablabla".byterindex("", 0).should == 0
+ "blablabla".byterindex("", 1).should == 1
+ "blablabla".byterindex("", 2).should == 2
+ "blablabla".byterindex("", 7).should == 7
+ "blablabla".byterindex("", 8).should == 8
+ "blablabla".byterindex("", 9).should == 9
+ "blablabla".byterindex("", 10).should == 9
+ end
- it "starts the search at offset + self.length if offset is negative" do
- str = "blablabla"
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
- ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
- (-str.length .. -1).each do |offset|
- str.byterindex(needle, offset).should ==
- str.byterindex(needle, offset + str.length)
- end
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byterindex(needle, offset).should ==
+ str.byterindex(needle, offset + str.length)
end
end
+ end
- it "returns nil if the substring isn't found" do
- "blablabla".byterindex("B").should == nil
- "blablabla".byterindex("z").should == nil
- "blablabla".byterindex("BLA").should == nil
- "blablabla".byterindex("blablablabla").should == nil
+ it "returns nil if the substring isn't found" do
+ "blablabla".byterindex("B").should == nil
+ "blablabla".byterindex("z").should == nil
+ "blablabla".byterindex("BLA").should == nil
+ "blablabla".byterindex("blablablabla").should == nil
- "hello".byterindex("lo", 0).should == nil
- "hello".byterindex("lo", 1).should == nil
- "hello".byterindex("lo", 2).should == nil
+ "hello".byterindex("lo", 0).should == nil
+ "hello".byterindex("lo", 1).should == nil
+ "hello".byterindex("lo", 2).should == nil
- "hello".byterindex("llo", 0).should == nil
- "hello".byterindex("llo", 1).should == nil
+ "hello".byterindex("llo", 0).should == nil
+ "hello".byterindex("llo", 1).should == nil
- "hello".byterindex("el", 0).should == nil
- "hello".byterindex("ello", 0).should == nil
+ "hello".byterindex("el", 0).should == nil
+ "hello".byterindex("ello", 0).should == nil
- "hello".byterindex("", -6).should == nil
- "hello".byterindex("", -7).should == nil
+ "hello".byterindex("", -6).should == nil
+ "hello".byterindex("", -7).should == nil
- "hello".byterindex("h", -6).should == nil
- end
+ "hello".byterindex("h", -6).should == nil
+ end
- it "tries to convert start_offset to an integer via to_int" do
- obj = mock('5')
- def obj.to_int() 5 end
- "str".byterindex("st", obj).should == 0
+ it "tries to convert start_offset to an integer via to_int" do
+ obj = mock('5')
+ def obj.to_int() 5 end
+ "str".byterindex("st", obj).should == 0
- obj = mock('5')
- def obj.respond_to?(arg, *) true end
- def obj.method_missing(*args) 5 end
- "str".byterindex("st", obj).should == 0
- end
+ obj = mock('5')
+ def obj.respond_to?(arg, *) true end
+ def obj.method_missing(*args) 5 end
+ "str".byterindex("st", obj).should == 0
+ end
- it "raises a TypeError when given offset is nil" do
- -> { "str".byterindex("st", nil) }.should raise_error(TypeError)
- end
+ it "raises a TypeError when given offset is nil" do
+ -> { "str".byterindex("st", nil) }.should raise_error(TypeError)
+ end
- it "handles a substring in a superset encoding" do
- 'abc'.dup.force_encoding(Encoding::US_ASCII).byterindex('é').should == nil
- end
+ it "handles a substring in a superset encoding" do
+ 'abc'.dup.force_encoding(Encoding::US_ASCII).byterindex('é').should == nil
+ end
- it "handles a substring in a subset encoding" do
- 'été'.byterindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 2
- end
+ it "handles a substring in a subset encoding" do
+ 'été'.byterindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 2
end
end
describe "String#byterindex with Regexp" do
- ruby_version_is "3.2" do
- it "behaves the same as String#byterindex(string) for escaped string regexps" do
- ["blablabla", "hello cruel world...!"].each do |str|
- ["", "b", "bla", "lab", "o c", "d."].each do |needle|
- regexp = Regexp.new(Regexp.escape(needle))
- str.byterindex(regexp).should == str.byterindex(needle)
-
- 0.upto(str.size + 1) do |start|
- str.byterindex(regexp, start).should == str.byterindex(needle, start)
- end
-
- (-str.size - 1).upto(-1) do |start|
- str.byterindex(regexp, start).should == str.byterindex(needle, start)
- end
+ it "behaves the same as String#byterindex(string) for escaped string regexps" do
+ ["blablabla", "hello cruel world...!"].each do |str|
+ ["", "b", "bla", "lab", "o c", "d."].each do |needle|
+ regexp = Regexp.new(Regexp.escape(needle))
+ str.byterindex(regexp).should == str.byterindex(needle)
+
+ 0.upto(str.size + 1) do |start|
+ str.byterindex(regexp, start).should == str.byterindex(needle, start)
+ end
+
+ (-str.size - 1).upto(-1) do |start|
+ str.byterindex(regexp, start).should == str.byterindex(needle, start)
end
end
end
+ end
- it "returns the index of the first match from the end of string of regexp" do
- "blablabla".byterindex(/bla/).should == 6
- "blablabla".byterindex(/BLA/i).should == 6
-
- "blablabla".byterindex(/.{0}/).should == 9
- "blablabla".byterindex(/.{1}/).should == 8
- "blablabla".byterindex(/.{2}/).should == 7
- "blablabla".byterindex(/.{6}/).should == 3
- "blablabla".byterindex(/.{9}/).should == 0
+ it "returns the index of the first match from the end of string of regexp" do
+ "blablabla".byterindex(/bla/).should == 6
+ "blablabla".byterindex(/BLA/i).should == 6
- "blablabla".byterindex(/.*/).should == 9
- "blablabla".byterindex(/.+/).should == 8
+ "blablabla".byterindex(/.{0}/).should == 9
+ "blablabla".byterindex(/.{1}/).should == 8
+ "blablabla".byterindex(/.{2}/).should == 7
+ "blablabla".byterindex(/.{6}/).should == 3
+ "blablabla".byterindex(/.{9}/).should == 0
- "blablabla".byterindex(/bla|a/).should == 8
+ "blablabla".byterindex(/.*/).should == 9
+ "blablabla".byterindex(/.+/).should == 8
- not_supported_on :opal do
- "blablabla".byterindex(/\A/).should == 0
- "blablabla".byterindex(/\Z/).should == 9
- "blablabla".byterindex(/\z/).should == 9
- "blablabla\n".byterindex(/\Z/).should == 10
- "blablabla\n".byterindex(/\z/).should == 10
- end
+ "blablabla".byterindex(/bla|a/).should == 8
- "blablabla".byterindex(/^/).should == 0
- not_supported_on :opal do
- "\nblablabla".byterindex(/^/).should == 1
- "b\nlablabla".byterindex(/^/).should == 2
- end
- "blablabla".byterindex(/$/).should == 9
-
- "blablabla".byterindex(/.l./).should == 6
+ not_supported_on :opal do
+ "blablabla".byterindex(/\A/).should == 0
+ "blablabla".byterindex(/\Z/).should == 9
+ "blablabla".byterindex(/\z/).should == 9
+ "blablabla\n".byterindex(/\Z/).should == 10
+ "blablabla\n".byterindex(/\z/).should == 10
end
- it "starts the search at the given offset" do
- "blablabla".byterindex(/.{0}/, 5).should == 5
- "blablabla".byterindex(/.{1}/, 5).should == 5
- "blablabla".byterindex(/.{2}/, 5).should == 5
- "blablabla".byterindex(/.{3}/, 5).should == 5
- "blablabla".byterindex(/.{4}/, 5).should == 5
-
- "blablabla".byterindex(/.{0}/, 3).should == 3
- "blablabla".byterindex(/.{1}/, 3).should == 3
- "blablabla".byterindex(/.{2}/, 3).should == 3
- "blablabla".byterindex(/.{5}/, 3).should == 3
- "blablabla".byterindex(/.{6}/, 3).should == 3
-
- "blablabla".byterindex(/.l./, 0).should == 0
- "blablabla".byterindex(/.l./, 1).should == 0
- "blablabla".byterindex(/.l./, 2).should == 0
- "blablabla".byterindex(/.l./, 3).should == 3
-
- "blablablax".byterindex(/.x/, 10).should == 8
- "blablablax".byterindex(/.x/, 9).should == 8
- "blablablax".byterindex(/.x/, 8).should == 8
-
- "blablablax".byterindex(/..x/, 10).should == 7
- "blablablax".byterindex(/..x/, 9).should == 7
- "blablablax".byterindex(/..x/, 8).should == 7
- "blablablax".byterindex(/..x/, 7).should == 7
-
- not_supported_on :opal do
- "blablabla\n".byterindex(/\Z/, 9).should == 9
- end
+ "blablabla".byterindex(/^/).should == 0
+ not_supported_on :opal do
+ "\nblablabla".byterindex(/^/).should == 1
+ "b\nlablabla".byterindex(/^/).should == 2
end
+ "blablabla".byterindex(/$/).should == 9
- it "starts the search at offset + self.length if offset is negative" do
- str = "blablabla"
+ "blablabla".byterindex(/.l./).should == 6
+ end
- ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
- (-str.length .. -1).each do |offset|
- str.byterindex(needle, offset).should ==
- str.byterindex(needle, offset + str.length)
- end
- end
+ it "starts the search at the given offset" do
+ "blablabla".byterindex(/.{0}/, 5).should == 5
+ "blablabla".byterindex(/.{1}/, 5).should == 5
+ "blablabla".byterindex(/.{2}/, 5).should == 5
+ "blablabla".byterindex(/.{3}/, 5).should == 5
+ "blablabla".byterindex(/.{4}/, 5).should == 5
+
+ "blablabla".byterindex(/.{0}/, 3).should == 3
+ "blablabla".byterindex(/.{1}/, 3).should == 3
+ "blablabla".byterindex(/.{2}/, 3).should == 3
+ "blablabla".byterindex(/.{5}/, 3).should == 3
+ "blablabla".byterindex(/.{6}/, 3).should == 3
+
+ "blablabla".byterindex(/.l./, 0).should == 0
+ "blablabla".byterindex(/.l./, 1).should == 0
+ "blablabla".byterindex(/.l./, 2).should == 0
+ "blablabla".byterindex(/.l./, 3).should == 3
+
+ "blablablax".byterindex(/.x/, 10).should == 8
+ "blablablax".byterindex(/.x/, 9).should == 8
+ "blablablax".byterindex(/.x/, 8).should == 8
+
+ "blablablax".byterindex(/..x/, 10).should == 7
+ "blablablax".byterindex(/..x/, 9).should == 7
+ "blablablax".byterindex(/..x/, 8).should == 7
+ "blablablax".byterindex(/..x/, 7).should == 7
+
+ not_supported_on :opal do
+ "blablabla\n".byterindex(/\Z/, 9).should == 9
end
+ end
- it "returns nil if the substring isn't found" do
- "blablabla".byterindex(/BLA/).should == nil
- "blablabla".byterindex(/.{10}/).should == nil
- "blablablax".byterindex(/.x/, 7).should == nil
- "blablablax".byterindex(/..x/, 6).should == nil
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
- not_supported_on :opal do
- "blablabla".byterindex(/\Z/, 5).should == nil
- "blablabla".byterindex(/\z/, 5).should == nil
- "blablabla\n".byterindex(/\z/, 9).should == nil
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byterindex(needle, offset).should ==
+ str.byterindex(needle, offset + str.length)
end
end
+ end
+
+ it "returns nil if the substring isn't found" do
+ "blablabla".byterindex(/BLA/).should == nil
+ "blablabla".byterindex(/.{10}/).should == nil
+ "blablablax".byterindex(/.x/, 7).should == nil
+ "blablablax".byterindex(/..x/, 6).should == nil
not_supported_on :opal do
- it "supports \\G which matches at the given start offset" do
- "helloYOU.".byterindex(/YOU\G/, 8).should == 5
- "helloYOU.".byterindex(/YOU\G/).should == nil
-
- idx = "helloYOUall!".index("YOU")
- re = /YOU.+\G.+/
- # The # marks where \G will match.
- [
- ["helloYOU#all.", nil],
- ["helloYOUa#ll.", idx],
- ["helloYOUal#l.", idx],
- ["helloYOUall#.", idx],
- ["helloYOUall.#", nil]
- ].each do |i|
- start = i[0].index("#")
- str = i[0].delete("#")
-
- str.byterindex(re, start).should == i[1]
- end
+ "blablabla".byterindex(/\Z/, 5).should == nil
+ "blablabla".byterindex(/\z/, 5).should == nil
+ "blablabla\n".byterindex(/\z/, 9).should == nil
+ end
+ end
+
+ not_supported_on :opal do
+ it "supports \\G which matches at the given start offset" do
+ "helloYOU.".byterindex(/YOU\G/, 8).should == 5
+ "helloYOU.".byterindex(/YOU\G/).should == nil
+
+ idx = "helloYOUall!".index("YOU")
+ re = /YOU.+\G.+/
+ # The # marks where \G will match.
+ [
+ ["helloYOU#all.", nil],
+ ["helloYOUa#ll.", idx],
+ ["helloYOUal#l.", idx],
+ ["helloYOUall#.", idx],
+ ["helloYOUall.#", nil]
+ ].each do |i|
+ start = i[0].index("#")
+ str = i[0].delete("#")
+
+ str.byterindex(re, start).should == i[1]
end
end
+ end
- it "tries to convert start_offset to an integer" do
- obj = mock('5')
- def obj.to_int() 5 end
- "str".byterindex(/../, obj).should == 1
+ it "tries to convert start_offset to an integer" do
+ obj = mock('5')
+ def obj.to_int() 5 end
+ "str".byterindex(/../, obj).should == 1
- obj = mock('5')
- def obj.respond_to?(arg, *) true end
- def obj.method_missing(*args); 5; end
- "str".byterindex(/../, obj).should == 1
- end
+ obj = mock('5')
+ def obj.respond_to?(arg, *) true end
+ def obj.method_missing(*args); 5; end
+ "str".byterindex(/../, obj).should == 1
+ end
- it "raises a TypeError when given offset is nil" do
- -> { "str".byterindex(/../, nil) }.should raise_error(TypeError)
- end
+ it "raises a TypeError when given offset is nil" do
+ -> { "str".byterindex(/../, nil) }.should raise_error(TypeError)
+ end
- it "returns the reverse byte index of a multibyte character" do
- "ã‚りãŒã‚ŠãŒã¨ã†".byterindex("ãŒ").should == 12
- "ã‚りãŒã‚ŠãŒã¨ã†".byterindex(/ãŒ/).should == 12
- end
+ it "returns the reverse byte index of a multibyte character" do
+ "ã‚りãŒã‚ŠãŒã¨ã†".byterindex("ãŒ").should == 12
+ "ã‚りãŒã‚ŠãŒã¨ã†".byterindex(/ãŒ/).should == 12
+ end
- it "returns the character index before the finish" do
- "ã‚りãŒã‚ŠãŒã¨ã†".byterindex("ãŒ", 9).should == 6
- "ã‚りãŒã‚ŠãŒã¨ã†".byterindex(/ãŒ/, 9).should == 6
- end
+ it "returns the character index before the finish" do
+ "ã‚りãŒã‚ŠãŒã¨ã†".byterindex("ãŒ", 9).should == 6
+ "ã‚りãŒã‚ŠãŒã¨ã†".byterindex(/ãŒ/, 9).should == 6
end
end
diff --git a/spec/ruby/core/string/byteslice_spec.rb b/spec/ruby/core/string/byteslice_spec.rb
index 9fe504aeb1..4ad9e8d8f1 100644
--- a/spec/ruby/core/string/byteslice_spec.rb
+++ b/spec/ruby/core/string/byteslice_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/slice'
diff --git a/spec/ruby/core/string/bytesplice_spec.rb b/spec/ruby/core/string/bytesplice_spec.rb
index 5cb3b2c158..2c770e340a 100644
--- a/spec/ruby/core/string/bytesplice_spec.rb
+++ b/spec/ruby/core/string/bytesplice_spec.rb
@@ -3,60 +3,58 @@
require_relative '../../spec_helper'
describe "String#bytesplice" do
- ruby_version_is "3.2" do
- it "raises IndexError when index is less than -bytesize" do
- -> { "hello".bytesplice(-6, 0, "xxx") }.should raise_error(IndexError, "index -6 out of string")
- end
+ it "raises IndexError when index is less than -bytesize" do
+ -> { "hello".bytesplice(-6, 0, "xxx") }.should raise_error(IndexError, "index -6 out of string")
+ end
- it "raises IndexError when index is greater than bytesize" do
- -> { "hello".bytesplice(6, 0, "xxx") }.should raise_error(IndexError, "index 6 out of string")
- end
+ it "raises IndexError when index is greater than bytesize" do
+ -> { "hello".bytesplice(6, 0, "xxx") }.should raise_error(IndexError, "index 6 out of string")
+ end
- it "raises IndexError for negative length" do
- -> { "abc".bytesplice(0, -2, "") }.should raise_error(IndexError, "negative length -2")
- end
+ it "raises IndexError for negative length" do
+ -> { "abc".bytesplice(0, -2, "") }.should raise_error(IndexError, "negative length -2")
+ end
- it "replaces with integer indices" do
- "hello".bytesplice(-5, 0, "xxx").should == "xxxhello"
- "hello".bytesplice(0, 0, "xxx").should == "xxxhello"
- "hello".bytesplice(0, 1, "xxx").should == "xxxello"
- "hello".bytesplice(0, 5, "xxx").should == "xxx"
- "hello".bytesplice(0, 6, "xxx").should == "xxx"
- end
+ it "replaces with integer indices" do
+ "hello".bytesplice(-5, 0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0, 0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0, 1, "xxx").should == "xxxello"
+ "hello".bytesplice(0, 5, "xxx").should == "xxx"
+ "hello".bytesplice(0, 6, "xxx").should == "xxx"
+ end
- it "raises RangeError when range left boundary is less than -bytesize" do
- -> { "hello".bytesplice(-6...-6, "xxx") }.should raise_error(RangeError, "-6...-6 out of range")
- end
+ it "raises RangeError when range left boundary is less than -bytesize" do
+ -> { "hello".bytesplice(-6...-6, "xxx") }.should raise_error(RangeError, "-6...-6 out of range")
+ end
- it "replaces with ranges" do
- "hello".bytesplice(-5...-5, "xxx").should == "xxxhello"
- "hello".bytesplice(0...0, "xxx").should == "xxxhello"
- "hello".bytesplice(0..0, "xxx").should == "xxxello"
- "hello".bytesplice(0...1, "xxx").should == "xxxello"
- "hello".bytesplice(0..1, "xxx").should == "xxxllo"
- "hello".bytesplice(0..-1, "xxx").should == "xxx"
- "hello".bytesplice(0...5, "xxx").should == "xxx"
- "hello".bytesplice(0...6, "xxx").should == "xxx"
- end
+ it "replaces with ranges" do
+ "hello".bytesplice(-5...-5, "xxx").should == "xxxhello"
+ "hello".bytesplice(0...0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0..0, "xxx").should == "xxxello"
+ "hello".bytesplice(0...1, "xxx").should == "xxxello"
+ "hello".bytesplice(0..1, "xxx").should == "xxxllo"
+ "hello".bytesplice(0..-1, "xxx").should == "xxx"
+ "hello".bytesplice(0...5, "xxx").should == "xxx"
+ "hello".bytesplice(0...6, "xxx").should == "xxx"
+ end
- it "raises TypeError when integer index is provided without length argument" do
- -> { "hello".bytesplice(0, "xxx") }.should raise_error(TypeError, "wrong argument type Integer (expected Range)")
- end
+ it "raises TypeError when integer index is provided without length argument" do
+ -> { "hello".bytesplice(0, "xxx") }.should raise_error(TypeError, "wrong argument type Integer (expected Range)")
+ end
- it "replaces on an empty string" do
- "".bytesplice(0, 0, "").should == ""
- "".bytesplice(0, 0, "xxx").should == "xxx"
- end
+ it "replaces on an empty string" do
+ "".bytesplice(0, 0, "").should == ""
+ "".bytesplice(0, 0, "xxx").should == "xxx"
+ end
- it "mutates self" do
- s = "hello"
- s.bytesplice(2, 1, "xxx").should.equal?(s)
- end
+ it "mutates self" do
+ s = "hello"
+ s.bytesplice(2, 1, "xxx").should.equal?(s)
+ end
- it "raises when string is frozen" do
- s = "hello".freeze
- -> { s.bytesplice(2, 1, "xxx") }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
- end
+ it "raises when string is frozen" do
+ s = "hello".freeze
+ -> { s.bytesplice(2, 1, "xxx") }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
end
ruby_version_is "3.3" do
@@ -134,75 +132,73 @@ describe "String#bytesplice" do
end
describe "String#bytesplice with multibyte characters" do
- ruby_version_is "3.2" do
- it "raises IndexError when index is out of byte size boundary" do
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-16, 0, "xxx") }.should raise_error(IndexError, "index -16 out of string")
- end
+ it "raises IndexError when index is out of byte size boundary" do
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-16, 0, "xxx") }.should raise_error(IndexError, "index -16 out of string")
+ end
- it "raises IndexError when index is not on a codepoint boundary" do
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(1, 0, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- end
+ it "raises IndexError when index is not on a codepoint boundary" do
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(1, 0, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ end
- it "raises IndexError when length is not matching the codepoint boundary" do
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0, 1, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0, 2, "xxx") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- end
+ it "raises IndexError when length is not matching the codepoint boundary" do
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0, 1, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0, 2, "xxx") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ end
- it "replaces with integer indices" do
- "ã“ã‚“ã«ã¡ã¯".bytesplice(-15, 0, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0, 0, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0, 3, "xxx").should == "xxxã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã¯ã¯").should == "ã“ã¯ã¯ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(15, 0, "xxx").should == "ã“ã‚“ã«ã¡ã¯xxx"
- end
+ it "replaces with integer indices" do
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(-15, 0, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0, 0, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0, 3, "xxx").should == "xxxã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(3, 3, "ã¯ã¯").should == "ã“ã¯ã¯ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(15, 0, "xxx").should == "ã“ã‚“ã«ã¡ã¯xxx"
+ end
- it "replaces with range" do
- "ã“ã‚“ã«ã¡ã¯".bytesplice(-15...-16, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0...0, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "xxx").should == "xxxã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0...3, "xxx").should == "xxxã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..5, "xxx").should == "xxxã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0..-1, "xxx").should == "xxx"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0...15, "xxx").should == "xxx"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0...18, "xxx").should == "xxx"
- end
+ it "replaces with range" do
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(-15...-16, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0...0, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0..2, "xxx").should == "xxxã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0...3, "xxx").should == "xxxã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0..5, "xxx").should == "xxxã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0..-1, "xxx").should == "xxx"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0...15, "xxx").should == "xxx"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0...18, "xxx").should == "xxx"
+ end
- it "treats negative length for range as 0" do
- "ã“ã‚“ã«ã¡ã¯".bytesplice(0...-100, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(3...-100, "xxx").should == "ã“xxxã‚“ã«ã¡ã¯"
- "ã“ã‚“ã«ã¡ã¯".bytesplice(-15...-100, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
- end
+ it "treats negative length for range as 0" do
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(0...-100, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(3...-100, "xxx").should == "ã“xxxã‚“ã«ã¡ã¯"
+ "ã“ã‚“ã«ã¡ã¯".bytesplice(-15...-100, "xxx").should == "xxxã“ã‚“ã«ã¡ã¯"
+ end
- it "raises when ranges not match codepoint boundaries" do
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0..0, "x") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0..1, "x") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
- # Begin is incorrect
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-4..-1, "x") }.should raise_error(IndexError, "offset 11 does not land on character boundary")
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-5..-1, "x") }.should raise_error(IndexError, "offset 10 does not land on character boundary")
- # End is incorrect
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-3..-2, "x") }.should raise_error(IndexError, "offset 14 does not land on character boundary")
- -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-3..-3, "x") }.should raise_error(IndexError, "offset 13 does not land on character boundary")
- end
+ it "raises when ranges not match codepoint boundaries" do
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0..0, "x") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(0..1, "x") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ # Begin is incorrect
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-4..-1, "x") }.should raise_error(IndexError, "offset 11 does not land on character boundary")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-5..-1, "x") }.should raise_error(IndexError, "offset 10 does not land on character boundary")
+ # End is incorrect
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-3..-2, "x") }.should raise_error(IndexError, "offset 14 does not land on character boundary")
+ -> { "ã“ã‚“ã«ã¡ã¯".bytesplice(-3..-3, "x") }.should raise_error(IndexError, "offset 13 does not land on character boundary")
+ end
- it "deals with a different encoded argument" do
- s = "ã“ã‚“ã«ã¡ã¯"
- s.encoding.should == Encoding::UTF_8
- sub = "xxxxxx"
- sub.force_encoding(Encoding::US_ASCII)
+ it "deals with a different encoded argument" do
+ s = "ã“ã‚“ã«ã¡ã¯"
+ s.encoding.should == Encoding::UTF_8
+ sub = "xxxxxx"
+ sub.force_encoding(Encoding::US_ASCII)
- result = s.bytesplice(0, 3, sub)
- result.should == "xxxxxxã‚“ã«ã¡ã¯"
- result.encoding.should == Encoding::UTF_8
+ result = s.bytesplice(0, 3, sub)
+ result.should == "xxxxxxã‚“ã«ã¡ã¯"
+ result.encoding.should == Encoding::UTF_8
- s = "xxxxxx"
- s.force_encoding(Encoding::US_ASCII)
- sub = "ã“ã‚“ã«ã¡ã¯"
- sub.encoding.should == Encoding::UTF_8
+ s = "xxxxxx"
+ s.force_encoding(Encoding::US_ASCII)
+ sub = "ã“ã‚“ã«ã¡ã¯"
+ sub.encoding.should == Encoding::UTF_8
- result = s.bytesplice(0, 3, sub)
- result.should == "ã“ã‚“ã«ã¡ã¯xxx"
- result.encoding.should == Encoding::UTF_8
- end
+ result = s.bytesplice(0, 3, sub)
+ result.should == "ã“ã‚“ã«ã¡ã¯xxx"
+ result.encoding.should == Encoding::UTF_8
end
ruby_version_is "3.3" do
diff --git a/spec/ruby/core/string/chilled_string_spec.rb b/spec/ruby/core/string/chilled_string_spec.rb
index b8fb6eedc9..73d055cbdf 100644
--- a/spec/ruby/core/string/chilled_string_spec.rb
+++ b/spec/ruby/core/string/chilled_string_spec.rb
@@ -47,6 +47,14 @@ describe "chilled String" do
input.should == "chilled-mutated"
end
+ it "emits a warning for concatenated strings" do
+ input = "still" "+chilled"
+ -> {
+ input << "-mutated"
+ }.should complain(/literal string will be frozen in the future/)
+ input.should == "still+chilled-mutated"
+ end
+
it "emits a warning on singleton_class creation" do
-> {
"chilled".singleton_class
@@ -64,7 +72,7 @@ describe "chilled String" do
input.freeze
-> {
-> {
- input << "mutated"
+ input << "mutated"
}.should raise_error(FrozenError)
}.should_not complain(/literal string will be frozen in the future/)
end
@@ -133,7 +141,7 @@ describe "chilled String" do
input.freeze
-> {
-> {
- input << "mutated"
+ input << "mutated"
}.should raise_error(FrozenError)
}.should_not complain(/string returned by :chilled\.to_s will be frozen in the future/)
end
diff --git a/spec/ruby/core/string/codepoints_spec.rb b/spec/ruby/core/string/codepoints_spec.rb
index b276d0baa8..12a5bf5892 100644
--- a/spec/ruby/core/string/codepoints_spec.rb
+++ b/spec/ruby/core/string/codepoints_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'shared/codepoints'
require_relative 'shared/each_codepoint_without_block'
diff --git a/spec/ruby/core/string/count_spec.rb b/spec/ruby/core/string/count_spec.rb
index 06ba5a4f0e..e614e901dd 100644
--- a/spec/ruby/core/string/count_spec.rb
+++ b/spec/ruby/core/string/count_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
diff --git a/spec/ruby/core/string/dedup_spec.rb b/spec/ruby/core/string/dedup_spec.rb
index 57d2be2cfd..2b31d80708 100644
--- a/spec/ruby/core/string/dedup_spec.rb
+++ b/spec/ruby/core/string/dedup_spec.rb
@@ -2,7 +2,5 @@ require_relative '../../spec_helper'
require_relative 'shared/dedup'
describe 'String#dedup' do
- ruby_version_is '3.2' do
- it_behaves_like :string_dedup, :dedup
- end
+ it_behaves_like :string_dedup, :dedup
end
diff --git a/spec/ruby/core/string/lstrip_spec.rb b/spec/ruby/core/string/lstrip_spec.rb
index 99bab6f349..c83650207e 100644
--- a/spec/ruby/core/string/lstrip_spec.rb
+++ b/spec/ruby/core/string/lstrip_spec.rb
@@ -7,11 +7,11 @@ describe "String#lstrip" do
it_behaves_like :string_strip, :lstrip
it "returns a copy of self with leading whitespace removed" do
- " hello ".lstrip.should == "hello "
- " hello world ".lstrip.should == "hello world "
- "\n\r\t\n\v\r hello world ".lstrip.should == "hello world "
- "hello".lstrip.should == "hello"
- " ã“ã«ã¡ã‚".lstrip.should == "ã“ã«ã¡ã‚"
+ " hello ".lstrip.should == "hello "
+ " hello world ".lstrip.should == "hello world "
+ "\n\r\t\n\v\r hello world ".lstrip.should == "hello world "
+ "hello".lstrip.should == "hello"
+ " ã“ã«ã¡ã‚".lstrip.should == "ã“ã«ã¡ã‚"
end
it "works with lazy substrings" do
@@ -22,8 +22,8 @@ describe "String#lstrip" do
end
it "strips leading \\0" do
- "\x00hello".lstrip.should == "hello"
- "\000 \000hello\000 \000".lstrip.should == "hello\000 \000"
+ "\x00hello".lstrip.should == "hello"
+ "\000 \000hello\000 \000".lstrip.should == "hello\000 \000"
end
end
diff --git a/spec/ruby/core/string/modulo_spec.rb b/spec/ruby/core/string/modulo_spec.rb
index 8e3853551f..46e0aa0f36 100644
--- a/spec/ruby/core/string/modulo_spec.rb
+++ b/spec/ruby/core/string/modulo_spec.rb
@@ -391,16 +391,8 @@ describe "String#%" do
("%c" % 'A').should == "A"
end
- ruby_version_is ""..."3.2" do
- it "raises an exception for multiple character strings as argument for %c" do
- -> { "%c" % 'AA' }.should raise_error(ArgumentError)
- end
- end
-
- ruby_version_is "3.2" do
- it "supports only the first character as argument for %c" do
- ("%c" % 'AA').should == "A"
- end
+ it "supports only the first character as argument for %c" do
+ ("%c" % 'AA').should == "A"
end
it "calls to_str on argument for %c formats" do
@@ -749,9 +741,11 @@ describe "String#%" do
(format % "-10.4e-20").should == (format % -10.4e-20)
(format % ".5").should == (format % 0.5)
(format % "-.5").should == (format % -0.5)
- ruby_bug("#20705", ""..."3.4") do
+
+ ruby_version_is "3.4" do
(format % "10.").should == (format % 10)
end
+
# Something's strange with this spec:
# it works just fine in individual mode, but not when run as part of a group
(format % "10_1_0.5_5_5").should == (format % 1010.555)
diff --git a/spec/ruby/core/string/rindex_spec.rb b/spec/ruby/core/string/rindex_spec.rb
index 88ce733583..0863a9c3be 100644
--- a/spec/ruby/core/string/rindex_spec.rb
+++ b/spec/ruby/core/string/rindex_spec.rb
@@ -371,8 +371,8 @@ describe "String#rindex with Regexp" do
end
it "returns the character index before the finish" do
- "ã‚りãŒã‚ŠãŒã¨ã†".rindex("ãŒ", 3).should == 2
- "ã‚りãŒã‚ŠãŒã¨ã†".rindex(/ãŒ/, 3).should == 2
+ "ã‚りãŒã‚ŠãŒã¨ã†".rindex("ãŒ", 3).should == 2
+ "ã‚りãŒã‚ŠãŒã¨ã†".rindex(/ãŒ/, 3).should == 2
end
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
diff --git a/spec/ruby/core/string/rstrip_spec.rb b/spec/ruby/core/string/rstrip_spec.rb
index 6d46eb590e..55773f5238 100644
--- a/spec/ruby/core/string/rstrip_spec.rb
+++ b/spec/ruby/core/string/rstrip_spec.rb
@@ -68,27 +68,13 @@ describe "String#rstrip!" do
-> { "".freeze.rstrip! }.should raise_error(FrozenError)
end
- ruby_version_is "3.2" do
- it "raises an Encoding::CompatibilityError if the last non-space codepoint is invalid" do
- s = "abc\xDF".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.rstrip! }.should raise_error(Encoding::CompatibilityError)
+ it "raises an Encoding::CompatibilityError if the last non-space codepoint is invalid" do
+ s = "abc\xDF".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.rstrip! }.should raise_error(Encoding::CompatibilityError)
- s = "abc\xDF ".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.rstrip! }.should raise_error(Encoding::CompatibilityError)
- end
- end
-
- ruby_version_is ""..."3.2" do
- it "raises an ArgumentError if the last non-space codepoint is invalid" do
- s = "abc\xDF".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.rstrip! }.should raise_error(ArgumentError)
-
- s = "abc\xDF ".force_encoding(Encoding::UTF_8)
- s.valid_encoding?.should be_false
- -> { s.rstrip! }.should raise_error(ArgumentError)
- end
+ s = "abc\xDF ".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.rstrip! }.should raise_error(Encoding::CompatibilityError)
end
end
diff --git a/spec/ruby/core/string/scan_spec.rb b/spec/ruby/core/string/scan_spec.rb
index 70c3b7fb7b..bbe843b591 100644
--- a/spec/ruby/core/string/scan_spec.rb
+++ b/spec/ruby/core/string/scan_spec.rb
@@ -103,11 +103,11 @@ describe "String#scan with pattern and block" do
offsets = []
str.scan(/([aeiou])/) do
- md = $~
- md.string.should == str
- matches << md.to_a
- offsets << md.offset(0)
- str
+ md = $~
+ md.string.should == str
+ matches << md.to_a
+ offsets << md.offset(0)
+ str
end
matches.should == [["e", "e"], ["o", "o"]]
@@ -117,11 +117,11 @@ describe "String#scan with pattern and block" do
offsets = []
str.scan("l") do
- md = $~
- md.string.should == str
- matches << md.to_a
- offsets << md.offset(0)
- str
+ md = $~
+ md.string.should == str
+ matches << md.to_a
+ offsets << md.offset(0)
+ str
end
matches.should == [["l"], ["l"]]
diff --git a/spec/ruby/core/string/shared/codepoints.rb b/spec/ruby/core/string/shared/codepoints.rb
index f71263054a..1c28ba3d5e 100644
--- a/spec/ruby/core/string/shared/codepoints.rb
+++ b/spec/ruby/core/string/shared/codepoints.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :string_codepoints, shared: true do
it "returns self" do
s = "foo"
diff --git a/spec/ruby/core/string/shared/dedup.rb b/spec/ruby/core/string/shared/dedup.rb
index 97b5df6ed1..1ffd6aa0fd 100644
--- a/spec/ruby/core/string/shared/dedup.rb
+++ b/spec/ruby/core/string/shared/dedup.rb
@@ -48,9 +48,4 @@ describe :string_dedup, shared: true do
dynamic.send(@method).should_not equal("this string is frozen".send(@method).freeze)
dynamic.send(@method).should equal(dynamic)
end
-
- it "interns the provided string if it is frozen" do
- dynamic = "this string is unique and frozen #{rand}".freeze
- dynamic.send(@method).should equal(dynamic)
- end
end
diff --git a/spec/ruby/core/string/shared/each_codepoint_without_block.rb b/spec/ruby/core/string/shared/each_codepoint_without_block.rb
index 31b4c02c9c..c88e5c54c7 100644
--- a/spec/ruby/core/string/shared/each_codepoint_without_block.rb
+++ b/spec/ruby/core/string/shared/each_codepoint_without_block.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :string_each_codepoint_without_block, shared: true do
describe "when no block is given" do
it "returns an Enumerator" do
diff --git a/spec/ruby/core/string/shared/eql.rb b/spec/ruby/core/string/shared/eql.rb
index 845b0a3e15..d5af337d53 100644
--- a/spec/ruby/core/string/shared/eql.rb
+++ b/spec/ruby/core/string/shared/eql.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
diff --git a/spec/ruby/core/string/shared/slice.rb b/spec/ruby/core/string/shared/slice.rb
index 2f69b9ddce..7b9b9f6a14 100644
--- a/spec/ruby/core/string/shared/slice.rb
+++ b/spec/ruby/core/string/shared/slice.rb
@@ -119,6 +119,18 @@ describe :string_slice_index_length, shared: true do
"hello there".send(@method, -4,-3).should == nil
end
+ platform_is pointer_size: 64 do
+ it "returns nil if the length is negative big value" do
+ "hello there".send(@method, 4, -(1 << 31)).should == nil
+
+ # by some reason length < -(1 << 31) on CI on Windows leads to
+ # 'RangeError: bignum too big to convert into `long'' error
+ platform_is_not :windows do
+ "hello there".send(@method, 4, -(1 << 63)).should == nil
+ end
+ end
+ end
+
it "calls to_int on the given index and the given length" do
"hello".send(@method, 0.5, 1).should == "h"
"hello".send(@method, 0.5, 2.5).should == "he"
@@ -152,6 +164,11 @@ describe :string_slice_index_length, shared: true do
-> { "hello".send(@method, 0, bignum_value) }.should raise_error(RangeError)
end
+ it "raises a RangeError if the index or length is too small" do
+ -> { "hello".send(@method, -bignum_value, 1) }.should raise_error(RangeError)
+ -> { "hello".send(@method, 0, -bignum_value) }.should raise_error(RangeError)
+ end
+
it "returns String instances" do
s = StringSpecs::MyString.new("hello")
s.send(@method, 0,0).should be_an_instance_of(String)
diff --git a/spec/ruby/core/string/shared/succ.rb b/spec/ruby/core/string/shared/succ.rb
index b69a394875..7c68345f10 100644
--- a/spec/ruby/core/string/shared/succ.rb
+++ b/spec/ruby/core/string/shared/succ.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :string_succ, shared: true do
it "returns an empty string for empty strings" do
"".send(@method).should == ""
diff --git a/spec/ruby/core/string/squeeze_spec.rb b/spec/ruby/core/string/squeeze_spec.rb
index 4ea238e6b5..981d480684 100644
--- a/spec/ruby/core/string/squeeze_spec.rb
+++ b/spec/ruby/core/string/squeeze_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
diff --git a/spec/ruby/core/string/sub_spec.rb b/spec/ruby/core/string/sub_spec.rb
index 4f9f87a433..6ff28ec851 100644
--- a/spec/ruby/core/string/sub_spec.rb
+++ b/spec/ruby/core/string/sub_spec.rb
@@ -232,10 +232,10 @@ describe "String#sub with pattern and block" do
offsets = []
str.sub(/([aeiou])/) do
- md = $~
- md.string.should == str
- offsets << md.offset(0)
- str
+ md = $~
+ md.string.should == str
+ offsets << md.offset(0)
+ str
end.should == "hhellollo"
offsets.should == [[1, 2]]
@@ -339,10 +339,10 @@ describe "String#sub! with pattern and block" do
offsets = []
str.dup.sub!(/([aeiou])/) do
- md = $~
- md.string.should == str
- offsets << md.offset(0)
- str
+ md = $~
+ md.string.should == str
+ offsets << md.offset(0)
+ str
end.should == "hhellollo"
offsets.should == [[1, 2]]
diff --git a/spec/ruby/core/string/swapcase_spec.rb b/spec/ruby/core/string/swapcase_spec.rb
index 7f4c68366d..011a213501 100644
--- a/spec/ruby/core/string/swapcase_spec.rb
+++ b/spec/ruby/core/string/swapcase_spec.rb
@@ -5,9 +5,9 @@ require_relative 'fixtures/classes'
describe "String#swapcase" do
it "returns a new string with all uppercase chars from self converted to lowercase and vice versa" do
- "Hello".swapcase.should == "hELLO"
- "cYbEr_PuNk11".swapcase.should == "CyBeR_pUnK11"
- "+++---111222???".swapcase.should == "+++---111222???"
+ "Hello".swapcase.should == "hELLO"
+ "cYbEr_PuNk11".swapcase.should == "CyBeR_pUnK11"
+ "+++---111222???".swapcase.should == "+++---111222???"
end
it "returns a String in the same encoding as self" do
diff --git a/spec/ruby/core/string/to_c_spec.rb b/spec/ruby/core/string/to_c_spec.rb
index 9d24f1f56c..1813890e72 100644
--- a/spec/ruby/core/string/to_c_spec.rb
+++ b/spec/ruby/core/string/to_c_spec.rb
@@ -13,18 +13,20 @@ describe "String#to_c" do
it "ignores trailing garbage" do
'79+4iruby'.to_c.should == Complex(79, 4)
- ruby_bug "[Bug #19087]", ""..."3.2" do
- '7__9+4__0i'.to_c.should == Complex(7, 0)
- end
+ '7__9+4__0i'.to_c.should == Complex(7, 0)
end
- it "understands Float::INFINITY" do
- 'Infinity'.to_c.should == Complex(0, 1)
- '-Infinity'.to_c.should == Complex(0, -1)
- end
+ context "it treats special float value strings as characters" do
+ it "parses any string that starts with 'I' as 1i" do
+ 'Infinity'.to_c.should == Complex(0, 1)
+ '-Infinity'.to_c.should == Complex(0, -1)
+ 'Insecure'.to_c.should == Complex(0, 1)
+ '-Insecure'.to_c.should == Complex(0, -1)
+ end
- it "understands Float::NAN" do
- 'NaN'.to_c.should == Complex(0, 0)
+ it "does not parse any numeric information in 'NaN'" do
+ 'NaN'.to_c.should == Complex(0, 0)
+ end
end
it "allows null-byte" do
@@ -39,15 +41,13 @@ describe "String#to_c" do
}.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
end
- ruby_version_is "3.2" do
- it "treats a sequence of underscores as an end of Complex string" do
- "5+3_1i".to_c.should == Complex(5, 31)
- "5+3__1i".to_c.should == Complex(5)
- "5+3___1i".to_c.should == Complex(5)
+ it "treats a sequence of underscores as an end of Complex string" do
+ "5+3_1i".to_c.should == Complex(5, 31)
+ "5+3__1i".to_c.should == Complex(5)
+ "5+3___1i".to_c.should == Complex(5)
- "12_3".to_c.should == Complex(123)
- "12__3".to_c.should == Complex(12)
- "12___3".to_c.should == Complex(12)
- end
+ "12_3".to_c.should == Complex(123)
+ "12__3".to_c.should == Complex(12)
+ "12___3".to_c.should == Complex(12)
end
end
diff --git a/spec/ruby/core/string/to_f_spec.rb b/spec/ruby/core/string/to_f_spec.rb
index cf64ecfc5d..abfd2517b6 100644
--- a/spec/ruby/core/string/to_f_spec.rb
+++ b/spec/ruby/core/string/to_f_spec.rb
@@ -5,16 +5,15 @@ require_relative 'fixtures/classes'
describe "String#to_f" do
it "treats leading characters of self as a floating point number" do
- "123.45e1".to_f.should == 1234.5
- "45.67 degrees".to_f.should == 45.67
- "0".to_f.should == 0.0
- "123.45e1".to_f.should == 1234.5
+ "123.45e1".to_f.should == 1234.5
+ "45.67 degrees".to_f.should == 45.67
+ "0".to_f.should == 0.0
- ".5".to_f.should == 0.5
- ".5e1".to_f.should == 5.0
- "5.".to_f.should == 5.0
- "5e".to_f.should == 5.0
- "5E".to_f.should == 5.0
+ ".5".to_f.should == 0.5
+ ".5e1".to_f.should == 5.0
+ "5.".to_f.should == 5.0
+ "5e".to_f.should == 5.0
+ "5E".to_f.should == 5.0
end
it "treats special float value strings as characters" do
@@ -43,18 +42,39 @@ describe "String#to_f" do
"1_234_567.890_1".to_f.should == 1_234_567.890_1
end
- it "returns 0 for strings with any non-digit in them" do
- "blah".to_f.should == 0
- "0b5".to_f.should == 0
- "0d5".to_f.should == 0
- "0o5".to_f.should == 0
- "0xx5".to_f.should == 0
- end
-
it "returns 0 for strings with leading underscores" do
"_9".to_f.should == 0
end
+ it "stops if the underscore is not followed or preceded by a number" do
+ "1__2".to_f.should == 1.0
+ "1_.2".to_f.should == 1.0
+ "1._2".to_f.should == 1.0
+ "1.2_e2".to_f.should == 1.2
+ "1.2e_2".to_f.should == 1.2
+ "1_x2".to_f.should == 1.0
+ "1x_2".to_f.should == 1.0
+ "+_1".to_f.should == 0.0
+ "-_1".to_f.should == 0.0
+ end
+
+ it "does not allow prefixes to autodetect the base" do
+ "0b10".to_f.should == 0
+ "010".to_f.should == 10
+ "0o10".to_f.should == 0
+ "0d10".to_f.should == 0
+ "0x10".to_f.should == 0
+ end
+
+ it "treats any non-numeric character other than '.', 'e' and '_' as terminals" do
+ "blah".to_f.should == 0
+ "1b5".to_f.should == 1
+ "1d5".to_f.should == 1
+ "1o5".to_f.should == 1
+ "1xx5".to_f.should == 1
+ "x5".to_f.should == 0
+ end
+
it "takes an optional sign" do
"-45.67 degrees".to_f.should == -45.67
"+45.67 degrees".to_f.should == 45.67
@@ -63,8 +83,60 @@ describe "String#to_f" do
(1.0 / "-0".to_f).to_s.should == "-Infinity"
end
+ it "treats a second 'e' as terminal" do
+ "1.234e1e2".to_f.should == 1.234e1
+ end
+
+ it "treats a second '.' as terminal" do
+ "1.2.3".to_f.should == 1.2
+ end
+
+ it "treats a '.' after an 'e' as terminal" do
+ "1.234e1.9".to_f.should == 1.234e1
+ end
+
it "returns 0.0 if the conversion fails" do
"bad".to_f.should == 0.0
"thx1138".to_f.should == 0.0
end
+
+ it "ignores leading and trailing whitespace" do
+ " 1.2".to_f.should == 1.2
+ "1.2 ".to_f.should == 1.2
+ " 1.2 ".to_f.should == 1.2
+ "\t1.2".to_f.should == 1.2
+ "\n1.2".to_f.should == 1.2
+ "\v1.2".to_f.should == 1.2
+ "\f1.2".to_f.should == 1.2
+ "\r1.2".to_f.should == 1.2
+ end
+
+ it "treats non-printable ASCII characters as terminals" do
+ "\0001.2".to_f.should == 0
+ "\0011.2".to_f.should == 0
+ "\0371.2".to_f.should == 0
+ "\1771.2".to_f.should == 0
+ "\2001.2".b.to_f.should == 0
+ "\3771.2".b.to_f.should == 0
+ end
+
+ ruby_version_is "3.2.3" do
+ it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
+ -> {
+ '1.2'.encode("UTF-16").to_f
+ }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ end
+ end
+
+ it "allows String representation without a fractional part" do
+ "1.".to_f.should == 1.0
+ "+1.".to_f.should == 1.0
+ "-1.".to_f.should == -1.0
+ "1.e+0".to_f.should == 1.0
+ "1.e+0".to_f.should == 1.0
+
+ ruby_bug "#20705", ""..."3.4" do
+ "1.e-2".to_f.should be_close(0.01, TOLERANCE)
+ end
+ end
end
diff --git a/spec/ruby/core/string/to_i_spec.rb b/spec/ruby/core/string/to_i_spec.rb
index 9931502baa..39f69acda3 100644
--- a/spec/ruby/core/string/to_i_spec.rb
+++ b/spec/ruby/core/string/to_i_spec.rb
@@ -10,7 +10,7 @@ describe "String#to_i" do
"1_2_3asdf".to_i.should == 123
end
- it "ignores multiple non-consecutive underscoes when the first digit is 0" do
+ it "ignores multiple non-consecutive underscores when the first digit is 0" do
(2..16).each do |base|
"0_0_010".to_i(base).should == base;
end
diff --git a/spec/ruby/core/string/to_r_spec.rb b/spec/ruby/core/string/to_r_spec.rb
index 7e1d635d3b..4ffbb10d98 100644
--- a/spec/ruby/core/string/to_r_spec.rb
+++ b/spec/ruby/core/string/to_r_spec.rb
@@ -33,6 +33,10 @@ describe "String#to_r" do
"-20".to_r.should == Rational(-20, 1)
end
+ it "accepts leading plus signs" do
+ "+20".to_r.should == Rational(20, 1)
+ end
+
it "does not treat a leading period without a numeric prefix as a decimal point" do
".9".to_r.should_not == Rational(8106479329266893, 9007199254740992)
end
diff --git a/spec/ruby/core/string/unpack/a_spec.rb b/spec/ruby/core/string/unpack/a_spec.rb
index 4002ece697..a68e842e15 100644
--- a/spec/ruby/core/string/unpack/a_spec.rb
+++ b/spec/ruby/core/string/unpack/a_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/string/unpack/at_spec.rb b/spec/ruby/core/string/unpack/at_spec.rb
index 70b2389d69..d4133c23ee 100644
--- a/spec/ruby/core/string/unpack/at_spec.rb
+++ b/spec/ruby/core/string/unpack/at_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/string/unpack/b_spec.rb b/spec/ruby/core/string/unpack/b_spec.rb
index 23d93a8aea..b088f901fc 100644
--- a/spec/ruby/core/string/unpack/b_spec.rb
+++ b/spec/ruby/core/string/unpack/b_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/string/unpack/c_spec.rb b/spec/ruby/core/string/unpack/c_spec.rb
index c2bf813954..1e9548fb82 100644
--- a/spec/ruby/core/string/unpack/c_spec.rb
+++ b/spec/ruby/core/string/unpack/c_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/string/unpack/comment_spec.rb b/spec/ruby/core/string/unpack/comment_spec.rb
index e18a53df3c..050d2b7fc0 100644
--- a/spec/ruby/core/string/unpack/comment_spec.rb
+++ b/spec/ruby/core/string/unpack/comment_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
diff --git a/spec/ruby/core/string/unpack/h_spec.rb b/spec/ruby/core/string/unpack/h_spec.rb
index 19c4d63664..535836087d 100644
--- a/spec/ruby/core/string/unpack/h_spec.rb
+++ b/spec/ruby/core/string/unpack/h_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/string/unpack/m_spec.rb b/spec/ruby/core/string/unpack/m_spec.rb
index c551c755d1..357987a053 100644
--- a/spec/ruby/core/string/unpack/m_spec.rb
+++ b/spec/ruby/core/string/unpack/m_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/string/unpack/shared/basic.rb b/spec/ruby/core/string/unpack/shared/basic.rb
index b37a447683..734630bda0 100644
--- a/spec/ruby/core/string/unpack/shared/basic.rb
+++ b/spec/ruby/core/string/unpack/shared/basic.rb
@@ -9,12 +9,19 @@ describe :string_unpack_basic, shared: true do
"abc".unpack(d).should be_an_instance_of(Array)
end
+ ruby_version_is ""..."3.3" do
+ it "warns about using an unknown directive" do
+ -> { "abcdefgh".unpack("a R" + unpack_format) }.should complain(/unknown unpack directive 'R' in 'a R#{unpack_format}'/)
+ -> { "abcdefgh".unpack("a 0" + unpack_format) }.should complain(/unknown unpack directive '0' in 'a 0#{unpack_format}'/)
+ -> { "abcdefgh".unpack("a :" + unpack_format) }.should complain(/unknown unpack directive ':' in 'a :#{unpack_format}'/)
+ end
+ end
+
ruby_version_is "3.3" do
- # https://bugs.ruby-lang.org/issues/19150
- it 'raise ArgumentError when a directive is unknown' do
- -> { "abcdefgh".unpack("a R" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive 'R'/)
- -> { "abcdefgh".unpack("a 0" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive '0'/)
- -> { "abcdefgh".unpack("a :" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive ':'/)
+ it "raises ArgumentError when a directive is unknown" do
+ -> { "abcdefgh".unpack("a K" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive 'K' in 'a K#{unpack_format}'")
+ -> { "abcdefgh".unpack("a 0" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive '0' in 'a 0#{unpack_format}'")
+ -> { "abcdefgh".unpack("a :" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive ':' in 'a :#{unpack_format}'")
end
end
end
diff --git a/spec/ruby/core/string/unpack/shared/float.rb b/spec/ruby/core/string/unpack/shared/float.rb
index 93282bf4c9..b31c2c8bdc 100644
--- a/spec/ruby/core/string/unpack/shared/float.rb
+++ b/spec/ruby/core/string/unpack/shared/float.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :string_unpack_float_le, shared: true do
it "decodes one float for a single format character" do
diff --git a/spec/ruby/core/string/unpack/shared/integer.rb b/spec/ruby/core/string/unpack/shared/integer.rb
index d71a2cf00d..d3934753ba 100644
--- a/spec/ruby/core/string/unpack/shared/integer.rb
+++ b/spec/ruby/core/string/unpack/shared/integer.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
describe :string_unpack_16bit_le, shared: true do
it "decodes one short for a single format character" do
diff --git a/spec/ruby/core/string/unpack/u_spec.rb b/spec/ruby/core/string/unpack/u_spec.rb
index 456abee784..68c8f6f11c 100644
--- a/spec/ruby/core/string/unpack/u_spec.rb
+++ b/spec/ruby/core/string/unpack/u_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/string/unpack/w_spec.rb b/spec/ruby/core/string/unpack/w_spec.rb
index 6a1cff1965..7d3533ccae 100644
--- a/spec/ruby/core/string/unpack/w_spec.rb
+++ b/spec/ruby/core/string/unpack/w_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/string/unpack/x_spec.rb b/spec/ruby/core/string/unpack/x_spec.rb
index 5e248de77e..2926ebbe0f 100644
--- a/spec/ruby/core/string/unpack/x_spec.rb
+++ b/spec/ruby/core/string/unpack/x_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/string/unpack/z_spec.rb b/spec/ruby/core/string/unpack/z_spec.rb
index ce8da4b29e..1030390550 100644
--- a/spec/ruby/core/string/unpack/z_spec.rb
+++ b/spec/ruby/core/string/unpack/z_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/basic'
diff --git a/spec/ruby/core/string/unpack1_spec.rb b/spec/ruby/core/string/unpack1_spec.rb
index df830916a3..cfb47fe695 100644
--- a/spec/ruby/core/string/unpack1_spec.rb
+++ b/spec/ruby/core/string/unpack1_spec.rb
@@ -8,29 +8,40 @@ describe "String#unpack1" do
"A".unpack1("B*").should == "01000001"
end
- ruby_version_is "3.1" do
- it "starts unpacking from the given offset" do
- "ZZABCD".unpack1('x3C', offset: 2).should == "ABCD".unpack('x3C')[0]
- "ZZZZaG9nZWZ1Z2E=".unpack1("m", offset: 4).should == "hogefuga"
- "ZA".unpack1("B*", offset: 1).should == "01000001"
- end
+ it "starts unpacking from the given offset" do
+ "ZZABCD".unpack1('x3C', offset: 2).should == "ABCD".unpack('x3C')[0]
+ "ZZZZaG9nZWZ1Z2E=".unpack1("m", offset: 4).should == "hogefuga"
+ "ZA".unpack1("B*", offset: 1).should == "01000001"
+ end
- it "traits offset as a bytes offset" do
- "؈".unpack("CC").should == [216, 136]
- "؈".unpack1("C").should == 216
- "؈".unpack1("C", offset: 1).should == 136
- end
+ it "traits offset as a bytes offset" do
+ "؈".unpack("CC").should == [216, 136]
+ "؈".unpack1("C").should == 216
+ "؈".unpack1("C", offset: 1).should == 136
+ end
- it "raises an ArgumentError when the offset is negative" do
- -> { "a".unpack1("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative")
- end
+ it "raises an ArgumentError when the offset is negative" do
+ -> { "a".unpack1("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative")
+ end
+
+ it "returns nil if the offset is at the end of the string" do
+ "a".unpack1("C", offset: 1).should == nil
+ end
+
+ it "raises an ArgumentError when the offset is larger than the string bytesize" do
+ -> { "a".unpack1("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string")
+ end
+
+ context "with format 'm0'" do
+ # unpack1("m0") takes a special code path that calls Pack.unpackBase46Strict instead of Pack.unpack_m,
+ # which is why we repeat the tests for unpack("m0") here.
- it "returns nil if the offset is at the end of the string" do
- "a".unpack1("C", offset: 1).should == nil
+ it "decodes base64" do
+ "dGVzdA==".unpack1("m0").should == "test"
end
- it "raises an ArgumentError when the offset is larger than the string bytesize" do
- -> { "a".unpack1("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string")
+ it "raises an ArgumentError for an invalid base64 character" do
+ -> { "dGV%zdA==".unpack1("m0") }.should raise_error(ArgumentError)
end
end
end
diff --git a/spec/ruby/core/string/unpack_spec.rb b/spec/ruby/core/string/unpack_spec.rb
index 52b4af3a95..a0abf8fa99 100644
--- a/spec/ruby/core/string/unpack_spec.rb
+++ b/spec/ruby/core/string/unpack_spec.rb
@@ -9,26 +9,24 @@ describe "String#unpack" do
-> { "abc".unpack(1) }.should raise_error(TypeError)
end
- ruby_version_is "3.1" do
- it "starts unpacking from the given offset" do
- "abc".unpack("CC", offset: 1).should == [98, 99]
- end
+ it "starts unpacking from the given offset" do
+ "abc".unpack("CC", offset: 1).should == [98, 99]
+ end
- it "traits offset as a bytes offset" do
- "؈".unpack("CC").should == [216, 136]
- "؈".unpack("CC", offset: 1).should == [136, nil]
- end
+ it "traits offset as a bytes offset" do
+ "؈".unpack("CC").should == [216, 136]
+ "؈".unpack("CC", offset: 1).should == [136, nil]
+ end
- it "raises an ArgumentError when the offset is negative" do
- -> { "a".unpack("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative")
- end
+ it "raises an ArgumentError when the offset is negative" do
+ -> { "a".unpack("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative")
+ end
- it "returns nil if the offset is at the end of the string" do
- "a".unpack("C", offset: 1).should == [nil]
- end
+ it "returns nil if the offset is at the end of the string" do
+ "a".unpack("C", offset: 1).should == [nil]
+ end
- it "raises an ArgumentError when the offset is larget than the string" do
- -> { "a".unpack("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string")
- end
+ it "raises an ArgumentError when the offset is larger than the string" do
+ -> { "a".unpack("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string")
end
end
diff --git a/spec/ruby/core/string/uplus_spec.rb b/spec/ruby/core/string/uplus_spec.rb
index c0b0c49ede..20767bcc01 100644
--- a/spec/ruby/core/string/uplus_spec.rb
+++ b/spec/ruby/core/string/uplus_spec.rb
@@ -13,14 +13,48 @@ describe 'String#+@' do
output.should == 'foobar'
end
- it 'returns self if the String is not frozen' do
- input = 'foo'
+ it 'returns a mutable String itself' do
+ input = String.new("foo")
output = +input
- output.equal?(input).should == true
+ output.should.equal?(input)
+
+ input << "bar"
+ output.should == "foobar"
+ end
+
+ context 'if file has "frozen_string_literal: true" magic comment' do
+ it 'returns mutable copy of a literal' do
+ ruby_exe(fixture(__FILE__, "freeze_magic_comment.rb")).should == 'mutable'
+ end
end
- it 'returns mutable copy despite freeze-magic-comment in file' do
- ruby_exe(fixture(__FILE__, "freeze_magic_comment.rb")).should == 'mutable'
+ context 'if file has "frozen_string_literal: false" magic comment' do
+ it 'returns literal string itself' do
+ input = 'foo'
+ output = +input
+
+ output.equal?(input).should == true
+ end
+ end
+
+ context 'if file has no frozen_string_literal magic comment' do
+ ruby_version_is ''...'3.4' do
+ it 'returns literal string itself' do
+ eval(<<~RUBY).should == true
+ s = "foo"
+ s.equal?(+s)
+ RUBY
+ end
+ end
+
+ ruby_version_is '3.4' do
+ it 'returns mutable copy of a literal' do
+ eval(<<~RUBY).should == false
+ s = "foo"
+ s.equal?(+s)
+ RUBY
+ end
+ end
end
end
diff --git a/spec/ruby/core/struct/constants_spec.rb b/spec/ruby/core/struct/constants_spec.rb
index fa61a4b912..7e8af1a211 100644
--- a/spec/ruby/core/struct/constants_spec.rb
+++ b/spec/ruby/core/struct/constants_spec.rb
@@ -1,15 +1,13 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "Struct::Group" do
- it "is no longer defined" do
- Struct.should_not.const_defined?(:Group)
- end
+describe "Struct::Group" do
+ it "is no longer defined" do
+ Struct.should_not.const_defined?(:Group)
end
+end
- describe "Struct::Passwd" do
- it "is no longer defined" do
- Struct.should_not.const_defined?(:Passwd)
- end
+describe "Struct::Passwd" do
+ it "is no longer defined" do
+ Struct.should_not.const_defined?(:Passwd)
end
end
diff --git a/spec/ruby/core/struct/deconstruct_keys_spec.rb b/spec/ruby/core/struct/deconstruct_keys_spec.rb
index b4c84c49df..e16b50f930 100644
--- a/spec/ruby/core/struct/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/struct/deconstruct_keys_spec.rb
@@ -40,6 +40,21 @@ describe "Struct#deconstruct_keys" do
s.deconstruct_keys([0, 1, 2]).should == {0 => 10, 1 => 20, 2 => 30}
s.deconstruct_keys([0, 1] ).should == {0 => 10, 1 => 20}
s.deconstruct_keys([0] ).should == {0 => 10}
+ s.deconstruct_keys([-1] ).should == {-1 => 30}
+ end
+
+ it "ignores incorrect position numbers" do
+ struct = Struct.new(:x, :y, :z)
+ s = struct.new(10, 20, 30)
+
+ s.deconstruct_keys([0, 3]).should == {0 => 10}
+ end
+
+ it "support mixing attribute names and argument position numbers" do
+ struct = Struct.new(:x, :y)
+ s = struct.new(1, 2)
+
+ s.deconstruct_keys([0, :x]).should == {0 => 1, :x => 1}
end
it "returns an empty hash when there are more keys than attributes" do
@@ -57,6 +72,14 @@ describe "Struct#deconstruct_keys" do
s.deconstruct_keys([:x, :a]).should == {x: 1}
end
+ it "returns at first not existing argument position number" do
+ struct = Struct.new(:x, :y)
+ s = struct.new(1, 2)
+
+ s.deconstruct_keys([3, 0]).should == {}
+ s.deconstruct_keys([0, 3]).should == {0 => 1}
+ end
+
it "accepts nil argument and return all the attributes" do
struct = Struct.new(:x, :y)
obj = struct.new(1, 2)
@@ -64,6 +87,37 @@ describe "Struct#deconstruct_keys" do
obj.deconstruct_keys(nil).should == {x: 1, y: 2}
end
+ it "tries to convert a key with #to_int if index is not a String nor a Symbol, but responds to #to_int" do
+ struct = Struct.new(:x, :y)
+ s = struct.new(1, 2)
+
+ key = mock("to_int")
+ key.should_receive(:to_int).and_return(1)
+
+ s.deconstruct_keys([key]).should == { key => 2 }
+ end
+
+ it "raises a TypeError if the conversion with #to_int does not return an Integer" do
+ struct = Struct.new(:x, :y)
+ s = struct.new(1, 2)
+
+ key = mock("to_int")
+ key.should_receive(:to_int).and_return("not an Integer")
+
+ -> {
+ s.deconstruct_keys([key])
+ }.should raise_error(TypeError, /can't convert MockObject to Integer/)
+ end
+
+ it "raises TypeError if index is not a String, a Symbol and not convertible to Integer" do
+ struct = Struct.new(:x, :y)
+ s = struct.new(1, 2)
+
+ -> {
+ s.deconstruct_keys([0, []])
+ }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
+ end
+
it "raise TypeError if passed anything except nil or array" do
struct = Struct.new(:x, :y)
s = struct.new(1, 2)
diff --git a/spec/ruby/core/struct/element_set_spec.rb b/spec/ruby/core/struct/element_set_spec.rb
index 6ba7b081a9..0a0e34a5ee 100644
--- a/spec/ruby/core/struct/element_set_spec.rb
+++ b/spec/ruby/core/struct/element_set_spec.rb
@@ -26,4 +26,11 @@ describe "Struct#[]=" do
-> { car[-4] = true }.should raise_error(IndexError)
-> { car[Object.new] = true }.should raise_error(TypeError)
end
+
+ it "raises a FrozenError on a frozen struct" do
+ car = StructClasses::Car.new('Ford', 'Ranger')
+ car.freeze
+
+ -> { car[:model] = 'Escape' }.should raise_error(FrozenError)
+ end
end
diff --git a/spec/ruby/core/struct/fixtures/classes.rb b/spec/ruby/core/struct/fixtures/classes.rb
index bf838d05df..7b80b814ef 100644
--- a/spec/ruby/core/struct/fixtures/classes.rb
+++ b/spec/ruby/core/struct/fixtures/classes.rb
@@ -29,4 +29,6 @@ module StructClasses
super
end
end
+
+ class StructSubclass < Struct; end
end
diff --git a/spec/ruby/core/struct/initialize_spec.rb b/spec/ruby/core/struct/initialize_spec.rb
index a5ebe9551c..06055594d5 100644
--- a/spec/ruby/core/struct/initialize_spec.rb
+++ b/spec/ruby/core/struct/initialize_spec.rb
@@ -41,21 +41,11 @@ describe "Struct#initialize" do
StructClasses::SubclassX.new(:y).new.key.should == :value
end
- ruby_version_is "3.1"..."3.2" do
- it "warns about passing only keyword arguments" do
- -> {
- StructClasses::Ruby.new(version: "3.1", platform: "OS")
- }.should complain(/warning: Passing only keyword arguments/)
- end
- end
+ it "can be initialized with keyword arguments" do
+ positional_args = StructClasses::Ruby.new("3.2", "OS")
+ keyword_args = StructClasses::Ruby.new(version: "3.2", platform: "OS")
- ruby_version_is "3.2" do
- it "can be initialized with keyword arguments" do
- positional_args = StructClasses::Ruby.new("3.2", "OS")
- keyword_args = StructClasses::Ruby.new(version: "3.2", platform: "OS")
-
- positional_args.version.should == keyword_args.version
- positional_args.platform.should == keyword_args.platform
- end
+ positional_args.version.should == keyword_args.version
+ positional_args.platform.should == keyword_args.platform
end
end
diff --git a/spec/ruby/core/struct/keyword_init_spec.rb b/spec/ruby/core/struct/keyword_init_spec.rb
index 8de4c14351..536b82041a 100644
--- a/spec/ruby/core/struct/keyword_init_spec.rb
+++ b/spec/ruby/core/struct/keyword_init_spec.rb
@@ -1,40 +1,45 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
-ruby_version_is "3.1" do
- # See https://bugs.ruby-lang.org/issues/18008
- describe "StructClass#keyword_init?" do
- it "returns true for a struct that accepts keyword arguments to initialize" do
- struct = Struct.new(:arg, keyword_init: true)
- struct.keyword_init?.should be_true
- end
+# See https://bugs.ruby-lang.org/issues/18008
+describe "StructClass#keyword_init?" do
+ it "returns true for a struct that accepts keyword arguments to initialize" do
+ struct = Struct.new(:arg, keyword_init: true)
+ struct.keyword_init?.should be_true
+ end
- it "returns false for a struct that does not accept keyword arguments to initialize" do
- struct = Struct.new(:arg, keyword_init: false)
- struct.keyword_init?.should be_false
- end
+ it "returns false for a struct that does not accept keyword arguments to initialize" do
+ struct = Struct.new(:arg, keyword_init: false)
+ struct.keyword_init?.should be_false
+ end
- it "returns nil for a struct that did not explicitly specify keyword_init" do
- struct = Struct.new(:arg)
- struct.keyword_init?.should be_nil
- end
+ it "returns nil for a struct that did not explicitly specify keyword_init" do
+ struct = Struct.new(:arg)
+ struct.keyword_init?.should be_nil
+ end
- it "returns nil for a struct that does specify keyword_init to be nil" do
- struct = Struct.new(:arg, keyword_init: nil)
- struct.keyword_init?.should be_nil
- end
+ it "returns nil for a struct that does specify keyword_init to be nil" do
+ struct = Struct.new(:arg, keyword_init: nil)
+ struct.keyword_init?.should be_nil
+ end
- it "returns true for any truthy value, not just for true" do
- struct = Struct.new(:arg, keyword_init: 1)
- struct.keyword_init?.should be_true
+ it "returns true for any truthy value, not just for true" do
+ struct = Struct.new(:arg, keyword_init: 1)
+ struct.keyword_init?.should be_true
- struct = Struct.new(:arg, keyword_init: "")
- struct.keyword_init?.should be_true
+ struct = Struct.new(:arg, keyword_init: "")
+ struct.keyword_init?.should be_true
- struct = Struct.new(:arg, keyword_init: [])
- struct.keyword_init?.should be_true
+ struct = Struct.new(:arg, keyword_init: [])
+ struct.keyword_init?.should be_true
+
+ struct = Struct.new(:arg, keyword_init: {})
+ struct.keyword_init?.should be_true
+ end
- struct = Struct.new(:arg, keyword_init: {})
- struct.keyword_init?.should be_true
+ context "class inheriting Struct" do
+ it "isn't available in a subclass" do
+ StructClasses::StructSubclass.should_not.respond_to?(:keyword_init?)
end
end
end
diff --git a/spec/ruby/core/struct/members_spec.rb b/spec/ruby/core/struct/members_spec.rb
index 1f2ff950d9..1ff7b9387a 100644
--- a/spec/ruby/core/struct/members_spec.rb
+++ b/spec/ruby/core/struct/members_spec.rb
@@ -11,3 +11,15 @@ describe "Struct#members" do
it_behaves_like :struct_accessor, :members
end
+
+describe "StructClass#members" do
+ it "returns an array of attribute names" do
+ StructClasses::Car.members.should == [:make, :model, :year]
+ end
+
+ context "class inheriting Struct" do
+ it "isn't available in a subclass" do
+ StructClasses::StructSubclass.should_not.respond_to?(:members)
+ end
+ end
+end
diff --git a/spec/ruby/core/struct/new_spec.rb b/spec/ruby/core/struct/new_spec.rb
index a94eb852e1..1d35de7b87 100644
--- a/spec/ruby/core/struct/new_spec.rb
+++ b/spec/ruby/core/struct/new_spec.rb
@@ -6,6 +6,8 @@ describe "Struct.new" do
struct = Struct.new('Animal', :name, :legs, :eyeballs)
struct.should == Struct::Animal
struct.name.should == "Struct::Animal"
+ ensure
+ Struct.send(:remove_const, :Animal)
end
it "overwrites previously defined constants with string as first argument" do
@@ -19,6 +21,8 @@ describe "Struct.new" do
second.should == Struct::Person
first.members.should_not == second.members
+ ensure
+ Struct.send(:remove_const, :Person)
end
it "calls to_str on its first argument (constant name)" do
@@ -27,6 +31,8 @@ describe "Struct.new" do
struct = Struct.new(obj)
struct.should == Struct::Foo
struct.name.should == "Struct::Foo"
+ ensure
+ Struct.send(:remove_const, :Foo)
end
it "creates a new anonymous class with nil first argument" do
@@ -67,20 +73,8 @@ describe "Struct.new" do
-> { Struct.new(:animal, ['chris', 'evan']) }.should raise_error(TypeError)
end
- ruby_version_is ""..."3.2" do
- it "raises a TypeError or ArgumentError if passed a Hash with an unknown key" do
- # CRuby < 3.2 raises ArgumentError: unknown keyword: :name, but that seems a bug:
- # https://bugs.ruby-lang.org/issues/18632
- -> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(StandardError) { |e|
- [ArgumentError, TypeError].should.include?(e.class)
- }
- end
- end
-
- ruby_version_is "3.2" do
- it "raises a TypeError if passed a Hash with an unknown key" do
- -> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(TypeError)
- end
+ it "raises a TypeError if passed a Hash with an unknown key" do
+ -> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(TypeError)
end
ruby_version_is ""..."3.3" do
@@ -138,6 +132,8 @@ describe "Struct.new" do
it "creates a constant in subclass' namespace" do
struct = StructClasses::Apple.new('Computer', :size)
struct.should == StructClasses::Apple::Computer
+ ensure
+ StructClasses::Apple.send(:remove_const, :Computer)
end
it "creates an instance" do
@@ -158,29 +154,43 @@ describe "Struct.new" do
-> { StructClasses::Ruby.new('2.0', 'i686', true) }.should raise_error(ArgumentError)
end
- ruby_version_is ''...'3.1' do
- it "passes a hash as a normal argument" do
- type = Struct.new(:args)
+ it "accepts keyword arguments to initialize" do
+ type = Struct.new(:args)
- obj = suppress_warning {type.new(keyword: :arg)}
- obj2 = type.new(*[{keyword: :arg}])
+ obj = type.new(args: 42)
+ obj2 = type.new(42)
- obj.should == obj2
- obj.args.should == {keyword: :arg}
- obj2.args.should == {keyword: :arg}
- end
+ obj.should == obj2
+ obj.args.should == 42
+ obj2.args.should == 42
end
- ruby_version_is '3.2' do
- it "accepts keyword arguments to initialize" do
- type = Struct.new(:args)
+ context "given positional and keyword arguments" do
+ it "treats keyword arguments as a positional parameter" do
+ type = Struct.new(:a, :b)
+ s = type.new("a", b: "b")
+ s.a.should == "a"
+ s.b.should == {b: "b"}
+
+ type = Struct.new(:a, :b, :c)
+ s = type.new("a", b: "b", c: "c")
+ s.a.should == "a"
+ s.b.should == {b: "b", c: "c"}
+ s.c.should == nil
+ end
+
+ it "ignores empty keyword arguments" do
+ type = Struct.new(:a, :b)
+ h = {}
+ s = type.new("a", **h)
- obj = type.new(args: 42)
- obj2 = type.new(42)
+ s.a.should == "a"
+ s.b.should == nil
+ end
- obj.should == obj2
- obj.args.should == 42
- obj2.args.should == 42
+ it "raises ArgumentError when all struct attribute values are specified" do
+ type = Struct.new(:a, :b)
+ -> { type.new("a", "b", c: "c") }.should raise_error(ArgumentError, "struct size differs")
end
end
end
diff --git a/spec/ruby/core/struct/struct_spec.rb b/spec/ruby/core/struct/struct_spec.rb
index 8817dc1a58..1b6a4488ce 100644
--- a/spec/ruby/core/struct/struct_spec.rb
+++ b/spec/ruby/core/struct/struct_spec.rb
@@ -33,6 +33,13 @@ describe "Struct anonymous class instance methods" do
car['model'].should == 'F150'
car[1].should == 'F150'
end
+
+ it "writer methods raise a FrozenError on a frozen struct" do
+ car = StructClasses::Car.new('Ford', 'Ranger')
+ car.freeze
+
+ -> { car.model = 'Escape' }.should raise_error(FrozenError)
+ end
end
describe "Struct subclasses" do
diff --git a/spec/ruby/core/symbol/inspect_spec.rb b/spec/ruby/core/symbol/inspect_spec.rb
index 6dbb36c2ad..df4566c48e 100644
--- a/spec/ruby/core/symbol/inspect_spec.rb
+++ b/spec/ruby/core/symbol/inspect_spec.rb
@@ -6,7 +6,7 @@ describe "Symbol#inspect" do
:fred? => ":fred?",
:fred! => ":fred!",
:BAD! => ":BAD!",
- :_BAD! => ":_BAD!",
+ :_BAD! => ":_BAD!",
:$ruby => ":$ruby",
:@ruby => ":@ruby",
:@@ruby => ":@@ruby",
@@ -66,9 +66,9 @@ describe "Symbol#inspect" do
:~ => ":~",
:| => ":|",
- :"!" => [":\"!\"", ":!" ],
- :"!=" => [":\"!=\"", ":!="],
- :"!~" => [":\"!~\"", ":!~"],
+ :"!" => ":!",
+ :"!=" => ":!=",
+ :"!~" => ":!~",
:"\$" => ":\"$\"", # for justice!
:"&&" => ":\"&&\"",
:"'" => ":\"\'\"",
@@ -96,10 +96,15 @@ describe "Symbol#inspect" do
:"foo " => ":\"foo \"",
:" foo" => ":\" foo\"",
:" " => ":\" \"",
+
+ :"ê" => [":ê", ":\"\\u00EA\""],
+ :"测" => [":测", ":\"\\u6D4B\""],
+ :"🦊" => [":🦊", ":\"\\u{1F98A}\""],
}
+ expected_by_encoding = Encoding::default_external == Encoding::UTF_8 ? 0 : 1
symbols.each do |input, expected|
- expected = expected[1] if expected.is_a?(Array)
+ expected = expected[expected_by_encoding] if expected.is_a?(Array)
it "returns self as a symbol literal for #{expected}" do
input.inspect.should == expected
end
diff --git a/spec/ruby/core/symbol/shared/id2name.rb b/spec/ruby/core/symbol/shared/id2name.rb
index d012b7634e..00a9c7d7dc 100644
--- a/spec/ruby/core/symbol/shared/id2name.rb
+++ b/spec/ruby/core/symbol/shared/id2name.rb
@@ -13,4 +13,18 @@ describe :symbol_id2name, shared: true do
symbol.send(@method).encoding.should == Encoding::US_ASCII
end
+
+ ruby_version_is "3.4" do
+ it "warns about mutating returned string" do
+ -> { :bad!.send(@method).upcase! }.should complain(/warning: string returned by :bad!.to_s will be frozen in the future/)
+ end
+
+ it "does not warn about mutation when Warning[:deprecated] is false" do
+ deprecated = Warning[:deprecated]
+ Warning[:deprecated] = false
+ -> { :bad!.send(@method).upcase! }.should_not complain
+ ensure
+ Warning[:deprecated] = deprecated
+ end
+ end
end
diff --git a/spec/ruby/core/symbol/shared/slice.rb b/spec/ruby/core/symbol/shared/slice.rb
index 0df87e183d..d3d4aad617 100644
--- a/spec/ruby/core/symbol/shared/slice.rb
+++ b/spec/ruby/core/symbol/shared/slice.rb
@@ -7,7 +7,7 @@ describe :symbol_slice, shared: true do
end
it "returns nil if the index starts from the end and is greater than the length" do
- :symbol.send(@method, -10).should be_nil
+ :symbol.send(@method, -10).should be_nil
end
it "returns nil if the index is greater than the length" do
diff --git a/spec/ruby/core/symbol/to_proc_spec.rb b/spec/ruby/core/symbol/to_proc_spec.rb
index 54eccdba11..def5d6d344 100644
--- a/spec/ruby/core/symbol/to_proc_spec.rb
+++ b/spec/ruby/core/symbol/to_proc_spec.rb
@@ -27,31 +27,29 @@ describe "Symbol#to_proc" do
pr.parameters.should == [[:req], [:rest]]
end
- ruby_version_is "3.2" do
- it "only calls public methods" do
- body = proc do
- public def pub; @a << :pub end
- protected def pro; @a << :pro end
- private def pri; @a << :pri end
- attr_reader :a
- end
+ it "only calls public methods" do
+ body = proc do
+ public def pub; @a << :pub end
+ protected def pro; @a << :pro end
+ private def pri; @a << :pri end
+ attr_reader :a
+ end
- @a = []
- singleton_class.class_eval(&body)
- tap(&:pub)
- proc{tap(&:pro)}.should raise_error(NoMethodError, /protected method [`']pro' called/)
- proc{tap(&:pri)}.should raise_error(NoMethodError, /private method [`']pri' called/)
- @a.should == [:pub]
+ @a = []
+ singleton_class.class_eval(&body)
+ tap(&:pub)
+ proc{tap(&:pro)}.should raise_error(NoMethodError, /protected method [`']pro' called/)
+ proc{tap(&:pri)}.should raise_error(NoMethodError, /private method [`']pri' called/)
+ @a.should == [:pub]
- @a = []
- c = Class.new(&body)
- o = c.new
- o.instance_variable_set(:@a, [])
- o.tap(&:pub)
- proc{tap(&:pro)}.should raise_error(NoMethodError, /protected method [`']pro' called/)
- proc{o.tap(&:pri)}.should raise_error(NoMethodError, /private method [`']pri' called/)
- o.a.should == [:pub]
- end
+ @a = []
+ c = Class.new(&body)
+ o = c.new
+ o.instance_variable_set(:@a, [])
+ o.tap(&:pub)
+ proc{tap(&:pro)}.should raise_error(NoMethodError, /protected method [`']pro' called/)
+ proc{o.tap(&:pri)}.should raise_error(NoMethodError, /private method [`']pri' called/)
+ o.a.should == [:pub]
end
it "raises an ArgumentError when calling #call on the Proc without receiver" do
diff --git a/spec/ruby/core/thread/abort_on_exception_spec.rb b/spec/ruby/core/thread/abort_on_exception_spec.rb
index 34b648ca0f..49be84ea9f 100644
--- a/spec/ruby/core/thread/abort_on_exception_spec.rb
+++ b/spec/ruby/core/thread/abort_on_exception_spec.rb
@@ -72,7 +72,7 @@ describe "Thread.abort_on_exception" do
end
after do
- Thread.abort_on_exception = @abort_on_exception
+ Thread.abort_on_exception = @abort_on_exception
end
it "is false by default" do
diff --git a/spec/ruby/core/thread/backtrace/limit_spec.rb b/spec/ruby/core/thread/backtrace/limit_spec.rb
index 26a87a806c..b55ca67ea0 100644
--- a/spec/ruby/core/thread/backtrace/limit_spec.rb
+++ b/spec/ruby/core/thread/backtrace/limit_spec.rb
@@ -1,15 +1,13 @@
require_relative '../../../spec_helper'
-ruby_version_is "3.1" do
- describe "Thread::Backtrace.limit" do
- it "returns maximum backtrace length set by --backtrace-limit command-line option" do
- out = ruby_exe("print Thread::Backtrace.limit", options: "--backtrace-limit=2")
- out.should == "2"
- end
+describe "Thread::Backtrace.limit" do
+ it "returns maximum backtrace length set by --backtrace-limit command-line option" do
+ out = ruby_exe("print Thread::Backtrace.limit", options: "--backtrace-limit=2")
+ out.should == "2"
+ end
- it "returns -1 when --backtrace-limit command-line option is not set" do
- out = ruby_exe("print Thread::Backtrace.limit")
- out.should == "-1"
- end
+ it "returns -1 when --backtrace-limit command-line option is not set" do
+ out = ruby_exe("print Thread::Backtrace.limit")
+ out.should == "-1"
end
end
diff --git a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
index 6e381e4868..68a69049d9 100644
--- a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
@@ -27,20 +27,11 @@ describe 'Thread::Backtrace::Location#absolute_path' do
end
context "when used in eval with a given filename" do
- code = "caller_locations(0)[0].absolute_path"
+ it "returns nil with absolute_path" do
+ code = "caller_locations(0)[0].absolute_path"
- ruby_version_is ""..."3.1" do
- it "returns filename with absolute_path" do
- eval(code, nil, "foo.rb").should == "foo.rb"
- eval(code, nil, "foo/bar.rb").should == "foo/bar.rb"
- end
- end
-
- ruby_version_is "3.1" do
- it "returns nil with absolute_path" do
- eval(code, nil, "foo.rb").should == nil
- eval(code, nil, "foo/bar.rb").should == nil
- end
+ eval(code, nil, "foo.rb").should == nil
+ eval(code, nil, "foo/bar.rb").should == nil
end
end
diff --git a/spec/ruby/core/thread/each_caller_location_spec.rb b/spec/ruby/core/thread/each_caller_location_spec.rb
index 29c271789b..aa7423675b 100644
--- a/spec/ruby/core/thread/each_caller_location_spec.rb
+++ b/spec/ruby/core/thread/each_caller_location_spec.rb
@@ -1,49 +1,47 @@
require_relative '../../spec_helper'
describe "Thread.each_caller_location" do
- ruby_version_is "3.2" do
- it "iterates through the current execution stack and matches caller_locations content and type" do
- ScratchPad.record []
- Thread.each_caller_location { |l| ScratchPad << l; }
+ it "iterates through the current execution stack and matches caller_locations content and type" do
+ ScratchPad.record []
+ Thread.each_caller_location { |l| ScratchPad << l; }
- ScratchPad.recorded.map(&:to_s).should == caller_locations.map(&:to_s)
- ScratchPad.recorded[0].should be_kind_of(Thread::Backtrace::Location)
- end
+ ScratchPad.recorded.map(&:to_s).should == caller_locations.map(&:to_s)
+ ScratchPad.recorded[0].should be_kind_of(Thread::Backtrace::Location)
+ end
- it "returns subset of 'Thread.to_enum(:each_caller_location)' locations" do
- ar = []
- ecl = Thread.each_caller_location { |x| ar << x }
+ it "returns subset of 'Thread.to_enum(:each_caller_location)' locations" do
+ ar = []
+ ecl = Thread.each_caller_location { |x| ar << x }
- (ar.map(&:to_s) - Thread.to_enum(:each_caller_location).to_a.map(&:to_s)).should.empty?
- end
+ (ar.map(&:to_s) - Thread.to_enum(:each_caller_location).to_a.map(&:to_s)).should.empty?
+ end
- it "stops the backtrace iteration if 'break' occurs" do
- i = 0
- ar = []
- ecl = Thread.each_caller_location do |x|
- ar << x
- i += 1
- break x if i == 2
- end
-
- ar.map(&:to_s).should == caller_locations(1, 2).map(&:to_s)
- ecl.should be_kind_of(Thread::Backtrace::Location)
+ it "stops the backtrace iteration if 'break' occurs" do
+ i = 0
+ ar = []
+ ecl = Thread.each_caller_location do |x|
+ ar << x
+ i += 1
+ break x if i == 2
end
- it "returns nil" do
- Thread.each_caller_location {}.should == nil
- end
+ ar.map(&:to_s).should == caller_locations(1, 2).map(&:to_s)
+ ecl.should be_kind_of(Thread::Backtrace::Location)
+ end
- it "raises LocalJumpError when called without a block" do
- -> {
- Thread.each_caller_location
- }.should raise_error(LocalJumpError, "no block given")
- end
+ it "returns nil" do
+ Thread.each_caller_location {}.should == nil
+ end
- it "doesn't accept keyword arguments" do
- -> {
- Thread.each_caller_location(12, foo: 10) {}
- }.should raise_error(ArgumentError);
- end
+ it "raises LocalJumpError when called without a block" do
+ -> {
+ Thread.each_caller_location
+ }.should raise_error(LocalJumpError, "no block given")
+ end
+
+ it "doesn't accept keyword arguments" do
+ -> {
+ Thread.each_caller_location(12, foo: 10) {}
+ }.should raise_error(ArgumentError);
end
end
diff --git a/spec/ruby/core/thread/fixtures/classes.rb b/spec/ruby/core/thread/fixtures/classes.rb
index 23a090feb0..7c485660a8 100644
--- a/spec/ruby/core/thread/fixtures/classes.rb
+++ b/spec/ruby/core/thread/fixtures/classes.rb
@@ -6,6 +6,31 @@ module ThreadSpecs
end
end
+ class NewThreadToRaise
+ def self.raise(*args, **kwargs, &block)
+ thread = Thread.new do
+ Thread.current.report_on_exception = false
+
+ if block_given?
+ block.call do
+ sleep
+ end
+ else
+ sleep
+ end
+ end
+
+ Thread.pass until thread.stop?
+
+ thread.raise(*args, **kwargs)
+
+ thread.join
+ ensure
+ thread.kill if thread.alive?
+ Thread.pass while thread.alive? # Thread#kill may not terminate a thread immediately so it may be detected as a leaked one
+ end
+ end
+
class Status
attr_reader :thread, :inspect, :status, :to_s
def initialize(thread)
diff --git a/spec/ruby/core/thread/native_thread_id_spec.rb b/spec/ruby/core/thread/native_thread_id_spec.rb
index 17a08c8a15..374cc59279 100644
--- a/spec/ruby/core/thread/native_thread_id_spec.rb
+++ b/spec/ruby/core/thread/native_thread_id_spec.rb
@@ -1,37 +1,35 @@
require_relative '../../spec_helper'
-ruby_version_is "3.1" do
- platform_is :linux, :darwin, :windows, :freebsd do
- describe "Thread#native_thread_id" do
- it "returns an integer when the thread is alive" do
- Thread.current.native_thread_id.should be_kind_of(Integer)
- end
+platform_is :linux, :darwin, :windows, :freebsd do
+ describe "Thread#native_thread_id" do
+ it "returns an integer when the thread is alive" do
+ Thread.current.native_thread_id.should be_kind_of(Integer)
+ end
- it "returns nil when the thread is not running" do
- t = Thread.new {}
- t.join
- t.native_thread_id.should == nil
- end
+ it "returns nil when the thread is not running" do
+ t = Thread.new {}
+ t.join
+ t.native_thread_id.should == nil
+ end
- it "each thread has different native thread id" do
- t = Thread.new { sleep }
- Thread.pass until t.stop?
- main_thread_id = Thread.current.native_thread_id
- t_thread_id = t.native_thread_id
+ it "each thread has different native thread id" do
+ t = Thread.new { sleep }
+ Thread.pass until t.stop?
+ main_thread_id = Thread.current.native_thread_id
+ t_thread_id = t.native_thread_id
- if ruby_version_is "3.3"
- # native_thread_id can be nil on a M:N scheduler
- t_thread_id.should be_kind_of(Integer) if t_thread_id != nil
- else
- t_thread_id.should be_kind_of(Integer)
- end
+ if ruby_version_is "3.3"
+ # native_thread_id can be nil on a M:N scheduler
+ t_thread_id.should be_kind_of(Integer) if t_thread_id != nil
+ else
+ t_thread_id.should be_kind_of(Integer)
+ end
- main_thread_id.should_not == t_thread_id
+ main_thread_id.should_not == t_thread_id
- t.run
- t.join
- t.native_thread_id.should == nil
- end
+ t.run
+ t.join
+ t.native_thread_id.should == nil
end
end
end
diff --git a/spec/ruby/core/thread/raise_spec.rb b/spec/ruby/core/thread/raise_spec.rb
index 49323cf270..b473eabd42 100644
--- a/spec/ruby/core/thread/raise_spec.rb
+++ b/spec/ruby/core/thread/raise_spec.rb
@@ -3,6 +3,9 @@ require_relative 'fixtures/classes'
require_relative '../../shared/kernel/raise'
describe "Thread#raise" do
+ it_behaves_like :kernel_raise, :raise, ThreadSpecs::NewThreadToRaise
+ it_behaves_like :kernel_raise_across_contexts, :raise, ThreadSpecs::NewThreadToRaise
+
it "ignores dead threads and returns nil" do
t = Thread.new { :dead }
Thread.pass while t.alive?
diff --git a/spec/ruby/core/time/_dump_spec.rb b/spec/ruby/core/time/_dump_spec.rb
index 4dc1c43cd2..852f9a07ab 100644
--- a/spec/ruby/core/time/_dump_spec.rb
+++ b/spec/ruby/core/time/_dump_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
describe "Time#_dump" do
diff --git a/spec/ruby/core/time/_load_spec.rb b/spec/ruby/core/time/_load_spec.rb
index bb0d705bbc..30899de262 100644
--- a/spec/ruby/core/time/_load_spec.rb
+++ b/spec/ruby/core/time/_load_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: binary -*-
+# encoding: binary
require_relative '../../spec_helper'
describe "Time._load" do
diff --git a/spec/ruby/core/time/at_spec.rb b/spec/ruby/core/time/at_spec.rb
index 48fb3c6f52..97906b8c8c 100644
--- a/spec/ruby/core/time/at_spec.rb
+++ b/spec/ruby/core/time/at_spec.rb
@@ -102,8 +102,8 @@ describe "Time.at" do
it "needs for the argument to respond to #to_int too" do
o = mock('rational-but-no-to_int')
- o.should_receive(:to_r).and_return(Rational(5, 2))
- -> { Time.at(o) }.should raise_error(TypeError)
+ def o.to_r; Rational(5, 2) end
+ -> { Time.at(o) }.should raise_error(TypeError, "can't convert MockObject into an exact number")
end
end
end
@@ -228,6 +228,12 @@ describe "Time.at" do
time.utc_offset.should == -9*60*60
time.zone.should == nil
time.to_i.should == @epoch_time
+
+ time = Time.at(@epoch_time, in: "-09:00:01")
+
+ time.utc_offset.should == -(9*60*60 + 1)
+ time.zone.should == nil
+ time.to_i.should == @epoch_time
end
it "could be UTC offset as a number of seconds" do
@@ -280,5 +286,31 @@ describe "Time.at" do
-> { Time.at(@epoch_time, in: "+09:99") }.should raise_error(ArgumentError)
-> { Time.at(@epoch_time, in: "ABC") }.should raise_error(ArgumentError)
end
+
+ it "raises ArgumentError if hours greater than 23" do # TODO
+ -> { Time.at(@epoch_time, in: "+24:00") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.at(@epoch_time, in: "+2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+
+ -> { Time.at(@epoch_time, in: "+99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.at(@epoch_time, in: "+9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+ end
+
+ it "raises ArgumentError if minutes greater than 59" do # TODO
+ -> { Time.at(@epoch_time, in: "+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.at(@epoch_time, in: "+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+
+ -> { Time.at(@epoch_time, in: "+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.at(@epoch_time, in: "+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+ end
+
+ ruby_bug '#20797', ''...'3.4' do
+ it "raises ArgumentError if seconds greater than 59" do
+ -> { Time.at(@epoch_time, in: "+00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.at(@epoch_time, in: "+000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+
+ -> { Time.at(@epoch_time, in: "+00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.at(@epoch_time, in: "+000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
+ end
+ end
end
end
diff --git a/spec/ruby/core/time/deconstruct_keys_spec.rb b/spec/ruby/core/time/deconstruct_keys_spec.rb
index ee17e7dbd4..b5cfdaa93f 100644
--- a/spec/ruby/core/time/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/time/deconstruct_keys_spec.rb
@@ -1,45 +1,43 @@
require_relative '../../spec_helper'
-ruby_version_is "3.2" do
- describe "Time#deconstruct_keys" do
- it "returns whole hash for nil as an argument" do
- d = Time.utc(2022, 10, 5, 13, 30)
- res = { year: 2022, month: 10, day: 5, yday: 278, wday: 3, hour: 13,
- min: 30, sec: 0, subsec: 0, dst: false, zone: "UTC" }
- d.deconstruct_keys(nil).should == res
- end
-
- it "returns only specified keys" do
- d = Time.utc(2022, 10, 5, 13, 39)
- d.deconstruct_keys([:zone, :subsec]).should == { zone: "UTC", subsec: 0 }
- end
-
- it "requires one argument" do
- -> {
- Time.new(2022, 10, 5, 13, 30).deconstruct_keys
- }.should raise_error(ArgumentError)
- end
-
- it "it raises error when argument is neither nil nor array" do
- d = Time.new(2022, 10, 5, 13, 30)
-
- -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)")
- -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)")
- -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)")
- -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)")
- end
-
- it "returns {} when passed []" do
- Time.new(2022, 10, 5, 13, 30).deconstruct_keys([]).should == {}
- end
-
- it "ignores non-Symbol keys" do
- Time.new(2022, 10, 5, 13, 30).deconstruct_keys(['year', []]).should == {}
- end
-
- it "ignores not existing Symbol keys and processes keys after the first non-existing one" do
- d = Time.utc(2022, 10, 5, 13, 30)
- d.deconstruct_keys([:year, :a, :month, :b, :day]).should == { year: 2022, month: 10, day: 5 }
- end
+describe "Time#deconstruct_keys" do
+ it "returns whole hash for nil as an argument" do
+ d = Time.utc(2022, 10, 5, 13, 30)
+ res = { year: 2022, month: 10, day: 5, yday: 278, wday: 3, hour: 13,
+ min: 30, sec: 0, subsec: 0, dst: false, zone: "UTC" }
+ d.deconstruct_keys(nil).should == res
+ end
+
+ it "returns only specified keys" do
+ d = Time.utc(2022, 10, 5, 13, 39)
+ d.deconstruct_keys([:zone, :subsec]).should == { zone: "UTC", subsec: 0 }
+ end
+
+ it "requires one argument" do
+ -> {
+ Time.new(2022, 10, 5, 13, 30).deconstruct_keys
+ }.should raise_error(ArgumentError)
+ end
+
+ it "it raises error when argument is neither nil nor array" do
+ d = Time.new(2022, 10, 5, 13, 30)
+
+ -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)")
+ -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)")
+ -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)")
+ -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)")
+ end
+
+ it "returns {} when passed []" do
+ Time.new(2022, 10, 5, 13, 30).deconstruct_keys([]).should == {}
+ end
+
+ it "ignores non-Symbol keys" do
+ Time.new(2022, 10, 5, 13, 30).deconstruct_keys(['year', []]).should == {}
+ end
+
+ it "ignores not existing Symbol keys and processes keys after the first non-existing one" do
+ d = Time.utc(2022, 10, 5, 13, 30)
+ d.deconstruct_keys([:year, :a, :month, :b, :day]).should == { year: 2022, month: 10, day: 5 }
end
end
diff --git a/spec/ruby/core/time/getlocal_spec.rb b/spec/ruby/core/time/getlocal_spec.rb
index 926a6dbf45..398596f400 100644
--- a/spec/ruby/core/time/getlocal_spec.rb
+++ b/spec/ruby/core/time/getlocal_spec.rb
@@ -14,6 +14,7 @@ describe "Time#getlocal" do
t = Time.gm(2007, 1, 9, 12, 0, 0).getlocal(3630)
t.should == Time.new(2007, 1, 9, 13, 0, 30, 3630)
t.utc_offset.should == 3630
+ t.zone.should be_nil
end
platform_is_not :windows do
@@ -59,12 +60,24 @@ describe "Time#getlocal" do
t.utc_offset.should == 3600
end
+ it "returns a Time with a UTC offset specified as +HH:MM:SS" do
+ t = Time.gm(2007, 1, 9, 12, 0, 0).getlocal("+01:00:01")
+ t.should == Time.new(2007, 1, 9, 13, 0, 1, 3601)
+ t.utc_offset.should == 3601
+ end
+
it "returns a Time with a UTC offset specified as -HH:MM" do
t = Time.gm(2007, 1, 9, 12, 0, 0).getlocal("-01:00")
t.should == Time.new(2007, 1, 9, 11, 0, 0, -3600)
t.utc_offset.should == -3600
end
+ it "returns a Time with a UTC offset specified as -HH:MM:SS" do
+ t = Time.gm(2007, 1, 9, 12, 0, 0).getlocal("-01:00:01")
+ t.should == Time.new(2007, 1, 9, 10, 59, 59, -3601)
+ t.utc_offset.should == -3601
+ end
+
describe "with an argument that responds to #to_str" do
it "coerces using #to_str" do
o = mock('string')
@@ -97,6 +110,32 @@ describe "Time#getlocal" do
-> { t.getlocal(86400) }.should raise_error(ArgumentError)
end
+ it "raises ArgumentError if String argument and hours greater than 23" do
+ -> { Time.now.getlocal("+24:00") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now.getlocal("+2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+
+ -> { Time.now.getlocal("+99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now.getlocal("+9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+ end
+
+ it "raises ArgumentError if String argument and minutes greater than 59" do
+ -> { Time.now.getlocal("+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.now.getlocal("+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+
+ -> { Time.now.getlocal("+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.now.getlocal("+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+ end
+
+ ruby_bug '#20797', ''...'3.4' do
+ it "raises ArgumentError if String argument and seconds greater than 59" do
+ -> { Time.now.getlocal("+00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.now.getlocal("+000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+
+ -> { Time.now.getlocal("+00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.now.getlocal("+000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
+ end
+ end
+
describe "with a timezone argument" do
it "returns a Time in the timezone" do
zone = TimeSpecs::Timezone.new(offset: (5*3600+30*60))
diff --git a/spec/ruby/core/time/localtime_spec.rb b/spec/ruby/core/time/localtime_spec.rb
index 609b6532a1..71c0dfebde 100644
--- a/spec/ruby/core/time/localtime_spec.rb
+++ b/spec/ruby/core/time/localtime_spec.rb
@@ -72,6 +72,13 @@ describe "Time#localtime" do
t.utc_offset.should == 3600
end
+ it "returns a Time with a UTC offset specified as +HH:MM:SS" do
+ t = Time.gm(2007, 1, 9, 12, 0, 0)
+ t.localtime("+01:00:01")
+ t.should == Time.new(2007, 1, 9, 13, 0, 1, 3601)
+ t.utc_offset.should == 3601
+ end
+
it "returns a Time with a UTC offset specified as -HH:MM" do
t = Time.gm(2007, 1, 9, 12, 0, 0)
t.localtime("-01:00")
@@ -79,6 +86,13 @@ describe "Time#localtime" do
t.utc_offset.should == -3600
end
+ it "returns a Time with a UTC offset specified as -HH:MM:SS" do
+ t = Time.gm(2007, 1, 9, 12, 0, 0)
+ t.localtime("-01:00:01")
+ t.should == Time.new(2007, 1, 9, 10, 59, 59, -3601)
+ t.utc_offset.should == -3601
+ end
+
it "returns a Time with a UTC offset specified as UTC" do
t = Time.new(2007, 1, 9, 12, 0, 0, 3600)
t.localtime("UTC")
@@ -91,6 +105,32 @@ describe "Time#localtime" do
t.utc_offset.should == 3600 * 2
end
+ it "raises ArgumentError if String argument and hours greater than 23" do
+ -> { Time.now.localtime("+24:00") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now.localtime("+2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+
+ -> { Time.now.localtime("+99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now.localtime("+9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+ end
+
+ it "raises ArgumentError if String argument and minutes greater than 59" do
+ -> { Time.now.localtime("+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.now.localtime("+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+
+ -> { Time.now.localtime("+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.now.localtime("+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+ end
+
+ ruby_bug '#20797', ''...'3.4' do
+ it "raises ArgumentError if String argument and seconds greater than 59" do
+ -> { Time.now.localtime("+00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.now.localtime("+000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+
+ -> { Time.now.localtime("+00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.now.localtime("+000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
+ end
+ end
+
platform_is_not :windows do
it "changes the timezone according to the set one" do
t = Time.new(2005, 2, 27, 22, 50, 0, -3600)
@@ -128,6 +168,17 @@ describe "Time#localtime" do
end
end
+ describe "with an argument that responds to #utc_to_local" do
+ it "coerces using #utc_to_local" do
+ o = mock('string')
+ o.should_receive(:utc_to_local).and_return(Time.new(2007, 1, 9, 13, 0, 0, 3600))
+ t = Time.gm(2007, 1, 9, 12, 0, 0)
+ t.localtime(o)
+ t.should == Time.new(2007, 1, 9, 13, 0, 0, 3600)
+ t.utc_offset.should == 3600
+ end
+ end
+
it "raises ArgumentError if the String argument is not of the form (+|-)HH:MM" do
t = Time.now
-> { t.localtime("3600") }.should raise_error(ArgumentError)
diff --git a/spec/ruby/core/time/minus_spec.rb b/spec/ruby/core/time/minus_spec.rb
index 8449778465..9182d99652 100644
--- a/spec/ruby/core/time/minus_spec.rb
+++ b/spec/ruby/core/time/minus_spec.rb
@@ -109,7 +109,7 @@ describe "Time#-" do
it "does not return a subclass instance" do
c = Class.new(Time)
- x = c.now + 1
+ x = c.now - 1
x.should be_an_instance_of(Time)
end
diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb
index 24bb9fde0c..dc3ccbdc00 100644
--- a/spec/ruby/core/time/new_spec.rb
+++ b/spec/ruby/core/time/new_spec.rb
@@ -58,30 +58,28 @@ describe "Time.new with a utc_offset argument" do
Time.new(2000, 1, 1, 0, 0, 0, "-04:10:43").utc_offset.should == -15043
end
- ruby_bug '#13669', ''...'3.1' do
- it "returns a Time with a UTC offset specified as +HH" do
- Time.new(2000, 1, 1, 0, 0, 0, "+05").utc_offset.should == 3600 * 5
- end
+ it "returns a Time with a UTC offset specified as +HH" do
+ Time.new(2000, 1, 1, 0, 0, 0, "+05").utc_offset.should == 3600 * 5
+ end
- it "returns a Time with a UTC offset specified as -HH" do
- Time.new(2000, 1, 1, 0, 0, 0, "-05").utc_offset.should == -3600 * 5
- end
+ it "returns a Time with a UTC offset specified as -HH" do
+ Time.new(2000, 1, 1, 0, 0, 0, "-05").utc_offset.should == -3600 * 5
+ end
- it "returns a Time with a UTC offset specified as +HHMM" do
- Time.new(2000, 1, 1, 0, 0, 0, "+0530").utc_offset.should == 19800
- end
+ it "returns a Time with a UTC offset specified as +HHMM" do
+ Time.new(2000, 1, 1, 0, 0, 0, "+0530").utc_offset.should == 19800
+ end
- it "returns a Time with a UTC offset specified as -HHMM" do
- Time.new(2000, 1, 1, 0, 0, 0, "-0530").utc_offset.should == -19800
- end
+ it "returns a Time with a UTC offset specified as -HHMM" do
+ Time.new(2000, 1, 1, 0, 0, 0, "-0530").utc_offset.should == -19800
+ end
- it "returns a Time with a UTC offset specified as +HHMMSS" do
- Time.new(2000, 1, 1, 0, 0, 0, "+053037").utc_offset.should == 19837
- end
+ it "returns a Time with a UTC offset specified as +HHMMSS" do
+ Time.new(2000, 1, 1, 0, 0, 0, "+053037").utc_offset.should == 19837
+ end
- it "returns a Time with a UTC offset specified as -HHMMSS" do
- Time.new(2000, 1, 1, 0, 0, 0, "-053037").utc_offset.should == -19837
- end
+ it "returns a Time with a UTC offset specified as -HHMMSS" do
+ Time.new(2000, 1, 1, 0, 0, 0, "-053037").utc_offset.should == -19837
end
describe "with an argument that responds to #to_str" do
@@ -129,18 +127,9 @@ describe "Time.new with a utc_offset argument" do
end
end
- ruby_version_is ""..."3.1" do
- it "raises ArgumentError if the string argument is J" do
- message = '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset'
- -> { Time.new(2000, 1, 1, 0, 0, 0, "J") }.should raise_error(ArgumentError, message)
- end
- end
-
- ruby_version_is "3.1" do
- it "raises ArgumentError if the string argument is J" do
- message = '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: J'
- -> { Time.new(2000, 1, 1, 0, 0, 0, "J") }.should raise_error(ArgumentError, message)
- end
+ it "raises ArgumentError if the string argument is J" do
+ message = '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: J'
+ -> { Time.new(2000, 1, 1, 0, 0, 0, "J") }.should raise_error(ArgumentError, message)
end
it "returns a local Time if the argument is nil" do
@@ -193,6 +182,7 @@ describe "Time.new with a utc_offset argument" do
end
end
+# The method #local_to_utc is tested only here because Time.new is the only method that calls #local_to_utc.
describe "Time.new with a timezone argument" do
it "returns a Time in the timezone" do
zone = TimeSpecs::Timezone.new(offset: (5*3600+30*60))
@@ -213,9 +203,7 @@ describe "Time.new with a timezone argument" do
time
end
- -> {
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
- }.should_not raise_error
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
end
it "raises TypeError if timezone does not implement #local_to_utc method" do
@@ -226,7 +214,7 @@ describe "Time.new with a timezone argument" do
-> {
Time.new(2000, 1, 1, 12, 0, 0, zone)
- }.should raise_error(TypeError, /can't convert \w+ into an exact number/)
+ }.should raise_error(TypeError, /can't convert Object into an exact number/)
end
it "does not raise exception if timezone does not implement #utc_to_local method" do
@@ -235,51 +223,48 @@ describe "Time.new with a timezone argument" do
time
end
- -> {
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
- }.should_not raise_error
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
end
# The result also should be a Time or Time-like object (not necessary to be the same class)
- # The zone of the result is just ignored
+ # or respond to #to_int method. The zone of the result is just ignored.
describe "returned value by #utc_to_local and #local_to_utc methods" do
it "could be Time instance" do
zone = Object.new
def zone.local_to_utc(t)
- Time.utc(t.year, t.mon, t.day, t.hour - 1, t.min, t.sec)
+ time = Time.utc(t.year, t.mon, t.day, t.hour, t.min, t.sec)
+ time - 60 * 60 # - 1 hour
end
- -> {
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
- Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60
- }.should_not raise_error
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
+ Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60
end
it "could be Time subclass instance" do
zone = Object.new
def zone.local_to_utc(t)
- Class.new(Time).utc(t.year, t.mon, t.day, t.hour - 1, t.min, t.sec)
+ time = Time.utc(t.year, t.mon, t.day, t.hour, t.min, t.sec)
+ time -= 60 * 60 # - 1 hour
+ Class.new(Time).utc(time.year, time.mon, time.day, time.hour, t.min, t.sec)
end
- -> {
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
- Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60
- }.should_not raise_error
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
+ Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60
end
it "could be any object with #to_i method" do
zone = Object.new
def zone.local_to_utc(time)
- Struct.new(:to_i).new(time.to_i - 60*60)
+ obj = Object.new
+ obj.singleton_class.define_method(:to_i) { time.to_i - 60*60 }
+ obj
end
- -> {
- Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
- Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60
- }.should_not raise_error
+ Time.new(2000, 1, 1, 12, 0, 0, zone).should be_kind_of(Time)
+ Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 60*60
end
- it "could have any #zone and #utc_offset because they are ignored" do
+ it "could have any #zone and #utc_offset because they are ignored if it isn't an instance of Time" do
zone = Object.new
def zone.local_to_utc(time)
Struct.new(:to_i, :zone, :utc_offset).new(time.to_i, 'America/New_York', -5*60*60)
@@ -293,7 +278,15 @@ describe "Time.new with a timezone argument" do
Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 0
end
- it "leads to raising Argument error if difference between argument and result is too large" do
+ it "cannot have arbitrary #utc_offset if it is an instance of Time" do
+ zone = Object.new
+ def zone.local_to_utc(t)
+ Time.new(t.year, t.mon, t.mday, t.hour, t.min, t.sec, 9*60*60)
+ end
+ Time.new(2000, 1, 1, 12, 0, 0, zone).utc_offset.should == 9*60*60
+ end
+
+ it "raises ArgumentError if difference between argument and result is too large" do
zone = Object.new
def zone.local_to_utc(t)
Time.utc(t.year, t.mon, t.day + 1, t.hour, t.min, t.sec)
@@ -318,12 +311,9 @@ describe "Time.new with a timezone argument" do
end
it "implements subset of Time methods" do
+ # List only methods that are explicitly documented.
[
- :year, :mon, :month, :mday, :hour, :min, :sec,
- :tv_sec, :tv_usec, :usec, :tv_nsec, :nsec, :subsec,
- :to_i, :to_f, :to_r, :+, :-,
- :isdst, :dst?, :zone, :gmtoff, :gmt_offset, :utc_offset, :utc?, :gmt?,
- :to_s, :inspect, :to_a, :to_time,
+ :year, :mon, :mday, :hour, :min, :sec, :to_i, :isdst
].each do |name|
@obj.respond_to?(name).should == true
end
@@ -403,307 +393,360 @@ describe "Time.new with a timezone argument" do
end
end
- ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/17485
- describe ":in keyword argument" do
- it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do
- time = Time.new(2000, 1, 1, 12, 0, 0, in: "+05:00")
+ describe ":in keyword argument" do
+ it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do
+ time = Time.new(2000, 1, 1, 12, 0, 0, in: "+05:00")
- time.utc_offset.should == 5*60*60
- time.zone.should == nil
+ time.utc_offset.should == 5*60*60
+ time.zone.should == nil
- time = Time.new(2000, 1, 1, 12, 0, 0, in: "-09:00")
+ time = Time.new(2000, 1, 1, 12, 0, 0, in: "-09:00")
- time.utc_offset.should == -9*60*60
- time.zone.should == nil
- end
+ time.utc_offset.should == -9*60*60
+ time.zone.should == nil
- it "could be UTC offset as a number of seconds" do
- time = Time.new(2000, 1, 1, 12, 0, 0, in: 5*60*60)
+ time = Time.new(2000, 1, 1, 12, 0, 0, in: "-09:00:01")
- time.utc_offset.should == 5*60*60
- time.zone.should == nil
+ time.utc_offset.should == -(9*60*60 + 1)
+ time.zone.should == nil
+ end
- time = Time.new(2000, 1, 1, 12, 0, 0, in: -9*60*60)
+ it "could be UTC offset as a number of seconds" do
+ time = Time.new(2000, 1, 1, 12, 0, 0, in: 5*60*60)
- time.utc_offset.should == -9*60*60
- time.zone.should == nil
- end
+ time.utc_offset.should == 5*60*60
+ time.zone.should == nil
- it "returns a Time with UTC offset specified as a single letter military timezone" do
- Time.new(2000, 1, 1, 0, 0, 0, in: "W").utc_offset.should == 3600 * -10
- end
+ time = Time.new(2000, 1, 1, 12, 0, 0, in: -9*60*60)
+
+ time.utc_offset.should == -9*60*60
+ time.zone.should == nil
+ end
+
+ it "returns a Time with UTC offset specified as a single letter military timezone" do
+ Time.new(2000, 1, 1, 0, 0, 0, in: "W").utc_offset.should == 3600 * -10
+ end
- it "could be a timezone object" do
- zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo")
- time = Time.new(2000, 1, 1, 12, 0, 0, in: zone)
+ it "could be a timezone object" do
+ zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo")
+ time = Time.new(2000, 1, 1, 12, 0, 0, in: zone)
- time.utc_offset.should == 5*3600+30*60
- time.zone.should == zone
+ time.utc_offset.should == 5*3600+30*60
+ time.zone.should == zone
- zone = TimeSpecs::TimezoneWithName.new(name: "PST")
- time = Time.new(2000, 1, 1, 12, 0, 0, in: zone)
+ zone = TimeSpecs::TimezoneWithName.new(name: "PST")
+ time = Time.new(2000, 1, 1, 12, 0, 0, in: zone)
- time.utc_offset.should == -9*60*60
- time.zone.should == zone
- end
+ time.utc_offset.should == -9*60*60
+ time.zone.should == zone
+ end
- it "allows omitting minor arguments" do
- Time.new(2000, 1, 1, 12, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 1, "+05:00")
- Time.new(2000, 1, 1, 12, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 0, "+05:00")
- Time.new(2000, 1, 1, 12, in: "+05:00").should == Time.new(2000, 1, 1, 12, 0, 0, "+05:00")
- Time.new(2000, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
- Time.new(2000, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
- Time.new(2000, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
- Time.new(in: "+05:00").should be_close(Time.now.getlocal("+05:00"), TIME_TOLERANCE)
- end
+ it "allows omitting minor arguments" do
+ Time.new(2000, 1, 1, 12, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 1, "+05:00")
+ Time.new(2000, 1, 1, 12, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 0, "+05:00")
+ Time.new(2000, 1, 1, 12, in: "+05:00").should == Time.new(2000, 1, 1, 12, 0, 0, "+05:00")
+ Time.new(2000, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
+ Time.new(2000, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
+ Time.new(2000, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
+ Time.new(in: "+05:00").should be_close(Time.now.getlocal("+05:00"), TIME_TOLERANCE)
+ end
- it "converts to a provided timezone if all the positional arguments are omitted" do
- Time.new(in: "+05:00").utc_offset.should == 5*3600
- end
+ it "converts to a provided timezone if all the positional arguments are omitted" do
+ Time.new(in: "+05:00").utc_offset.should == 5*3600
+ end
- it "raises ArgumentError if format is invalid" do
- -> { Time.new(2000, 1, 1, 12, 0, 0, in: "+09:99") }.should raise_error(ArgumentError)
- -> { Time.new(2000, 1, 1, 12, 0, 0, in: "ABC") }.should raise_error(ArgumentError)
- end
+ it "raises ArgumentError if format is invalid" do
+ -> { Time.new(2000, 1, 1, 12, 0, 0, in: "+09:99") }.should raise_error(ArgumentError)
+ -> { Time.new(2000, 1, 1, 12, 0, 0, in: "ABC") }.should raise_error(ArgumentError)
+ end
- it "raises ArgumentError if two offset arguments are given" do
- -> {
- Time.new(2000, 1, 1, 12, 0, 0, "+05:00", in: "+05:00")
- }.should raise_error(ArgumentError, "timezone argument given as positional and keyword arguments")
- end
+ it "raises ArgumentError if two offset arguments are given" do
+ -> {
+ Time.new(2000, 1, 1, 12, 0, 0, "+05:00", in: "+05:00")
+ }.should raise_error(ArgumentError, "timezone argument given as positional and keyword arguments")
end
end
- ruby_version_is "3.2" do
- describe "Time.new with a String argument" do
- it "parses an ISO-8601 like format" do
- t = Time.utc(2020, 12, 24, 15, 56, 17)
+ describe "Time.new with a String argument" do
+ it "parses an ISO-8601 like format" do
+ t = Time.utc(2020, 12, 24, 15, 56, 17)
- Time.new("2020-12-24T15:56:17Z").should == t
- Time.new("2020-12-25 00:56:17 +09:00").should == t
- Time.new("2020-12-25 00:57:47 +09:01:30").should == t
- Time.new("2020-12-25 00:56:17 +0900").should == t
- Time.new("2020-12-25 00:57:47 +090130").should == t
- Time.new("2020-12-25T00:56:17+09:00").should == t
+ Time.new("2020-12-24T15:56:17Z").should == t
+ Time.new("2020-12-25 00:56:17 +09:00").should == t
+ Time.new("2020-12-25 00:57:47 +09:01:30").should == t
+ Time.new("2020-12-25 00:56:17 +0900").should == t
+ Time.new("2020-12-25 00:57:47 +090130").should == t
+ Time.new("2020-12-25T00:56:17+09:00").should == t
- Time.new("2020-12-25T00:56:17.123456+09:00").should == Time.utc(2020, 12, 24, 15, 56, 17, 123456)
- end
+ Time.new("2020-12-25T00:56:17.123456+09:00").should == Time.utc(2020, 12, 24, 15, 56, 17, 123456)
+ end
- it "accepts precision keyword argument and truncates specified digits of sub-second part" do
- Time.new("2021-12-25 00:00:00.123456789876 +09:00").subsec.should == 0.123456789r
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: nil).subsec.should == 0.123456789876r
- Time.new("2021-12-25 00:00:00 +09:00", precision: 0).subsec.should == 0
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: -1).subsec.should == 0.123456789876r
- end
+ it "accepts precision keyword argument and truncates specified digits of sub-second part" do
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00").subsec.should == 0.123456789r
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: nil).subsec.should == 0.123456789876r
+ Time.new("2021-12-25 00:00:00 +09:00", precision: 0).subsec.should == 0
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: -1).subsec.should == 0.123456789876r
+ end
- it "returns Time in local timezone if not provided in the String argument" do
- Time.new("2021-12-25 00:00:00").zone.should == Time.new(2021, 12, 25).zone
- Time.new("2021-12-25 00:00:00").utc_offset.should == Time.new(2021, 12, 25).utc_offset
- end
+ it "returns Time in local timezone if not provided in the String argument" do
+ Time.new("2021-12-25 00:00:00").zone.should == Time.new(2021, 12, 25).zone
+ Time.new("2021-12-25 00:00:00").utc_offset.should == Time.new(2021, 12, 25).utc_offset
+ end
- it "returns Time in timezone specified in the String argument" do
- Time.new("2021-12-25 00:00:00 +05:00").to_s.should == "2021-12-25 00:00:00 +0500"
- end
+ it "returns Time in timezone specified in the String argument" do
+ Time.new("2021-12-25 00:00:00 +05:00").to_s.should == "2021-12-25 00:00:00 +0500"
+ end
- it "returns Time in timezone specified in the String argument even if the in keyword argument provided" do
- Time.new("2021-12-25 00:00:00 +09:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 +0900"
- end
+ it "returns Time in timezone specified in the String argument even if the in keyword argument provided" do
+ Time.new("2021-12-25 00:00:00 +09:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 +0900"
+ end
- it "returns Time in timezone specified with in keyword argument if timezone isn't provided in the String argument" do
- Time.new("2021-12-25 00:00:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 -0100"
- end
+ it "returns Time in timezone specified with in keyword argument if timezone isn't provided in the String argument" do
+ Time.new("2021-12-25 00:00:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 -0100"
+ end
- it "returns Time of Jan 1 for string with just year" do
- Time.new("2021").should == Time.new(2021, 1, 1)
- Time.new("2021").zone.should == Time.new(2021, 1, 1).zone
- Time.new("2021").utc_offset.should == Time.new(2021, 1, 1).utc_offset
- end
+ it "returns Time of Jan 1 for string with just year" do
+ Time.new("2021").should == Time.new(2021, 1, 1)
+ Time.new("2021").zone.should == Time.new(2021, 1, 1).zone
+ Time.new("2021").utc_offset.should == Time.new(2021, 1, 1).utc_offset
+ end
- it "returns Time of Jan 1 for string with just year in timezone specified with in keyword argument" do
- Time.new("2021", in: "+17:00").to_s.should == "2021-01-01 00:00:00 +1700"
- end
+ it "returns Time of Jan 1 for string with just year in timezone specified with in keyword argument" do
+ Time.new("2021", in: "+17:00").to_s.should == "2021-01-01 00:00:00 +1700"
+ end
- it "converts precision keyword argument into Integer if is not nil" do
- obj = Object.new
- def obj.to_int; 3; end
+ it "converts precision keyword argument into Integer if is not nil" do
+ obj = Object.new
+ def obj.to_int; 3; end
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 1.2).subsec.should == 0.1r
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: obj).subsec.should == 0.123r
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 3r).subsec.should == 0.123r
- end
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 1.2).subsec.should == 0.1r
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: obj).subsec.should == 0.123r
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 3r).subsec.should == 0.123r
+ end
- ruby_version_is ""..."3.3" do
- it "raise TypeError is can't convert precision keyword argument into Integer" do
- -> {
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: "")
- }.should raise_error(TypeError, "no implicit conversion from string")
- end
- end
+ it "returns Time with correct subseconds when given seconds fraction is shorted than 6 digits" do
+ Time.new("2020-12-25T00:56:17.123 +09:00").nsec.should == 123000000
+ Time.new("2020-12-25T00:56:17.123 +09:00").usec.should == 123000
+ Time.new("2020-12-25T00:56:17.123 +09:00").subsec.should == 0.123
+ end
- ruby_version_is "3.3" do
- it "raise TypeError is can't convert precision keyword argument into Integer" do
- -> {
- Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: "")
- }.should raise_error(TypeError, "no implicit conversion of String into Integer")
- end
- end
+ it "returns Time with correct subseconds when given seconds fraction is milliseconds" do
+ Time.new("2020-12-25T00:56:17.123456 +09:00").nsec.should == 123456000
+ Time.new("2020-12-25T00:56:17.123456 +09:00").usec.should == 123456
+ Time.new("2020-12-25T00:56:17.123456 +09:00").subsec.should == 0.123456
+ end
- it "raises ArgumentError if part of time string is missing" do
- -> {
- Time.new("2020-12-25 00:56 +09:00")
- }.should raise_error(ArgumentError, /missing sec part: 00:56 |can't parse:/)
+ it "returns Time with correct subseconds when given seconds fraction is longer that 6 digits but shorted than 9 digits" do
+ Time.new("2020-12-25T00:56:17.12345678 +09:00").nsec.should == 123456780
+ Time.new("2020-12-25T00:56:17.12345678 +09:00").usec.should == 123456
+ Time.new("2020-12-25T00:56:17.12345678 +09:00").subsec.should == 0.12345678
+ end
+ it "returns Time with correct subseconds when given seconds fraction is nanoseconds" do
+ Time.new("2020-12-25T00:56:17.123456789 +09:00").nsec.should == 123456789
+ Time.new("2020-12-25T00:56:17.123456789 +09:00").usec.should == 123456
+ Time.new("2020-12-25T00:56:17.123456789 +09:00").subsec.should == 0.123456789
+ end
+
+ it "returns Time with correct subseconds when given seconds fraction is longer than 9 digits" do
+ Time.new("2020-12-25T00:56:17.123456789876 +09:00").nsec.should == 123456789
+ Time.new("2020-12-25T00:56:17.123456789876 +09:00").usec.should == 123456
+ Time.new("2020-12-25T00:56:17.123456789876 +09:00").subsec.should == 0.123456789
+ end
+
+ ruby_version_is ""..."3.3" do
+ it "raise TypeError is can't convert precision keyword argument into Integer" do
-> {
- Time.new("2020-12-25 00 +09:00")
- }.should raise_error(ArgumentError, /missing min part: 00 |can't parse:/)
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: "")
+ }.should raise_error(TypeError, "no implicit conversion from string")
end
+ end
- ruby_version_is "3.2.3" do
- it "raises ArgumentError if the time part is missing" do
- -> {
- Time.new("2020-12-25")
- }.should raise_error(ArgumentError, /no time information|can't parse:/)
- end
-
- it "raises ArgumentError if day is missing" do
- -> {
- Time.new("2020-12")
- }.should raise_error(ArgumentError, /no time information|can't parse:/)
- end
+ ruby_version_is "3.3" do
+ it "raise TypeError is can't convert precision keyword argument into Integer" do
+ -> {
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: "")
+ }.should raise_error(TypeError, "no implicit conversion of String into Integer")
end
+ end
- it "raises ArgumentError if subsecond is missing after dot" do
+ it "raises ArgumentError if part of time string is missing" do
+ -> {
+ Time.new("2020-12-25 00:56 +09:00")
+ }.should raise_error(ArgumentError, /missing sec part: 00:56 |can't parse:/)
+
+ -> {
+ Time.new("2020-12-25 00 +09:00")
+ }.should raise_error(ArgumentError, /missing min part: 00 |can't parse:/)
+ end
+
+ ruby_version_is "3.2.3" do
+ it "raises ArgumentError if the time part is missing" do
-> {
- Time.new("2020-12-25 00:56:17. +0900")
- }.should raise_error(ArgumentError, /subsecond expected after dot: 00:56:17. |can't parse:/)
+ Time.new("2020-12-25")
+ }.should raise_error(ArgumentError, /no time information|can't parse:/)
end
- it "raises ArgumentError if String argument is not in the supported format" do
+ it "raises ArgumentError if day is missing" do
-> {
- Time.new("021-12-25 00:00:00.123456 +09:00")
- }.should raise_error(ArgumentError, /year must be 4 or more digits: 021|can't parse:/)
+ Time.new("2020-12")
+ }.should raise_error(ArgumentError, /no time information|can't parse:/)
+ end
+ end
- -> {
- Time.new("2020-012-25 00:56:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -012-25 00:\z|can't parse:/)
+ it "raises ArgumentError if subsecond is missing after dot" do
+ -> {
+ Time.new("2020-12-25 00:56:17. +0900")
+ }.should raise_error(ArgumentError, /subsecond expected after dot: 00:56:17. |can't parse:/)
+ end
- -> {
- Time.new("2020-2-25 00:56:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -2-25 00:56\z|can't parse:/)
+ it "raises ArgumentError if String argument is not in the supported format" do
+ -> {
+ Time.new("021-12-25 00:00:00.123456 +09:00")
+ }.should raise_error(ArgumentError, /year must be 4 or more digits: 021|can't parse:/)
- -> {
- Time.new("2020-12-215 00:56:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits mday is expected after [`']-': -215 00:56:\z|can't parse:/)
+ -> {
+ Time.new("2020-012-25 00:56:17 +0900")
+ }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -012-25 00:\z|can't parse:/)
- -> {
- Time.new("2020-12-25 000:56:17 +0900")
- }.should raise_error(ArgumentError, /two digits hour is expected: 000:56:17 |can't parse:/)
+ -> {
+ Time.new("2020-2-25 00:56:17 +0900")
+ }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -2-25 00:56\z|can't parse:/)
- -> {
- Time.new("2020-12-25 0:56:17 +0900")
- }.should raise_error(ArgumentError, /two digits hour is expected: 0:56:17 \+0|can't parse:/)
+ -> {
+ Time.new("2020-12-215 00:56:17 +0900")
+ }.should raise_error(ArgumentError, /\Atwo digits mday is expected after [`']-': -215 00:56:\z|can't parse:/)
- -> {
- Time.new("2020-12-25 00:516:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :516:17 \+09\z|can't parse:/)
+ -> {
+ Time.new("2020-12-25 000:56:17 +0900")
+ }.should raise_error(ArgumentError, /two digits hour is expected: 000:56:17 |can't parse:/)
- -> {
- Time.new("2020-12-25 00:6:17 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :6:17 \+0900\z|can't parse:/)
+ -> {
+ Time.new("2020-12-25 0:56:17 +0900")
+ }.should raise_error(ArgumentError, /two digits hour is expected: 0:56:17 \+0|can't parse:/)
- -> {
- Time.new("2020-12-25 00:56:137 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :137 \+0900\z|can't parse:/)
+ -> {
+ Time.new("2020-12-25 00:516:17 +0900")
+ }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :516:17 \+09\z|can't parse:/)
- -> {
- Time.new("2020-12-25 00:56:7 +0900")
- }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :7 \+0900\z|can't parse:/)
+ -> {
+ Time.new("2020-12-25 00:6:17 +0900")
+ }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :6:17 \+0900\z|can't parse:/)
- -> {
- Time.new("2020-12-25 00:56. +0900")
- }.should raise_error(ArgumentError, /fraction min is not supported: 00:56\.|can't parse:/)
+ -> {
+ Time.new("2020-12-25 00:56:137 +0900")
+ }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :137 \+0900\z|can't parse:/)
- -> {
- Time.new("2020-12-25 00. +0900")
- }.should raise_error(ArgumentError, /fraction hour is not supported: 00\.|can't parse:/)
- end
+ -> {
+ Time.new("2020-12-25 00:56:7 +0900")
+ }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :7 \+0900\z|can't parse:/)
- it "raises ArgumentError if date/time parts values are not valid" do
- -> {
- Time.new("2020-13-25 00:56:17 +09:00")
- }.should raise_error(ArgumentError, /(mon|argument) out of range/)
+ -> {
+ Time.new("2020-12-25 00:56. +0900")
+ }.should raise_error(ArgumentError, /fraction min is not supported: 00:56\.|can't parse:/)
- -> {
- Time.new("2020-12-32 00:56:17 +09:00")
- }.should raise_error(ArgumentError, /(mday|argument) out of range/)
+ -> {
+ Time.new("2020-12-25 00. +0900")
+ }.should raise_error(ArgumentError, /fraction hour is not supported: 00\.|can't parse:/)
+ end
- -> {
- Time.new("2020-12-25 25:56:17 +09:00")
- }.should raise_error(ArgumentError, /(hour|argument) out of range/)
+ it "raises ArgumentError if date/time parts values are not valid" do
+ -> {
+ Time.new("2020-13-25 00:56:17 +09:00")
+ }.should raise_error(ArgumentError, /(mon|argument) out of range/)
- -> {
- Time.new("2020-12-25 00:61:17 +09:00")
- }.should raise_error(ArgumentError, /(min|argument) out of range/)
+ -> {
+ Time.new("2020-12-32 00:56:17 +09:00")
+ }.should raise_error(ArgumentError, /(mday|argument) out of range/)
- -> {
- Time.new("2020-12-25 00:56:61 +09:00")
- }.should raise_error(ArgumentError, /(sec|argument) out of range/)
+ -> {
+ Time.new("2020-12-25 25:56:17 +09:00")
+ }.should raise_error(ArgumentError, /(hour|argument) out of range/)
- -> {
- Time.new("2020-12-25 00:56:17 +23:59:60")
- }.should raise_error(ArgumentError, /utc_offset|argument out of range/)
+ -> {
+ Time.new("2020-12-25 00:61:17 +09:00")
+ }.should raise_error(ArgumentError, /(min|argument) out of range/)
- -> {
- Time.new("2020-12-25 00:56:17 +24:00")
- }.should raise_error(ArgumentError, /(utc_offset|argument) out of range/)
+ -> {
+ Time.new("2020-12-25 00:56:61 +09:00")
+ }.should raise_error(ArgumentError, /(sec|argument) out of range/)
- -> {
- Time.new("2020-12-25 00:56:17 +23:61")
- }.should raise_error(ArgumentError, /utc_offset|can't parse:/)
-
- ruby_bug '#20797', ''...'3.4' do
- -> {
- Time.new("2020-12-25 00:56:17 +00:23:61")
- }.should raise_error(ArgumentError, /utc_offset/)
- end
- end
+ -> {
+ Time.new("2020-12-25 00:56:17 +23:59:60")
+ }.should raise_error(ArgumentError, /utc_offset|argument out of range/)
- it "raises ArgumentError if string has not ascii-compatible encoding" do
- -> {
- Time.new("2021-11-31 00:00:60 +09:00".encode("utf-32le"))
- }.should raise_error(ArgumentError, "time string should have ASCII compatible encoding")
- end
+ -> {
+ Time.new("2020-12-25 00:56:17 +24:00")
+ }.should raise_error(ArgumentError, /(utc_offset|argument) out of range/)
- it "raises ArgumentError if string doesn't start with year" do
+ -> {
+ Time.new("2020-12-25 00:56:17 +23:61")
+ }.should raise_error(ArgumentError, /utc_offset/)
+
+ ruby_bug '#20797', ''...'3.4' do
-> {
- Time.new("a\nb")
- }.should raise_error(ArgumentError, "can't parse: \"a\\nb\"")
+ Time.new("2020-12-25 00:56:17 +00:23:61")
+ }.should raise_error(ArgumentError, /utc_offset/)
end
+ end
- it "raises ArgumentError if string has extra characters after offset" do
- -> {
- Time.new("2021-11-31 00:00:59 +09:00 abc")
- }.should raise_error(ArgumentError, /can't parse.+ abc/)
+ it "raises ArgumentError if utc offset parts are not valid" do
+ -> { Time.new("2020-12-25 00:56:17 +24:00") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.new("2020-12-25 00:56:17 +2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+
+ -> { Time.new("2020-12-25 00:56:17 +99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.new("2020-12-25 00:56:17 +9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+
+ -> { Time.new("2020-12-25 00:56:17 +00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.new("2020-12-25 00:56:17 +0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+
+ -> { Time.new("2020-12-25 00:56:17 +00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.new("2020-12-25 00:56:17 +0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+
+ ruby_bug '#20797', ''...'3.4' do
+ -> { Time.new("2020-12-25 00:56:17 +00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.new("2020-12-25 00:56:17 +000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+
+ -> { Time.new("2020-12-25 00:56:17 +00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.new("2020-12-25 00:56:17 +000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
end
+ end
+
+ it "raises ArgumentError if string has not ascii-compatible encoding" do
+ -> {
+ Time.new("2021-11-31 00:00:60 +09:00".encode("utf-32le"))
+ }.should raise_error(ArgumentError, "time string should have ASCII compatible encoding")
+ end
- ruby_version_is "3.2.3" do
- it "raises ArgumentError when there are leading space characters" do
- -> { Time.new(" 2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\t2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\n2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\v2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\f2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("\r2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
- end
-
- it "raises ArgumentError when there are trailing whitespaces" do
- -> { Time.new("2020-12-02 00:00:00 ") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\t") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\n") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\v") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\f") }.should raise_error(ArgumentError, /can't parse/)
- -> { Time.new("2020-12-02 00:00:00\r") }.should raise_error(ArgumentError, /can't parse/)
- end
+ it "raises ArgumentError if string doesn't start with year" do
+ -> {
+ Time.new("a\nb")
+ }.should raise_error(ArgumentError, "can't parse: \"a\\nb\"")
+ end
+
+ it "raises ArgumentError if string has extra characters after offset" do
+ -> {
+ Time.new("2021-11-31 00:00:59 +09:00 abc")
+ }.should raise_error(ArgumentError, /can't parse.+ abc/)
+ end
+
+ ruby_version_is "3.2.3" do
+ it "raises ArgumentError when there are leading space characters" do
+ -> { Time.new(" 2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("\t2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("\n2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("\v2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("\f2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("\r2020-12-02 00:00:00") }.should raise_error(ArgumentError, /can't parse/)
+ end
+
+ it "raises ArgumentError when there are trailing whitespaces" do
+ -> { Time.new("2020-12-02 00:00:00 ") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\t") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\n") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\v") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\f") }.should raise_error(ArgumentError, /can't parse/)
+ -> { Time.new("2020-12-02 00:00:00\r") }.should raise_error(ArgumentError, /can't parse/)
end
end
end
diff --git a/spec/ruby/core/time/now_spec.rb b/spec/ruby/core/time/now_spec.rb
index d47f00723e..e3fe6edad6 100644
--- a/spec/ruby/core/time/now_spec.rb
+++ b/spec/ruby/core/time/now_spec.rb
@@ -4,53 +4,177 @@ require_relative 'shared/now'
describe "Time.now" do
it_behaves_like :time_now, :now
- ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/17485
- describe ":in keyword argument" do
- it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do
- time = Time.now(in: "+05:00")
+ describe ":in keyword argument" do
+ it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do
+ time = Time.now(in: "+05:00")
- time.utc_offset.should == 5*60*60
- time.zone.should == nil
+ time.utc_offset.should == 5*60*60
+ time.zone.should == nil
- time = Time.now(in: "-09:00")
+ time = Time.now(in: "-09:00")
- time.utc_offset.should == -9*60*60
- time.zone.should == nil
+ time.utc_offset.should == -9*60*60
+ time.zone.should == nil
+
+ time = Time.now(in: "-09:00:01")
+
+ time.utc_offset.should == -(9*60*60 + 1)
+ time.zone.should == nil
+ end
+
+ it "could be UTC offset as a number of seconds" do
+ time = Time.now(in: 5*60*60)
+
+ time.utc_offset.should == 5*60*60
+ time.zone.should == nil
+
+ time = Time.now(in: -9*60*60)
+
+ time.utc_offset.should == -9*60*60
+ time.zone.should == nil
+ end
+
+ it "returns a Time with UTC offset specified as a single letter military timezone" do
+ Time.now(in: "W").utc_offset.should == 3600 * -10
+ end
+
+ it "could be a timezone object" do
+ zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo")
+ time = Time.now(in: zone)
+
+ time.utc_offset.should == 5*3600+30*60
+ time.zone.should == zone
+
+ zone = TimeSpecs::TimezoneWithName.new(name: "PST")
+ time = Time.now(in: zone)
+
+ time.utc_offset.should == -9*60*60
+ time.zone.should == zone
+ end
+
+ it "raises ArgumentError if format is invalid" do
+ -> { Time.now(in: "+09:99") }.should raise_error(ArgumentError)
+ -> { Time.now(in: "ABC") }.should raise_error(ArgumentError)
+ end
+
+ it "raises ArgumentError if String argument and hours greater than 23" do
+ -> { Time.now(in: "+24:00") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now(in: "+2400") }.should raise_error(ArgumentError, "utc_offset out of range")
+
+ -> { Time.now(in: "+99:00") }.should raise_error(ArgumentError, "utc_offset out of range")
+ -> { Time.now(in: "+9900") }.should raise_error(ArgumentError, "utc_offset out of range")
+ end
+
+ it "raises ArgumentError if String argument and minutes greater than 59" do
+ -> { Time.now(in: "+00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:60')
+ -> { Time.now(in: "+0060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0060')
+
+ -> { Time.now(in: "+00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:99')
+ -> { Time.now(in: "+0099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +0099')
+ end
+
+ ruby_bug '#20797', ''...'3.4' do
+ it "raises ArgumentError if String argument and seconds greater than 59" do
+ -> { Time.now(in: "+00:00:60") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:60')
+ -> { Time.now(in: "+000060") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000060')
+
+ -> { Time.now(in: "+00:00:99") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +00:00:99')
+ -> { Time.now(in: "+000099") }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +000099')
end
+ end
+ end
- it "could be UTC offset as a number of seconds" do
- time = Time.now(in: 5*60*60)
+ describe "Timezone object" do # https://bugs.ruby-lang.org/issues/17485
+ it "raises TypeError if timezone does not implement #utc_to_local method" do
+ zone = Object.new
+ def zone.local_to_utc(time)
+ time
+ end
- time.utc_offset.should == 5*60*60
- time.zone.should == nil
+ -> {
+ Time.now(in: zone)
+ }.should raise_error(TypeError, /can't convert Object into an exact number/)
+ end
- time = Time.now(in: -9*60*60)
+ it "does not raise exception if timezone does not implement #local_to_utc method" do
+ zone = Object.new
+ def zone.utc_to_local(time)
+ time
+ end
+
+ Time.now(in: zone).should be_kind_of(Time)
+ end
- time.utc_offset.should == -9*60*60
- time.zone.should == nil
+ # The result also should be a Time or Time-like object (not necessary to be the same class)
+ # or Integer. The zone of the result is just ignored.
+ describe "returned value by #utc_to_local and #local_to_utc methods" do
+ it "could be Time instance" do
+ zone = Object.new
+ def zone.utc_to_local(t)
+ time = Time.new(t.year, t.mon, t.day, t.hour, t.min, t.sec, t.utc_offset)
+ time + 60 * 60 # + 1 hour
+ end
+
+ Time.now(in: zone).should be_kind_of(Time)
+ Time.now(in: zone).utc_offset.should == 3600
end
- it "returns a Time with UTC offset specified as a single letter military timezone" do
- Time.now(in: "W").utc_offset.should == 3600 * -10
+ it "could be Time subclass instance" do
+ zone = Object.new
+ def zone.utc_to_local(t)
+ time = Time.new(t.year, t.mon, t.day, t.hour, t.min, t.sec, t.utc_offset)
+ time += 60 * 60 # + 1 hour
+
+ Class.new(Time).new(time.year, time.mon, time.day, time.hour, time.min, time.sec, time.utc_offset)
+ end
+
+ Time.now(in: zone).should be_kind_of(Time)
+ Time.now(in: zone).utc_offset.should == 3600
end
- it "could be a timezone object" do
- zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo")
- time = Time.now(in: zone)
+ it "could be Integer" do
+ zone = Object.new
+ def zone.utc_to_local(time)
+ time.to_i + 60*60
+ end
+
+ Time.now(in: zone).should be_kind_of(Time)
+ Time.now(in: zone).utc_offset.should == 60*60
+ end
- time.utc_offset.should == 5*3600+30*60
- time.zone.should == zone
+ it "could have any #zone and #utc_offset because they are ignored" do
+ zone = Object.new
+ def zone.utc_to_local(t)
+ Struct.new(:year, :mon, :mday, :hour, :min, :sec, :isdst, :to_i, :zone, :utc_offset) # rubocop:disable Lint/StructNewOverride
+ .new(t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.isdst, t.to_i, 'America/New_York', -5*60*60)
+ end
+ Time.now(in: zone).utc_offset.should == 0
- zone = TimeSpecs::TimezoneWithName.new(name: "PST")
- time = Time.now(in: zone)
+ zone = Object.new
+ def zone.utc_to_local(t)
+ Struct.new(:year, :mon, :mday, :hour, :min, :sec, :isdst, :to_i, :zone, :utc_offset) # rubocop:disable Lint/StructNewOverride
+ .new(t.year, t.mon, t.mday, t.hour, t.min, t.sec, t.isdst, t.to_i, 'Asia/Tokyo', 9*60*60)
+ end
+ Time.now(in: zone).utc_offset.should == 0
- time.utc_offset.should == -9*60*60
- time.zone.should == zone
+ zone = Object.new
+ def zone.utc_to_local(t)
+ Time.new(t.year, t.mon, t.mday, t.hour, t.min, t.sec, 9*60*60)
+ end
+ Time.now(in: zone).utc_offset.should == 0
end
- it "raises ArgumentError if format is invalid" do
- -> { Time.now(in: "+09:99") }.should raise_error(ArgumentError)
- -> { Time.now(in: "ABC") }.should raise_error(ArgumentError)
+ it "raises ArgumentError if difference between argument and result is too large" do
+ zone = Object.new
+ def zone.utc_to_local(t)
+ time = Time.utc(t.year, t.mon, t.day, t.hour, t.min, t.sec, t.utc_offset)
+ time -= 24 * 60 * 60 # - 1 day
+ Time.utc(time.year, time.mon, time.day, time.hour, time.min, time.sec, time.utc_offset)
+ end
+
+ -> {
+ Time.now(in: zone)
+ }.should raise_error(ArgumentError, "utc_offset out of range")
end
end
end
diff --git a/spec/ruby/core/time/shared/time_params.rb b/spec/ruby/core/time/shared/time_params.rb
index b6a6c88c8e..9832fd17fe 100644
--- a/spec/ruby/core/time/shared/time_params.rb
+++ b/spec/ruby/core/time/shared/time_params.rb
@@ -179,6 +179,10 @@ describe :time_params, shared: true do
}.should raise_error(ArgumentError, "argument out of range")
end
+ it "raises ArgumentError when given 8 arguments" do
+ -> { Time.send(@method, *[0]*8) }.should raise_error(ArgumentError)
+ end
+
it "raises ArgumentError when given 9 arguments" do
-> { Time.send(@method, *[0]*9) }.should raise_error(ArgumentError)
end
diff --git a/spec/ruby/core/time/strftime_spec.rb b/spec/ruby/core/time/strftime_spec.rb
index 4cb300c916..fd233f3577 100644
--- a/spec/ruby/core/time/strftime_spec.rb
+++ b/spec/ruby/core/time/strftime_spec.rb
@@ -50,44 +50,42 @@ describe "Time#strftime" do
time.strftime("%::z").should == "+01:01:05"
end
- ruby_version_is "3.1" do
- it "supports RFC 3339 UTC for unknown offset local time, -0000, as %-z" do
- time = Time.gm(2022)
-
- time.strftime("%z").should == "+0000"
- time.strftime("%-z").should == "-0000"
- time.strftime("%-:z").should == "-00:00"
- time.strftime("%-::z").should == "-00:00:00"
- end
+ it "supports RFC 3339 UTC for unknown offset local time, -0000, as %-z" do
+ time = Time.gm(2022)
- it "applies '-' flag to UTC time" do
- time = Time.utc(2022)
- time.strftime("%-z").should == "-0000"
+ time.strftime("%z").should == "+0000"
+ time.strftime("%-z").should == "-0000"
+ time.strftime("%-:z").should == "-00:00"
+ time.strftime("%-::z").should == "-00:00:00"
+ end
- time = Time.gm(2022)
- time.strftime("%-z").should == "-0000"
+ it "applies '-' flag to UTC time" do
+ time = Time.utc(2022)
+ time.strftime("%-z").should == "-0000"
- time = Time.new(2022, 1, 1, 0, 0, 0, "Z")
- time.strftime("%-z").should == "-0000"
+ time = Time.gm(2022)
+ time.strftime("%-z").should == "-0000"
- time = Time.new(2022, 1, 1, 0, 0, 0, "-00:00")
- time.strftime("%-z").should == "-0000"
+ time = Time.new(2022, 1, 1, 0, 0, 0, "Z")
+ time.strftime("%-z").should == "-0000"
- time = Time.new(2022, 1, 1, 0, 0, 0, "+03:00").utc
- time.strftime("%-z").should == "-0000"
- end
+ time = Time.new(2022, 1, 1, 0, 0, 0, "-00:00")
+ time.strftime("%-z").should == "-0000"
- it "ignores '-' flag for non-UTC time" do
- time = Time.new(2022, 1, 1, 0, 0, 0, "+03:00")
- time.strftime("%-z").should == "+0300"
- end
+ time = Time.new(2022, 1, 1, 0, 0, 0, "+03:00").utc
+ time.strftime("%-z").should == "-0000"
+ end
- it "works correctly with width, _ and 0 flags, and :" do
- Time.now.utc.strftime("%-_10z").should == " -000"
- Time.now.utc.strftime("%-10z").should == "-000000000"
- Time.now.utc.strftime("%-010:z").should == "-000000:00"
- Time.now.utc.strftime("%-_10:z").should == " -0:00"
- Time.now.utc.strftime("%-_10::z").should == " -0:00:00"
- end
+ it "ignores '-' flag for non-UTC time" do
+ time = Time.new(2022, 1, 1, 0, 0, 0, "+03:00")
+ time.strftime("%-z").should == "+0300"
+ end
+
+ it "works correctly with width, _ and 0 flags, and :" do
+ Time.now.utc.strftime("%-_10z").should == " -000"
+ Time.now.utc.strftime("%-10z").should == "-000000000"
+ Time.now.utc.strftime("%-010:z").should == "-000000:00"
+ Time.now.utc.strftime("%-_10:z").should == " -0:00"
+ Time.now.utc.strftime("%-_10::z").should == " -0:00:00"
end
end
diff --git a/spec/ruby/core/time/utc_spec.rb b/spec/ruby/core/time/utc_spec.rb
index 566509fd33..ab3c0df657 100644
--- a/spec/ruby/core/time/utc_spec.rb
+++ b/spec/ruby/core/time/utc_spec.rb
@@ -22,10 +22,8 @@ describe "Time#utc?" do
Time.now.localtime("UTC").utc?.should == true
Time.at(Time.now, in: 'UTC').utc?.should == true
- ruby_version_is "3.1" do
- Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").utc?.should == true
- Time.now(in: "UTC").utc?.should == true
- end
+ Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").utc?.should == true
+ Time.now(in: "UTC").utc?.should == true
end
it "does treat time with Z offset as UTC" do
@@ -33,26 +31,26 @@ describe "Time#utc?" do
Time.now.localtime("Z").utc?.should == true
Time.at(Time.now, in: 'Z').utc?.should == true
- ruby_version_is "3.1" do
- Time.new(2022, 1, 1, 0, 0, 0, in: "Z").utc?.should == true
- Time.now(in: "Z").utc?.should == true
- end
+ Time.new(2022, 1, 1, 0, 0, 0, in: "Z").utc?.should == true
+ Time.now(in: "Z").utc?.should == true
end
- ruby_version_is "3.1" do
- it "does treat time with -00:00 offset as UTC" do
- Time.new(2022, 1, 1, 0, 0, 0, "-00:00").utc?.should == true
- Time.now.localtime("-00:00").utc?.should == true
- Time.at(Time.now, in: '-00:00').utc?.should == true
- end
+ it "does treat time with -00:00 offset as UTC" do
+ Time.new(2022, 1, 1, 0, 0, 0, "-00:00").utc?.should == true
+ Time.now.localtime("-00:00").utc?.should == true
+ Time.at(Time.now, in: '-00:00').utc?.should == true
end
it "does not treat time with +00:00 offset as UTC" do
Time.new(2022, 1, 1, 0, 0, 0, "+00:00").utc?.should == false
+ Time.now.localtime("+00:00").utc?.should == false
+ Time.at(Time.now, in: "+00:00").utc?.should == false
end
it "does not treat time with 0 offset as UTC" do
Time.new(2022, 1, 1, 0, 0, 0, 0).utc?.should == false
+ Time.now.localtime(0).utc?.should == false
+ Time.at(Time.now, in: 0).utc?.should == false
end
end
diff --git a/spec/ruby/core/time/zone_spec.rb b/spec/ruby/core/time/zone_spec.rb
index 63c92602d1..9a15bd569b 100644
--- a/spec/ruby/core/time/zone_spec.rb
+++ b/spec/ruby/core/time/zone_spec.rb
@@ -69,22 +69,18 @@ describe "Time#zone" do
Time.at(Time.now, in: 'UTC').zone.should == "UTC"
Time.at(Time.now, in: 'Z').zone.should == "UTC"
- ruby_version_is "3.1" do
- Time.new(2022, 1, 1, 0, 0, 0, "-00:00").zone.should == "UTC"
- Time.now.localtime("-00:00").zone.should == "UTC"
- Time.at(Time.now, in: '-00:00').zone.should == "UTC"
- end
+ Time.new(2022, 1, 1, 0, 0, 0, "-00:00").zone.should == "UTC"
+ Time.now.localtime("-00:00").zone.should == "UTC"
+ Time.at(Time.now, in: '-00:00').zone.should == "UTC"
- ruby_version_is "3.1" do
- Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").zone.should == "UTC"
- Time.new(2022, 1, 1, 0, 0, 0, in: "Z").zone.should == "UTC"
+ Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").zone.should == "UTC"
+ Time.new(2022, 1, 1, 0, 0, 0, in: "Z").zone.should == "UTC"
- Time.now(in: 'UTC').zone.should == "UTC"
- Time.now(in: 'Z').zone.should == "UTC"
+ Time.now(in: 'UTC').zone.should == "UTC"
+ Time.now(in: 'Z').zone.should == "UTC"
- Time.at(Time.now, in: 'UTC').zone.should == "UTC"
- Time.at(Time.now, in: 'Z').zone.should == "UTC"
- end
+ Time.at(Time.now, in: 'UTC').zone.should == "UTC"
+ Time.at(Time.now, in: 'Z').zone.should == "UTC"
end
platform_is_not :aix, :windows do
diff --git a/spec/ruby/core/tracepoint/allow_reentry_spec.rb b/spec/ruby/core/tracepoint/allow_reentry_spec.rb
index 6bff1bed76..75e9e859a9 100644
--- a/spec/ruby/core/tracepoint/allow_reentry_spec.rb
+++ b/spec/ruby/core/tracepoint/allow_reentry_spec.rb
@@ -1,32 +1,30 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "3.1" do
- describe 'TracePoint.allow_reentry' do
- it 'allows the reentrance in a given block' do
- event_lines = []
- l1 = l2 = l3 = l4 = nil
- TracePoint.new(:line) do |tp|
- next unless TracePointSpec.target_thread?
+describe 'TracePoint.allow_reentry' do
+ it 'allows the reentrance in a given block' do
+ event_lines = []
+ l1 = l2 = l3 = l4 = nil
+ TracePoint.new(:line) do |tp|
+ next unless TracePointSpec.target_thread?
- event_lines << tp.lineno
- next if (__LINE__ + 2 .. __LINE__ + 4).cover?(tp.lineno)
- TracePoint.allow_reentry do
- a = 1; l3 = __LINE__
- b = 2; l4 = __LINE__
- end
- end.enable do
- c = 3; l1 = __LINE__
- d = 4; l2 = __LINE__
+ event_lines << tp.lineno
+ next if (__LINE__ + 2 .. __LINE__ + 4).cover?(tp.lineno)
+ TracePoint.allow_reentry do
+ a = 1; l3 = __LINE__
+ b = 2; l4 = __LINE__
end
-
- event_lines.should == [l1, l3, l4, l2, l3, l4]
+ end.enable do
+ c = 3; l1 = __LINE__
+ d = 4; l2 = __LINE__
end
- it 'raises RuntimeError when not called inside a TracePoint' do
- -> {
- TracePoint.allow_reentry{}
- }.should raise_error(RuntimeError)
- end
+ event_lines.should == [l1, l3, l4, l2, l3, l4]
+ end
+
+ it 'raises RuntimeError when not called inside a TracePoint' do
+ -> {
+ TracePoint.allow_reentry{}
+ }.should raise_error(RuntimeError)
end
end
diff --git a/spec/ruby/core/tracepoint/enable_spec.rb b/spec/ruby/core/tracepoint/enable_spec.rb
index 6cc8bb3897..93a6b281e3 100644
--- a/spec/ruby/core/tracepoint/enable_spec.rb
+++ b/spec/ruby/core/tracepoint/enable_spec.rb
@@ -57,50 +57,25 @@ describe 'TracePoint#enable' do
end.enable { event_name.should equal(:line) }
end
- ruby_version_is '3.2' do
- it 'enables the trace object only for the current thread' do
- threads = []
- trace = TracePoint.new(:line) do |tp|
- # Runs on purpose on any Thread
- threads << Thread.current
- end
-
- thread = nil
- trace.enable do
- line_event = true
- thread = Thread.new do
- event_in_other_thread = true
- end
- thread.join
- end
-
- threads = threads.uniq
- threads.should.include?(Thread.current)
- threads.should_not.include?(thread)
+ it 'enables the trace object only for the current thread' do
+ threads = []
+ trace = TracePoint.new(:line) do |tp|
+ # Runs on purpose on any Thread
+ threads << Thread.current
end
- end
- ruby_version_is ''...'3.2' do
- it 'enables the trace object for any thread' do
- threads = []
- trace = TracePoint.new(:line) do |tp|
- # Runs on purpose on any Thread
- threads << Thread.current
- end
-
- thread = nil
- trace.enable do
- line_event = true
- thread = Thread.new do
- event_in_other_thread = true
- end
- thread.join
+ thread = nil
+ trace.enable do
+ line_event = true
+ thread = Thread.new do
+ event_in_other_thread = true
end
-
- threads = threads.uniq
- threads.should.include?(Thread.current)
- threads.should.include?(thread)
+ thread.join
end
+
+ threads = threads.uniq
+ threads.should.include?(Thread.current)
+ threads.should_not.include?(thread)
end
it 'can accept arguments within a block but it should not yield arguments' do
diff --git a/spec/ruby/core/unboundmethod/equal_value_spec.rb b/spec/ruby/core/unboundmethod/equal_value_spec.rb
index 036c6b7f8c..b2d78c50af 100644
--- a/spec/ruby/core/unboundmethod/equal_value_spec.rb
+++ b/spec/ruby/core/unboundmethod/equal_value_spec.rb
@@ -76,38 +76,19 @@ describe "UnboundMethod#==" do
(@identical_body == @original_body).should == false
end
- ruby_version_is ""..."3.2" do
- it "returns false if same method but one extracted from a subclass" do
- (@parent == @child1).should == false
- (@child1 == @parent).should == false
- end
-
- it "returns false if same method but extracted from two different subclasses" do
- (@child2 == @child1).should == false
- (@child1 == @child2).should == false
- end
-
- it "returns false if methods are the same but added from an included Module" do
- (@includee == @includer).should == false
- (@includer == @includee).should == false
- end
+ it "returns true if same method but one extracted from a subclass" do
+ (@parent == @child1).should == true
+ (@child1 == @parent).should == true
end
- ruby_version_is "3.2" do
- it "returns true if same method but one extracted from a subclass" do
- (@parent == @child1).should == true
- (@child1 == @parent).should == true
- end
-
- it "returns false if same method but extracted from two different subclasses" do
- (@child2 == @child1).should == true
- (@child1 == @child2).should == true
- end
+ it "returns true if same method but extracted from two different subclasses" do
+ (@child2 == @child1).should == true
+ (@child1 == @child2).should == true
+ end
- it "returns true if methods are the same but added from an included Module" do
- (@includee == @includer).should == true
- (@includer == @includee).should == true
- end
+ it "returns true if methods are the same but added from an included Module" do
+ (@includee == @includer).should == true
+ (@includer == @includee).should == true
end
it "returns false if both have same Module, same name, identical body but not the same" do
diff --git a/spec/ruby/core/unboundmethod/owner_spec.rb b/spec/ruby/core/unboundmethod/owner_spec.rb
index e8a734dac4..b099c56de1 100644
--- a/spec/ruby/core/unboundmethod/owner_spec.rb
+++ b/spec/ruby/core/unboundmethod/owner_spec.rb
@@ -25,9 +25,7 @@ describe "UnboundMethod#owner" do
child_singleton_class.instance_method(:another_class_method).owner.should == child_singleton_class
end
- ruby_version_is "3.2" do
- it "returns the class on which public was called for a private method in ancestor" do
- MethodSpecs::InheritedMethods::C.instance_method(:derp).owner.should == MethodSpecs::InheritedMethods::C
- end
+ it "returns the class on which public was called for a private method in ancestor" do
+ MethodSpecs::InheritedMethods::C.instance_method(:derp).owner.should == MethodSpecs::InheritedMethods::C
end
end
diff --git a/spec/ruby/core/unboundmethod/private_spec.rb b/spec/ruby/core/unboundmethod/private_spec.rb
index 8ea50bb5d4..5a563939d1 100644
--- a/spec/ruby/core/unboundmethod/private_spec.rb
+++ b/spec/ruby/core/unboundmethod/private_spec.rb
@@ -2,27 +2,8 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "UnboundMethod#private?" do
- ruby_version_is "3.1"..."3.2" do
- it "returns false when the method is public" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_public_method).unbind.private?.should == false
- end
-
- it "returns false when the method is protected" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_protected_method).unbind.private?.should == false
- end
-
- it "returns true when the method is private" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_private_method).unbind.private?.should == true
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_private_method).unbind.should_not.respond_to?(:private?)
- end
+ it "has been removed" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_private_method).unbind.should_not.respond_to?(:private?)
end
end
diff --git a/spec/ruby/core/unboundmethod/protected_spec.rb b/spec/ruby/core/unboundmethod/protected_spec.rb
index 0c215d8638..70622d658d 100644
--- a/spec/ruby/core/unboundmethod/protected_spec.rb
+++ b/spec/ruby/core/unboundmethod/protected_spec.rb
@@ -2,27 +2,8 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "UnboundMethod#protected?" do
- ruby_version_is "3.1"..."3.2" do
- it "returns false when the method is public" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_public_method).unbind.protected?.should == false
- end
-
- it "returns true when the method is protected" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_protected_method).unbind.protected?.should == true
- end
-
- it "returns false when the method is private" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_private_method).unbind.protected?.should == false
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_protected_method).unbind.should_not.respond_to?(:protected?)
- end
+ it "has been removed" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_protected_method).unbind.should_not.respond_to?(:protected?)
end
end
diff --git a/spec/ruby/core/unboundmethod/public_spec.rb b/spec/ruby/core/unboundmethod/public_spec.rb
index 552bbf6eab..ae75e2601c 100644
--- a/spec/ruby/core/unboundmethod/public_spec.rb
+++ b/spec/ruby/core/unboundmethod/public_spec.rb
@@ -2,27 +2,8 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "UnboundMethod#public?" do
- ruby_version_is "3.1"..."3.2" do
- it "returns true when the method is public" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_public_method).unbind.public?.should == true
- end
-
- it "returns false when the method is protected" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_protected_method).unbind.public?.should == false
- end
-
- it "returns false when the method is private" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_private_method).unbind.public?.should == false
- end
- end
-
- ruby_version_is "3.2" do
- it "has been removed" do
- obj = UnboundMethodSpecs::Methods.new
- obj.method(:my_public_method).unbind.should_not.respond_to?(:public?)
- end
+ it "has been removed" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_public_method).unbind.should_not.respond_to?(:public?)
end
end
diff --git a/spec/ruby/core/unboundmethod/shared/dup.rb b/spec/ruby/core/unboundmethod/shared/dup.rb
index 943a7faaa3..194e2cc1a1 100644
--- a/spec/ruby/core/unboundmethod/shared/dup.rb
+++ b/spec/ruby/core/unboundmethod/shared/dup.rb
@@ -16,7 +16,7 @@ describe :unboundmethod_dup, shared: true do
end
it "copies the finalizer" do
- code = <<-RUBY
+ code = <<-'RUBY'
obj = Class.instance_method(:instance_method)
ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" })
diff --git a/spec/ruby/core/unboundmethod/shared/to_s.rb b/spec/ruby/core/unboundmethod/shared/to_s.rb
index b92bb0b207..6b2c9c3e79 100644
--- a/spec/ruby/core/unboundmethod/shared/to_s.rb
+++ b/spec/ruby/core/unboundmethod/shared/to_s.rb
@@ -20,22 +20,11 @@ describe :unboundmethod_to_s, shared: true do
it "the String shows the method name, Module defined in and Module extracted from" do
@from_module.send(@method).should =~ /\bfrom_mod\b/
@from_module.send(@method).should =~ /\bUnboundMethodSpecs::Mod\b/
-
- ruby_version_is ""..."3.2" do
- @from_method.send(@method).should =~ /\bUnboundMethodSpecs::Methods\b/
- end
end
it "returns a String including all details" do
- ruby_version_is ""..."3.2" do
- @from_module.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Methods(UnboundMethodSpecs::Mod)#from_mod"
- @from_method.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Methods(UnboundMethodSpecs::Mod)#from_mod"
- end
-
- ruby_version_is "3.2" do
- @from_module.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod"
- @from_method.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod"
- end
+ @from_module.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod"
+ @from_method.send(@method).should.start_with? "#<UnboundMethod: UnboundMethodSpecs::Mod#from_mod"
end
it "does not show the defining module if it is the same as the origin" do
diff --git a/spec/ruby/core/unboundmethod/source_location_spec.rb b/spec/ruby/core/unboundmethod/source_location_spec.rb
index 5c2f14362c..9cc2198017 100644
--- a/spec/ruby/core/unboundmethod/source_location_spec.rb
+++ b/spec/ruby/core/unboundmethod/source_location_spec.rb
@@ -7,23 +7,23 @@ describe "UnboundMethod#source_location" do
end
it "sets the first value to the path of the file in which the method was defined" do
- file = @method.source_location.first
+ file = @method.source_location[0]
file.should be_an_instance_of(String)
file.should == File.realpath('fixtures/classes.rb', __dir__)
end
- it "sets the last value to an Integer representing the line on which the method was defined" do
- line = @method.source_location.last
+ it "sets the second value to an Integer representing the line on which the method was defined" do
+ line = @method.source_location[1]
line.should be_an_instance_of(Integer)
line.should == 5
end
it "returns the last place the method was defined" do
- UnboundMethodSpecs::SourceLocation.method(:redefined).unbind.source_location.last.should == 13
+ UnboundMethodSpecs::SourceLocation.method(:redefined).unbind.source_location[1].should == 13
end
it "returns the location of the original method even if it was aliased" do
- UnboundMethodSpecs::SourceLocation.instance_method(:aka).source_location.last.should == 17
+ UnboundMethodSpecs::SourceLocation.instance_method(:aka).source_location[1].should == 17
end
it "works for define_method methods" do
@@ -54,6 +54,12 @@ describe "UnboundMethod#source_location" do
c = Class.new do
eval('def m; end', nil, "foo", 100)
end
- c.instance_method(:m).source_location.should == ["foo", 100]
+ location = c.instance_method(:m).source_location
+ ruby_version_is(""..."4.1") do
+ location.should == ["foo", 100]
+ end
+ ruby_version_is("4.1") do
+ location.should == ["foo", 100, 0, 100, 10]
+ end
end
end
diff --git a/spec/ruby/core/warning/categories_spec.rb b/spec/ruby/core/warning/categories_spec.rb
new file mode 100644
index 0000000000..1e310ef38b
--- /dev/null
+++ b/spec/ruby/core/warning/categories_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.4" do
+ describe "Warning.categories" do
+ # There might be more, but these are standard across Ruby implementations
+ it "returns the list of possible warning categories" do
+ Warning.categories.should.include? :deprecated
+ Warning.categories.should.include? :experimental
+ Warning.categories.should.include? :performance
+ end
+ end
+end
diff --git a/spec/ruby/core/warning/warn_spec.rb b/spec/ruby/core/warning/warn_spec.rb
index 572885c2b4..2e4a822e02 100644
--- a/spec/ruby/core/warning/warn_spec.rb
+++ b/spec/ruby/core/warning/warn_spec.rb
@@ -97,6 +97,20 @@ describe "Warning.warn" do
end
end
+ ruby_version_is "3.4" do
+ it "warns when category is :strict_unused_block but Warning[:strict_unused_block] is false" do
+ warn_strict_unused_block = Warning[:strict_unused_block]
+ Warning[:strict_unused_block] = true
+ begin
+ -> {
+ Warning.warn("foo", category: :strict_unused_block)
+ }.should complain("foo")
+ ensure
+ Warning[:strict_unused_block] = warn_strict_unused_block
+ end
+ end
+ end
+
it "doesn't print message when category is :deprecated but Warning[:deprecated] is false" do
warn_deprecated = Warning[:deprecated]
Warning[:deprecated] = false
@@ -121,6 +135,20 @@ describe "Warning.warn" do
end
end
+ ruby_version_is "3.4" do
+ it "doesn't print message when category is :strict_unused_block but Warning[:strict_unused_block] is false" do
+ warn_strict_unused_block = Warning[:strict_unused_block]
+ Warning[:strict_unused_block] = false
+ begin
+ -> {
+ Warning.warn("foo", category: :strict_unused_block)
+ }.should_not complain
+ ensure
+ Warning[:strict_unused_block] = warn_strict_unused_block
+ end
+ end
+ end
+
ruby_bug '#20573', ''...'3.4' do
it "isn't called by Kernel.warn when category is :deprecated but Warning[:deprecated] is false" do
warn_deprecated = Warning[:deprecated]